我的博客

RAG 里的最后一公里:LLM 重排序

Aug 2, 2026
RAG重排序RerankLLM
7分钟
1347字

RAG 里的最后一公里:LLM 重排序

前言

RAG 管线跑到重排这一环时,我发现了一个问题:检索结果里有明显的噪声——一首”古典钢琴曲 安静优雅 适合睡前”在检索阶段排到了第二,但对”给健身房找动感的电子摇滚”这个 query,它根本不该出现在前三。检索按相似度排的序,相似 ≠ 相关。重排就是 RAG 的最后一公里:把检索回来的候选,用更强的判断重新精排。


一、检索的噪声问题

看一个我 e2e 里的真实案例:

1
query: 给健身房找动感的电子摇滚
2
3
检索 top3(RRF 融合分):
4
doc_0 健身房电子摇滚 BPM 140 RRF: 0.0328 ← 正确
5
doc_3 重金属摇滚 嘶吼唱腔 RRF: 0.0161 ← 沾边但噪
6
doc_1 古典钢琴曲 适合睡前 RRF: 0.0159 ← 明显噪声

为什么 doc_1 会进来?因为向量检索和 BM25 都是按相似度打分——“音乐”这个维度上它和 query 有重叠,但”场景”(健身房 vs 睡前)完全不匹配。检索阶段的分值是”像不像”,不是”合不合适”。这中间的缝隙,就是重排要填的。

前端类比:检索 ≈ 搜索引擎返回 100 条结果(按相关度粗排),重排 ≈ 你人工扫一眼把真正有用的三条挑出来。搜索是召回,人是精排。


二、方案选型:LLM 打分 vs cross-encoder

重排有两个主流方案:

方案 A:cross-encoder(如 bge-reranker-v2-m3)

  • 把 query 和文档拼成一句,一次前向传播输出相关性分数
  • 快、便宜,但只看 token 层面的匹配,不理解语义场景

方案 B:LLM 打分(本实现)

  • 把每份候选文档连同 query 喂给 LLM,让它打 0-10 分并给理由
  • 慢、贵,但能理解”这首歌适不适合健身房”这种语义

我选了 B。理由很实际:Ollama 官方库没有 bge-rerankerbge-reranker-v2-m3 是社区上传的,拉取命令都不同),而 LLM 打分零新依赖——复用已有的 qwen2.5:7b。更重要的是,7b 就能胜任”打分+给理由”这个任务,理解力远超 cross-encoder。


三、逐条打分 vs 批量排序

选定了 LLM,还有第二个决策:一次喂全部候选让 LLM 排个序(批量),还是每条候选单独打分(逐条)?

批量排序逐条打分(本实现)
LLM 调用次数1 次N 次(每条一次)
成本高(候选少时可控)
可解释只能拿到顺序每条有独立分数和理由
稳定性LLM 容易”端水”——全给 7-8 分分数可比,能看差距
失败隔离一次失败全盘皆输单条失败不影响其他

我选了逐条。候选就 3-5 条,成本可控;而且独立分数能看出”9 分 vs 2 分”的差距,批量排序拿不到这个信息。


四、工程细节三件套

1. temperature = 0.0

打分要确定性。temperature=0.8 时同样的候选可能打出不同分数,重排结果随机抖动。设 0.0 保证”同一输入同一输出”。

2. 分数归一化

LLM 的输出不可控——它可能打 0.6(以为是 0-1 制),也可能打 85(以为是 0-100 制)。_parse_score 做归一化:

1
if score <= 1.0 and score > 0:
2
score *= 10 # 0.6 → 6.0
3
elif score > 10:
4
score = score / 10 # 85 → 8.5

3. 解析容错

LLM 可能套 markdown 代码块、可能前后带废话、可能输出非法 JSON。解析逻辑:剥代码块 → 提取 {...}json.loads → 校验类型 → 失败重试 2 次 → 仍失败则丢弃该候选。


五、实测:重排改了什么

1
query: 给健身房找动感的电子摇滚
2
3
检索 top3 → 重排后:
4
doc_0 健身房电子摇滚 RRF:0.0328 → LLM: 9.0 ✅ 确认正确
5
doc_3 重金属摇滚 RRF:0.0161 → LLM: 3.0 ✅ 噪声被压
6
doc_1 古典钢琴 RRF:0.0159 → LLM: 0.0 ✅ 明显噪声被剔除

三个 query 的 top1 全部稳定——检索质量高时重排不改判。但它做了更重要的事:把正确候选的分数拉开(9 vs 3 vs 0),把噪声候选压到底部。重排前 RRF 分数 0.0328 vs 0.0159 差距不明显,重排后 9 vs 0 一目了然。


六、重排的价值边界

诚实说结论:重排不是万能的。

  • 检索质量高时,重排只是”确认正确”——top1 不变
  • 检索漏掉的内容,重排救不回来——它只能重排”已有的候选”,不能召回”没有的文档”
  • 重排的失败模式:LLM 打分错误(罕见但存在),或者全部候选解析失败返回空

一句话:检索决定上限(候选里有没有正确答案),重排决定交付质量(把正确答案放到最前面)。重排改不了”检索不到”——那是召回问题,不是排序问题。


结论

检索按相似度,精排按语义。相似 ≠ 相关,这是 RAG 管线里最容易忽视的缝隙。

重排的价值不在”纠正错误”(那靠更好的检索),而在”确认正确 + 压掉噪声”——让 LLM 在交付前最后把关一次。检索决定上限,重排决定你拿到的到底是上限还是下限。

本文标题:RAG 里的最后一公里:LLM 重排序
文章作者:vu-ji
发布时间:Aug 2, 2026
Copyright 2026
站点地图