ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

RAG检索质量优化:从数据切分到重排的完整决策链

RAG检索质量优化:从数据切分到重排的完整决策链 如果你正在做 RAG 项目大概率遇到过这种情况demo 里跑得丝滑顺畅一问一个准结果一上生产、面对真实用户问题就开始“车轱辘话”来回说甚至从知识库里捞出毫不相关的内容硬答。查了半天LLM 没问题Prompt 也调了 N 版最后才发现问题出在检索环节——根本没把对的资料捞出来。这几乎是每个 RAG 项目从“能跑”走向“好用”时必经的一道坎。RAG 系统的效果上限很大程度上不取决于大模型多聪明而取决于检索质量。模型再强喂进去的资料是错的输出也不可能对。所以搞 RAG 的人迟早都要直面“检索质量优化”这件事。这篇我梳理了一套从架构设计到调优的完整决策链先讲清楚检索质量差的本质再从数据切分、索引构建、召回策略、重排融合几个层面逐个拆解最后聊聊评测驱动调优的完整闭环。全文偏方法论但每个环节都会落到具体参数和可执行的方案上适合正在做 RAG 落地、被检索效果折磨过的架构师和算法工程师参考。1. 先把问题定义清楚RAG 检索质量差的本质到底是什么聊优化之前得先把“检索质量差”这件事定义清楚。很多人一上来就调 embedding 模型、换向量数据库折腾一圈发现没用原因就是没搞清楚问题到底出在哪个环节。RAG 检索质量差其实表现为三种典型症状分别指向不同的根因。1.1 三种典型症状召回不全、排序不准、语义偏差第一种症状是“召回不全”。用户问了一个问题知识库里明明有答案但检索结果里就是没有那条资料。我见过一个很典型的案例政务知识库里某政策文件的发布时间写的是“2024年3月”用户问的是“今年最新的补贴政策”关键词匹配和向量相似度都没能把这条文件捞出来。这种问题往往出在数据切分和索引构建上——信息在库里但检索链路够不着。第二种症状是“排序不准”。正确的资料其实被召回了但排在第 8 位、第 15 位而 RAG 系统通常只取 top-5 或 top-10 送入 LLM正确答案就没被用上。这种情况比召回不全更难排查因为从结果看好像“没检索到”实际上是“检索到了但排太靠后”。根因可能在向量相似度的排序精度不够也可能是 embedding 模型对领域术语的语义理解不到位。第三种症状是“语义偏差”。检索结果看起来和问题相关关键词都能对上但语义层面答非所问。比如用户问“合同违约的诉讼时效”检索回来的资料讲的是“合同违约的赔偿标准”。关键词重叠度高但意图对不上。这种问题通常出在 Query 理解环节也可能是 embedding 模型对这类细分语义的区分度不够。我建议每个 RAG 项目在启动优化前先把手头的 bad case 按这三类归个类。归类的过程其实就是定位根因的过程能帮你判断下一步该动数据、动索引、动召回策略还是动重排模型。1.2 三个关键量化指标命中率、MRR、NDCG定义问题不能只靠感觉得有量化指标。RAG 检索质量评估里最常用的三个指标是命中率Hit Rate、MRRMean Reciprocal Rank和 NDCGNormalized Discounted Cumulative Gain。命中率最简单看的是正确答案是否出现在检索结果的前 N 条里。比如 top-10 命中率就是看前 10 条结果里有没有正确答案。这个指标直接对应“召回好不好”RAG 场景下通常要求 90% 以上才算合格。MRR 看的是正确答案排在第几位。假设答案排在第 3 位那这次查询的 Reciprocal Rank 就是 1/3。把所有查询取平均就是 MRR。MRR 对应的是“排序准不准”对 RAG 这种只取 top-k 送 LLM 的场景来说很关键——就算正确答案被召回了排在 15 位和排在第 2 位效果天差地别。NDCG 更精细一些不仅看答案有没有、排第几还考虑多级相关性。比如检索回来的 10 条里有 3 条是直接答案2 条是相关背景5 条是无关内容。NDCG 会根据相关性等级计算加权得分对排序质量更敏感。实操中我的建议是先用 Hit Rate 看召回是否达标再用 MRR 看排序是否需要优化。这两个指标就能覆盖绝大多数 RAG 调优场景。NDCG 在需要精细化评估、或者重排模型效果对比时再用。1.3 定位问题边界数据、索引、检索、排序四个环节的职责划分RAG 检索质量的完整链路可以拆成四段数据准备与切分、索引构建、召回策略、排序融合。每一段都有自己明确的职责边界也对应着不同的优化手段。数据准备与切分阶段决定了“知识库长什么样”比如文档怎么切、切成多大、每个切片带什么元数据。这一步直接决定检索单位是粗是细。索引构建阶段负责“怎么存、怎么算相似度”比如选什么 embedding 模型、用什么索引结构、是否做混合索引。召回策略阶段管的是“怎么把候选捞出来”包括 Query 改写、多路召回、扩展召回。排序融合阶段做的是“怎么把最终要送给 LLM 的内容定下来”通常指 rerank 重排以及多路结果的融合规则。这四个环节像一条流水线上游出问题下游再优化也白搭。但反过来很多团队一上来就优化下游的 rerank结果数据切分一团糟rerank 再强也只是在垃圾候选里挑一个相对不垃圾的。我见过最夸张的一个项目embedding 模型换了三个版本、rerank 模型换了两版效果纹丝不动。最后排查发现文档切分逻辑一直是按固定 2000 字硬切的很多完整语义单元被拦腰切断任何检索模型都救不回来。所以检索质量优化的第一原则是先从上游往下游排查别一上来就换模型、调参数。下一章先从数据切分这个最上游、也最容易被忽视的环节讲起。2. 架构设计层的两个关键决策数据切分与索引策略数据切分和索引策略是 RAG 系统架构设计的基础大多数检索质量问题根子都在这两层。但这两层恰恰又是最容易被轻视的——因为效果好坏不直观不像 rerank 那样换了模型立刻能看到指标变化。可实际上数据切分的质量直接决定了检索的上限。2.1 切分策略为什么说 chunk 的质量就是检索的天花板RAG 的检索单位是 chunk文本切片不是整篇文档。chunk 切得合理检索到的内容才可能精准chunk 切坏了后面所有环节都是在坏地基上盖楼。这里最核心的矛盾是chunk 太小语义不完整chunk 太大噪音过多向量表示被稀释。我见过有人为了省 embedding 调用费用把整篇 5000 字的文档当做一个 chunk 存进去。这么干必然导致检索结果非常粗糙——用户问的是文档第 3 节里的一个细节方案但向量检索比较的是整篇文档的语义细节信息被淹没在大段文字里根本召不回来。实际操作中切分策略要考虑三个维度内容形态、模型上下文限制、业务问题粒度。内容形态决定切分方式。表格、代码、长文、FAQ 需要不同的处理方式。表格按行或按语义块切代码按函数或类切FAQ 按问答对切长文按标题和段落结构切。纯按固定字符数硬切是最偷懒也最容易出问题的方式。模型上下文限制决定 chunk 上限。如果你用的 LLM 上下文是 8K那单个 chunk 最好不要超过 1500 字否则检索结果拼接后很容易超限。一般经验是切分后单 chunk 控制在 300 到 800 字之间比较稳妥。这个量级既能保住语义完整性又不至于让单条检索结果的信息密度过低。业务问题粒度是很多人忽略的点。用户的问题如果通常是“XX 政策对中小企业有什么补贴”那 chunk 就应该尽量覆盖一个完整的政策条目如果用户的问题通常是“XX 参数配置命令是什么”那 chunk 就该围绕一个命令或一个配置项来切。这块没有标准答案需要拿真实用户问题去反推 chunk 的合理粒度。切分时还有一个容易踩的坑重叠窗口。为了让边界处的语义不被切断通常会在相邻 chunk 之间预留 10% 到 20% 的重叠。但如果重叠过多会出现多个 chunk 高度相似检索结果里前几名全是同一段内容的变体白白浪费了有限的候选位。我的经验是重叠控制在 50 到 150 字以内就够了具体按 chunk 大小调整比例。比较进阶的做法是结构化切分加父子 chunk 策略先把文档按自然段落或章节切出“父 chunk”再对每个父 chunk 细切出“子 chunk”。检索时用子 chunk 匹配命中后把对应的父 chunk 一并交给 LLM。这样既能保证检索精确度又不会丢失上下文完整性。这种方案在多轮对话场景下效果尤其明显。2.2 元数据设计让检索从“大海捞针”变成“定向查找”元数据是 RAG 架构设计里被低估得最厉害的一环。很多人把文档切完就往向量库里丢完全没有元数据的概念。结果用户问“2024 年发布的政策”时系统只能靠向量相似度硬扛——因为知识库里根本没有“发布时间”这个可过滤的字段。给每个 chunk 打上元数据本质上是在检索之前先做一轮“粗筛”。比如政务知识库里每条 chunk 带上发布机构、发布时间、文号、适用地区企业知识库里每条 chunk 带上部门、文档类型、密级、更新时间。用户查询时先用结构化条件把候选集缩小到一个可管理的范围再在这个范围内做向量检索效果会好很多。举个我实践过的例子一个企业制度知识库上线初期检索效果很差用户问“差旅报销标准”系统老是召回销售制度、薪酬制度里的相似段落。后来给每个 chunk 增加了“制度类别”和“适用人群”两个元数据字段用户查询时先做一次条件过滤只检索“行政制度 全员适用”的候选集bad case 直接减少一半以上。元数据还能配合时间衰减使用。很多知识库里有大量“过期但未删除”的内容比如旧版制度文件、已废止的政策条款。如果不在检索时做时间过滤这些历史内容会持续干扰检索结果。一个简单有效的做法是在元数据里标注生效日期和失效日期查询时自动过滤掉当前时间点已失效的内容。2.3 索引侧选型embedding 模型、向量索引和混合检索怎么选数据切分和元数据规划好之后才轮到索引侧选型。这里主要有三个决策点embedding 模型、向量索引结构、是否做混合检索。embedding 模型的选择不能只看公开榜单。榜单上的分数是通用语料测出来的你的业务领域可能是法律、医疗、制造或者政务这些专业领域的术语和表达方式通用模型不一定理解得好。我的建议是拿 100 到 200 条你业务里的真实 query 和对应正确文档去测候选模型的 top-10 命中率。哪个命中率高用哪个比看任何榜单都可靠。现在主流的开源 embedding 模型里BGE 系列、M3E、GTE 系列都是不错的选择各有侧重。BGE 对中文支持好M3E 在多语言场景下表现均衡GTE 在长文本上更稳。但这些都是通用经验回到你自己的数据上重新评测才是正道。向量索引结构方面主流的向量数据库都支持 HNSW 索引。这里有两个关键参数M每个节点的最大连接数和 efConstruction构建时的动态列表大小。M 越大召回越高但内存占用越大默认值 16 通常够用efConstruction 越大索引构建越慢但质量越高默认 200 也算合理。线上查询时还有 efSearch 参数控制查询精度需要高召回时可适当调大但查询延迟会上升。这些参数不是一劳永逸的要结合你的数据规模和延迟要求去调。混合检索的选择上我的观点很明确不要迷信纯向量检索。关键词匹配BM25在 RAG 场景里的价值被严重低估尤其是处理人名、产品型号、政策文号这类精确实体时BM25 的精确匹配能力是向量检索替代不了的。一个稳妥的做法是“BM25 向量检索”双路召回两路结果合并去重后再送入重排阶段。具体权重怎么定、合并策略怎么选放到第三章讲召回策略时展开说。3. 检索链路上的核心调优动作多路召回、Query 改写与上下文增强架构设计层搞定了接下来才是检索链路本身的优化动作。这一层直接决定“能捞回什么候选”也是日常调优工作量最大的部分。我把它拆成三块多路召回怎么搭、Query 改写怎么做、上下文增强怎么补。3.1 多路召回怎么搭为什么单靠向量检索走不远单路向量检索的问题前面提过对精确实体匹配不敏感对语义相近但意图不同的文本区分度不够。多路召回就是为了解决这些问题——用多路互补的方案去捞候选每路解决一部分问题最后合并。最常见的多路召回组合是“BM25 关键词召回 向量语义召回”。BM25 负责精确匹配用户输入了一个产品型号、合同编号、政策文号BM25 能快速命中包含这些精确实体的 chunk。向量召回负责语义泛化用户输入的问题和库里的资料没有关键词重叠但语义相关这时靠向量相似度找回。组合方式上我推荐先各自召回 top-20 或 top-30做加权合并。权重的初始设定可以简单一点比如 BM25 结果和向量结果各占 0.5合并后按综合得分排序取 top-10。后续根据线上 bad case 调整权重如果发现精确实体匹配失败多就调高 BM25 权重如果发现语义泛化不足就调高向量权重。有条件的话还可以加第三路或第四路召回。比如基于规则的检索针对特定业务设计关键词模板或者基于图结构的召回适合实体关系密集的知识库这就是最近很热门的 Graph RAG 思路但落地成本较高建议先用常规多路召回跑通再考虑。多路召回的核心逻辑是一致的每一路覆盖一类检索模式合在一起才能把召回率顶上去。3.2 Query 改写为什么重要用户问题不等于检索表达式用户的原始问题往往不适合直接拿去检索。口语化表达、指代、省略、反问都会让检索质量大打折扣。一个很常见的例子用户第一轮问“差旅报销标准是什么”第二轮问“那住宿标准呢”。如果直接把“那住宿标准呢”拿去检索大概率什么都搜不到——因为它没有主语检索系统根本不知道你在问谁的标准。Query 改写就是解决这类问题的手段。最基础的做法是让 LLM 担任改写器把用户原始 query 结合历史对话上下文改写成适合检索的完整表达式。上面那个例子改写后应该是“公司差旅报销制度中的住宿报销标准是什么”。改写后的 query 再拿去检索效果会好得多。进阶一点的改写策略包括query 扩展和同义词改写。query 扩展是把一个简短的 query 扩展成包含多个相关表述的检索集合比如“劳动争议”扩展成“劳动争议仲裁 劳动合同纠纷 劳动维权 工伤赔偿”同义词改写是把用户口语化的表达改写为知识库里的标准术语比如“被开了”改写为“解除劳动合同”。这两种策略在长尾 query 和用户表达多样化的场景下非常有效。Query 改写的一个注意事项是控制改写成本。如果每一个用户 query 都让 LLM 改写一遍会产生不小的延迟和费用。我的做法是先用规则判断 query 是否需要改写——比如 query 过短少于 6 个字、包含明显指代词、与上一轮对话有关联才触发 LLM 改写其他情况直接用原始 query。这样既能保证效果又不至于让系统变慢变贵。3.3 上下文增强父文档、历史会话与窗口扩展的取舍检索结果送入 LLM 之前还有一个提升效果的手段上下文增强。核心思想是检索命中的 chunk 本身信息量可能不够需要把它的上下文补全才能让 LLM 更好理解和使用。最简单的上下文增强是父文档回填。前面提过“父子 chunk”策略检索用子 chunk 匹配命中后把对应的父 chunk 一并送入 LLM。这样 LLM 看到的不仅有命中的细节还有这个细节所在的完整语境。比如用户问“报销标准”命中的子 chunk 可能是“住宿费 400 元/天”回填父 chunk 后LLM 还能看到“适用范围一线城市超标需审批”等上下文回答自然更准确。历史会话增强是另一种方式。多轮对话场景下用户的当前问题往往依赖前面的对话内容。除了在 Query 改写时利用历史上下文也可以在检索时做历史信息的拼接检索。比如用户前一轮提到了“某项目”当前问“它的截止时间”检索时可以带着“某项目”这个主题词去检索避免漏掉关键信息。窗口扩展则是在检索命中后把 chunk 前后相邻的几个 chunk 也一并取出来。操作简单但在某些场景下会引入噪音——相邻 chunk 不一定和命中 chunk 语义相关。我建议只在召回率明显不足时使用而且不要一次扩展太多前后各取一个 chunk 就够。这几种上下文增强方式各有适用场景没有哪个是必选的。我的判断标准很简单如果命中 chunk 的答案完整度不够就考虑父文档回填如果是多轮对话就必须做历史会话增强如果评估发现召回率尚可但答案不完整可以试试窗口扩展。按需选择别一上来就全上会增加系统复杂度和检索噪音。4. 最后的精度保障Rerank 重排的落地方法与收益召回阶段把候选集扩大后面临的核心问题是候选太多了而且顺序并不理想。向量检索和 BM25 的排序逻辑都过于“粗糙”不考虑候选之间以及与 query 之间的精细语义关系。这时候就需要重排模型登场对候选重新打分排序。4.1 为什么需要 rerank两阶段检索的必然选择前面说过向量检索用的是双塔bi-encoder结构query 和 doc 分别编码成向量然后算相似度。这种结构的好处是 doc 向量可以离线算好、建索引线上只需算一次 query 向量延迟低适合海量候选的召回阶段。但坏处也很明显query 和 doc 之间没有充分交互语义匹配精度有限。rerank 模型通常用交叉编码器cross-encoder结构把 query 和 doc 拼接成一个序列让模型同时看两者输出一个相关性分数。由于模型能看到 query 和 doc 的完整交互信息匹配精度远高于双塔。但代价是计算成本高没法对全库文档做排序只能在召回后的几百条候选里做精排。所以 RAG 系统的标准架构是两阶段先用廉价的召回方法向量 BM25从全库把候选从几十万缩小到几十条再用昂贵的 rerank 模型精排。召回阶段解决“有没有”重排阶段解决“准不准”。这也是为什么说 RAG 系统检索质量优化的核心是“多路召回 精准重排”这套组合拳。4.2 重排模型选型与融合策略从 bge-reranker 到 API 服务开源社区已经有了不少可用的 rerank 模型。中文场景下bge-reranker-base 和 bge-reranker-large 是覆盖面最广的选择。base 版本速度快适合在延迟敏感的场景使用large 版本精度更高适合对质量要求更高的场景。实测下来在政务、法律等中文专业领域bge-reranker-large 在 top-5 命中率上通常能比 base 版本高出 3 到 5 个百分点但如果你的 QPS 压力大base 版本更务实。如果预算允许也可以考虑商用 API 的 rerank 服务效果通常更好稳定性也有保障。不过我对 API 方案的忠告是先做好本地 baseline再评估 API 提升是否显著。很多时候 bge-reranker-large 已经够用没必要为了一点提升付出额外的成本和延迟。多路召回结果怎么送入 rerank也有讲究。如果只有一路召回比如纯向量直接把 top-20 或 top-50 送到 rerank 即可。如果是多路召回需要先做合并去重。常见做法是每路召回 top-30按路数和得分做简单加权合并后取 top-30 至 top-50 送入 rerank。这里有个细节送入 rerank 的候选数量rerank_top_n不宜太多一般 30 到 50 条即可。太多了 rerank 延迟会明显上升而收益并不大——排在 50 名之后的候选相关性普遍很低rerank 也翻不出什么水花。Rerank 之后的“如何截断送给 LLM”同样值得斟酌。我的做法是先按 rerank 分数排序然后设置一个相关性阈值低于阈值的直接过滤掉如果过滤后不足 3 条就把阈值放宽保证至少取到 3 条候选送 LLM。这样既能避免低质量内容污染 LLM 的上下文又能控制幻觉风险。final_top_k 的取值通常在 3 到 8 之间取决于你的 LLM 上下文长度和 chunk 大小。4.3 重排的实际收益用数据说话重排到底值不值得做我拿一个真实项目的数据来说明。某企业知识库项目检索候选 30 条LLM 上下文能容纳约 5 条 chunk。纯向量召回 直接取 top-5 的方式top-5 命中率大约 76%。加上 BM25 多路召回后top-5 命中率提升到 82%——多路召回的主要贡献是让更多正确答案进入了候选集。在此基础上加 bge-reranker-large 重排top-5 命中率进一步提升到 91% 左右。也就是说rerank 在固定候选集的基础上把正确答案排进前 5 的比例提升了约 9 个百分点。从用户可感知的问答质量来看bad case 大约减少了 40%对体验的提升非常明显。另一个反向的观察单纯升级 embedding 模型从较弱的通用模型换到较强的领域模型top-5 命中率提升通常只有 2 到 4 个百分点。这说明在已经有多路召回的基础上重排带来的提升往往比换 embedding 模型更显著。所以我的建议很直接如果预算只能投一个地方优先投 rerank而不是反复折腾 embedding 模型。5. 评测驱动调优没有 eval set 的优化就是自嗨所有优化动作做下来最终都要回到一个问题怎么证明你的优化有效很多团队调 RAG 就是“感觉好多了”或者“用户反馈好一些”这种主观评价方式没法指导系统性调优。没有一套可量化的评测方案你根本不知道哪个改动起了作用哪个改动反而让效果变差了。5.1 构建 RAG 评估集从真实用户问题出发别自造数据构建评估集是评测的第一步。评估集的来源应该是真实用户问题不是你自己想象的、或者从文档反推出来的问题。真实问题才反映了用户的表达习惯——口语化、省略、不精确这些特征恰恰是检索最容易出错的地方。你可以从线上日志里抽取最近 1 到 3 个月的用户问题按渠道、业务线做分层抽样整理出 200 到 500 条作为评估集。规模不需要太大但要有代表性覆盖高频问题、长尾问题、口语化问题、多轮对话问题等不同类别。每条问题需要标注对应的正确答案相关文档或相关 chunk这个标注工作通常需要业务方参与因为他们最清楚什么答案算正确。如果是新项目还没有线上日志也可以从知识库里已有的 FAQ 反向构造问题但要特别注意不要只构造和文档标题高度相关的问题那样的评估集太“简单”测不出检索的真实水平。多构造一些需要跨文档推理、需要理解上下文背景的问题才更有区分度。评估集的标注粒度也要想清楚。粗一点的方案是只标“这条 query 应该命中哪篇文章”细一点的方案是标到 chunk 级或段落级。RAG 场景下我建议标到文档级就够用了——因为最终目标是判断是否正确文档被检索出来而不是精确到哪一行。标到 chunk 级会显著增加标注成本但对优化指导意义有限。5.2 从 bad case 到根因定位一轮完整的调优循环怎么做有了评估集就可以跑评测、看指标、找 bad case。但这里有个关键点光看指标变化还不够必须要逐个分析 bad case 的根因。指标只能告诉你好不好bad case 分析才能告诉你为什么不好、下一轮应该改哪里。一轮完整的调优循环大概是这样的跑评测记录 Hit Rate 和 MRR把所有未命中的 bad case 拉出来逐个分析是召回环节的问题、排序环节的问题还是数据切分的问题按根因归类找出占比最高的那个问题类型针对这一类问题做定向优化改完重新跑评测对比指标变化。举个例子。第一轮评测发现命中率 80%有 20% 的 bad case。逐个分析后发现10% 是纯向量召回漏检6% 是召回命中但 rerank 排太靠后4% 是数据切分导致语义断裂。如果只盯着命中率 80% 这个数字你可能会盲目去换 embedding 模型。但根因分析告诉你向量召回漏检才是主要矛盾应该先去优化召回策略——比如加强 BM25 多路召回、做 Query 改写。这就是评测驱动调优的价值让你把有限的时间花在最有杠杆的点上。另外每次改动只改一个变量改完就跑评测。同时改三个东西效果变好了你也说不清是哪个起了作用效果变差了更是一头雾水。保持单一变量原则调优过程才能积累出可复用的经验。5.3 常见问题排查实录与速查表最后分享几个实际排查过程中常遇到的问题整理成速查表遇到类似情况可以直接对照排查。现象可能原因验证方法解决方案检索结果全是长文片段找不到细节答案chunk 切分粒度过大查看召回 chunk 的长度分布缩小 chunk 大小或采用父子 chunk 策略精确型号、编号检索不到纯向量检索对精确实体不敏感单独测 BM25 召回增加 BM25 召回路调高关键词权重答案在库里但召回了完全无关内容embedding 模型对领域语义理解不足用领域数据测多个模型命中率换领域 embedding 模型或微调召回命中但最终回答仍错误rerank 排序不准正确答案排太靠后查看 rerank 后 top-5 是否含正确答案换更大 rerank 模型或调大 rerank_top_n多个检索结果重复度高重叠窗口设置过大查看召回 chunk 的文本相似度减小重叠窗口或做去重多轮对话第二轮答非所问未做 Query 改写和上下文补全查看第二轮实际检索 query加入 LLM Query 改写检索延迟高向量候选数或 rerank 候选数过大检测各环节耗时减小 top_n、限制 rerank 候选数量6. 从架构设计到线上调优我的踩坑经验与决策链总结文章最后我把自己在多个 RAG 项目里反复踩过的坑和沉淀下来的经验做个梳理。这些经验不一定适用于所有业务但至少能帮你少走一些弯路。6.1 几个印象深刻的教训第一个教训是不要迷信“大模型能力强就能弥补检索质量差”。早期的几个项目我总想着 LLM 足够聪明喂点噪音也能自己分辨。实际测试发现根本不是那么回事——LLM 对检索结果里的错误信息几乎不设防给它错误的上下文它就一本正经地编错误答案。RAG 系统的幻觉问题很多时候不是 LLM 的错是检索质量差把 LLM 逼上了绝路。第二个教训是指标不是越高越好要看业务场景的实际约束。之前一个项目把 top-5 命中率从 82% 优化到 91%效果确实好但代价是检索链路从纯向量单路变成了“多路召回 LLM Query 改写 rerank”的复杂链路单次检索延迟从 200ms 涨到了 2 秒。用户根本不接受这个延迟。后来我们做了一层缓存和异步预检索才在延迟和效果之间找到平衡。检索质量优化不是无限堆叠环节每个环节都有成本和收益需要综合权衡。第三个教训是上线之后要持续做质量监控。很多团队上线 RAG 系统后就不管了直到用户集中投诉才发现知识库里新增的文档索引出现问题。我建议至少做到两级监控一是检索指标监控定期用小批量评估集跑一下 Hit Rate看有没有退化二是线上检索日志的抽样检查每周人工看一批真实 query 的检索结果及时发现新出现的 bad case。RAG 系统的知识库是动态的文档在变、用户在变、问题分布也在变检索质量优化不是一个一次性的项目而是一个持续迭代的过程。6.2 端到端优化决策链遇到检索问题时按这个顺序排查把前面五章的内容串起来就是一条完整的检索质量优化决策链。我建议所有 RAG 项目都按这个顺序去排查和优化亲测效率最高。第一步检查数据切分和元数据。知识库文档是否按语义完整性切分chunk 大小是否合理是否带了必要的过滤字段这一步不做后面全白搭。第二步验证 embedding 模型和索引配置。用业务数据的评测集跑一遍候选模型的命中率选最优模型确认向量索引参数HNSW 的 M、efSearch匹配当前数据规模和延迟要求。第三步检查召回策略。单路召回还是多路召回Query 需要改写吗问题的表达是否多样到必须做同义词扩展这一层的重点是提高召回率核心指标是 Hit Rate。第四步上重排。多路召回合并后引入 rerank 模型做精排。核心指标是 MRR 或 top-5 命中率提升幅度。如果这一步发现提升不明显先回去检查召回候选集的质量——候选里根本没有正确答案rerank 怎么排都没用。第五步建立评测闭环。构建评估集跑基线指标分析 bad case按根因归类判断下一轮优化优先改哪里。然后循环第三步到第五步直到指标达标且稳定。这套决策链本质上是一个“由粗到细、由上游到下游”的思路先把数据基础打牢再优化召回最后精排和迭代。每一步解决一类问题每一步都可以量化验证。不会出现“所有环节都优化了一遍但不知道起作用的到底是哪一步”的失控感。做 RAG 检索质量优化与其说是技术活不如说是一个系统性的工程问题。把数据、索引、召回、重排、评测这五个环节看成一条完整的决策链按正确的顺序去排查和优化远比零散地尝试各种“魔法参数”更有用。最后再分享一个小建议不管你的知识库是几千条还是几十万条都先拿 200 条真实 query 做一版 eval set 再开始优化。这一步花不了太多时间但会让后面所有的调优动作都有据可依也让你在向团队或领导汇报效果时拿出的不是“我感觉变好了”而是实打实的命中率数字。
返回列表