上一篇文章里,我们讨论了 RAG 检索质量怎么提升。
一个重要结论是:
只靠向量检索并不能覆盖所有真实问题。
在企业知识库、技术文档、产品文档和接口文档里,很多查询既需要语义理解,也需要关键词命中、编号匹配、版本过滤和业务边界控制。
所以一个更稳定的检索链路,往往会从单一向量检索走向 Hybrid Search。
也就是把向量检索、关键词检索、元数据过滤等能力组合起来,让系统先召回更多可能相关的候选内容。
但这里马上会出现另一个问题:
候选内容召回来了,并不代表这些内容就应该全部塞给大模型。
很多 RAG 系统答不好,不是因为完全没有检索到相关内容,而是因为检索结果里混入了太多无关、重复、过旧、太碎或者优先级不对的片段。
这些片段一起进入上下文后,模型看到的信息变多了,但真正有用的信息反而被淹没了。
这篇文章就讨论一个很容易被忽略的问题:
Rerank 为什么重要,为什么 RAG 不是简单把 TopK 检索结果塞给模型。
TopK 看起来简单,但问题很多
很多最小 RAG Demo 会这样做:
用户问题 ↓ Embedding ↓ 向量检索 TopK ↓ 把 TopK 片段拼进 Prompt ↓ 大模型生成答案这个流程很容易理解,也很容易实现。
比如从向量数据库里取 Top5:
Top1: score 0.82 Top2: score 0.79 Top3: score 0.76 Top4: score 0.73 Top5: score 0.71然后把这五个片段都放进 Prompt。
在 Demo 阶段,这样做经常可以跑通。
但真实项目里,TopK 往往没有想象中可靠。
第一,TopK 的分数不等于答案质量。
向量相似度只能说明“语义接近”,不能保证“片段里有答案”。
比如用户问:
试用期员工能不能休年假?系统可能召回这些片段:
Top1: 公司年假制度总则 Top2: 试用期员工管理办法 Top3: 年假折算规则 Top4: 考勤异常处理办法 Top5: 离职员工假期结算这些内容都和问题有关系。
但真正能回答问题的,可能是 Top3 里的“年假折算规则”,而不是 Top1。
如果直接按向量分数排序,把 Top1 放在最前面,模型可能会优先参考不够具体的制度总则。
第二,TopK 里可能有重复内容。
同一份文档被切成多个相邻 Chunk 后,Top5 里可能有三个都来自同一段附近。
它们语义很接近,但信息增量很低。
结果就是上下文看起来很长,实际有效信息并没有增加。
第三,TopK 里可能混入相似但错误的内容。
比如用户问:
ERR_1024 表示什么?检索结果可能包含:
ERR_1024: 用户认证失败 ERR_1025: token 已过期 ERR_1042: 权限不足 错误码处理通用说明 登录失败排查流程从语义上看,它们都和“错误码”“登录”“认证”有关。
但业务上,ERR_1024和ERR_1025不能混用。
如果模型看到多个相似错误码,很容易生成一个看似合理但并不准确的答案。
第四,TopK 可能忽略版本和权限。
比如新旧制度内容非常相似,向量分数也接近。
如果系统没有把版本、发布时间、适用范围、用户权限纳入排序逻辑,模型可能引用过期文档。
第五,TopK 会带来 token 浪费。
不是所有召回内容都值得进入最终 Prompt。
把无效片段塞给模型,不仅增加成本,还会增加模型判断难度。
所以 TopK 只是粗筛,不是最终答案上下文。
Rerank 到底在做什么?
Rerank 可以理解为“重排序”。
它通常发生在召回之后、生成之前。
一个更完整的流程是:
用户问题 ↓ 多路召回 ↓ 候选内容合并 ↓ 去重和过滤 ↓ Rerank 重排序 ↓ 选择最终上下文 ↓ Prompt 生成答案Retriever 负责把可能相关的内容找出来。
Rerank 负责从这些候选内容里判断:
哪些内容更能回答当前问题。
这两件事的目标不一样。
Retriever 更关注召回率。
它希望不要漏掉可能相关的内容。
Rerank 更关注精确性。
它希望把最有用、最能支撑答案的片段排到前面。
举个例子。
用户问:
采购审批超过 10 万元需要几级审批?召回阶段可能拿到这些候选:
候选 A: 采购申请流程说明 候选 B: 报销审批权限表 候选 C: 采购金额审批分级表 候选 D: 合同审批流程 候选 E: 采购系统字段说明这些候选都和“审批”“采购”“金额”有一定关系。
但真正最适合回答问题的是候选 C。
Rerank 的作用,就是把候选 C 排到最前面。
如果没有 Rerank,系统可能按照向量相似度把候选 A 放在第一位。
候选 A 也相关,但它可能只讲流程,不讲金额分级。
模型如果优先看到候选 A,就可能给出模糊答案。
这就是 Rerank 的价值:
它不是简单判断“像不像”,而是进一步判断“能不能回答”。
为什么召回分数不能直接当排序依据?
很多人会把向量数据库返回的 score 当成最终排序依据。
这在简单场景里可以用,但在复杂 RAG 系统里很容易出问题。
原因有几个。
第一,向量分数通常只表示语义相似。
语义相似和答案可用不是同一件事。
比如用户问:
新员工入职后多久可以申请电脑?片段 A 写的是:
新员工入职流程包括账号开通、工牌办理和设备申请。片段 B 写的是:
员工入职当天由直属主管提交电脑申请,IT 部门在 2 个工作日内完成发放。片段 A 和问题很相似。
但片段 B 才真正包含答案。
如果只看向量相似度,片段 A 可能排得更靠前。
Rerank 要做的,就是把片段 B 识别出来。
第二,不同召回方式的分数不可直接比较。
Hybrid Search 里可能同时有向量检索分数、BM25 分数、业务规则分数。
这些分数的含义不同,范围也不同。
比如:
向量检索: 0.78 BM25: 12.6 业务规则加权: 3它们不能简单相加,也不能直接比较大小。
Rerank 可以在候选集合上重新判断相关性,减少不同召回分数之间的不可比问题。
第三,检索分数不一定考虑上下文完整性。
某个 Chunk 可能包含关键词,所以分数很高。
但它可能只是表格的一行、流程中的一步、标题下的一个碎片。
如果没有上下文,模型仍然无法回答。
Rerank 可以结合问题和片段内容,优先选择信息更完整的候选。
第四,检索分数不一定考虑业务优先级。
同样相关的内容里,最新版本、正式制度、用户有权限访问的文档,通常应该排得更靠前。
这类优先级不一定体现在向量相似度里。
所以在真实系统中,召回分数只能作为参考。
最终进入 Prompt 的内容,需要经过更细的排序和筛选。
Rerank 和 Hybrid Search 的关系
上一篇文章讲到,Hybrid Search 的价值在于把多种召回方式结合起来。
比如:
向量召回: 找语义相似内容 关键词召回: 找精确词和编号 元数据过滤: 限定权限、版本、部门、时间范围多路召回之后,候选集合会变大。
这时候如果不做重排序,问题会更明显。
比如用户问:
POST /orders 的 quantity 参数是否必填?向量检索可能召回:
订单创建接口说明 订单查询接口说明 订单字段定义 库存扣减流程关键词检索可能召回:
POST /orders quantity required 订单参数表元数据过滤可能保留:
当前版本 v2.3.1 正式接口文档 当前租户可见文档最后候选内容可能有十几个。
它们都不是完全无关。
但最终真正应该给模型看的,可能只有两三个片段:
POST /orders 接口定义 quantity 参数说明 当前版本参数变更记录Rerank 就是在这个阶段发挥作用。
它可以把多路召回结果放到同一个排序逻辑里,判断哪些片段更贴近当前问题。
所以 Hybrid Search 和 Rerank 不是互相替代的关系。
Hybrid Search 解决的是“候选从哪里来”。
Rerank 解决的是“候选怎么排”。
没有 Hybrid Search,可能召回不够全。
没有 Rerank,召回多了以后可能更乱。
Rerank 常见的实现方式
在工程实践里,Rerank 不一定只有一种做法。
可以根据系统规模、成本要求和质量要求选择不同方案。
第一种是规则型 Rerank。
比如根据文档类型、发布时间、标题命中、关键词命中、权限范围进行加权。
示例:
最终分数 = 检索分数 + 标题命中加分 + 关键词精确命中加分 + 最新版本加分 - 过期文档扣分这种方式成本低、可解释性强。
适合早期系统,也适合业务规则比较明确的场景。
但它的缺点是理解能力有限。
规则能处理“是否命中某个词”,但很难判断一个片段是否真正能回答复杂问题。
第二种是模型型 Rerank。
模型型 Rerank 会把用户问题和候选片段一起输入模型,让模型判断相关性。
它关注的是 query 和 document 之间的匹配程度。
一个简化流程是:
输入: 用户问题 + 候选片段 输出: 相关性分数然后按相关性分数重新排序。
这种方式通常比单纯向量分数更精细。
因为它可以直接比较“这个片段是否有助于回答这个问题”。
缺点是会增加额外计算成本。
如果候选片段太多,Rerank 的延迟和费用都会上升。
第三种是混合型 Rerank。
实际系统里经常会把规则和模型结合起来。
比如先用规则过滤明显无效内容,再用模型对剩下的候选做排序。
流程可以是:
召回 50 个候选 ↓ 规则过滤到 20 个 ↓ 模型 Rerank 排序 ↓ 选前 5 个进入 Prompt这样既能控制成本,又能提升排序质量。
对于大多数工程项目来说,混合型方案会更稳。
Rerank 不只是排序,也影响上下文压缩
Rerank 的作用不只是把片段排个顺序。
它还会影响最终上下文的选择和压缩。
大模型的上下文窗口虽然越来越大,但这不代表应该把所有内容都塞进去。
上下文越长,成本越高。
同时,模型需要在更多信息里找答案,干扰也会变多。
所以 RAG 系统通常要做两件事:
第一,选择哪些片段进入 Prompt。
第二,决定每个片段保留多少内容。
比如召回 30 个候选,Rerank 后只选择前 5 个。
但这 5 个片段也不一定原样放进去。
有些片段可能太长,需要只保留和问题相关的部分。
可以这样处理:
候选片段 ↓ Rerank 排序 ↓ 选择高相关片段 ↓ 提取关键段落 ↓ 控制总 token ↓ 拼接最终上下文这一步很关键。
因为最终模型看到的不是整个知识库,也不是全部召回结果,而是经过选择后的上下文。
如果上下文选择错了,后面的 Prompt 再好也很难补救。
所以 Rerank 本质上是在决定:
模型应该基于哪些证据回答。
什么时候一定要考虑 Rerank?
并不是所有 RAG 系统一开始都必须上复杂 Rerank。
如果知识库很小、问题很简单、文档结构很清晰,直接 TopK 可能已经够用。
但如果出现下面这些情况,就应该认真考虑 Rerank。
第一,检索结果看起来相关,但答案经常不准。
这说明系统不是完全没召回,而是排序和上下文选择出了问题。
第二,TopK 里经常有重复片段。
重复片段会浪费上下文,让模型看到很多类似但没有增量的信息。
第三,文档里有大量相似流程。
比如采购审批、报销审批、合同审批、立项审批。
这些流程语义相似,如果不重排,很容易混在一起。
第四,知识库里有大量编号、参数、版本、产品型号。
这类内容要求精确命中。
相似但错误的片段会直接导致错误答案。
第五,Hybrid Search 召回结果变多。
多路召回能提高召回率,但也会带来更多候选。
这时必须有一个更精细的排序步骤。
第六,模型上下文成本开始变高。
如果每次都把大量 Chunk 塞给模型,成本会快速上升。
Rerank 可以帮助减少无效上下文。
第七,用户开始要求引用来源。
一旦答案需要给出处,系统就不能只生成一个看似合理的回答。
它必须选择真正支撑答案的片段。
这些场景都说明,Rerank 不是高级装饰,而是 RAG 从 Demo 走向可用系统的重要环节。
一个更合理的 RAG 检索链路
把前几篇文章串起来,一个更合理的 RAG 检索链路可以这样设计:
用户问题 ↓ Query 预处理 ↓ 向量检索 ↓ 关键词检索 ↓ Metadata Filter ↓ 候选结果合并 ↓ 去重 ↓ Rerank ↓ 上下文压缩 ↓ Prompt 生成 ↓ 答案和引用来源这里每一步都有自己的作用。
Query 预处理负责理解用户问题,必要时做改写、拆分或补全。
向量检索负责召回语义相似内容。
关键词检索负责命中精确词、编号、代码、参数名。
Metadata Filter 负责控制权限、租户、版本、时间范围和文档类型。
候选合并负责把多路结果放到一起。
去重负责减少重复片段。
Rerank 负责重新判断候选内容和问题的匹配程度。
上下文压缩负责控制最终进入 Prompt 的内容量。
Prompt 生成负责要求模型基于证据回答,并在证据不足时明确说明。
这个链路比最小 Demo 复杂。
但它更接近真实可用的 RAG 系统。
因为真实问题不是“能不能跑通”,而是:
检索结果是否稳定,答案是否可解释,成本是否可控,错误是否能排查。
Rerank 的常见误区
第一个误区是认为 Rerank 可以解决所有检索问题。
Rerank 的前提是候选集合里已经有正确内容。
如果召回阶段完全没有把正确片段找出来,Rerank 也排不出来。
所以 Rerank 不能替代文档切分、Embedding 选型、关键词检索和元数据过滤。
它是在候选内容里做精排,不是凭空创造答案。
第二个误区是候选越多越好。
候选太少可能漏掉答案。
候选太多会增加排序成本,也会引入更多噪声。
需要根据知识库规模和问题类型设置合理的候选数量。
比如先召回 30 到 50 个候选,再 Rerank 到前 5 或前 8 个。
具体数字不应该拍脑袋,而应该通过测试集评估。
第三个误区是只看 Rerank 后的分数。
分数本身只是辅助判断。
更重要的是看最终答案是否引用了正确片段,是否减少了无关上下文。
第四个误区是忽略延迟。
模型型 Rerank 会带来额外计算。
如果每个用户请求都对大量候选做 Rerank,系统响应可能变慢。
所以工程上要做取舍:
召回数量 Rerank 候选数量 最终上下文数量 延迟 成本 答案质量这些指标要一起看。
第五个误区是把 Rerank 当成最后一步补丁。
如果前面的文档切分很差,Chunk 缺少标题和上下文,Rerank 也会很难判断。
Rerank 依赖候选片段本身的质量。
所以它应该和数据处理、切分策略、检索策略一起设计。
怎么评估 Rerank 是否有效?
判断 Rerank 有没有价值,不能只靠感觉。
至少应该准备一组真实问题集。
每个问题最好包含:
用户问题 标准答案 应该命中的文档或片段 不应该命中的干扰片段然后比较两个版本。
一个是不使用 Rerank 的版本。
一个是使用 Rerank 的版本。
重点观察几个指标。
第一,正确片段是否排得更靠前。
比如原来正确片段在第 8 位,Rerank 后到了第 2 位。
这说明重排序确实提高了证据优先级。
第二,最终答案是否更准确。
Rerank 的目的不是让排序看起来更漂亮,而是让答案更可靠。
第三,无关上下文是否减少。
如果进入 Prompt 的片段更少,但答案质量不下降,说明上下文选择更高效。
第四,引用来源是否更准确。
如果系统需要展示引用来源,Rerank 后应该更容易引用真正支撑答案的文档。
第五,延迟和成本是否可接受。
质量提升如果换来不可接受的延迟,也不能直接上线。
所以评估时不能只看准确率,还要看性能和成本。
一个实用的评估方式是:
同一批问题 ↓ 分别跑无 Rerank 和有 Rerank ↓ 记录召回结果、排序结果、最终上下文、答案 ↓ 人工或自动评估答案质量 ↓ 比较准确率、引用命中、延迟和成本这样才能知道 Rerank 是否真的带来了收益。
落地建议
如果你正在做一个 RAG 系统,可以按下面顺序推进。
第一步,先把召回链路打通。
不要一开始就堆复杂 Rerank。
先确认文档解析、切分、Embedding、向量检索和关键词检索基本可用。
第二步,记录完整召回日志。
至少要记录:
用户问题 召回片段 原始检索分数 来源文档 metadata 最终进入 Prompt 的片段 模型答案没有日志,就很难判断问题出在召回、排序还是生成。
第三步,先做简单规则。
比如:
标题命中加权 关键词精确命中加权 过期文档降权 重复片段去重 同一文档片段数量限制 权限和版本过滤这些规则成本低,很多时候就能明显改善质量。
第四步,再引入模型型 Rerank。
当规则已经不够用,或者问题复杂度上升时,再考虑模型型 Rerank。
第五步,控制候选数量。
不要对所有召回结果都做 Rerank。
可以先召回较多候选,再通过规则过滤和去重缩小范围。
第六步,持续评估。
每次改检索、改切分、改 Rerank,都应该用同一批问题回归测试。
否则很容易出现某些问题变好了,另一些问题变差了。
总结
RAG 不是把 TopK 检索结果直接塞给模型这么简单。
TopK 只是粗召回结果,不代表最终答案上下文。
向量分数高,只能说明语义相似,不代表片段一定能回答问题。
Hybrid Search 可以让系统召回更多候选内容,但候选变多以后,更需要 Rerank 来判断优先级。
Rerank 的核心作用,是在生成之前重新排序候选片段,让真正能支撑答案的内容排到前面。
它可以减少无关上下文、降低 token 浪费、提升引用准确性,也能让模型更容易基于正确证据回答。
但 Rerank 不是万能的。
它依赖前面的文档解析、切分、Embedding、关键词检索和 metadata filter。
如果正确片段没有被召回,Rerank 也无法补救。
所以更合理的做法,是把 Rerank 放进完整 RAG 链路里一起设计。
从工程角度看,Rerank 是 RAG 从“能跑”走向“稳定可用”的关键步骤之一。
下一篇文章,可以继续讨论 RAG 的 Prompt 应该怎么写。
因为即使检索和排序都做对了,最终答案仍然需要 Prompt 来约束模型基于资料回答。