
RAG 这个词现在确实被说烂了。随便打开一个技术社区满屏都是“十分钟搭建你的第一个 RAG”“RAG 从入门到精通”“手把手教你做企业知识库”。但如果你真的在生产环境里跑过几个 RAG 项目就会发现一个很尴尬的事实Demo 阶段效果惊艳上线之后用户骂声一片。答非所问、检索不到、胡编乱造、多跳问题直接崩盘——这些问题几乎每个做过 RAG 的人都遇到过。问题出在哪我的判断是烂大街的从来不是 RAG 这个技术方向而是那条“文档切块 → 向量化 → 余弦相似度检索 → 塞进 Prompt”的流水线。这条流水线在 2023 年被无数教程复制粘贴成了 RAG 的“标准答案”。但它本质上只是一个最朴素的基线方案离“能用”还差得远离“好用”差得更远。真正拉开差距的是流水线之外的六个地方。这六处分水岭决定了一个 RAG 系统是停留在玩具阶段还是能扛住真实业务场景的考验。下面我按自己的实战经验把这六处逐一拆开讲每一处都会说清楚“为什么流水线在这里会断”“正确的做法是什么”“实操中怎么落地”。1. 第一处分水岭检索粒度——你的 chunk 到底该切多大1.1 固定长度切块为什么必然翻车几乎所有入门教程都会告诉你把文档按 512 个 token 切一块重叠 50 个 token。这个做法不是错而是太粗糙。它假设“语义单元”和“字符长度”是对齐的但现实里根本不是这么回事。我拿一份典型的技术文档举例。一个完整的 API 说明可能包含接口用途、请求参数表、返回字段说明、错误码列表、调用示例。如果你按固定长度切很可能出现这种情况——参数表被从中间切断前半截在 chunk 3后半截在 chunk 4调用示例的代码块被切碎检索出来的是半段代码。用户问“这个接口的 timeout 参数怎么设”检索到的 chunk 里只有参数名没有说明模型只能靠猜。更隐蔽的问题是固定切块会破坏“上下文依赖”。比如文档里写“该参数默认为 30 秒超过此值将触发重试机制”这里的“该参数”指代的是上一段提到的某个字段。切块之后指代关系断了检索出来的片段孤立无援模型理解不了。1.2 语义切块与结构切块的实际取舍正确的做法是让切块边界对齐语义边界。具体来说有三种策略我按推荐程度排序结构切块优先。如果原始文档有明确结构Markdown 标题、HTML 标签、PDF 的章节层级直接按结构切。一个二级标题下的内容作为一个 chunk如果太长再按段落细分。这样做的好处是每个 chunk 天然自带主题检索时语义聚焦度高。我用 Markdown 文档测试过结构切块比固定切块的检索命中率高出 20 个百分点以上。语义切块兜底。对于没有明显结构的纯文本用嵌入模型计算相邻句子的相似度在相似度骤降的地方切一刀。这个方法的成本是要多跑一遍嵌入计算但效果比固定切块好很多。实操中我会设一个阈值比如相邻句子余弦相似度低于 0.6 就切块。混合策略。结构切块为主结构内部如果单块超过 800 token再用语义切块细分。这是我在生产环境里用得最多的方案。1.3 小块检索、大块生成一个被低估的技巧这里有一个很实用的技巧叫“小块检索、大块生成”。具体做法是索引的时候存小 chunk比如 256 token保证检索精度但检索命中之后把该 chunk 所属的父块比如 1024 token一起取出来送给模型。这样既保证了检索的准确性又给模型提供了足够的上下文。实现上很简单给每个小 chunk 存一个 parent_id检索到小 chunk 后根据 parent_id 取父块内容。这个技巧在处理长文档时特别管用我实测能把答案完整度提升一大截。注意父块不能无限大。我的经验是父块控制在 1500 token 以内再大就会引入太多噪声反而干扰模型判断。2. 第二处分水岭检索方式——向量检索只是起点不是终点2.1 纯向量检索的三个致命盲区向量检索的核心是“语义相似”但它有三个绕不过去的盲区第一精确匹配失效。用户问“错误码 E5023 是什么意思”向量检索可能返回一堆讲错误处理的段落但就是找不到精确包含“E5023”的那一段。因为嵌入模型对数字、代号、专有名词的区分度很低。第二关键词权重丢失。向量检索把整句话压成一个稠密向量句子里每个词的重要性被平均化了。但实际检索中某些关键词的权重应该远高于其他词。第三长尾查询表现差。对于训练数据里少见的表达方式嵌入模型给出的向量可能偏离语义空间导致检索结果莫名其妙。2.2 混合检索的工程实现细节解决方案是混合检索向量检索 关键词检索BM25 或 SPLADE然后做融合排序。融合算法我推荐 RRFReciprocal Rank Fusion它不依赖两路检索的分数可比性只依赖排名工程上最稳。具体流程是向量检索取 Top 20BM25 取 Top 20用 RRF 融合后取 Top 10再送重排序。RRF 的公式很简单每个文档的得分等于它在各路检索中排名的倒数之和。排名越靠前贡献越大。这里有个实操细节BM25 的分词器要针对中文优化。默认的英文分词器对中文是按字切的效果很差。我一般用 jieba 分词并且把业务领域的专有名词加进自定义词典比如产品名、接口名、错误码前缀。2.3 重排序模型性价比最高的一步优化如果说混合检索是“广撒网”那重排序就是“精挑选”。重排序模型Reranker是一个交叉编码器它把 query 和每个候选文档拼在一起打分精度远高于向量相似度。代价是计算量大所以只能对少量候选做。我的标准配置是混合检索召回 Top 50重排序取 Top 5 送给模型。这一步的投入产出比极高基本上加一个重排序模型答案准确率能提升 15% 到 30%。常用的重排序模型有 BGE-Reranker 系列、Cohere Rerank 等中文场景我推荐 BGE-Reranker-v2-m3效果稳定。检索方式优势盲区适用场景纯向量检索语义理解强精确匹配差、关键词丢失概念性、描述性问题BM25 关键词精确匹配强无法理解同义表达代号、错误码、专有名词混合检索RRF兼顾两者需要调参绝大多数生产场景加重排序精度最高增加延迟对准确率要求高的场景3. 第三处分水岭上下文增强——Contextual Retrieval 到底解决了什么3.1 孤立 chunk 的“指代丢失”问题前面提到固定切块会破坏上下文其实即使切块切得再好chunk 一旦脱离原文就会丢失大量隐含信息。举个例子原文写“该公司第三季度营收同比增长 15%主要得益于新产品的市场表现”。如果这个 chunk 被单独检索出来用户问“哪家公司”模型根本不知道。因为“该公司”的指代对象在上一段。这就是 Contextual Retrieval 要解决的核心问题给每个 chunk 补充它所属的上下文信息让 chunk 即使孤立存在也能被正确理解。3.2 用 LLM 给每个 chunk 写“上下文摘要”Contextual Retrieval 的做法是在索引之前用 LLM 为每个 chunk 生成一段简短的上下文说明然后把这段说明拼接到 chunk 前面一起做嵌入。比如上面那个例子LLM 会生成“本段讨论的是 XX 公司 2024 年第三季度财报”拼接后 chunk 就自带了主体信息。这个方法的成本在于每个 chunk 都要调一次 LLM。对于大规模文档库这是一笔不小的开销。我的优化做法是按文档批量处理把整篇文档作为背景一次性为文档内所有 chunk 生成上下文说明这样能摊薄 token 成本。另外可以用小模型比如 7B 级别的来做这件事效果够用成本低很多。3.3 上下文增强的边界什么时候不该用Contextual Retrieval 不是万能的。有两种情况我建议慎用一是文档本身高度独立、chunk 之间没有强依赖关系比如 FAQ 列表、独立的知识条目。这种情况下补充上下文反而可能引入噪声。二是对延迟极度敏感的场景。因为索引阶段多了 LLM 调用虽然不影响查询延迟但会拉长索引构建时间。如果文档更新频繁这个成本要算进去。提示Contextual Retrieval 的收益在“文档内部指代多、跨段落依赖强”的场景下最大比如技术手册、法律合同、研究报告。FAQ 类文档收益有限。4. 第四处分水岭知识组织——从扁平向量库到 GraphRAG 与本体4.1 扁平向量库为什么回答不了多跳问题向量库本质是一个扁平的键值存储它擅长“找相似”但不擅长“找关联”。当用户的问题需要多跳推理时扁平结构就崩了。举个典型的多跳问题“A 公司的 CEO 毕业于哪所大学”要回答这个问题需要两步第一步找到 A 公司的 CEO 是谁第二步找到这个人的毕业院校。如果知识库里“A 公司-CEO-张三”和“张三-毕业院校-XX大学”分别存在不同的 chunk 里向量检索可能只召回其中一个模型就答不全。4.2 GraphRAG 的实体关系抽取与社区摘要GraphRAG 的思路是把知识组织成图节点是实体边是关系。构建过程是用 LLM 从文档中抽取实体和关系构建知识图谱然后对图做社区检测为每个社区生成摘要。查询时既可以用图遍历做多跳推理也可以用社区摘要做全局性回答。GraphRAG 的优势在于它能回答“全局性”问题比如“这份文档库主要讲了哪几个主题”。纯向量检索对这类问题几乎无能为力因为它只能返回局部片段。而 GraphRAG 的社区摘要天然就是全局视角。但 GraphRAG 的代价也很明显构建成本高大量 LLM 调用、更新困难图结构变动牵一发动全身、实现复杂。我的建议是只有当业务确实存在大量多跳查询和全局性查询需求时才上 GraphRAG。否则混合检索加好的切块策略已经够用。4.3 本体与知识库结构什么时候需要人工建模比 GraphRAG 更进一步的是引入本体Ontology也就是人工定义领域内的实体类型、关系类型和约束规则。比如在医疗领域定义“疾病-症状-药物-禁忌”这套关系模式抽取时按这个模式来。本体的价值在于“约束”。LLM 自由抽取实体关系时容易抽出一堆同义重复、粒度不一的东西。有了本体约束抽取结果更规范图结构更干净。但本体的成本是人工建模需要领域专家参与。我的经验是通用场景用 GraphRAG 自动抽取就够了垂直领域、对准确性要求极高的场景值得投入做本体。另外本体和 RAG 结合还有一个用法用本体来指导检索路由比如识别出 query 问的是“药物禁忌”就只检索禁忌相关的子图。知识组织方式构建成本多跳能力全局问答适用场景扁平向量库低弱弱简单问答、FAQ向量库元数据过滤中中弱有明确分类的知识库GraphRAG高强强多跳推理、全局分析本体RAG很高强强垂直领域、高准确要求5. 第五处分水岭Agentic RAG——让检索变成主动行为5.1 单次检索的天花板在哪里标准 RAG 是“一次检索一次生成”。这个模式的天花板很低如果第一次检索没召回正确内容整个回答就废了。而且它无法处理需要多轮检索的问题比如“先查 A 再根据 A 的结果查 B”。更麻烦的是有些问题需要判断“要不要检索”。比如用户说“你好”根本不需要检索直接回复就行。但标准 RAG 会无脑检索一遍浪费资源还可能引入噪声。5.2 查询改写、分解与自我反思的落地方式Agentic RAG 的核心是让模型自己决定检索策略。具体包含几个能力查询改写。用户的问题往往口语化、有歧义直接拿去检索效果差。先让 LLM 把问题改写成更适合检索的形式。比如“那个报错咋回事”改写成“XX 系统报错 E5023 的原因和解决方法”。查询分解。对于复杂问题拆成多个子问题分别检索。比如“对比 A 和 B 两个方案的优缺点”拆成“A 方案的优缺点”和“B 方案的优缺点”两个子查询。自我反思。检索回来之后让模型判断“这些内容够不够回答问题”。如果不够触发第二轮检索可能换个查询词或者换个知识源。工具路由。判断问题该走哪个知识源是查向量库还是查数据库还是调 API还是直接回答。5.3 多轮检索的成本控制与终止条件Agentic RAG 最大的风险是“无限循环”和“成本失控”。模型可能反复检索就是不给出答案。我的做法是设硬性终止条件最多检索 3 轮每轮最多召回 10 个片段总 token 预算设上限。超过就强制生成并在回答里标注“信息可能不完整”。另外不是所有问题都值得走 Agentic 流程。我会先用一个轻量分类器判断问题复杂度简单问题走标准 RAG复杂问题才走 Agentic。这样能控制平均成本。提示Agentic RAG 的调试比标准 RAG 难得多因为多了很多 LLM 决策环节。建议先把标准 RAG 调好再逐步加 Agent 能力一次加一个方便定位问题。6. 第六处分水岭评估与迭代——没有度量就没有优化6.1 为什么“感觉还行”是 RAG 最大的敌人我见过太多团队RAG 上线之后靠“用户反馈”来判断好坏。用户不骂就认为没问题。这是最危险的做法。因为 RAG 的错误往往是“静默”的模型答得很流畅但内容是错的用户如果不熟悉领域根本发现不了。没有量化评估你根本不知道改动是变好了还是变差了。今天调了切块大小明天换了嵌入模型效果全靠感觉最后就是一团乱麻。6.2 检索指标与生成指标要分开测RAG 的评估必须拆成两段检索质量和生成质量。检索指标看RecallK前 K 个结果里有没有正确文档、MRR正确文档排在第几位、NDCG排序质量。这些指标衡量的是“该找的有没有找到排得对不对”。生成指标看忠实度回答是否基于检索内容没有胡编、答案相关性是否回答了问题、完整性关键信息有没有遗漏。忠实度尤其重要它是 RAG 的底线。实操中我会建一个测试集包含 100 到 200 个真实问题每个问题标注正确答案和对应的源文档。每次改动都跑一遍测试集看指标变化。这个投入是值得的它让优化从“玄学”变成“工程”。6.3 用 LLM 做评估RAGAS 类框架的实操心得人工标注测试集成本高可以用 LLM 做自动评估。RAGAS 是这类框架里比较成熟的它用 LLM 来打分计算忠实度、答案相关性等指标。但 LLM 评估有个坑它本身也会出错尤其是对领域专业内容。我的做法是LLM 评估做日常迭代的快速反馈人工评估做关键节点的校准。两者结合既保证效率又保证准确。另外评估集要定期更新。业务在变用户问题在变半年前的测试集可能已经不代表当前场景了。我一般每季度补充一批新问题进测试集。评估维度具体指标测量方式优化方向检索质量RecallK、MRR标注测试集切块、嵌入模型、混合检索生成忠实度FaithfulnessLLM 评估人工抽检Prompt 约束、重排序答案相关性Answer RelevancyLLM 评估查询改写、上下文质量端到端用户满意度线上反馈综合优化7. 这六处之外还有两个容易被忽略的工程细节7.1 图片和表格RAG 知识库能存图片吗经常有人问 RAG 知识库能不能存图片。答案是能但方式有讲究。纯向量库存的是文本嵌入图片本身存不进去。常见做法有两种一是用多模态嵌入模型把图片转成向量和文本向量放同一个空间二是用 LLM 对图片生成描述文本把描述文本入库。表格的处理更麻烦。表格直接转文本会丢失结构信息。我的做法是小表格转成 Markdown 保留结构大表格拆成“表头行”的形式每行作为一个独立条目并带上表头信息。这样检索时能精确定位到某一行。7.2 增量更新文档变了怎么办生产环境的文档是不断更新的。全量重建索引成本太高必须支持增量更新。这里的关键是维护好文档 ID 和 chunk ID 的映射关系。文档更新时先删除该文档对应的所有旧 chunk再插入新 chunk。如果是 GraphRAG还要处理图结构的增量更新这个更复杂一般建议批量更新而非实时更新。注意增量更新时要注意嵌入模型的一致性。如果中途换了嵌入模型新旧向量不在同一空间检索会出问题。换模型必须全量重建。8. 我的实战配置清单说了这么多给一份我目前在用的配置供参考切块结构切块为主单块 256 到 512 token父块 1024 token嵌入模型BGE-M3中文场景支持多语言和长文本检索向量 BM25 混合RRF 融合召回 Top 50重排序BGE-Reranker-v2-m3取 Top 5上下文增强对技术文档启用 Contextual Retrieval知识组织普通场景扁平向量库元数据过滤复杂场景上 GraphRAGAgent 能力查询改写必开多轮检索按需最多 3 轮评估RAGAS 日常跑人工季度校准这套配置不是最优解但是我在多个项目里验证过的稳定方案。具体到你的场景切块大小、召回数量这些参数都要根据实际数据调。没有银弹只有不断迭代。最后说一句我的真实体会RAG 的难点从来不在“搭起来”而在“调得好”。那条流水线人人都会搭但真正决定效果的是上面这六处的细节打磨。把每一处都做扎实RAG 才能从 Demo 变成产品。