
1. 从“流水线”说起为什么大多数 RAG 项目止步于 Demo这两年但凡沾点 AI 的应用十有八九会挂上一个“知识库问答”的标签。你随便打开一个技术社区搜“RAG 实战”出来的教程几乎是一个模子刻出来的文档加载、文本切块、向量化、存进向量库、检索 Top-K、拼进 Prompt、调模型生成。这条链路本身没错问题是它太标准了标准到任何人花一个下午就能跑通也标准到任何人跑通之后都会发现——效果也就那样。我前前后后参与过七八个 RAG 相关的项目从内部文档助手到面向客户的智能客服踩过的坑足够写一本小册子。最深的感受是RAG 的门槛从来不在“搭起来”而在“调得好”。那条流水线只是入场券真正决定一个 RAG 系统是能用还是不能用、是玩具还是产品的是流水线之外的那些东西。标题里说的“分水岭在这六处”指的就是这些流水线覆盖不到、但直接决定成败的关键环节。我把它拆成六个维度切块策略、检索质量、上下文组织、知识结构化、智能体编排、评估与迭代。这六处每一处都有人栽跟头每一处也都有成熟的应对思路。下面我逐个展开结合我自己踩过的坑和验证过的方案尽量讲透。先说清楚这篇文章适合谁看如果你已经跑通过最基础的 RAG 链路但发现回答质量不稳定、检索经常召回无关内容、或者面对复杂问题模型总是答非所问那这篇就是写给你的。如果你还没搭过建议先找个教程把基础链路跑一遍再回来看收获会更大。2. 分水岭一切块策略决定了检索的天花板2.1 固定长度切块为什么是灾难几乎所有入门教程都会教你用RecursiveCharacterTextSplitter设个chunk_size500、chunk_overlap50然后就开始检索。这个做法在 Demo 阶段没问题但一旦文档结构复杂一点问题立刻暴露。我做过一个实验拿一份 80 页的产品需求文档用固定 500 字符切块然后问“这个产品的付费流程是怎样的”。检索回来的 Top-5 里有三块是流程图旁边的说明文字一块是目录页只有一块真正讲付费逻辑而且被从中间截断了——前半段在上一块后半段在下一块。模型拿到这种上下文能答对才怪。固定长度切块的根本问题在于它假设“语义单元”和“字符长度”是对齐的但现实里这两者几乎从不重合。一个完整的操作步骤可能只有 80 个字而一段背景介绍可能有 800 个字。你用一个固定尺子去量所有内容必然会把该在一起的切开把不该在一起的粘上。2.2 按语义和结构切块的具体做法我的经验是切块策略要分三层来设计。第一层是结构感知。如果文档本身有标题层级Markdown、HTML、Word 的大纲就优先按标题切。一级标题下的内容作为一个大块二级标题下作为子块这样天然保留了文档的逻辑结构。LangChain 里的MarkdownHeaderTextSplitter就是干这个的它会根据#、##、###把文档拆成带元数据的块检索时还能按标题过滤。第二层是语义切块。对于没有明显结构的纯文本可以用语义相似度来判断切点。思路很简单把文本按句子拆开计算相邻句子的 embedding 相似度相似度骤降的地方就是话题切换点在那里切。这个方法的代码量不大但效果比固定长度好很多。我实测下来同样一份文档语义切块的检索命中率能提升 20% 到 30%。第三层是父子块Parent-Child。这是我觉得最实用的一个技巧检索时用小块比如 200 字符去匹配保证精度但送给模型的是小块所属的父块比如 1500 字符保证上下文完整。这样既解决了“小块信息不全”的问题又解决了“大块检索不准”的问题。实现上就是在切块时记录每个小块的parent_id检索到小块后回溯取父块内容。注意父子块方案会增加存储和检索的复杂度如果你的文档量不大比如几百页以内收益可能不明显但文档量上千页之后这个方案几乎是必选项。2.3 切块参数怎么定一个可复用的计算过程很多人问chunk_size到底设多少。我的做法是反推先看你的 embedding 模型的最大输入长度再看你的典型问题需要多少上下文才能回答。举个例子假设你用某个支持 512 token 的 embedding 模型中文大概 1 token 对应 1.5 到 2 个字符那单块上限大概在 700 到 1000 字符。但这是上限不是最优值。我通常会从 300 到 500 字符起步然后做 A/B 测试准备 20 个典型问题分别用不同 chunk_size 跑检索看 Top-5 的召回率和准确率。实测下来中文技术文档的最佳区间通常在 300 到 600 字符之间overlap 设在 chunk_size 的 10% 到 20%。还有一个容易被忽略的点不同文档类型要用不同策略。FAQ 类文档一条问答就是一个天然块不要切API 文档按接口切教程类文档按步骤切。一刀切是懒人的做法效果也必然是懒人的效果。3. 分水岭二检索质量别只盯着向量相似度3.1 纯向量检索的三个致命缺陷向量检索很强大但它不是万能的。我在实际项目里总结出它的三个硬伤。第一个是关键词失配。用户问“ERR_4032 怎么解决”向量检索可能召回一堆讲“权限错误”的文档但真正包含这个错误码的那一页反而排在第 8 位。因为 embedding 模型对这类精确标识符的区分度很低它更擅长捕捉语义不擅长匹配字面。第二个是多跳问题。用户问“A 功能和 B 功能有什么区别”答案可能分散在两份文档里向量检索只会返回和问题最相似的那一块另一块可能因为表述差异被漏掉。第三个是否定和条件失效。用户问“哪些情况不需要配置 SSL”向量检索会把所有讲 SSL 配置的文档都召回来因为它捕捉到的是“SSL 配置”这个语义而不是“不需要”这个条件。3.2 混合检索的落地配置解决前两个问题的标准答案是混合检索Hybrid Search向量检索 关键词检索BM25然后做融合排序。这个方案现在主流向量库基本都支持比如 Milvus、Qdrant、Weaviate 都有内置的 hybrid 接口。具体配置上我的经验是向量检索和 BM25 各取 Top-20然后用 RRFReciprocal Rank Fusion融合取融合后的 Top-5 送给模型。RRF 的公式很简单就是score Σ 1/(k rank)k 一般取 60。这个方法的妙处在于它不需要调权重对两路检索的分数尺度不敏感实测比加权求和稳定得多。如果向量库不支持 RRF也可以用加权求和但权重要调。我的起步值是向量 0.7、BM25 0.3然后根据测试集微调。技术文档、法律文书这类精确性要求高的场景BM25 的权重可以提到 0.4 到 0.5。3.3 重排序检索质量的最后一道闸混合检索解决了召回问题但排序问题还在。Top-20 里可能混着不少相关但不精准的内容直接送给模型会干扰生成。这时候就需要重排序Rerank。Rerank 模型和 embedding 模型的区别在于embedding 是双塔结构问题和文档分别编码速度快但精度有限Rerank 是交叉编码问题和文档一起送进模型打分速度慢但精度高。所以标准做法是用 embedding 做粗筛召回 20 到 50 条用 Rerank 做精排选出 3 到 5 条。我常用的 Rerank 方案是 BGE-Reranker 系列中文场景效果很稳。部署上可以用FlagEmbedding库几行代码就能跑起来。实测下来加了 Rerank 之后Top-3 的准确率能提升 15% 到 25%尤其是那些“看起来相关但实际不相关”的干扰项基本都能被压下去。提示Rerank 会增加延迟一般每条 50 到 100 毫秒。如果你的场景对延迟敏感比如实时对话可以把候选集缩小到 10 到 15 条或者用更小的 Rerank 模型。3.4 Contextual Retrieval给每个块补上“它从哪来”这是 Anthropic 提出来的一个思路我觉得特别值得单独讲。核心想法是在切块之后、向量化之前用 LLM 给每个块生成一段简短的上下文说明然后把这段说明拼在块前面一起向量化。举个例子原文里有一块内容是“该参数默认为 30 秒超过后会自动重试”。单独看这块你不知道“该参数”是什么参数。Contextual Retrieval 会让 LLM 根据整篇文档生成一句“这段讲的是 API 超时参数 timeout 的默认值和重试行为”拼上去之后这块的向量就带上了明确的语义指向检索时更容易被正确的问题命中。这个方法的成本在于每个块都要调一次 LLM文档量大时费用不低。我的优化做法是只对检索效果差的块做 contextual 增强或者用更小更便宜的模型来做这件事。实测下来Contextual Retrieval 能把检索失败率降低 30% 以上对于问答类场景性价比很高。4. 分水岭三上下文组织别把检索结果一股脑塞进去4.1 上下文窗口不是越大越好很多人有个误区既然模型支持 128K 上下文那就把检索到的 20 条全塞进去让模型自己挑。这个做法有两个问题。第一是成本。上下文越长token 消耗越大延迟也越高。20 条 500 字的块就是 1 万字加上系统提示和对话历史轻松突破 2 万 token。按现在的 API 价格一次问答几毛钱量大了就是一笔不小的开销。第二是干扰。模型不是越给越多就答得越好。研究表明当上下文里混入大量无关信息时模型的注意力会被稀释反而更容易答错。这就是所谓的“lost in the middle”现象模型对上下文开头和结尾的信息记得牢中间的信息容易被忽略。4.2 上下文压缩与重组的实操我的做法是先压缩再重组。压缩有两层一是用 Rerank 把候选压到 3 到 5 条二是对每条内容做摘要或抽取只保留和问题相关的部分。具体操作上可以用 LLM 对每个检索块做一次“相关性抽取”给它问题和块内容让它输出块里和问题相关的句子。这样能把 500 字的块压到 100 到 200 字既保留了关键信息又减少了干扰。这个步骤会增加一次 LLM 调用但省下来的上下文成本通常能覆盖掉。重组则是指按逻辑顺序排列上下文。不要按检索分数排而是按内容之间的逻辑关系排。比如先放背景再放具体步骤最后放注意事项。如果检索结果里有相互矛盾的内容要在 Prompt 里明确提示模型注意区分。4.3 引用溯源让模型说清楚“这话从哪来”这是产品化 RAG 的必备能力。用户看到答案之后第一反应往往是“这是真的吗”如果系统能给出引用来源可信度立刻提升一个档次。实现上在拼接上下文时给每个块编号然后在 Prompt 里要求模型在生成时标注引用编号。比如“根据 [1] 和 [3]付费流程分为三步……”。生成之后再解析这些编号映射回原始文档和位置前端就能做成可点击的引用链接。这个功能看起来简单但要做好不容易。常见问题是模型不按格式标注或者标注了错误的编号。我的经验是在 Prompt 里给一两个 few-shot 示例明确格式要求同时在解析时做容错编号对不上就降级为不显示引用不要让整个回答崩掉。5. 分水岭四知识结构化GraphRAG 和 Ontology 的真正价值5.1 向量库解决不了的关系问题向量库擅长的是“找相似”不擅长“找关系”。用户问“A 模块依赖哪些其他模块”向量检索会召回所有提到 A 模块的文档但依赖关系是散落在各处的模型需要自己拼。如果依赖关系复杂一点模型很容易拼错或漏掉。这就是知识图谱要解决的问题。GraphRAG 的核心思路是把文档里的实体和关系抽出来建成图检索时既查向量也查图把图上的关联路径作为上下文补充给模型。5.2 GraphRAG 的落地路径与成本GraphRAG 听起来高大上但落地成本不低。微软的 GraphRAG 方案需要先用 LLM 对全量文档做实体和关系抽取这个过程的 token 消耗可能是文档本身的几十倍。一份 100 万字的文档抽取成本可能上千块。我的建议是分阶段上。第一阶段先做轻量版只对核心实体比如产品名、功能名、关键概念做抽取建一个简单的实体-关系图检索时用实体做一跳或两跳扩展。这个成本可控效果也能覆盖大部分关系型问题。第二阶段再考虑全量抽取和社区摘要。如果预算有限还有一个更轻的方案用元数据做结构化。在切块时给每个块打上标签比如所属模块、文档类型、更新时间。检索时先按标签过滤再做向量检索。这个方案不需要建图但能解决很大一部分“范围限定”类的问题。5.3 Ontology 在 RAG 里的实际作用Ontology本体这个词听起来很学术但在 RAG 里它的作用很实在定义你的领域里有哪些概念、概念之间有什么关系、每个概念有哪些属性。举个例子做一个医疗知识库Ontology 会定义“疾病”“症状”“药物”“检查”这几类实体以及“疾病-症状”“疾病-药物”“药物-副作用”这些关系。有了这个定义抽取实体和关系时就有了明确的 schema不会抽出一堆乱七八糟的东西。实际操作上Ontology 不需要一开始就建得很完整。我的做法是先跑一版 RAG收集用户真实问题看哪些问题答不好然后针对性地补充 Ontology。这样建出来的本体是问题驱动的不会过度设计。6. 分水岭五Agentic RAG让检索从“一次”变成“多轮”6.1 单轮检索的天花板标准 RAG 是单轮检索用户问一个问题系统检索一次生成答案。这个模式对简单问题够用但遇到复杂问题就力不从心。比如用户问“对比 A 方案和 B 方案在成本和性能上的差异”。单轮检索可能只召回 A 方案的文档或者只召回成本相关的部分。模型拿到的上下文不完整答案自然也不完整。6.2 Agentic RAG 的编排逻辑Agentic RAG 的思路是把检索变成一个可以多轮、可以决策的过程。系统先分析问题判断需要哪些信息然后分步检索每步检索后评估信息是否足够不够就继续检索够了就生成答案。具体实现上可以用一个简单的状态机分析问题 - 生成检索计划 - 执行检索 - 评估结果 - 决定是否继续 - 生成答案。每一步都可以用 LLM 来做决策。LangGraph 这类框架就是为这种编排设计的它把每个步骤定义成节点用边来控制流转。我做过一个对比测试同样 50 个复杂问题单轮 RAG 的准确率是 52%Agentic RAG 是 78%。提升很明显但代价是延迟从 2 秒涨到了 8 到 15 秒成本也翻了几倍。所以我的建议是简单问题走单轮复杂问题走 Agentic用一个分类器来做路由。6.3 查询改写与分解的实用技巧Agentic RAG 里最实用的两个技巧是查询改写和查询分解。查询改写是指用户的问题往往口语化、有指代、有省略直接拿去检索效果差。先用 LLM 把问题改写成适合检索的形式。比如“它怎么配置”改写成“XX 功能的配置方法”指代消解掉检索命中率立刻提升。查询分解是指把复杂问题拆成几个子问题分别检索。比如“A 和 B 的区别”拆成“A 是什么”“B 是什么”“A 和 B 的差异点”。每个子问题检索一轮最后合并上下文生成答案。这个技巧对对比类、多跳类问题特别有效。注意查询改写和分解都会增加 LLM 调用延迟和成本都会上升。建议只在检测到复杂问题时才启用简单问题直接走原查询。7. 分水岭六评估与迭代没有度量就没有优化7.1 为什么你的 RAG 调不动我见过太多团队RAG 上线之后效果不好然后就开始瞎调换 embedding 模型、换 chunk_size、换 Prompt调了一圈发现效果时好时坏也不知道是哪个改动起了作用。根本原因是没有评估体系。没有评估你就不知道问题出在检索还是生成不知道改动是变好了还是变差了不知道当前系统的瓶颈在哪。调优变成了玄学。7.2 搭建一套最小可用的评估集评估集不需要很大50 到 100 个问题就够起步。关键是这些问题要覆盖你的真实场景简单事实类、多跳推理类、对比类、否定类各占一定比例。每个问题要标注三样东西标准答案、相关文档 ID、难度等级。标准答案用来评估生成质量相关文档 ID 用来评估检索质量难度等级用来分析系统在不同难度下的表现。检索评估用 RecallK 和 MRRMean Reciprocal Rank。Recall5 衡量前 5 条里有没有包含相关文档MRR 衡量相关文档排得靠不靠前。生成评估可以用 LLM-as-Judge让一个强模型给答案打分维度包括准确性、完整性、引用正确性。7.3 用数据驱动迭代的实操流程有了评估集之后迭代流程就清晰了第一步跑基线。记录当前系统在评估集上的各项指标。第二步定位瓶颈。如果 Recall5 低问题在检索如果 Recall 高但生成分数低问题在上下文组织或 Prompt。第三步单变量改动。每次只改一个东西跑评估看指标变化。变好了就保留变差了就回滚。第四步定期回归。每次改动后都跑一遍全量评估防止改 A 坏 B。我用这套流程帮一个团队把 RAG 的准确率从 60% 提到了 85%前后大概迭代了 20 多轮。每一轮都有明确的数据支撑没有一次是拍脑袋决定的。8. 常见问题速查与避坑清单8.1 检索类问题排查表现象可能原因排查方法解决方向召回内容完全不相关embedding 模型不适配领域人工看 Top-10 的相似度分布换领域微调的 embedding 模型相关文档排在第 8 位之后缺少 Rerank对比有无 Rerank 的 MRR加 Rerank 模型精确术语检索不到纯向量检索的缺陷用关键词搜一下能否命中上混合检索多跳问题只召回一半单轮检索局限看问题是否需要多个信息源查询分解 多轮检索否定条件失效语义检索不敏感构造否定类测试问题Prompt 里强调条件或加规则过滤8.2 生成类问题排查表现象可能原因排查方法解决方向答案编造上下文不足或 Prompt 没约束看检索结果是否包含答案补检索 Prompt 加“不知道就说不知道”答案不完整上下文被截断看送给模型的上下文长度用父子块或压缩重组引用错误编号映射出错检查解析逻辑加 few-shot 示例 容错降级答非所问问题理解错误看查询改写结果优化改写 Prompt 或加分类路由前后矛盾上下文有冲突信息看检索结果是否矛盾加时间过滤或 Prompt 提示注意区分8.3 几个我踩过的坑第一个坑是过度依赖默认参数。刚开始做的时候我直接用教程里的 chunk_size1000结果检索效果一直不好。后来降到 400效果立刻上来了。默认参数是给通用场景的你的场景一定要自己调。第二个坑是忽略文档预处理。PDF 里的表格、页眉页脚、乱码如果不清理会严重污染检索。我现在的流程里文档预处理占了整个 pipeline 三分之一的工作量但非常值得。第三个坑是Prompt 写得太随意。早期我觉得 Prompt 差不多就行后来发现同样的检索结果Prompt 改几个字答案质量能差一个档次。现在我的 Prompt 都是经过十几轮迭代的每一句都有存在的理由。第四个坑是不做版本管理。改了 Prompt、换了模型、调了参数没有记录出了问题不知道回滚到哪。现在我所有的配置都进 Git每次改动都有 commit message评估结果也一起存。9. 关于 DeepWiki 和知识库形态的一点思考最近 DeepWiki 这类产品挺火它把代码仓库自动转成可问答的 Wiki本质上还是 RAG但它的聪明之处在于利用了代码本身的结构化信息。函数调用关系、类继承关系、文件目录结构这些都是天然的知识图谱不需要额外抽取。这给了我一个启发做 RAG 之前先看看你的数据里有没有现成的结构可以用。很多领域的数据其实都有隐含结构。法律文书有条款编号医疗记录有诊断编码工单系统有分类标签。把这些结构利用起来比单纯做向量检索效果好得多。这也是为什么我一直强调RAG 的核心不是那条流水线而是对数据的理解和组织。至于“RAG 知识库能不能存图片”答案是能但要看怎么存。简单做法是把图片 OCR 成文字再向量化但会丢失视觉信息。更好的做法是用多模态 embedding 模型把图片和文字映射到同一空间检索时图文一起召回。这个方向现在还在快速演进值得关注。最后分享一个我个人的判断RAG 这条流水线确实烂大街了但烂大街的是“能跑通”的那部分。真正把 RAG 做成产品、做出差异化的团队功夫都下在流水线之外——切块策略、检索融合、上下文组织、知识结构化、智能体编排、评估迭代。这六处每一处都值得深挖每一处也都还有很大的优化空间。我到现在也不敢说自己把这六处都吃透了每次做新项目还是会有新的坑冒出来。但至少知道坑在哪比盲目地调参要强得多。