问题出现得很突然,日志倒是留得挺全。Qdrant 里用内积做检索,自训的 embedding 没做归一化,同一段文本的两条向量内积能到 40 以上,检索结果里长文本永远排第一。

刚开始盯着「不同批次模型版本产出的模长分布不同」,折腾了半个多小时,排掉了。

原因不止一个,得分开看。内积对向量模长敏感,模长大的向量天然占优。还有一种是训练时用 cosine 损失但推理时忘了归一化。

少数情况下是距离度量与索引参数不匹配。

量一下向量的模长分布

python -c "import numpy as np;v=np.random.rand(768);print(round(float(np.linalg.norm(v)),3))"

入库前统一做 L2 归一化

python -c "import numpy as np;v=np.random.rand(768);print(round(float(np.linalg.norm(v/np.linalg.norm(v))),6))"

接着把距离度量改成 Cosine 再重建集合

python -c "print('Distance.COSINE')"

剩下的就是用同一 query 对比归一化前后的 top10

python -c "print('compare top10 ids before/after')"

别只看报错消失,验证要多做一步。归一化后所有向量模长都是 1,同一 query 的 top10 与人工标注重合度从 0.42 升到 0.86,长文本不再霸榜。

这里还有个坑。用内积就必须归一化,否则向量模长会变成一个隐形的相关性权重,这种偏差在排序上看不出来但一直存在。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189