现场是这样的。一部分文档入库时做了 L2 归一化,另一部分没有,用内积检索时分数出现 1.4 这种值,按 0.7 设的阈值完全失效。
中间走过弯路,把「归一化写在应用层,绕开应用的导入没做」当成主因,改完现象没变。
原因不止一个,得分开看。内积在未归一化时没有上界,与余弦不可比;两条入库路径的预处理不一致,补数据的脚本漏了;索引的度量类型与查询时的假设不一致。
先抽查库里向量的模长
python -c "import numpy as np;print(round(float(np.linalg.norm([0.6,0.8])),3))"
接着统一在入库前做 L2 归一化
python -c "import numpy as np;print((np.array([3,4])/np.linalg.norm([3,4])).round(3))"
然后把度量改成余弦,减少对归一化的依赖
curl -X PATCH http://127.0.0.1:6333/collections/kb -H "Content-Type: application/json" -d '{"vectors":{"distance":"Cosine"}}'
全量重算后统计模长分布
python -c "import numpy as np;print(np.linalg.norm(np.random.rand(5,8),axis=1).round(2))"
这类改动我都写进变更记录,过两周再出问题时能对上号。
怎么算真的好了,看的是同一批现象。全部向量模长落在 0.999 到 1.001 之间,检索分数不超过 1,阈值 0.7 的判断结果稳定。
余弦在部分引擎内部就是归一化后的内积,混用两种度量比混用归一化更隐蔽。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
