Reranker 指南 2026
Top-k 检索把正确文档排在第9位,模型就答不上来。Reranker 改几行代码就能把排序拉正,是 RAG 里性价比最高的一步升级。这篇讲两阶段架构、模型选型、参数、评估和踩坑。
Reranker 指南 2026:不重训模型就提升 RAG 检索
Top-k 检索把正确文档排在第 9 位,模型就答不上来。改嵌入模型要重跑全量索引,改分块要重洗数据,唯独加一层 reranker 只需要几行代码:召回不变,排序变准。这是 2026 年 RAG 里性价比最高的一步升级。
一、向量检索为什么会排错
双编码器(bi-encoder)把 query 和文档分别编码成向量,再算余弦相似度。问题是编码时两者互相看不见,模型只能判断"主题像不像",判断不了"这段话能不能回答这个问题"。用户问退款流程,术语表里"退款"的定义往往比退款政策本身更像。
| 类型 | 编码方式 | 成本 | 精度 | 能否预计算 |
|---|---|---|---|---|
| 双编码器 | query 和 doc 各自编码 | 低,可建索引 | 中 | 能 |
| 交叉编码器 | query 和 doc 拼在一起打分 | 高,逐对计算 | 高 | 不能 |
所以两者不是替代关系,是流水线的两段。
二、两阶段流程
标准做法是:向量检索召回 50 到 100 条,reranker 逐对打分,取前 3 到 8 条塞进上下文。
用户提问
└─ 向量检索 top 100(召回优先,宁多勿少)
└─ Reranker 逐对打分(精排)
└─ 取 top 5 + 元数据 → 拼进提示词
召回阶段的目标是"别漏",精排阶段的目标是"别错"。两个阶段用不同模型,各自优化各自的指标。
三、模型怎么选
| 模型 | 部署 | 语言 | 成本 | 适合 |
|---|---|---|---|---|
| bge-reranker-v2-m3 | 自托管(FlagEmbedding) | 多语言,中文表现稳 | 算力成本 | 默认首选,可 CPU 跑小批量 |
| bge-reranker-base / large | 自托管 | 中英 | 算力成本 | 显存紧张时的轻量选择 |
| Cohere Rerank | 托管 API | 多语言 | 按调用计费 | 不想运维模型的小团队 |
| Jina Reranker | 托管 API / 自托管 | 多语言 | 按量或自托管 | 长文档场景 |
| Qwen3-Reranker 系列 | 自托管 | 多语言 | 算力成本 | 想要更大模型、有 GPU |
| 用 LLM 直接打分 | 任意 LLM | 任意 | 最贵最慢 | 候选少、要求极高的场景 |
自托管优先,因为 reranker 的调用量和查询量同阶,按次计费的 API 在流量上来后并不便宜。中文场景不要用纯英文模型,分数分布会很难看。
四、最小可用代码
from FlagEmbedding import FlagReranker
reranker = FlagReranker("BAAI/bge-reranker-v2-m3", use_fp16=True)
def rerank(query, candidates, top_n=5, threshold=0.0):
pairs = [[query, c["text"]] for c in candidates]
scores = reranker.compute_score(pairs, normalize=True, batch_size=8)
ranked = sorted(zip(scores, candidates), key=lambda x: x[0], reverse=True)
return [c for s, c in ranked[:top_n] if s >= threshold]
normalize=True 把分数压到 0 到 1,方便设阈值和做展示。不归一化也能排序,但不同批次之间的分数不可比。
五、参数怎么调
| 参数 | 建议起点 | 影响 |
|---|---|---|
| recall_k(召回条数) | 50-100 | 太小 reranker 没料可选,太大延迟线性上涨 |
| top_n(最终条数) | 3-8 | 多了挤占上下文,少了容易缺关键段 |
| batch_size | 8-32 | 显存和吞吐的平衡点,CPU 上小批量反而快 |
| max_length | 512 | 覆盖多数段落;超长文档先分块再打分 |
| 阈值 | 先不设,跑完看分布 | 归一化后不同模型不可通用,要自己标数据定 |
调参顺序建议:先把 recall_k 拉大验证上限,再收 top_n 看答案质量,最后才动阈值。反过来做,你分不清是召回不够还是排序不准。
六、怎么证明它真的有用
离线评估:固定 50 到 100 条真实 query,人工标出每条 query 的正确答案段落,比较加 reranker 前后的 recall@5、nDCG@10 和 MRR。只看"感觉回答变好了"不算证据。
上线评估:看答案里的引用命中率、用户追问率、人工抽检 30 条的通过率。追问率下降通常比满意度评分更灵敏。
七、常见坑
把分数当概率用。 0.7 不代表 70% 正确,只代表在这批候选里相对靠前。阈值要靠标注数据定。
候选里本来就有重复块。 rerank 之后前五条还是同一段话的五个切片。精排前先按文本指纹去重。
忽略延迟预算。 50 条候选在 GPU 上是几十毫秒量级,在 CPU 上可能是几百毫秒。交互式场景要把它算进端到端预算,必要时把 recall_k 降到 20 到 30。
长文档直接截断。 超过 max_length 的部分会被切掉,答案刚好在后半段就白排了。先按语义分块,再 rerank。
八、混合检索加精排的组合
纯向量召回对订单号、型号、人名这类精确词不敏感:用户搜「A1278 电池」,向量模型看到的是"电池"的语义,具体型号被抹平。加一路 BM25 关键词召回,用倒数排名融合(RRF)合并,再统一 rerank,是生产环境最常见的组合。
| 组合 | 召回质量 | 复杂度 | 适用 |
|---|---|---|---|
| 纯向量 | 中 | 低 | 语义问句为主 |
| 向量 + BM25 融合 | 高 | 中 | 有编号、型号、专有名词 |
| 融合 + rerank | 最高 | 中 | 多数生产场景 |
def rrf(ranked_lists, k=60):
scores = {}
for lst in ranked_lists:
for rank, doc_id in enumerate(lst):
scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1)
return sorted(scores, key=scores.get, reverse=True)
RRF 的好处是不用调权重,按名次倒数相加就行,两路召回的分数尺度不同也不影响。但融合前必须去重:同一文档在两路都排前面会拿到两份加分,结果过度集中,rerank 的候选多样性反而下降。
常见问题
Q:一定要有 GPU 吗? A:不一定。bge-reranker 系列的中小模型在 CPU 上能跑,只是吞吐低。日查询量在几千次以内,CPU 加批处理够用。
Q:和混合检索冲突吗? A:不冲突,而且建议叠加。BM25 加向量做召回,再统一 rerank,对专有名词和编号类查询提升明显。
Q:要不要微调 reranker? A:先把通用模型跑出 baseline。只有在标注数据足够、且业务术语特别偏门时才考虑微调,否则收益不如换更大的通用模型。
Q:top_n 到底取几条? A:先按 5 条起步。答案需要多段拼接的任务取 8,单点事实问答取 3。用离线评估扫一遍 3、5、8 就有答案。
Q:召回条数从 50 降到 20 会掉多少质量? A:取决于文档库规模和分块粒度,通常掉得比想象中少。用离线评估扫 20、50、100 三个值,如果 20 和 50 在 recall@5 上的差距可以接受,就按 20 跑,延迟能省一半。反过来,如果 50 和 100 差距明显,说明该先修分块策略,而不是继续加召回量。
注:模型名称、授权和价格随版本变化,具体以官方模型卡与定价页为准。
相关文章
本站文章由编辑人工撰写,收录的工具均经过实测或公开资料核验。文中链接指向工具官网或 GitHub 仓库,仅作信息参考,不构成付费推广。