BM25 与向量各取 50 条用 RRF 融合,k 用默认 60,实测前 10 条几乎全来自向量那一路,关键词精确命中的条款被压到 30 名往后。

一开始怀疑是「k 偏大时头部差异被压平,弱势那路的贡献更小」,查了一圈,方向不对。

真正麻烦的地方在于,几个原因的现象几乎一样。RRF 只看排名不看分数,单路排名靠前的文档天然占优。另一种情况是两路候选数相同但分布不同,一路更集中在头部。

还有一种情况,融合后没去重,同一文档在两路都出现被重复计数。

动手时先分别看两路前十条的重合度

python -c "a=set(range(10));b=set(range(5,15));print(round(len(a&b)/len(a|b),3))"

随后把 k 调到 10 再融合对比

python -c "s={};[s.__setitem__(d,s.get(d,0)+1/(10+r)) for r,d in enumerate(range(5))];print(sorted(s.items(),key=lambda x:-x[1])[:3])"

给两路加权后再排序

python -c "print(round(0.4*(1/(60+2))+0.6*(1/(60+1)),5))"

末了用评测集对比不同 k 的命中率

python -c "import pandas as pd;print(pd.read_csv('rrf_eval.csv').groupby('k').hit10.mean())"

别只看报错消失,验证要多做一步。融合后前十条能覆盖关键词精确命中的条款,hit@10 从 0.62 升到 0.78,两路贡献比例接近配置权重。

RRF 不需要分数归一化,但也就丢了强度信息,业务里该实测加权分数融合和 RRF 哪个更稳。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189