一位开发者的 RAG 原型拒绝回答任何余弦相似度低于 0.50 的查询。它运行得非常完美——直到更换了嵌入模型。随后,该防护机制开始悄无声息地让错误答案流出。这一事件证明,硬编码的相似度阈值可能会随着模型的更换而失效,这种风险威胁着任何依赖嵌入相似度进行安全检查的系统。
为什么阈值至关重要
检索增强生成 (RAG) 流水线通常使用相似度防护机制:如果查询与其最近文档之间的余弦相似度低于预设值,系统将中止回答。当检索到的上下文较弱时,该防护机制可以防止模型产生幻觉。在最初的设置中,0.50 的阈值保证了系统的诚实——无法回答的查询得分低于该线,可以回答的查询得分高于该线。
当嵌入后端发生变化时,同样的 0.50 截断值不再能区分这两组数据。流水线开始返回自信但错误的响应,且没有任何崩溃或明确的错误提示。这种失败逃避了标准的排序指标,只有在人工注意到偏差时才会显现。
几何结构并非通用
每个嵌入模型都将语言映射到一个具有其自身几何结构的高维空间中。因此,余弦相似度值在不同模型之间具有不同的含义。对于一个模型来说,0.50 的得分可能处于清晰间隙的边缘,而对于另一个模型来说,则可能处于重叠区域的深处。
- Voyage-3 – 0.50 的界限位于低分的无法回答查询与高分的可以回答查询之间。防护机制按预期工作。
- BGE-Small – 许多无法回答的查询得分高于 0.50,因此防护机制从未触发。将截断值提高到 0.70 可以恢复安全余量。
- Hashing-64 – 可以回答和无法回答查询的得分交织得非常紧密,以至于没有任何单一阈值可以将它们分开;该模型太弱,根本无法支持相似度防护机制。
这些案例说明了一个更广泛的事实:阈值属于特定的“模型-数据”对,而非通用规则。
常量的隐藏成本
相似度阈值出现在许多下游任务中:
- 语义缓存 (semantic caching)
- 重复检测 (duplicate detection)
- 文档相关性检查 (document relevance checks)
- 实体匹配 (entity matching)
使用常量值意味着假设所有嵌入模型都共享相同的得分分布——这是一个危险的假设。当假设失效时,系统会悄无声息地产生过度自信的输出,侵蚀用户信任,并为下游决策提供虚假数据。
为每个模型校准防护机制
解决方法很简单:永远不要发布硬编码的常量。将阈值视为必须为每个新嵌入模型进行调优的超参数。
- 组建一个适中的、带有标签的验证集,涵盖可以回答和无法回答的查询。
- 使用目标模型计算每个“查询-文档”对的余弦相似度。
- 绘制两个分布图,或计算过度自信率 (false-confident rate)——即超过候选阈值的无法回答查询所占的比例。
- 选择能将过度自信率保持在可接受风险水平以下的最小相似度值。
由于目标是防止过度自信,传统的排序指标(如平均倒数排名 MRR)是不够的。过度自信率直接衡量了防护机制的失效模式。
反方观点:“有些模型开箱即用”
的确,某些表现良好的模型(如示例中的 Voyage-3)恰好与 0.50 的防护机制相匹配。但这并不保证未来的稳定性。模型更新、微调,甚至底层语料库的变化都可能改变相似度分布,从而再次破坏防护机制。依赖单一的“幸运对齐”会让人产生懈怠。
下一步关注点
-
-
-
总结
相似度阈值不是通用的安全开关;它是一个特定于模型的防护机制,每次更换嵌入后端或其处理的数据时,都必须重新校准。忽视这一事实会让 RAG 系统陷入“沉默的幻觉”中,从而违背了防护机制的初衷。唯一可靠的前进道路是进行系统的逐模型校准,并持续监控过度自信率。
