
过去在做企业级知识库和智能体项目时团队里最常争论的问题不是“选哪个大模型”而是“LLM 到底应该怎么接进现有系统”。不同框架各有侧重本地部署和 API 调用又各有适用场景再加上团队里有人提到“LLMs and Xfwl4”这种工程代号时新人往往一脸茫然。这篇文章就围绕大语言模型LLM在实际项目中的落地路径展开结合 LLM 框架选型、多模态工作流部署结构以及业务系统集成时容易踩的坑整理一份较完整的实操笔记。适合正在做 LLM 应用开发、需要从零搭建知识问答或智能体服务以及在本地和云端之间做技术选型的开发者。1. 背景与核心概念1.1 什么是 LLMLLM 是 Large Language Model 的缩写中文通常翻译为“大语言模型”。它本质上是基于海量文本数据训练出来的深度神经网络模型能够根据输入的文本内容预测并生成后续文本。2023 年以来以 GPT 系列、Llama 系列、ChatGLM 系列、Qwen 系列为代表的大语言模型逐步走入工程应用不再只是研究机构的实验品。通俗一点理解LLM 的输入是一段文字输出也是一段文字。你可以问它“帮我写一封请假邮件”它能给出完整回复你可以给它一段长文档让它总结要点你也可以在代码里调用它的接口让程序自动完成文本分类、实体抽取、信息检索等任务。但这里有一个关键认知需要提前建立LLM 并不是数据库也不是搜索引擎。它并不“存储”你的私有文档也不能保证每次输出完全准确。它只是在做“概率化的文本生成”。因此在实际工程中我们需要通过检索增强生成RAG、提示词工程、模型微调等手段让 LLM 在可控范围内输出更可靠的结果。1.2 Xfwl4 在本文中的定位Xfwl4 并不是大语言模型领域里的公开通用术语但在不少企业内部项目中它经常被用作某一代业务系统的代号例如“知识服务系统 4.0”“信息处理平台 4.0”的缩写。这里我以 Xfwl4 代指一类“面向业务场景的 LLM 知识服务系统”通俗说就是第四代基于 LLM 的信息处理架构。这类系统的常见能力包括多格式文档解析PDF、Word、Markdown、PPT向量化存储与语义检索基于 LLM 的自动问答与内容生成与现有业务系统对接通过 API 提供 AI 能力支持多模态输入文本、图片、语音转写结果把 LLM 和 Xfwl4 放在一起本质上就是在讨论如何把大语言模型真正嵌入到业务系统里让它从“聊天机器人”变成“生产力工具”。这是很多开发者从“调通 API”到“完成项目交付”之间必须跨越的一道坎。1.3 为什么 LLM 应用开发需要系统化教程网上关于 LLM 的教程很多但大部分停留在“调用一个 API 拿到返回结果”的层面。真正做项目时会发现以下几个问题几乎无法回避框架选型困难。LangChain、LlamaIndex、Spring AI、Haystack 各有特点到底选哪个模型部署方式多样。云端 API、私有化部署、本地推理、边缘设备部署成本和效果差异巨大。多模态流程复杂。当 LLM 与图像生成、音频处理等模型配合时部署拓扑会直接影响性能和资源占用。生产环境问题多。上下文长度限制、Token 计费、响应延迟、流式输出、内容安全、日志追踪每一个都要处理。因此本文将以“从零搭建一套 LLM 知识服务系统Xfwl4 架构”为主线逐步讲解模型选择、框架使用、服务部署和问题排查帮助读者建立一套可复用的 LLM 工程化方法论。2. 环境准备与版本说明2.1 硬件与操作系统在开始之前需要先确认你的运行环境。LLM 应用开发不像普通 Web 开发那么轻量尤其是本地部署模型时对硬件有一定要求。本文示例的环境如下项目说明操作系统Windows 11 / Ubuntu 20.04 / macOS 12CPU4 核以上内存16 GB 以上推荐 32 GBGPU可选NVIDIA 显卡显存 8 GB 以上Python 版本3.10 或 3.11包管理工具pip 或 conda容器化工具可选Docker 20.10如果你的机器没有独立显卡也可以完成本文的大部分示例。没有 GPU 时建议直接调用云端模型 API或者在 CPU 上运行较小的模型例如 Qwen2.5-0.5B-Instruct、ChatGLM3-6B 的 CPU 推理版本体验完整流程后再考虑性能优化。2.2 Python 环境安装推荐使用 conda 创建独立的 Python 环境避免依赖冲突。conda create -n llm-xfwl4 python3.11 conda activate llm-xfwl4如果你更习惯使用 venv也可以这样操作python3.11 -m venv llm-xfwl4-env source llm-xfwl4-env/bin/activate2.3 模型与框架版本策略在写本文时大语言模型和开发框架的版本迭代非常快。为了不让教程内容迅速失效这里不锁定某个绝对版本号而是给出一个相对稳定的版本组合思路开发框架LangChain 0.2.x 或 0.3.x 均可API 变化不是特别大如果项目已经使用了 LlamaIndex则保持团队内统一。模型 API优先使用 OpenAI 兼容接口例如 OpenAI、DeepSeek、Qwen DashScope、Ollama 提供的兼容服务这样方便切换供应商。向量数据库Chroma 或 FAISS 足够用于学习和中小项目生产环境再考虑 Milvus、pgvector、Elasticsearch。本地推理工具Ollama 对新手最友好支持一键拉取模型。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。2.4 推荐的项目结构一个成熟的 LLM 应用项目建议从一开始就按模块拆分llm-xfwl4/ ├── app/ │ ├── main.py # FastAPI 入口 │ ├── config.py # 全局配置 │ ├── models/ # 数据模型定义 │ ├── services/ # LLM 调用与业务逻辑 │ ├── vector_store/ # 向量库相关操作 │ └── utils/ # 工具函数 ├── data/ # 本地文档与测试数据 ├── scripts/ # 初始化脚本 ├── requirements.txt ├── .env # 环境变量注意加入 .gitignore └── README.md本文后面的示例会围绕这个结构展开但不会把每个文件都写出来只保留最能说明问题的主干代码。3. LLM 核心原理与框架拆解3.1 从 Token 到上下文窗口无论使用哪个 LLM都绕不开 Token 这个概念。Token 是模型处理文本的基本单位可以理解为“词元”。英文通常一个单词拆成 1 到 2 个 Token中文通常一个字或一个词对应 1 到 2 个 Token。模型每一次请求能接受的 Token 总数是有限的这个上限称为“上下文窗口”。举个例子如果某个模型的上下文窗口是 128K Token那么在对话中用户输入的 Prompt、历史对话记录以及模型生成的回复三者的总 Token 数不能超过这个上限。超过后要么截断要么报错。这直接影响了我们的程序设计。在开发 LLM 应用时需要自己管理上下文例如把历史对话窗口限制为最近 10 轮。在送入模型前修剪过长的文档片段。使用摘要压缩历史信息。3.2 Prompt 提示词设计Prompt 是用户输入给模型的指令。好的 Prompt 能把模型的输出质量提升一个档次而不需要修改任何模型参数。一个标准的业务 Prompt 通常包含以下部分角色设定告诉模型你是谁例如“你是一名资深的 Java 后端工程师”。任务描述说明你要模型做什么例如“根据给定的需求文档生成接口设计”。输入数据你要分析或处理的文本内容。输出格式要求例如“用 JSON 格式返回包含 name 和 reason 字段”。边界与限制例如“不要编造数据不确定时回复未知”。示例system_prompt 你是一名知识库问答助手。 请严格根据以下资料回答问题不要编造资料中不存在的信息。 如果资料中没有答案请回答资料中未找到相关信息。 资料内容 {context} 用户问题 {question} 请用简洁的中文回答。3.3 RAG 检索增强生成RAG 是当前 LLM 应用落地最主流的方案。它的核心思路是“先检索再生成”。当用户提出问题时系统不是直接把问题丢给模型而是先从文档库中检索出相关片段再把片段和问题一起传给模型。这样做的好处很明显模型可以引用你的私有知识而不是依赖训练数据。减少模型“一本正经地胡说八道”。可以随时更新知识库不用重新训练模型。一个简单的 RAG 流程如下文档加载与切分文本向量化向量存入向量库用户提问问题向量化检索相似片段构造 Prompt调用 LLM 生成回答3.4 主流 LLM 框架对比在实际项目中我们通常会借助框架来简化开发。目前比较常见的有框架优点适用场景LangChain生态完善组件丰富文档多快速搭建 RAG、Agent、对话应用LlamaIndex数据索引和检索能力更强文档问答、知识库、数据密集型应用Spring AIJava 技术栈友好与 Spring Boot 集成自然Java 后端团队的 AI 功能集成Haystack生产级 NLP 流水线支持中文搜索、问答、文档处理流水线Dify / FastGPT低代码可视化内置知识库和 Agent产品和运营团队快速搭建 AI 应用选型建议如果你的团队以 Python 为主且需要快速验证 AI 能力选 LangChain 或 LlamaIndex。如果团队是 Java 背景建议选 Spring AI降低学习成本。如果目标是快速做一个可演示的 AI 应用不写太多代码Dify 这类平台更合适。4. 大语言模型部署与调用实战本章将演示一个完整的“LLM 知识问答服务”核心流程并重点说明本地部署与云端 API 的区别。由于完整代码很长这里给出主干实现读者可以根据自己的模型供应商和框架版本做适配。4.1 使用 OpenAI 兼容接口调用云端模型目前国内外的模型厂商大多提供 OpenAI 兼容的 HTTP 接口所以代码通常可以写成一套底层地址和 API Key 换一下即可。# 文件路径app/services/llm_client.py import os from openai import OpenAI client OpenAI( api_keyos.getenv(LLM_API_KEY), base_urlos.getenv(LLM_BASE_URL, https://api.openai.com/v1), ) def chat_completion(prompt: str, system_prompt: str , temperature: float 0.3): messages [] if system_prompt: messages.append({role: system, content: system_prompt}) messages.append({role: user, content: prompt}) resp client.chat.completions.create( modelos.getenv(LLM_MODEL_NAME, gpt-4o-mini), messagesmessages, temperaturetemperature, ) return resp.choices[0].message.content这里有几个关键参数需要了解model模型名称具体值以模型供应商提供为准。temperature控制随机性值越大回答越随机0 到 1 之间。知识问答场景建议调低比如 0.2。max_tokens限制生成的最大 Token 数防止输出过长。stream是否流式返回适合聊天界面逐字输出。调用示例result chat_completion( system_prompt你是一个简洁的助手。, prompt用一句话解释什么是 RAG。 ) print(result)预期输出示例RAG 是一种将信息检索与文本生成结合的方法先生成中先从外部知识库检索相关内容再交给大模型生成回答。4.2 使用 Ollama 部署本地模型本地部署的核心价值在于数据不出内网、不产生 Token 费用、离线可用。Ollama 是目前最简单的方式之一。安装 Ollama 后在终端执行ollama pull qwen2.5:7b ollama run qwen2.5:7b执行完第二条命令后会进入交互式对话说明本地推理服务已经正常运行。Ollama 默认提供了一个 OpenAI 兼容接口地址为http://localhost:11434/v1。因此你可以复用刚才的代码只需要修改环境变量export LLM_BASE_URLhttp://localhost:11434/v1 export LLM_API_KEYollama export LLM_MODEL_NAMEqwen2.5:7b这种设计非常方便。开发时用云端模型部署到内网时切成本地模型业务代码几乎不需要改动。4.3 构建一个最简单的 RAG 问答服务下面演示一个基于 LangChain、Chroma 和 LLM 的本地 RAG 服务核心逻辑。首先安装依赖pip install langchain langchain-community langchain-openai chromadb fastapi uvicorn python-dotenv这里说明一下langchain-community包含了很多第三方集成langchain-openai负责 OpenAI 兼容接口的封装chromadb是向量数据库fastapi和uvicorn用于搭建接口服务。初始化向量库# 文件路径scripts/init_vector_store.py from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma # 1. 加载文档 loader TextLoader(data/company_manual.txt, encodingutf-8) documents loader.load() # 2. 切分文档 splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , , , ] ) chunks splitter.split_documents(documents) # 3. 向量化并入库 embeddings OpenAIEmbeddings( modeltext-embedding-3-small, base_urlhttp://localhost:11434/v1, api_keyollama ) # 如果使用 OpenAI 云端则不必传 base_url 和 api_key vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db ) print(f已处理 {len(chunks)} 个文本块向量库初始化完成。)这里需要特别注意的是切分策略。chunk_size500表示每块文本大约 500 个字符chunk_overlap50表示相邻块之间有 50 个字符的重叠目的是避免因为切分位置不当导致语义断裂。中文文档的切分最好把中文标点也纳入分隔符否则会出现一段话被硬切到两个 chunk 的情况。然后写一个检索问答函数# 文件路径app/services/rag_service.py from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.vectorstores import Chroma from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough # 初始化组件 embeddings OpenAIEmbeddings( modeltext-embedding-3-small, base_urlhttp://localhost:11434/v1, api_keyollama ) vectorstore Chroma( persist_directory./chroma_db, embedding_functionembeddings ) retriever vectorstore.as_retriever(search_kwargs{k: 4}) llm ChatOpenAI( modelqwen2.5:7b, base_urlhttp://localhost:11434/v1, api_keyollama ) prompt ChatPromptTemplate.from_template( 请根据以下资料回答问题如果资料中没有答案请回答“资料中未找到相关信息”。 资料 {context} 问题 {question} ) rag_chain ( {context: retriever, question: RunnablePassthrough()} | prompt | llm | StrOutputParser() ) def ask_question(question: str) - str: return rag_chain.invoke(question)调用示例result ask_question(公司请病假需要提前多久申请) print(result)4.4 使用 FastAPI 对外提供接口为了让其他系统可以调用我们可以用 FastAPI 包一层 HTTP 接口。# 文件路径app/main.py from fastapi import FastAPI from pydantic import BaseModel from app.services.rag_service import ask_question app FastAPI(titleLLM Xfwl4 知识服务) class QuestionRequest(BaseModel): question: str class AnswerResponse(BaseModel): answer: str app.post(/api/ask, response_modelAnswerResponse) def ask(req: QuestionRequest): answer ask_question(req.question) return AnswerResponse(answeranswer) if __name__ __main__: import uvicorn uvicorn.run(app, host0.0.0.0, port8000)启动服务uvicorn app.main:app --host 0.0.0.0 --port 8000测试接口curl -X POST http://localhost:8000/api/ask \ -H Content-Type: application/json \ -d {question: 公司请病假需要提前多久申请}预期会返回一个 JSON{answer: 根据公司员工手册请病假需要在就诊当天通过 OA 系统提交申请并上传医院开具的病假证明。}到这里一个最小可用的 LLM 知识问答服务就已经跑起来了。它结合了本地文档解析、向量检索、Prompt 构造和 LLM 推理是 Xfwl4 架构里最核心的闭环。5. ComfyUI 与 LLM 的部署关系5.1 ComfyUI 是什么ComfyUI 是一个基于节点工作流的多模态生成工具常用于 Stable Diffusion 等图像生成模型的流程编排。它允许用户把“加载模型”“文本编码”“采样”“解码”“保存图片”等步骤用节点连接起来形成可视化工作流。5.2 LLM 与 ComfyUI 是否必须部署在同一台机器这是很多做多模态应用的同学都会遇到的问题“ComfyUI 与 LLM 必须在同一台电脑上么”答案是否定的。它们不需要在同一台电脑上。两者之间可以通过 HTTP API、消息队列或共享存储进行通信。典型的部署方式有两种方式一同机部署适合个人开发和单机演示。优点是延迟低传输方便。缺点是显存和内存争抢严重启动多个模型容易导致 OOM。方式二分布式部署LLM 服务部署在一台 GPU 服务器ComfyUI 部署在另一台 GPU 服务器。业务后端通过 API 调用两边。优点是资源隔离、可按需扩容。缺点是网络传输会增加一定延迟需要设计好超时和重试机制。在实际项目中更推荐把它们作为独立的微服务通过 API 网关统一暴露能力。例如用户在聊天窗口输入“生成一张赛博朋克风格的猫咪图片”后端先调用 LLM 理解意图、生成英文 Prompt再把 Prompt 传给 ComfyUI 的 API 生成图片最后把图片 URL 返回给前端。整个链路中LLM 和 ComfyUI 各自独立部署互不依赖。5.3 多模态工作流的简单示例这里给出一个简化版的多模态调度思路不依赖具体框架。# 伪代码仅供参考需按实际接口调整 def handle_multimodal_request(user_text: str): # 第一步LLM 判断意图并生成图像描述 image_prompt llm_client.chat( system_prompt你是图像提示词专家。, promptf根据用户请求生成英文图像提示词{user_text} ) # 第二步调用 ComfyUI 工作流接口 comfy_response requests.post( http://comfy-server:8188/prompt, json{ prompt: { 3: { class_type: CLIPTextEncode, inputs: { text: image_prompt, clip: [4, 0] } }, # 其他节点略 } } ) # 第三步轮询任务结果并返回图片地址 return poll_comfy_result(comfy_response.json().get(prompt_id))从这个示例可以看出LLM 和 ComfyUI 只是通过 API 交互完全不需要部署在同一台电脑上。真正需要关心的是接口稳定性、任务队列和图片存储。6. 常见问题与排查思路在 LLM 应用开发中下面这些报错和现象出现频率非常高。我整理成表格方便快速排查。问题现象常见原因解决思路请求超时模型推理时间长或网络不稳定增加超时时间使用流式输出检查网络连通性返回内容为空Prompt 未触发输出或 max_tokens 过小检查 Prompt调大 max_tokens尝试 temperature 设为 0上下文长度超限输入文本太长对文档做更细切分使用摘要压缩限制历史对话轮数回答与资料无关检索到的片段不相关优化切分策略增加检索数量 k尝试换 embedding 模型本地模型推理慢无 GPU 或显存不足换更小模型使用量化版本升级硬件乱码或中英文混杂模型对中文支持不佳或 Prompt 未指定语言在 Prompt 中明确“请用简体中文回答”换中文优化模型向量库数据更新后不生效向量库未重新构建确认持久化路径重新执行初始化脚本注意缓存同时给出一个通用排查顺序先隔离问题层次是调用报错、返回异常还是结果质量差打印完整的请求和响应日志包括 Prompt 和输出。用一个非常简单的 Prompt 测试模型本身是否正常工作。逐步加回你的业务 Prompt定位是哪一步引入了问题。如果是 RAG 问题先检查检索结果再检查生成结果。7. 最佳实践与工程建议7.1 配置管理不要把 API Key 写在代码里更不要提交到 Git 仓库。建议统一使用.env文件管理配置并把.env加入.gitignore。# .env 示例 LLM_BASE_URLhttp://localhost:11434/v1 LLM_API_KEYsk-xxx LLM_MODEL_NAMEqwen2.5:7b EMBEDDING_MODELtext-embedding-3-small VECTOR_DB_PATH./chroma_db在 Python 中使用python-dotenv加载from dotenv import load_dotenv load_dotenv()7.2 上下文与 Token 管理生产环境中必须建立 Token 监控机制。每次请求后记录 Token 使用量用于成本评估和性能调优。def chat_completion_with_usage(prompt: str): resp client.chat.completions.create( modelos.getenv(LLM_MODEL_NAME, gpt-4o-mini), messages[{role: user, content: prompt}], temperature0.2 ) # 记录 usage print(prompt_tokens:, resp.usage.prompt_tokens) print(completion_tokens:, resp.usage.completion_tokens) return resp.choices[0].message.content同时尽量把历史对话保存在 Redis 或数据库中而不是在内存中无限增长。根据业务场景设置会话过期时间例如 30 分钟无操作则清理上下文。7.3 安全与权限在涉及 LLM 的系统中需要注意以下几点API Key 的访问权限要最小化。对用户输入要做长度限制和内容格式校验防止超长文本攻击。对模型输出要做基础的内容过滤避免生成不合规内容直接展示给用户。如果系统对接外部 API要设计好鉴权、限流和审计日志。不要在日志中打印完整的 Prompt因为其中的上下文可能包含敏感业务数据。7.4 可观测性把一个 LLM 应用投入生产之前至少需要记录以下指标请求耗时总 Token 数模型名称与版本返回状态码错误类型检索结果数量与来源文档推荐使用结构化日志例如 JSON 格式方便后续接入 ELK 或 Loki 等日志系统。7.5 模型与框架版本锁定LLM 领域版本变化很快建议在requirements.txt或锁文件中锁定框架版本避免自动升级后行为不一致。langchain0.3.7 langchain-openai0.2.14 chromadb0.5.15 fastapi0.115.6 openai1.55.3同时在模型侧也要记录模型版本。例如使用 Qwen 时qwen2.5:7b和qwen2.5:7b-instruct行为不同升级前要做回归测试。7.6 不要把 Agent 和 RAG 混为一谈RAG 解决的是“从资料中找到答案”的问题Agent 解决的是“根据目标自主决策并调用工具”的问题。两者可以结合但在架构设计上要区分开。很多团队一开始就把系统做成“全能 Agent”结果调试成本极高。建议优先用确定性流程实现 RAG再逐步向 Agent 演进。8. 总结与学习路线本文从 LLM 的基本概念出发围绕 Xfwl4 知识服务系统的构建介绍了 Token、Prompt、RAG、本地部署、云端调用、向量检索、FastAPI 接口开发、ComfyUI 与 LLM 的分布式部署等核心内容。如果你完整走完了上面几个示例你应该已经具备搭建一个最小可用的 LLM 问答服务的能力同时理解了不同部署方式对资源、成本和数据安全的影响。接下来可以继续深入的方向有三个第一学习 Agent 开发理解函数调用Function Calling和工具使用第二学习微调掌握如何让模型适配特定领域的表达风格第三学习向量数据库优化包括混合检索、重排序和召回率评估。每一个方向都是一块独立且深入的知识领域实际项目中往往需要组合使用。最后给你一个实用建议刚开始做 LLM 应用时不要追求一次到位先把一个最简单的问答闭环跑通再逐步加入权限、日志、监控和更多模型能力。这样即使在开发中遇到问题也能快速定位原因不会在一堆复杂组件中迷失方向。