这道题其实是在问,[[RAG]] 系统里向量检索拿到候选块之后,我们还能不能进一步做点什么,让最终送给大模型的内容更准、更相关。我的回答是,[[重排]]这一步非常有必要,但具体怎么做,取决于你对精度和成本的容忍度。
先说为什么需要重排。向量检索用的是 [[Bi-Encoder]],query 和 doc 分别编码,算一个余弦相似度。这个分数有个问题,就是跨查询不可比,同一个分数在不同 query 下意义可能完全不一样。而且它本质是粗粒度匹配,丢失了 query 和 doc 之间细粒度的交互信息。这就导致 Top-K 里可能漏掉真正好的文档,或者混进去一些语义相似但实际不相关的内容。所以重排相当于加了一道精筛,用更高精度的模型重新打分。
具体方法上,我重点讲三个方向。先看 [[Cross-Encoder]],把 query 和 doc 拼起来过一遍 Transformer,直接输出相关性分数。精度最高,但延迟也最高,适合对精度要求极严、延迟可以接受的高价值场景。再看 [[ColBERT]],它做 token 级的延迟交互,算一个相似度矩阵再求和,精度接近 Cross-Encoder,但速度快很多,尤其适合长文档。还要看多路融合,比如把向量检索、[[BM25]]、稀疏向量结果混合起来,用加权或 RRF 融合,适合数据分布复杂、单一通道不够稳的情况。
举个例子,在客服退款场景里,用户问“我买的东西没收到,怎么退款”,向量检索可能召回一堆关于退款流程的文档,但真正需要的是“物流异常+未签收”这种组合。这时候如果只用向量,很容易把“退款流程”和“物流状态”两条线混在一起。我的做法是先用向量检索取 Top-200,然后用轻量 Cross-Encoder(比如 bge-reranker-base)粗排到 Top-50,最后再用大模型精排 Top-10。这样既保证了精度,又把延迟控制在了可接受范围。
这里有个坑,就是重排的候选集大小。如果 Top-K 取太大,比如 1000,重排的延迟会暴涨,而且很多噪声文档根本没必要排。如果取太小,比如 10,又可能漏掉好文档。我一般取 100 到 200 作为起点,然后根据实际召回的 Recall@K 曲线调整。另外,级联过滤是个很实用的策略:先轻量模型过滤掉明显不相关的,再重量级模型精排,这样能在成本和精度之间找到平衡。
所以回到问题,我会把重排看成 RAG 从“可用”到“好用”的关键一步。具体落地时,我倾向于至少部署一个轻量 Cross-Encoder,高价值场景再叠加 LLM 重排。但前提是你要评估好延迟和成本,否则重排本身可能成为瓶颈。
不过还有一个点值得注意,就是 LLM 做重排时,它自己也可能产生[[幻觉]],尤其当文档本身有歧义时,它给的分数不一定可靠。所以我会额外加一层置信度校验,比如让模型输出理由,再验证理由是否和文档一致。