Skip to main content

10 · 重排序与对话式 RAG:从”能答”到”答得准”

本片目标:解决第 09 篇遗留的两个质量问题——① 检索噪音(用重排序精排);② 多轮追问失准(用历史感知检索)。 新增规定性:10(两段式检索:粗排召回 + 精排重排;查询改写:结合历史) 数据字典:CrossEncoder(sentence_transformers)。 进程线程模型:重排是本地 GPU/CPU 推理;历史感知检索是多一次模型调用。 网络模型:重排本地;历史感知检索 = 1 次模型调用(改写查询)+ 1 次主问答调用。

1. 上集回顾

第 09 篇 RAG 能答了,但两个真实场景会翻车: 场景 A:检索噪音。问”转正需要什么条件”,向量检索召回 3 块,可能第 3 块是”自带电脑补助”——语义距离没拉开。模型被迫在噪音里找答案,容易被带偏。 场景 B:多轮追问
第二个问题脱离上下文就无法检索。必须结合对话历史改写查询(“那答辩要几位评委” → “转正答辩需要几位评委打分”)。

2. 重排序:为什么需要两段式

向量检索(粗排)是”快而粗”:一次把千万块向量算相似度,秒级,但用的是双塔模型(query 和 doc 分别编码,最后算点积)——它牺牲精度换速度。 CrossEncoder(精排)是”慢而准”:把 query 和 doc 拼接成一条喂给模型,做深度交叉注意力——精度高,但一次只能处理一对。 生产方案 = 粗排捞 + 精排挑
为什么不能全用精排:知识库 1 万块,CrossEncoder 要跑 1 万次——太慢。先粗排砍到 8 块,再精排挑 3 块。重排救不了粗排漏掉的块——所以粗排 k 要足够大。

3. 数据字典:CrossEncoder

实测分数(2026-08,models/bge-reranker-base):
区分度极高——重排能干净地把噪音块剔除。

4. 重排接入 RAG(代码形态)


5. 对话式 RAG:历史感知检索(查询改写)

问题本质:第 06 篇的对话记忆 + 第 09 篇的 RAG 是两条独立的链,没打通。追问时检索器看到的是残缺的问题 解法(查询改写,无 agent、无 LangGraph)
实测效果

6. 关键方法(本片完整链路)


7. 进程线程模型

代价意识:对话式 RAG 把延迟从”1 次模型调用”变成”2 次模型调用”(改写 + 生成)。这是”准”的代价。生产级取舍见第 15 篇(可以只对多轮场景启用改写)。

8. 网络模型

两次模型调用都是标准 POST——没有新协议。区别只在输入内容:一次是”改写指令”,一次是”带资料的问答”。

9. 验证:跑起来

配套代码 code/10_rerank.py(分三幕):
  1. 重排演示:粗排 k=8 → CrossEncoder 打分 → 观察分数分布(相关 0.98 vs 噪音 0.00);
  2. 重排接入 RAG:对比有/无重排的答案质量;
  3. 对话式 RAG:两轮追问,观察改写前后检索命中变化。
预期输出(节选)

10. 边界

  • 重排增加延迟:CrossEncoder 逐对推理,粗排 k 越大越慢。k=8~20 是常见区间。
  • 改写会漂移:改写模型可能改错原意。生产可在改写失败时回退用原始问题。
  • 重排模型要下载bge-reranker-base 约 1.1GB(本机已在 models/)。也可用更小的 bge-reranker-v2-m3
  • 粗排 k 必须大于最终 k:精排只从粗排结果里挑,粗排漏了精排救不了。

推荐资料(延伸阅读)


11. 未完待续

RAG 已经完整(对话 + 重排),能回答文档问题了。但有个天花板:
模型只能”说”,不能”做”。 用户问”转正答辩还有几天?“——手册里没有答案,得出来。你不想为每个问题写死函数。
让模型在回答时调用你写的工具(算日期、查系统、发请求)——这就是第 11 篇:工具调用。 11 · 工具调用