什么是重排序(Rerank)?为什么检索之后还要重排序?

#RAG#Agent#面试八股

什么是重排序(Rerank)?为什么检索之后还要重排序?

结论:重排序(Rerank)是"召回之后、生成之前"的第二阶段精排,用**交叉编码器(Cross-Encoder)**把"查询 + 候选片段" 拼在一起过一遍模型,逐对给出相关性分数。向量召回用的是双塔(Bi-Encoder),两边独立编码、只靠点积交互, 又快又粗;重排模型慢但看得见词与词的对应关系,所以能把"沾边"的候选压下去、"真正回答"的顶上来。

1. 双塔与交叉编码器的结构差异

双塔(Bi-Encoder)—— 召回用
  query ─▶ [编码器] ─▶ q_vec ─┐
                              ├─▶ 点积/余弦 ─▶ 分数
  doc   ─▶ [编码器] ─▶ d_vec ─┘        (doc 向量可以离线预计算)

交叉编码器(Cross-Encoder)—— 重排用
  [CLS] query [SEP] doc [SEP] ─▶ [编码器] ─▶ 分类头 ─▶ 相关性分数
                (必须在查询时联合前向,无法预计算)
对比项双塔交叉编码器
文档向量能否预计算能,索引一次查千次不能,每次查询都要现算
候选规模百万到亿级20~100 条
精度中高,能捕捉否定、限定、数字对应
单条延迟微秒级(点积)毫秒级(GPU 上 1~5 ms)

2. 为什么非要重排:召回阶段的四类系统性失真

失真来源具体表现
交互缺失query 和 doc 分别压缩成一个向量,"不包含 X 的方案"与"包含 X 的方案"可能贴得很近
ANN 近似误差图索引只走"大概率正确"的邻居,真近邻可能被跳过
长片段均值化500 字的块里只有一句相关,向量被其余内容稀释
分数不可比不同查询的余弦分布不同,0.72 在这题是有希望,在另一题是噪声

重排模型读的是原文全文,能判断"这句话到底回答了问题没有",这是双塔结构永远做不到的。

3. 延迟预算怎么分配

阶段条数单条耗时合计
向量/BM25 召回50 + 50< 1 ms~30 ms
RRF 融合100 → 20微秒< 5 ms
交叉编码器重排203 ms(GPU)60 ms
生成1 次调用—0.8~2 s

重排放在 20~50 条上是性价比最高的区间:再多,延迟线性上涨而召回收益趋零——因为正确片段早就在召回结果里了。

4. 代码:用 bge-reranker 做精排

from sentence_transformers import CrossEncoder

# 中文场景优先 bge-reranker-v2-m3(多语言)或 bge-reranker-base
reranker = CrossEncoder("BAAI/bge-reranker-v2-m3", max_length=512)

def rerank(query: str, candidates: list[dict], top_n: int = 5,
           min_score: float = 0.35) -> list[dict]:
    pairs = [(query, c["text"]) for c in candidates]
    scores = reranker.predict(pairs, batch_size=16, show_progress_bar=False)

    for c, s in zip(candidates, scores):
        c["rerank_score"] = float(s)

    kept = [c for c in candidates if c["rerank_score"] >= min_score]
    kept.sort(key=lambda c: c["rerank_score"], reverse=True)
    # 没有一条过阈值就返回空列表,让上层走"无资料"分支而不是硬编
    return kept[:top_n]

# 输出:[{'text': '差旅住宿标准为每晚上限 600 元', 'rerank_score': 0.91}, ...]

min_score 是抑制幻觉的第一道闸门:交叉编码器的分数在同一模型内可比,比向量余弦更适合当"相关性阈值"。 具体阈值要在评估集上扫出来,别照抄。

5. 重排与"中间遗忘"要一起处理

模型对长上下文的注意力是 U 形分布的:开头和结尾记得牢,中间容易忽略。所以重排之后不要简单按分数从高到低平铺, 可以把最相关的两条放首尾,其余放中间:

[资料1 最高分]  ...  [资料3] [资料4]  ...  [资料2 次高分]
        ↑ 首尾位置更容易被引用        ↑ 中间区域是遗忘区

6. 常见追问

Q:重排能提升召回率吗? 不能。重排只在候选集内重新排序,如果正确片段没被召回,重排无能为力。所以指标上:重排提 precision/NDCG,召回要靠混合检索与查询改写。

Q:为什么不用大模型直接打分? 可以,但 20 条候选 × 每次一条 LLM 调用,延迟和成本都不可接受。专用交叉编码器小两个数量级,效果在相关性判断上并不差。

Q:本地模型还是 API? 有 GPU 就本地部署 bge-reranker,无 GPU 可用 Cohere Rerank 这类接口;注意 API 有单次条数上限,且数据要出域。

Q:重排后再截断到几条? 3~8 条。条目数与单块大小要联动算总 token,超过 8k 就该做上下文压缩了。

小结

召回负责"别漏",重排负责"别错"。把两者混为一谈,就会出现"堆更多候选"这种越调越慢、效果不涨的优化。

笔记加载中…