RAG 召回之后还差最后一公里:bge-reranker 重排实战
召回准,不等于排序准 混合检索把候选召回了,但有个致命问题:向量相似度是双向独立编码——query 和文档各自先变成向量,再算距离。这种方式快,但它没法精细判断「这份文档到底答没答这个问题」。Top-20 里经常混着几条主题接近、实则答非所问的 chunk,大模型把它们一起读进去,就容易被带偏。解决办法是在召回之后加一道重排(rerank):用交叉编码模型把 query 和每篇候选拼在一起,让模型直接打一个相关性分数,再按分数重排取 Top-3 或 Top-5。 为什么用 bge-reranker 重排模型里,Cohere Rerank 是商业服务里最成熟的,但要按调用量付费、数据要出域。国内生产环境更常用的是开源的 bge-reranker 系列(智源 BAAI 出品):bge-reranker-v2-m3 支持中英文多语言,参数约 568M,单张消费级显卡就能跑;更小的 bge-reranker-base 约 278M。它和 embedding 模型同源,配 bge-m3 做向量召回、bge-reranker-v2-m3 做重排,是一套经过大量生产验证的组合。 环节 模型 作用 量级 召回 bge-m3(1024维) 语义+稀疏双路 百万条索引 重排 bge-reranker-v2-m3 query-doc 交叉打分 只对 Top-20 逐条算 关键认知:重排只对召回后的小候选集(20-50 条)逐条打分,不用对全库算,所以慢一点也无所谓——交叉编码比向量检索慢,但调用量小,整体延迟通常增加 100-300ms,换来的是 Top-5 准确率显著上升。 三个实操参数 第一,重排后取 Top-3 到 Top-5 喂给大模型:别贪多,上下文里塞 8 条文档反而稀释注意力,3-5 条最相关的效果往往更好。第二,设置分数阈值:bge-reranker 输出的 logits 过 0 大致算相关,可以把分数低于阈值的候选直接丢掉,避免硬塞不相关内容。第三,GPU 批处理:transformers 加载时用 torch_dtype=torch.float16、批推理,20 条候选一次算完;没有独显就用 ONNX Runtime CPU 版,慢但够用。LlamaIndex 里直接挂 SentenceTransformerRerank,几行代码接上。 ...