检索完为什么要 rerank?重排模型实测与接入
很多 RAG 项目做到"能检索出东西"就停了,但检索质量其实还有很大提升空间。召回阶段(retrieval)和精排阶段(rerank)分开做,是效果最好的做法。这篇文章讲我怎么接入 rerank。
为什么需要 rerank:向量检索是"双塔"结构,文档和查询各自编码再算相似度,快但对细粒度匹配不敏感。rerank 用 cross-encoder:把查询和文档拼在一起过一遍模型,直接算相关性分数。慢但准。经典组合:召回 top-20 → rerank 精排 top-5。
实现(用 bge-reranker):
from FlagEmbedding import FlagReranker
reranker = FlagReranker("BAAI/bge-reranker-v2-m3")
# 查询和候选文档两两打分
scores = reranker.compute_score([
[query, doc1], [query, doc2], ...
])
# 按分数排序,取 top-5
实测效果:同样的检索链(bge-m3 召回 + bge-reranker 精排),在中文知识库测试集上 Recall@5 从 0.83 提到 0.91,最终问答准确率也从 78% 提到 85%。
坑:
-
rerank 很慢。cross-encoder 是逐对打分的,20 个候选就是 20 次前向。本地 CPU 上 20 对要 2-3 秒,用户会明显感觉变慢。我的方案:只对 top-20 做 rerank(召回时多取点),且用 GPU 跑 reranker,能压到几百毫秒。
-
rerank 阈值要设。不是分数最高的就一定是好结果,如果所有候选分数都低,说明检索本身就没找到对的,硬塞给模型反而误导。我设了 0.5 的阈值,低于它宁可让模型说"没找到"。
-
模型选择。bge-reranker 有两个版本:v2-m3 支持 8192 token(适合长文档),基础版只有 512。长文档场景选错了会截断。
-
别迷信 rerank 万能。如果召回阶段就没召回来,rerank 再强也没用。先调好 embedding 和分块,再加 rerank 才是正确顺序。
一句话总结:召回做"宽",rerank 做"准",两者配合才是完整的高质量检索链。
评论0
还没有评论,来抢沙发~