☰
生产级RAG的六大分水岭:从Naive RAG到高召回率系统的工程实践
2026/10/7 19:14:39 网站建设 项目流程

1. 为什么“RAG 烂大街”是个伪命题

这两年但凡跟大模型沾点边的团队,几乎人手一套 RAG 流水线。文档切片、向量化、存库、检索、拼 prompt、丢给模型生成——这套东西已经标准化到随便找个开源框架半天就能跑通 demo。于是圈子里开始流行一句话:“RAG 烂大街了”。

我一开始也这么觉得。直到去年接手一个企业知识库项目,客户丢过来 12 万份文档,涵盖产品手册、工单记录、合同模板、内部 Wiki,要求“问什么都能答准”。我拿最熟悉的 Naive RAG 跑了一版,Top-5 召回率勉强 60%,答非所问的比例高得离谱。那一刻我才意识到:烂大街的从来不是 RAG 本身,而是那条最粗糙的流水线。

真正拉开差距的地方,藏在六个关键分水岭上。这篇文章就把这六处逐一拆开,讲清楚每一处为什么是分水岭、怎么判断自己卡在哪、以及具体怎么改。不管你是刚搭完第一个 RAG demo 的新手,还是正在被召回率折磨的老手,应该都能找到能直接抄作业的东西。

先给个全局认知:一条完整的 RAG 链路,从数据进来到答案出去,大致经过数据解析、切片策略、索引构建、检索召回、重排过滤、生成编排六个环节。Naive RAG 在每个环节都用了最省事的默认方案,而生产级 RAG 需要在每个环节做针对性设计。下面逐个说。

2. 分水岭一:数据解析与切片策略

2.1 为什么切片是第一个分水岭

很多人把切片当成“预处理”,随便按 512 token 一刀切就完事。这是最致命的误区。切片质量直接决定了检索的上限——切错了,后面检索再花哨也救不回来。

我见过一个典型案例:一份产品故障排查手册,每个故障现象和解决方案是一一对应的。按固定长度切片后,某个故障现象的描述在 chunk 3 的末尾,对应的解决方案在 chunk 4 的开头。用户问“XX 报错怎么解决”,检索命中了 chunk 3,但解决方案根本没被召回,模型只能瞎编。

固定长度切片的根本问题在于:它假设语义边界和字符长度边界重合,而现实中这两者几乎从不重合。

2.2 分层切片的具体做法

我的做法是分层处理,不同文档类型用不同策略:

文档类型切片策略切片长度重叠理由
结构化手册按标题层级切按章节自然长度无章节本身就是语义单元
合同/法律文本按条款切按条款条款号重叠条款独立性极强
工单记录单条工单为单元整条无问答对天然完整
长篇文章语义切片256-512 token10%-15%平衡粒度与上下文
表格数据整表 + 行摘要按表表头重复表格脱离表头无意义

语义切片的核心思路是:先按句子切分,再计算相邻句子的语义相似度,在相似度骤降的地方断开。这样切出来的每个 chunk 内部语义连贯,边界落在真正的语义转折处。

具体实现上,我常用一个组合方案:先用规则做粗切(按标题、段落),再用语义相似度做细调。纯语义切片计算量大,纯规则切片又不够灵活,两者结合性价比最高。

2.3 实操心得:切片长度不是拍脑袋定的

切片长度怎么定?我的经验是看检索粒度需求。如果你希望检索返回的是“一个完整答案”,切片就要包含完整答案;如果你希望检索返回的是“相关线索”,切片可以更细。

一个可参考的计算方法:假设你的文档平均每 100 字包含一个完整信息点,用户提问通常需要 2-3 个信息点才能回答,那么切片长度应该在 200-300 字左右。太短则信息不完整,太长则噪声过多。

注意:切片重叠不是越多越好。重叠 10%-15% 足够覆盖边界信息,超过 20% 会导致检索结果大量重复,浪费上下文窗口。

3. 分水岭二:索引构建与向量化选型

3.1 向量模型不是越贵越好

索引构建环节,最大的坑是盲目追求“最强向量模型”。我见过团队用最大的 embedding 模型,结果检索效果还不如一个小模型——因为向量模型和你的数据领域不匹配。

通用向量模型在通用语料上训练,对专业术语、行业黑话的表示能力有限。比如医疗领域的“心梗”和“心肌梗死”在通用模型里可能距离较远,但在专业模型里应该很近。

选型时我会做三件事:

  1. 拿真实 query 做小规模评测:从历史提问里抽 100 条,人工标注正确答案,然后对比不同模型的召回率。这比看论文榜单靠谱得多。
  2. 考虑维度与成本:高维向量检索慢、存储贵。如果 768 维和 1536 维效果差不到 5%,果断选 768。
  3. 测试领域适配性:如果通用模型效果差,考虑用领域数据做微调,或者用领域预训练模型。

3.2 混合索引:向量 + 关键词 + 图

纯向量检索有个硬伤:对精确匹配不敏感。用户问“产品型号 XR-2000 的保修期”,向量检索可能召回一堆“保修期”相关但型号不对的文档。

我的方案是混合索引,三路并行:

  • 向量索引:负责语义相似召回,解决“意思相近但用词不同”的问题。
  • 关键词索引(BM25):负责精确匹配,解决型号、编号、专有名词的召回。
  • 图索引:负责关系推理,解决“A 的上级部门是谁”这类需要多跳的问题。

三路结果用加权融合(Reciprocal Rank Fusion 是常用方法),权重根据业务调。一般场景下向量 0.5、关键词 0.3、图 0.2 是个不错的起点。

3.3 GraphRAG 到底解决了什么问题

GraphRAG 这两年很火,但很多人没搞明白它到底解决什么。简单说:当答案需要跨多个文档、多跳推理才能得出时,纯向量检索无能为力。

举个例子:文档 A 说“项目 Alpha 由张三负责”,文档 B 说“张三隶属于技术二部”,文档 C 说“技术二部的预算审批人是李四”。用户问“项目 Alpha 的预算谁审批”。纯向量检索可能只召回文档 A,答不出李四。GraphRAG 通过实体关系图,能从 Alpha 走到张三、走到技术二部、走到李四,完成多跳推理。

但 GraphRAG 不是银弹。构建知识图谱的成本很高,实体抽取、关系抽取都需要额外模型,而且图谱质量直接决定效果。我的建议是:只有当你的业务确实存在大量多跳推理需求时,才上 GraphRAG。否则混合索引 + 重排就够了。

4. 分水岭三:检索召回与 Contextual Retrieval

4.1 召回阶段的核心矛盾

召回阶段永远在解决一对矛盾:召回率与精确率的平衡。召回太少,答案可能不在候选里;召回太多,噪声会干扰模型判断。

Naive RAG 通常设 Top-K=3 或 5,这是拍脑袋的值。我的做法是动态 Top-K:根据 query 的复杂度调整。简单事实性问题 Top-K=3 足够,复杂分析性问题可能需要 Top-K=10 甚至更多。

判断 query 复杂度可以用一个轻量分类器,或者直接用规则:包含“对比”“分析”“为什么”等词的 query 判为复杂,扩大召回。

4.2 Contextual Retrieval 的关键改进

Contextual Retrieval 是这两年检索侧最重要的改进之一。它的核心思想是:切片在脱离原文后,会丢失上下文信息,导致检索和生成都受影响。

具体做法是:在切片入库前,用模型为每个切片生成一段上下文说明,然后把这段说明拼接到切片前面一起向量化。比如一个切片内容是“保修期为 24 个月”,单独看不知道是什么的保修期。加上上下文说明“本段来自产品 XR-2000 的售后条款”,检索时就能准确匹配到“XR-2000 保修期”的 query。

这个改动的成本很低——一次额外的模型调用——但效果提升明显。我在多个项目里实测,召回率能提升 10-20 个百分点。

4.3 实操:召回结果去重与多样性

召回阶段还有一个容易被忽略的问题:结果高度重复。尤其是切片有重叠时,Top-10 里可能有 5 条内容几乎一样,真正有用的信息只占 2-3 条。

我的处理方式是做 MMR(最大边际相关性)去重:在保证相关性的前提下,优先选择与已选结果差异大的候选。这样能在有限的名额里塞进更多样的信息。

具体参数上,MMR 的 lambda 设 0.7 左右比较合适——偏向相关性,但保留一定多样性。lambda=1 就是纯相关性排序,lambda=0 就是纯多样性,都不好用。

5. 分水岭四:重排与过滤

5.1 为什么需要重排

召回阶段用的是向量相似度,这是个“粗筛”。向量相似度高不代表真的相关——可能只是用词相似。重排阶段用更精细的模型(通常是 cross-encoder)对候选做二次打分,能显著提升精度。

我做过对比:同一批 query,召回 Top-20 直接给模型生成,准确率约 65%;经过重排后取 Top-5 再生成,准确率能到 82%。重排是性价比最高的精度提升手段之一。

5.2 重排模型的选型

重排模型分两档:

  • 轻量档:小型 cross-encoder,延迟低,适合对响应速度敏感的场景。
  • 重量档:大型 cross-encoder 或 LLM 打分,精度高但延迟大。

我的建议是:线上用轻量档做初排,离线用重量档做评测和调优。如果业务对精度要求极高且能接受延迟,再考虑线上用重量档。

5.3 过滤规则的设计

重排之后还需要过滤,把明显不相关或低质量的结果剔除。常用过滤规则:

  • 相似度阈值:低于阈值的直接丢,避免“矮子里拔将军”。
  • 时间过滤:如果业务对时效敏感,过期文档降权或剔除。
  • 权限过滤:不同用户能看到的文档不同,检索前就要做权限隔离。
  • 去重过滤:内容重复的只保留一条。

注意:过滤规则不要设得太激进。我见过团队把阈值设太高,导致召回结果被砍到只剩 1-2 条,模型反而没足够信息生成。阈值应该通过评测确定,而不是拍脑袋。

6. 分水岭五:生成编排与 Agentic RAG

6.1 从“一次检索”到“多轮编排”

Naive RAG 是“一次检索 + 一次生成”,但很多问题需要多轮检索才能回答。比如“对比 A 产品和 B 产品的保修政策”,需要分别检索 A 和 B 的信息,再对比。

Agentic RAG 的核心就是把检索变成 Agent 的一个工具,让 Agent 自主决定检索什么、检索几次、什么时候停止。这需要一套编排框架来管理流程。

6.2 LangGraph 在 RAG 编排中的角色

LangGraph 是目前做 Agentic RAG 编排比较顺手的框架。它把流程建模成图:节点是操作(检索、生成、判断),边是流转条件。相比链式编排,图编排能表达循环、分支、并行,更适合复杂 RAG 流程。

一个典型的 Agentic RAG 图结构:

  1. 入口节点:接收 query,判断复杂度。
  2. 检索节点:执行检索,可多次调用。
  3. 判断节点:判断当前信息是否足够回答。
  4. 生成节点:信息足够时生成答案。
  5. 回退边:信息不足时回到检索节点,调整 query 再检索。

这个结构的关键在于判断节点——它决定了要不要继续检索。判断逻辑可以用规则(比如“召回结果相似度都低于阈值就继续检索”),也可以用模型判断。

6.3 实操:控制 Agent 的检索轮次

Agentic RAG 最大的风险是无限循环——Agent 一直觉得信息不够,一直检索。必须设上限。

我的做法是设两个上限:最大轮次(比如 3 轮)和最大 token 消耗(比如 8000 token)。任一超限就强制进入生成节点,用现有信息回答,并在答案里标注“信息可能不完整”。

另外,每轮检索后要更新 query。第一轮用原始 query,第二轮用“原始 query + 缺失信息点”,第三轮再调整。这样每轮检索都有针对性,而不是重复检索同样的内容。

7. 分水岭六:评测与持续迭代

7.1 没有评测就没有优化

前面五处改进,怎么知道有没有效果?靠评测。没有评测的 RAG 优化就是盲人摸象。

RAG 评测分两个层面:

  • 检索层:召回率、精确率、MRR、NDCG。衡量检索系统找到相关内容的能力。
  • 生成层:答案准确率、忠实度(是否基于检索内容)、完整性。衡量最终答案的质量。

7.2 评测集的构建

评测集是评测的基础。我的构建方法:

  1. 从真实提问中采样:历史提问是最真实的评测数据。
  2. 人工标注答案:每条 query 标注标准答案和对应的源文档。
  3. 覆盖各类场景:简单事实、多跳推理、对比分析、否定查询都要有。
  4. 定期更新:业务在变,评测集也要跟着更新。

规模上,100-200 条 query 就能给出有参考价值的评测结果。太少波动大,太多标注成本高。

7.3 常见问题速查表

问题现象可能原因排查方向解决思路
召回结果不相关切片粒度过粗/过细检查切片长度和边界调整切片策略,加语义切片
答案答非所问检索没命中正确文档看召回结果里有没有正确答案加混合索引,加 Contextual Retrieval
答案编造内容模型没基于检索内容检查 prompt 和忠实度强化 prompt 约束,加引用要求
多跳问题答不出缺少关系推理能力看是否需要跨文档推理上 GraphRAG 或 Agentic RAG
响应太慢检索或重排太重看各环节耗时轻量化模型,加缓存
结果重复度高切片重叠过多检查重叠比例降重叠,加 MMR 去重

7.4 持续迭代的节奏

RAG 系统不是一次搭好就完事。我的迭代节奏是:

  • 每周:看线上 bad case,归类问题。
  • 每月:跑一次完整评测,对比指标变化。
  • 每季度:review 整体架构,看有没有新的技术值得引入。

迭代时一次只改一个变量,否则无法判断是哪个改动带来的效果。这是做实验的基本纪律。

8. 我在实际项目中的几点体会

踩了这么多坑,有几个体会特别深。

第一,不要迷信新技术。GraphRAG、Agentic RAG 都很火,但如果你的业务就是简单事实问答,上这些就是杀鸡用牛刀,徒增复杂度和成本。先把基础流水线做扎实,再考虑进阶方案。

第二,数据质量比算法重要。我见过太多团队在算法上反复调优,但源文档本身就有大量错误、重复、过期内容。垃圾进垃圾出,数据不清洗,算法再强也白搭。

第三,评测要趁早。很多团队做到一半才想起来评测,结果发现前面做的改动都没法量化效果。评测集应该和系统同步建设,甚至先建评测集再搭系统。

第四,简单方案往往够用。混合索引 + 重排 + Contextual Retrieval 这套组合,能解决 80% 的召回问题。剩下 20% 再考虑 GraphRAG 或 Agentic RAG。不要一上来就上最复杂的方案。

最后分享一个我常用的小技巧:给每个 chunk 打上来源标签(文档名、章节、更新时间),生成答案时要求模型标注引用来源。这样既能提升答案可信度,又方便排查问题——答案错了,直接看引用的 chunk 就知道是检索错了还是生成错了。这个习惯帮我省了大量排查时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询