1. 为什么我要把 RAG 从 Demo 推到生产RAG 这个词在过去一年里被聊烂了但真正在企业内部把它跑通、跑稳、跑出业务价值的人并不多。我所在的团队从去年下半年开始陆续接了三个知识库问答项目从最开始的 LangChain 快速原型到后来自己拆链路、换向量库、加图谱、做评测踩的坑几乎覆盖了 RAG 全流程。这篇文章不讲概念科普只讲落地一个 RAG 系统从零到上线到底要经过哪些步骤每一步的决策依据是什么哪些地方最容易翻车。先说清楚 RAG 解决的核心问题。大模型本身的知识是冻结的训练数据有截止时间企业内部文档、产品手册、工单记录这些私有知识它一概不知道。微调成本高、更新慢而且容易灾难性遗忘。RAG 的思路很直接把外部知识存进一个可检索的库用户提问时先检索出相关片段拼进提示词让模型基于这些片段回答。这样知识可以随时更新答案有出处幻觉也能压下去。但“检索增强生成”这五个字拆开来看检索、增强、生成每一环都有坑。检索召回不准后面全白搭增强时上下文拼得乱七八糟模型直接跑偏生成阶段没有约束模型照样编。我见过太多团队卡在“Demo 效果惊艳上线后用户骂街”这个阶段。下面我按实际落地顺序把完整步骤和踩坑记录摊开讲。2. 落地前的整体设计与技术选型2.1 先想清楚你的 RAG 到底服务什么场景这一步最容易被跳过但恰恰决定了后面所有技术选型。RAG 不是万能锤不同场景对检索精度、响应延迟、知识更新频率的要求完全不同。我一般把场景分成三类。第一类是事实型问答比如“年假怎么申请”“产品保修期多久”答案在文档里是明确的一句话或一段话检索到就能答。这类场景对召回率要求高对生成能力要求低甚至可以用抽取式方法直接返回原文。第二类是分析型问答比如“最近三个月客户投诉集中在哪些功能”需要跨多篇文档聚合信息这时候单纯向量检索不够得考虑图谱或结构化查询。第三类是多轮对话型用户会追问、会指代检索时要带上对话历史做查询改写。我踩过的第一个大坑就是拿事实型场景的方案去套分析型场景。当时用纯向量检索做“对比 A 产品和 B 产品的差异”结果每次只召回单篇文档的片段模型只能看到 A 或 B 的一半信息答案永远不完整。后来加了 GraphRAG 的思路把产品、功能、版本做成实体关系图才把跨文档聚合做起来。提示在写第一行代码之前先拿 20 个真实用户问题做人工标注标出每个问题的答案在哪些文档、需要几跳推理。这个标注集后面就是你的评测基准没有它你根本不知道系统是好是坏。2.2 技术栈选型别一上来就上最复杂的网上热词里提到的 LangChain4j、Ollama、GraphRAG、Agentic RAG都是好东西但不是每个项目都需要。我的选型原则是从最简链路开始哪里不够补哪里。基础链路我一般这样搭文档解析用 unstructured 或 pymupdf切分用递归字符切分向量化用 bge-m3 或 text-embedding-3-large向量库用 Milvus 或 Qdrant编排用 LangChain 或直接自己写。这套组合足够跑通 80% 的事实型场景。什么时候需要升级如果发现召回率上不去先别急着换模型先看切分策略和查询改写。如果发现跨文档推理不行再考虑 GraphRAG。如果发现需要多步工具调用比如先查数据库再查文档才上 Agentic RAG。我见过一个团队场景就是查产品手册硬上了 Agent 框架结果延迟从 800ms 涨到 4s用户直接弃用。关于本地化部署Ollama 确实让本地跑模型变得简单但要注意本地小模型的生成质量和大模型差距明显。我的做法是检索和向量化用本地模型保证数据不出域生成环节如果合规允许走 API 调大模型如果必须全本地那就得在提示词工程和上下文压缩上花更多功夫。2.3 评测体系没有度量就没有优化这是我最想强调的一点。RAG 落地最大的误区是“凭感觉调”。今天觉得召回不好换个切分参数明天觉得答案不对改改提示词。改来改去不知道是变好了还是变差了。必须建评测集。我一般分两层检索层看 Hit Rate 和 MRR生成层看忠实度和答案相关性。检索层的标注相对客观就是看标准答案所在的片段有没有被召回排在第几位。生成层可以用 LLM 做裁判但裁判提示词要反复调不然它自己都判不准。我实际用的评测流程是这样的准备 100 到 200 个问答对每个问题标注标准答案和出处文档。跑完检索后计算 Hit Rate5、Hit Rate10、MRR。生成层用 GPT-4 或 Claude 做裁判给忠实度和相关性打分。每次改动只动一个变量跑完评测对比。这套流程听起来笨但它是唯一能让你知道“这次改动到底有没有用”的方法。3. 文档处理与切分RAG 的地基3.1 文档解析PDF 是永远的痛企业文档里 PDF 占大头而 PDF 解析是 RAG 第一道坎。扫描件要 OCR双栏排版会串行表格会散架页眉页脚会混进正文。我试过 pypdf、pdfplumber、pymupdf、unstructured没有一个能通吃。我的经验是分情况处理。文字型 PDF用 pymupdf 提取速度快版面保留好。扫描型 PDF走 OCRPaddleOCR 中文效果好但慢建议离线批量跑。表格多的 PDF单独用 camelot 或 tabula 抽表格转成 Markdown 再进切分流程。双栏学术论文用 layoutparser 做版面分析按栏切分。这里有个细节页眉页脚一定要去掉。我遇到过一份产品手册每页页脚都有“版权所有 翻印必究”切分后每个片段都带着这句话检索时疯狂命中把真正的内容挤下去了。处理方法是统计每页重复出现的文本行出现频率超过阈值的直接删。注意文档解析阶段丢的信息后面任何环节都补不回来。宁可解析慢一点也要保证正文完整。我一般会抽 10 份文档人工比对解析结果确认没有大面积丢失才继续。3.2 切分策略不是越小越好也不是越大越好切分是 RAG 里最玄学的环节。切太大检索精度下降噪声多切太小语义不完整模型看不懂。网上教程一般说 512 或 1000 个 token但实际要看文档类型。我的切分策略是分层切分。先按文档结构切比如 Markdown 按标题层级HTML 按 DOM 树PDF 按章节。然后在结构块内部按语义切用句子边界或语义相似度做断点。最后加重叠窗口一般重叠 10% 到 20%防止关键信息被切断。具体参数上技术文档我一般用 300 到 500 token 的块因为技术概念密集小块检索准。叙述型文档用 800 到 1000 token因为需要上下文才能理解。代码块单独处理不切分整块保留。还有个热词里提到的“本地 RAG 文本拆解工具”我试过几个说实话效果参差。比较靠谱的是用 spaCy 做句子分割再按语义相似度合并。但最稳的还是针对你的文档类型写规则通用工具很难适配所有场景。3.3 元数据被低估的检索利器很多人切完就完了元数据一概不留。这是巨大的浪费。元数据在检索时可以做过滤大幅提升精度。我一般保留这些元数据文档标题、章节路径、页码、文档类型、更新时间、权限标签。检索时可以先按权限过滤再按时间排序再做向量检索。比如用户问“最新的报销政策”时间过滤就能把旧版本排除掉。更进一步可以把章节路径拼进片段文本里。比如“第三章 报销流程 3.2 差旅报销 3.2.1 交通费标准”这样片段本身就带上下文检索和生成都更准。我实测下来加章节路径能让 Hit Rate 提升 5 到 10 个百分点。4. 检索环节召回不准一切归零4.1 向量检索的局限与补救向量检索擅长语义匹配但有几个硬伤。第一精确匹配差用户问“X200 型号”向量可能召回“X100”“X300”因为语义相近。第二长尾实体弱罕见词、专有名词的向量表示不好。第三否定和条件用户问“不含酒精的饮料”向量可能召回含酒精的因为语义主体是饮料。补救方法是混合检索。向量检索加 BM25 关键词检索两路结果融合。融合算法用 RRF倒数排名融合最简单效果也稳。我一般向量召回 top 20BM25 召回 top 20RRF 融合后取 top 10 进重排。BM25 对精确匹配和长尾实体特别有效。我做过对比纯向量 Hit Rate5 是 72%加 BM25 后到 85%。这个提升在事实型场景里是决定性的。4.2 查询改写让用户的问题更好检索用户的问题往往口语化、有指代、缺上下文。直接拿去做检索效果打折。查询改写就是先把问题“翻译”成适合检索的形式。我常用的改写策略有几种。指代消解多轮对话里“它”“这个”要替换成具体实体。查询扩展把“报销”扩展成“报销 流程 标准 材料”。查询分解复杂问题拆成多个子问题分别检索。HyDE让模型先“幻想”一个答案再用答案去检索适合短查询。这里有个坑改写不是越多越好。我试过用大模型做多轮改写结果改写后的查询偏离原意召回反而变差。后来改成规则加轻量模型只在检测到指代或查询过短时才触发改写效果稳定很多。4.3 重排把最相关的顶上来检索召回 top 20 后真正相关的可能只有 3 到 5 个。重排模型的作用就是把这几个挑出来排到最前面。重排模型我用过 bge-reranker 和 Cohere Rerank。bge-reranker 本地跑免费效果不错。Cohere Rerank 效果更好但收费。选型看预算和数据合规要求。重排的收益很明显。我实测 Hit Rate3 从 68% 提升到 82%。但代价是延迟增加重排 20 个片段大概增加 200 到 500ms。如果场景对延迟敏感可以减少重排数量或者用更轻量的重排模型。提示重排模型和向量模型最好来自同一家族比如都用 bge 系列语义空间一致效果更稳。混用不同家族的模型有时候会互相打架。4.4 检索参数调优用数据说话检索环节的参数很多top_k、相似度阈值、RRF 的 k 值、重排的 top_n。这些参数不能拍脑袋定要用评测集跑。我的调参流程是固定其他变量只调一个参数跑评测画曲线找拐点。比如 top_k从 5 跑到 50看 Hit Rate 和延迟的权衡。一般 Hit Rate 在 top_k20 左右趋于平缓再往上收益递减延迟却线性增长。相似度阈值也很关键。设太低噪声进来设太高漏召回。我一般先用 0.5 做基线然后看评测集里漏召回和误召回的比例再微调。不同向量模型的相似度分布不一样不能直接套用别人的阈值。5. 生成环节让模型基于证据说话5.1 上下文组装顺序和格式都有讲究检索出片段后怎么拼进提示词直接影响生成质量。我踩过的坑包括片段顺序乱、片段之间没有分隔、片段太长把关键信息挤掉。我的做法是按相关性排序最相关的放最前面和最后面因为模型对首尾信息更敏感。加明确分隔符每个片段用[文档1][文档2]标号方便模型引用。控制总长度一般不超过模型上下文窗口的 60%留空间给系统提示和用户问题。去重相似度高的片段合并避免重复信息占位。还有个细节片段里如果有表格或代码要保留格式。我试过把表格拍平成文本模型理解能力直线下降。后来改成保留 Markdown 表格效果好很多。5.2 提示词设计约束比指令更重要RAG 的提示词核心就一句话基于给定资料回答资料没有就说不知道。但怎么写这句话效果差别很大。我的提示词模板一般包含这几块角色定义、资料说明、回答规则、引用要求、兜底话术。角色定义让模型知道自己是知识库助手。资料说明告诉模型资料可能不完整。回答规则要求基于资料、不许编造、不确定就明说。引用要求让模型标出答案来自哪个片段。兜底话术是当资料不足时的标准回复。这里有个反直觉的经验不要过度强调“必须基于资料”。我试过把这句话写得很重结果模型变得过于保守资料里明明有答案它却说“资料未提及”。后来改成“优先基于资料资料不足时可结合常识但需说明”效果好很多。5.3 幻觉抑制RAG 不是万能药RAG 能降低幻觉但不能消除。我见过模型把检索到的两个片段拼接起来编出一个资料里没有的结论。也见过模型忽略检索结果直接用自己的知识回答。抑制幻觉的手段有几个。引用溯源要求模型每个结论都标出处没有出处的结论人工复核。忠实度评测用 LLM 裁判检查答案是否完全来自资料。温度调低生成时 temperature 设 0 到 0.3减少随机性。后置校验答案生成后再做一次检索检查关键实体是否在资料中出现。我实际项目里忠实度能到 90% 左右剩下 10% 主要是多跳推理时模型自己“补全”了逻辑。这部分目前没有完美解法只能靠人工抽检和用户反馈持续优化。6. 进阶方案GraphRAG 与 Agentic RAG 的取舍6.1 GraphRAG什么时候值得上GraphRAG 的核心是把文档里的实体和关系抽出来建成知识图谱检索时走图查询。它擅长跨文档聚合、多跳推理、全局性问题。但 GraphRAG 的成本很高。实体抽取要用大模型建图慢更新麻烦。我做过一个项目5000 篇文档建图跑了整整两天而且抽取质量不稳定实体对齐经常出错。我的判断标准是如果纯向量加 BM25 能解决 80% 的问题就不上 GraphRAG。只有当用户频繁问“A 和 B 有什么关系”“哪些文档提到了 C 且与 D 相关”这类问题时GraphRAG 才值得投入。而且建议先用轻量方案比如把实体关系存成三元组检索时做简单的图遍历不要一上来就上 Neo4j 加复杂图算法。6.2 Agentic RAG多步推理的代价Agentic RAG 是让模型自己决定检索什么、检索几次、要不要调工具。适合复杂任务比如“对比三个产品的优缺点并给出推荐”。但 Agent 的延迟和成本是硬伤。每次工具调用都是一次模型推理多步下来延迟轻松上秒级。而且 Agent 的行为不稳定同样的输入可能走不同的路径评测和调试都难。我的建议是只在明确需要多步推理的场景用 Agentic RAG且要加最大步数限制和超时兜底。大部分知识库问答单轮检索加生成就够了。我见过太多项目为了“技术先进”上 Agent结果用户体验还不如简单链路。7. 常见问题与排查技巧实录7.1 召回不准的排查路径召回不准是最常见的问题。我的排查顺序是先看文档解析有没有丢内容再看切分有没有切断关键信息再看查询改写有没有跑偏最后看检索参数和模型。具体操作上我会拿一个失败案例把它的检索结果打出来人工看标准答案在不在召回列表里。如果在但排名靠后是重排问题如果不在是召回问题。召回问题再往下拆是向量模型不行还是 BM25 没生效还是查询本身有问题。有个隐蔽的坑向量库的索引类型。有些向量库默认用 IVF 索引召回率不如 HNSW。如果发现召回率莫名偏低检查一下索引配置。我遇到过换索引类型后 Hit Rate 提升 15% 的情况。7.2 答案不完整的排查路径答案不完整通常是上下文组装的问题。检查点包括检索片段数量够不够、片段顺序对不对、总长度有没有超、关键片段有没有被截断。我遇到过一个案例用户问“退款流程”检索到了正确片段但片段被截断了只保留了前半部分后半部分的关键步骤丢了。原因是切分时按固定长度切没考虑句子边界。后来改成按句子边界切问题解决。还有个情况是多跳问题只检索了一跳。用户问“A 产品的保修政策”答案需要先找到 A 产品属于哪个系列再找该系列的保修政策。单轮检索只能召回其中一篇。这种要么做查询分解要么上 GraphRAG。7.3 延迟过高的优化手段延迟高一般来自几个环节向量检索、重排、生成。优化要分环节定位。向量检索慢检查索引类型和向量维度。HNSW 比 IVF 快低维度比高维度快。如果数据量不大可以考虑用 FAISS 本地索引比服务化向量库快。重排慢减少重排数量或者换轻量模型。我一般重排 top 20如果延迟敏感就降到 top 10。生成慢换更小的模型或者用流式输出让用户先看到部分结果。流式输出对感知延迟改善很大用户看到字在往外蹦就不觉得慢了。7.4 常见问题速查表问题现象可能原因排查方法解决手段召回率低切分过大/过小人工检查召回片段调整切分参数加重叠精确匹配差纯向量检索测试关键词查询加 BM25 混合检索答案编造提示词约束弱检查忠实度评分加强引用要求降温度多跳失败单轮检索局限分析问题推理链查询分解或 GraphRAG延迟高重排或生成慢分环节计时减重排数量流式输出更新不及时索引未重建检查文档更新时间增量索引定时重建8. 上线后的持续运营RAG 上线不是终点是起点。用户的问题分布会变文档会更新模型会迭代。没有持续运营系统会慢慢退化。我一般做三件事。日志分析每周看用户问了什么、哪些问题没答好、哪些片段被频繁召回。bad case 复盘把失败案例归类是检索问题还是生成问题针对性优化。评测回归每次改动跑一遍评测集确保没有退化。还有个实用技巧让用户反馈。在答案旁边加“有用/没用”按钮收集反馈数据。这些数据是最真实的评测集比人工构造的更有价值。我有个项目靠用户反馈发现了一批文档解析错误修复后满意度提升了 20%。最后分享一个我踩过的最大的坑不要一次性把所有文档都灌进去。我早期项目把整个共享盘的文件全索引了结果大量过期文档、草稿、重复文件混在里面检索噪声极大。后来改成按业务线分批接入每批都做质量审核效果立竿见影。RAG 的质量从源头就决定了。