RAG 检索不准怎么办?先分清“召回不足”和“排序不准”
摘要:RAG 的“检索不准”至少包含召回不足、排序不准和生成偏航三类问题。真正有效的排障,不是立刻换模型或堆组件,而是保留完整候选集,用分层指标确认相关证据究竟消失在哪一步,再把改动落到对应环节。
RAG 上线后,最常见的反馈不是“系统报错”,而是“明明知识库里有,为什么回答不出来”。这类问题看起来都叫检索不准,背后的故障位置却可能完全不同。
很多排障文章一上来就换 embedding、加重排器、调相似度阈值,或者同时改一轮参数再看答案有没有变好。这样的做法看似积极,实际上把多个变量搅在一起:结果好了不知道是谁起作用,结果没变也不知道该继续查哪里。
RAG 排障的第一步不是优化,而是归因:先判断相关证据有没有进入候选集,再判断它有没有被排到最终上下文里。召回不足和排序不准不是同一种病,混着治才是最大的浪费。
一、先把“检索不准”拆成三种故障
第一种是召回不足。相关证据确实存在于可检索索引中,但在足够深的候选集合里仍然找不到。此时问题发生在“找没找到”,而不是“排得好不好”。继续调最终 Top-K,等于给一份缺少正确选项的试卷重新排序。
第二种是排序不准。相关证据已出现在较深候选列表里,却被大量“语义相似但无法作答”的内容压在后面,没有进入送给模型的上下文。它不是没有召回,而是好内容没有排到该在的位置。
第三种是生成偏航。证据已经进入最终上下文,引用片段也足以回答,但模型仍然忽略证据、拼错结论或拒答。此时继续折腾检索链路,大概率是在修错层。判断故障要看证据经过了哪一层,不是只看最终答案对不对。
一句话比喻:召回不足是仓库里没把货找出来,排序不准是货找到了却被压在箱底,生成偏航则是货已经摆到柜台,店员还是拿错了。
坑点 1:只保存最终 Top-K
只记录交给模型的少量片段,会把“从未召回”和“召回后被挤掉”压成同一个现象。排障时至少要保留更深的原始候选列表、排序前后位置以及最终入选结果,否则没有证据做分流。
二、诊断前先准备三份最小材料
第一份是查询与证据的对应关系。每条评测问题不能只标一个参考答案,还要标出能够支撑答案的证据位置或稳定标识。标注目标不是规定必须命中第几个块,而是回答一个更朴素的问题:什么内容出现,才算检索成功。
第二份是完整检索轨迹。一次请求至少要能追到原始查询、改写后的查询、原始候选、候选分数、排序后位置和最终上下文。线上日志只剩一句“回答失败”,就像只拿到体检结论,却看不到任何检查项。
第三份是阶段化错误标签。建议把失败先归为“索引中不存在”“候选集未命中”“候选已命中但未入选”“上下文已命中但回答错误”四种状态。标签可以有四类,但排查入口仍是三层:索引、候选、最终上下文。
没有这三份材料,任何“模型不行”“向量库不准”的结论都只是猜测。
坑点 2:默认知识库里有,就等于索引里有
原文件存在,不代表目标段落完成了解析、入库和版本更新。诊断召回之前,应先用文档标识核对索引中的实际内容;如果证据根本没进索引,这不是召回不足,而是数据链路问题。
三、召回不足要看三个信号
第一,看相关证据是否出现在足够深的原始候选中。这里的 N 不应凭习惯写死,而要覆盖系统实际允许进入后续阶段的候选深度。若扩大观察范围后仍然没有证据,才有资格把问题归到召回侧。
第二,看失败是否集中在特定查询形态。缩写、内部术语、口语问法和跨句指代如果成片失败,通常说明“用户怎么问”和“知识库怎么写”之间存在表达落差。多数时候不是知识不存在,而是查询没有把正确检索意图表达出来。
第三,看证据单元本身能否被独立命中。若黄金证据无法表达完整事实,或与大量无关内容粘在同一单元里,检索器拿到的输入已经失真。这里要确认的是索引单元是否支持命中,具体参数不在本文范围内。
召回侧的改动方向可以归为三类:修正查询表达、修正索引单元、调整检索通道。每次只动一类,再观察候选命中是否变化。具体怎么改不是这一阶段的问题,先证明该改这里才是。
坑点 3:把相似度阈值当成召回开关
阈值主要决定候选是否被放行,不能凭空创造没有被找到的证据。阈值不是排序的补丁,而是候选的门槛;盲目降低只会把更多噪声一起放进来,让后续判断更乱。
四、排序不准要找三类证据
第一类证据是位置倒挂。相关证据在原始候选中稳定出现,却长期排在最终截断线之后;排在前面的内容往往共享关键词或主题,但不能直接支撑答案。此时召回器完成了任务,失败发生在候选优先级上。
第二类证据是“相似”与“可回答”不一致。向量相似度擅长判断两段话是否接近,却不天然等于这段内容能否回答问题。概述页可能比细则页更像查询,但真正的答案藏在细则中。排序目标不是找最像的话,而是把最能支撑答案的证据放到前面。
第三类证据是排序收益可验证。固定同一批候选,只改变顺序,再比较黄金证据进入最终上下文的比例;结果明显改善,才说明排序环节值得投入。这里回答的是要不要重排,不是重排器怎么选型。
排序侧还要分清两种长得像的错误:一种是“高相似但不可回答”,内容主题贴切却缺少关键限定;另一种是“低相似却必须回答”,证据用词与查询完全不同但确实能作答。前者需要收紧可回答口径,后者需要补齐标注,两者混在一起统计,会让排序指标既不上升也不下降,看起来像调了个寂寞。
排序侧也只看三个动作:明确可回答性的标注口径,比较排序前后的证据位置,核对新增延迟是否落在业务预算内。排序能力不是免费午餐,若候选集本身没有正确证据,再强的重排器也只是精致地排列错误答案。
坑点 4:候选没命中,却先上重排器
重排器只能重排已经拿到的候选,不能把候选集之外的证据捞回来。先证明“证据在池子里但位置不对”,再讨论排序投入;否则就是杀鸡用牛刀,而且刀还砍错了地方。
五、用三层指标代替一个总准确率
第一层看候选命中,回答“相关证据有没有进入候选集”。可以使用 Hit@N 或候选召回率,但分母必须以已标注的可接受证据为准。这个指标下降,优先排查数据入库、查询表达和召回通道。
第二层看排序质量,回答“已经召回的证据有没有进入最终上下文”。可以观察黄金证据的排名、MRR,或从候选命中到最终入选的转化率。候选命中衡量找没找到,排序指标衡量找到了有没有摆对位置。
第三层看端到端答案,回答“证据到位以后模型有没有正确使用”。答案正确率必须与前两层并排展示,不能单独充当检索指标。否则生成模型的一次幻觉,会被错误记在检索器头上。
三层指标还要配两种展示方式:趋势看每次发布后的变化,分布看错误集中在召回、排序还是生成。只有趋势没有分布,会误以为系统变好了;只有分布没有趋势,则判断不出改动是否生效。
报表还要做三种切片:按查询类型切,定位术语、口语和多条件问题;按内容类型切,定位规则、流程和事实描述;按失败阶段切,观察召回、排序与生成各占多少。离线评测不是做排行榜,而是给线上错误找到归属。
坑点 5:一次改三个变量,只比较最终答案
同时修改查询改写、候选深度和排序策略,即使答案变好也无法复现收益。正确做法不是追求一次“调好”,而是固定评测集与其余链路,每轮只验证一个假设。
六、一条可以直接执行的排障路径
第一道门检查索引事实:参考证据是否真的存在于当前版本索引中,是否能通过文档标识被定位。不能,就回到数据链路;能,再进入候选检查。
第二道门检查候选事实:在预设观察深度内,相关证据是否出现。没有出现,归为召回不足;已经出现,不要继续扩大“召回问题”的帽子,而应进入位置检查。
第三道门检查上下文事实:相关证据是否进入最终上下文。候选中有、最终没有,归为排序不准;最终已有、答案仍错,转去检查提示约束、上下文冲突和生成行为。
这条路径的价值,不是把问题命名得更专业,而是给每类错误指定唯一的下一步。模型管生成,检索器管候选,排序器管位置;责任边界越清楚,调优成本越可控。
线上监控也应沿用同一套标签。不是只统计“今天错了多少次”,而是统计错误消失在哪一道门。只有阶段分布发生变化,团队才知道一次发布究竟改善了系统,还是把故障从一个环节搬到了另一个环节。
这套标签还决定了复盘速度:分布稳定时,团队查的是参数;分布突变时,团队查的是发布本身。阶段分布本身就是一种监控指标,它比总准确率更接近系统的真实变化。
写在最后
RAG 的难点从来不只是把文档塞进向量库,而是建立一条可观测、可归因、可复现的证据链。召回不足解决“有没有”,排序不准解决“靠不靠前”,生成偏航解决“会不会用”,三者不能用同一组参数混着调。
当检索效果下降时,先保留深候选,再核对证据位置,最后才决定改查询、动索引还是投入排序。真正成熟的 RAG 工程,不是组件堆得多,而是每一次错误都能回答:证据究竟在哪一步丢了。



