Skip to content

召回与精排

五层读懂一个词。这次拆的是:召回与精排(Recall & Rerank)--两阶段检索的工程架构,工业级搜索系统的标配漏斗。


L1 · 一句话点破

召回从百万级筛到 top-1000(保 recall,速度快),精排从 top-1000 重排到 top-10(求 precision,精度高)。两阶段配合,把"快但粗"和"慢但准"的优点结合起来。


L2 · 通俗类比

想象超市选苹果:

  • 召回阶段:在仓库十万颗苹果中快速扫一遍,挑出可能新鲜的 1000 颗。要求快,宁可多挑不可漏。这步用粗筛标准(颜色、大小)。
  • 精排阶段:把这 1000 颗逐个仔细检查(闻香、看把儿、测糖度),挑出最好的 10 颗摆上货架。要求准,可以慢。

为什么不直接精排十万颗?因为精排慢,逐个仔细检查要几小时。为什么召回后不只看 top-10?因为粗筛标准不够准,真正最好的苹果可能排到 top-500,被截断就漏了。

工程取舍:召回保 recall(不漏好货),精排求 precision(前排都是好货)。两阶段配合是工业检索系统的标配。

实际系统可能更多阶段:召回 -> 粗排 -> 精排 -> 重排(多样性 / 业务),形成多级漏斗。


L3 · 正经定义

召回 (Recall) 阶段:从大规模文档库(百万~十亿)快速筛选出候选集(千级),目标是高 recall(相关文档不漏)。

精排 (Rerank) 阶段:对候选集(千级)用复杂模型重排,输出 top-k(十级),目标是高 precision(top-k 都是相关的)。

典型架构

全库 (10^9)
  ↓ 召回(双塔 + ANN + BM25)
候选集 (10^3)
  ↓ 精排(Cross-encoder)
top-k (10)
  ↓ 重排(多样性 / 业务规则)
最终展示 (10)

召回阶段特性

  • 高 recall(> 95% 相关文档在候选集中)
  • 低延迟(< 100ms)
  • 可并行多路召回(双塔、BM25、ColBERT 等)
  • 模型轻量(双塔、IVF-PQ)

精排阶段特性

  • 高 precision(top-k 都相关)
  • 中等延迟(100~500ms)
  • 模型重量级(Cross-encoder、LLM-reranker)
  • 可用更多特征(文档元数据、用户行为、上下文)

多路召回融合

python
def multi_recall(query, top_k_per_channel=500):
    # 多路召回
    dense_results = bi_encoder_retrieve(query, top_k=500)  # 双塔
    sparse_results = bm25_retrieve(query, top_k=500)        # BM25
    colbert_results = colbert_retrieve(query, top_k=500)    # ColBERT

    # 融合(RRF 或加权)
    fused = rrf_fuse([dense_results, sparse_results, colbert_results])
    return fused[:1000]  # 精排候选

精排重排

python
def rerank(query, candidates, top_k=10):
    pairs = [(query, c.text) for c in candidates]
    scores = cross_encoder.score(pairs)  # 批量打分
    reranked = sorted(zip(candidates, scores), key=lambda x: -x[1])
    return reranked[:top_k]

评估指标分阶段

  • 召回阶段:recall@1000(候选集中相关文档比例)
  • 精排阶段:recall@10、MRR@10、NDCG@10(top-k 中相关文档排序质量)

L4 · 原理深挖

4.1 为什么要两阶段

单阶段方案的局限

  • 全用 Cross-encoder:精度高但每对前向,百万级不可行
  • 全用双塔:可扩展但精度不足,top-1 可能不够准

两阶段的优势

  • 召回用快模型,从百万筛到千级
  • 精排用重模型,在千级上求精度
  • 总延迟 = 召回延迟 + 精排延迟 ≈ 50ms + 200ms = 250ms,可接受

信息论视角:召回是"宽网捞鱼",让真正相关的候选进入下一步;精排是"细筛分鱼",在候选中精确排序。两者目标不同,模型设计也不同。

4.2 召回阶段的多路融合

现代系统几乎都用多路召回(hybrid retrieval):

典型多路组合

  • 双塔(Dense):语义召回,强项是同义、近义
  • BM25(Sparse):字面召回,强项是精确匹配、专有名词
  • ColBERT(Late interaction):精度高于双塔,速度低于双塔,可作为补充召回
  • 用户行为召回:基于点击日志、协同过滤
  • 业务规则召回:如最新发布、热门、订阅等

融合方法

  • RRF (Reciprocal Rank Fusion):$\text{score}(d) = \sum_i \frac{1}{k + \text{rank}_i(d)}$,无需归一化,鲁棒
  • 加权融合:$\text{score}(d) = \sum_i w_i \cdot \text{normalize}(s_i(d))$,需调权重
  • 学习融合(LTR):训练排序模型融合多路分数

详见后续 hybrid-search、rrf、weighted-fusion 词条。

4.3 精排阶段的特征工程

Cross-encoder 主要用文本特征,但精排可加更多特征:

文本特征

  • query-doc 文本匹配分数(Cross-encoder)
  • BM25 分数(保留作特征)
  • 双塔相似度分数(保留作特征)

文档特征

  • 文档长度、发布时间、质量分
  • 文档历史点击率、收藏率
  • 文档作者权重、来源权威度

查询特征

  • query 长度、意图分类
  • 用户历史查询、用户画像
  • 上下文(如会话历史)

交叉特征

  • query 与 doc 的主题匹配度
  • 用户与 doc 的历史交互
  • 个性化偏好

精排模型

  • Cross-encoder:纯文本 rerank
  • GBDT (LightGBM / XGBoost):特征工程强,可解释
  • DNN:深度融合文本和特征
  • LTR (Learning to Rank):LambdaMART 等经典方法

4.4 多阶段排序的漏斗

工业级系统常是多阶段,每阶段过滤比例约 10:1:

1. 召回(百万 -> 千)
   - 多路并行:双塔 + BM25 + ColBERT
   - 融合:RRF 或加权
   - 目标:recall > 95%

2. 粗排(千 -> 百)
   - 轻量 Cross-encoder 或 GBDT
   - 用更多特征
   - 目标:保留 top-100 中至少 90% 真正相关

3. 精排(百 -> 十)
   - 重 Cross-encoder 或 DNN
   - 全特征
   - 目标:top-10 中至少 8 个相关

4. 重排(十 -> 展示)
   - 多样性(MMR)
   - 业务规则(去重、过滤、加权)
   - 个性化

为什么多阶段

  • 单次精排 top-1000 延迟太大(Cross-encoder 每对 50ms,千对 = 50s 不可行)
  • 粗排用轻量模型先把千筛到百,再上重模型
  • 每阶段过滤比例小(10:1)保证 recall 不掉太多

4.5 召回与精排的训练数据差异

召回训练数据

  • 大规模点击日志(千万~亿级)
  • 弱监督(点击视为正样本,但点击 ≠ 相关)
  • 难负样本挖掘(BM25 top-k 非相关)
  • 偏好覆盖广(多领域、多查询类型)

精排训练数据

  • 人工标注(千~万级,质量高)
  • 多级标签(高度相关 / 相关 / 一般 / 不相关)
  • 偏好精度(细分相关度)
  • 难负样本(与正样本相似的负样本)

关键差异:召回数据多但噪声大,精排数据少但精确。两阶段配合,召回用大数据泛化,精排用小数据精调。

4.6 召回阶段的 recall 上限决定整体上限

铁律:如果召回阶段漏掉相关文档(recall@1000 = 80%),精排再准也无法恢复(最高 recall@10 = 80%)。

工程含义:

  • 召回阶段宁可多召回(top_k = 1000 而非 100),保证 recall
  • 多路召回互补(BM25 + Dense + ColBERT),各路召回率叠加
  • 召回质量评估比精排更重要(recall@1000 是关键指标)

实践:定期监控召回阶段的 recall@1000,掉到 90% 以下就要调参或加路。

4.7 精排的延迟优化

精排 top-1000 延迟大,优化手段:

优化 1:粗排预筛。粗排(轻量模型)先把 1000 筛到 100,再上 Cross-encoder。粗排可用 GBDT、轻量 BERT。

优化 2:批量化。top-100 一次前向,比逐对快 10 倍+。

优化 3:量化。FP16 / INT8 量化,速度 2~4 倍。

优化 4:缓存。同 query 候选分数缓存。

优化 5:异步预计算。可预知 query 时提前算(如热门 query 缓存结果)。

优化 6:模型蒸馏。把重 Cross-encoder 蒸馏到轻量 student,部署时用 student。

4.8 重排阶段:多样性与业务

精排后还需重排,原因:

多样性:top-10 都是相关,但内容雷同(如 10 篇都讲同一观点),用户体验差。用 MMR (Maximal Marginal Relevance) 等算法保证多样性:

$$ \text{MMR}(d) = \arg\max_{d \in C} [\lambda \cdot \text{sim}(q, d) - (1 - \lambda) \cdot \max_{d' \in S} \text{sim}(d, d')] $$

$S$ 是已选集,$\lambda$ 控制相关性与多样性的权衡。

业务规则

  • 去重(同作者、同来源限流)
  • 过滤(敏感内容、过期内容)
  • 加权(精品内容、付费内容加权)
  • 个性化(用户偏好)

位置偏见:top 位置有展示优势,重排时考虑位置偏差(如用 ELO 评分)。


L5 · 沿革与坑

5.1 历史脉络

  • 1990s:搜索引擎早期就是 BM25 单阶段排序
  • 2000s:Yahoo、Google 引入 LTR(Learning to Rank),多特征精排
  • 2010s:深度学习兴起,DSSM 等双塔召回
  • 2016:YouTube 双塔推荐召回,工业级两阶段架构
  • 2019:BERT-based reranker 兴起,精排精度大幅提升
  • 2020:DPR 论文确立两阶段架构(双塔召回 + Cross-encoder 精排)
  • 2021+:多路召回融合(BM25 + Dense)成为标配
  • 2023+:RAG 系统采用同样架构(向量召回 + Cross-encoder 精排)

5.2 工程常见坑

坑 1:召回 top_k 太小

召回 top_k = 50,若真正相关文档在第 51~100 位,精排再准也救不回。建议 top_k = 500~1000,给精排足够候选。

坑 2:精排候选规模太大

精排 top_k = 1000 时 Cross-encoder 延迟太大(> 1 秒)。要么加粗排预筛,要么减小 top_k 到 100~200。

坑 3:召回和精排训练数据不一致

召回用点击日志(弱监督),精排用人工标注(强监督)。两模型见的"相关"定义可能不一致,精排时召回的候选可能与精排判断冲突。训练时对齐两阶段的相关性定义。

坑 4:忘了监控召回 recall

召回 recall 悄悄掉到 80%,精排再努力也救不回。监控 recall@1000,掉到 90% 以下立即调参。

坑 5:多路召回分数没归一化

Dense 分数范围 [0, 1],BM25 分数范围 [0, 50+],直接加权 BM25 主导。要用 RRF(无需归一化)或归一化后加权。

坑 6:精排用召回阶段特征

召回用文本向量,精排还用文本向量,信息冗余。精排要加新特征(点击率、用户行为、文档质量)提升价值。

坑 7:粗排召回率不够

粗排把 1000 筛到 100 时漏掉真正相关文档,精排救不回。粗排 recall@100 要 > 95%。

坑 8:精排模型未量化

FP32 推理慢,FP16 / INT8 量化速度快 2~4 倍,精度损失 < 1%。生产必量化。

坑 9:重排过度

重排加太多业务规则(去重、过滤、加权),把精排结果搞乱。重排要克制,主要做多样性和必要业务规则。

坑 10:评估只看精排指标

只看 recall@10、NDCG@10,不看 recall@1000,发现不了召回阶段问题。两阶段指标都要监控。

5.3 召回与精排的模型选择

召回模型

模型速度精度适用规模
BM25极快中(字面)任意
双塔 (DPR/BGE)中(语义)大规模
ColBERT中规模

精排模型

模型速度精度适用
Cross-encoder文本精排
GBDT特征精排
DNN多特征融合
LTR (LambdaMART)经典排序

典型组合

  • 通用:BM25 + 双塔召回 -> Cross-encoder 精排
  • 高精度:BM25 + 双塔 + ColBERT 召回 -> Cross-encoder 精排
  • 工业级:多路召回 -> GBDT 粗排 -> Cross-encoder 精排 -> MMR 重排
  • RAG 简化:BM25 + 双塔召回 -> 直接用 LLM 精排

5.4 RAG 中的召回与精排

RAG 系统的检索就是召回与精排的简化版:

知识库 (10^6 chunks)
  ↓ 召回(BM25 + Dense 混合)
候选 chunks (10^2)
  ↓ 精排(Cross-encoder 或 LLM)
top-k chunks (5~10)
  ↓ 喂给 LLM 生成回答

RAG 简化版的特点

  • 召回阶段常用 BM25 + Dense 双路
  • 精排可选(小规模知识库可省略)
  • top-k 通常 5~10(受 LLM context 限制)
  • 重排用 LLM 自身(生成时排序)

RAG 精排的取舍

  • 不精排:省延迟,但 top-k 可能有不相关 chunk,LLM 生成受影响
  • Cross-encoder 精排:精度提升,但加 200ms 延迟
  • LLM 精排:让 LLM 自己评估 chunk 相关性,精度高但成本高

速记卡

阶段目标模型延迟规模
召回recall 高BM25 / 双塔 / ColBERT< 100ms百万 -> 千
粗排中等过滤GBDT / 轻量 BERT< 50ms千 -> 百
精排precision 高Cross-encoder / DNN100~500ms百 -> 十
重排多样性 / 业务MMR / 规则< 10ms十 -> 展示

关键指标

  • 召回:recall@1000(候选集含相关文档比例)
  • 精排:recall@10 / MRR@10 / NDCG@10
  • 端到端:recall@10 / MRR@10

两阶段铁律

  1. 召回 recall 决定上限(精排救不回召回漏掉的)
  2. 召回宁多勿少(top_k = 1000 而非 100)
  3. 精排求 precision(top-k 都是相关的)
  4. 多路召回互补(BM25 + Dense + ColBERT)

一句话记忆:召回保 recall(百万筛千,快但粗),精排求 precision(千筛十,慢但准)。两阶段漏斗配合,是工业检索系统的标配。RAG 系统简化为 BM25 + Dense 召回 + 可选 Cross-encoder 精排。


上一篇:ColBERT -- 召回与精排的折中方案。下一篇:Top-K 检索 -- top-k 的语义与工程含义。

内容采用 CC BY-SA 4.0,代码采用 MIT。