Milvus 2.5 的 hybrid_search 里用 WeightedRanker 给 dense 0.8 与 sparse 0.2,结果几乎全是 dense 命中,型号类查询召回明显变差,BM25 那一路像没参与。

一开始怀疑是「两路请求的 limit 不一致,融合前就被截断」,查了一圈,方向不对。

这类报错背后常见的原因有几处,逐个排除就行。两路分数尺度不同,加权会被大分值主导。少数情况下是稀疏一路的 analyzer 没配,实际输出为空。

另外,权重写成了百分数,超过取值范围。

动手时先分别只跑 dense 与 sparse,看各自结果

python -c "from pymilvus import AnnSearchRequest;print(AnnSearchRequest(data=[q],anns_field='sparse',param={'metric_type':'BM25'},limit=20))"

再往下改用 RRFRanker 只依赖排名

python -c "from pymilvus import RRFRanker;print(RRFRanker(k=60))"

接着确认两路 limit 都设成 20 再融合

python -c "print({'dense':20,'sparse':20,'k':60})"

剩下的就是用型号类问题做一次对比评测

python eval_recall.py --mode hybrid --cases model_queries.json

当时还开着另一个排查窗口,两边日志对照着看才定位到。

恢复的判定其实很直接。型号查询的前 5 里出现正确文档,dense 与 sparse 各自也有命中,融合结果不再被单路主导。

这里还有个坑。加权融合要先做分数归一,图省事就用 RRF,只比排名不比分值,跨模型时更稳。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189