考察点
这是「多路召回」的必然后续追问,考察你对融合算法的理解深度:能不能说清楚为什么不同路的分不能直接加、RRF 为什么稳。能讲出「先免调参上线、再按 Bad Case 演进」节奏的才是工程思维。追问常往「怎么验证融合有效」走。
参考答案
为什么融合是个问题
多路召回每路输出一个带分的候选列表,但各路的分数量纲完全不同、分布也不同:向量余弦相似度在 0.5-0.9 之间挤成一团,BM25 从 5 分到 30 分不等且长尾,Rerank 输出的是 logit。直接把分数相加,等于让分布更「宽」的那一路天然主导结果——通常 BM25 会淹没向量分。所以融合的第一课:别直接加分。
方案一:归一化加权
先把每路分数归一化到 0-1(min-max 或 z-score),再加权求和:
final = w1·norm(vec_score) + w2·norm(bm25_score) + w3·norm(entity_score)
直观可调,但有两个坑:min-max 对离群分敏感(一个 30 分的 BM25 异常值把其他分全压扁);权重 w 没有先验,得拿评测集网格搜索,搜出来的权重还随数据分布漂移。
方案二:RRF 排名融合(推荐默认)
RRF 彻底扔掉分数,只用排名:
score(d) = Σ_i 1 / (k + rank_i(d))
rank_i(d) 是文档 d 在第 i 路的排名(未出现视为无穷大),k 是平滑常数,标准取 60。一个文档在向量路排第 2、BM25 路排第 5,得分为 1/62 + 1/65,比只在一路排第 1 的(1/61)还高——多路佐证优先,这正是混合召回想要的行为。
RRF 的工程优势:零权重可调、对各路分数分布完全免疫、新加一路召回不用重调。Elastic、Qdrant 都内置支持。它的代价是丢掉了分数里的「置信度」信息——两个文档排名相邻但分数差十倍时,RRF 视同相邻。实践中这个损失可以接受,因为后面还有 Rerank 用交叉编码器重新打一次可信的分。
方案三:级联与过滤
不是所有路都平等参与排名。实战里常见的结构化策略:
- 直通路:FAQ 精确命中、实体精确匹配(订单号、SKU)直接置顶,不参与融合——这类结果置信度天然最高。
- 佐证路:弱信号路(比如语义扩展召回)不独立贡献结果,只有当它的候选也被主路召回时才加权。
- 互斥路:结构化查询(「查我上个月订单」)识别后走 Text2SQL/接口,不走向量检索。
权重的演进节奏
我的实操路径:上线初版用纯 RRF,不调任何参数,先让系统跑起来收 Bad Case。积累几百条后归因分析:如果错误集中在「某路引入了字面相关语义无关的噪声」,给 RRF 加路权重(第 i 路乘 wi);如果错误是「正确文档各路线索都弱」,那是召回问题不是融合问题,回去修 Embedding 或切分。融合层能解决的问题边界要清醒——融合只重排已有候选,捞不回来的文档融合再聪明也没用。
验证方式固定:离线评测集跑 Recall@K 对比纯向量、纯 BM25、RRF 融合三组,融合组没有稳定超过单路 5 个点以上,说明你的「多路」可能互补性不足,该回去看各路的相关性矩阵。
可能的追问
Q:k 为什么取 60? 来自 RRF 原始论文在 TREC 数据上的实验结论,对 k 不敏感,30-100 之间结果差不多。k 越小头部排名权重越大,k 越大越接近平均。不用调,60 就行。
Q:LLM 能用来做融合吗? 可以,把多路候选一起给 LLM 做 listwise 排序,效果是天花板,但延迟和成本只适合离线蒸馏或高价值场景。线上主力还是 RRF + 交叉编码器。
Q:新增一路召回怎么评估价值? 看增量贡献:统计新路的「独家正确召回」(其他路都没捞到、只有它捞到的正确文档)占比。低于 2% 的路,维护成本大于收益,该砍。