嵌入模型更迭:当你的提供商悄然导致整个向量索引失效
你花了数周时间构建检索流水线。分块策略已调整,相似度阈值已校准,用户反馈看起来很积极。然后,在某个周一的早晨,在你没有任何部署的情况下,检索质量开始下降。以前能搜出正确文档的查询,现在返回的却是关联度极低的噪音。没有错误日志。没有异常。流水线运行顺畅。
发生变化的是你的嵌入(Embedding)提供商更新了模型。你的整个向量索引——那些费尽心力嵌入的数百万个文档——现在填充的是来自一套坐标系统的向量,而这套系统与你的查询编码器生成的向量已不再匹配。结果不是系统崩溃,而是不可见的垃圾数据。
为什么不同模型的嵌入向量不能混用
嵌入模型将文本映射到高维向量空间中。语义被编码为几何图形 :相似的概念聚集在一起,关系被捕捉为方向上的接近。但这种几何结构并不是通用的,它特定于创建它的模型。
当你切换嵌入模型时——即使是同一提供商的更新版本——你也在完全改变坐标系统。由不同模型版本生成的、代表相同文本的两个向量,可能会指向完全不同的方向。它们之间的余弦相似度(Cosine similarity)毫无意义。你是在比较不兼容空间中的距离。
当两个模型版本共享相同的输出维度时,这种失效模式尤为隐蔽。如果你从 text-embedding-ada-002(1536 维)切换到另一个同样输出 1536 维向量的版本,基础设施层面不会发生任何损坏。你的向量数据库会毫无怨言地接受新的查询向量。近似最近邻(Approximate nearest neighbor)结构——如 HNSW 图、IVF 集群——是围绕旧模型的几何结构构建的,但它们不会拒绝来自新模型的向量。它们只是返回了“错误邻里”中的邻居。
结果是:查询静默地返回看似合理但在语义上错误的搜索结果。用户得到的回答看起来像是检索出来的,但实际上并非基于他们的真实文档。你不会在错误率中看到这一点,但最终你会在用户信任度上看到它的影响。
你无法控制的提供商更新时间线
主要提供商的弃用周期往往比许多团队的产品路线图还要短。OpenAI 已于 2025 年 1 月起弃用 text-embedding-ada-002,停用窗口将于 2025 年 6 月结束。Cohere 在 2025 年 1 月弃用了其用于分类的默认 Embed 模型端点。HuggingFace 的 sentence-transformers 库在 v5.4 版本中更改了仅解码器(decoder-only)模型的默认池化策略,静默地改变了受影响架构的向量语义。
这些并非特例。它们是你无法控制的基础设施上的标准操作。
关键区别在于两种类型的模型变更:
- 已公告的弃用(Announced deprecations):提供商会给你一个迁移窗口(通常为六个月)。你仍然需要重新索引,但你有准备时间。
- 静默更新(Silent updates):提供商保留在不更改端点名称或不提前通知的情况下升级、微调或更换底层模型的权利。大多数 API 服务条款都明确允许这样做。
第二种类型是最危险的。你的索引是针对 text-embedding-large-preview-2024-03(或该端点目前指向的任何模型)构建的。明天它可能会指向别的东西。你的系统中没有任何变化,但语义空间中的一切都变了。
团队通常在替换发生数周后,当回归评估开始失败、产品经理注意到搜索质量下降,或者用户抱怨聊天机器人似乎忘记了如何查找相关文档时,才会发现这个问题。
在用户发现之前检测问题
如果你不持续衡量检索质量,在问题变得显而易见之前,你将无法检测到嵌入模型的漂移——这意味着问题已经发生一段时间了。
一个最小化的检测设置包含三个组件:
模型身份日志记录(Model identity logging)。每一次嵌入 API 调用都应记录实际使用的模型版本。许多提供商在响应元数据中返回此信息。将其与你 的嵌入向量一起存储。如果今天查询响应中的模型标识符与索引中存储的不符,则说明发生了不匹配。这是成本最低的预警系统。
检索质量基准(Retrieval quality baselines)。在任何计划内或计划外的模型变更之前,你都需要一个基准。一套“黄金查询集”:50 到 200 个带有已知相关文档的查询。每周运行一次。跟踪平均倒数排名(Mean Reciprocal Rank)或 NDCG。在没有部署的情况下,如果指标突然下降,则直接指向嵌入层的问题。
统计漂移检测(Statistical drift detection)。如果你定期嵌入同一组哨兵文档(sentinel documents),并将生成的向量与存储的参考嵌入进行比较,你就可以检测到嵌入函数何时改变了行为。工具如 Evidently AI 将此作为核心指标。当分类器尝试区分参考嵌入和当前嵌入时,如果 AUC 接近 0.5,则意味着分布稳定;如果 AUC 向 0.7 攀升,则意味着发生了某些偏移。
这些实施起来并不复杂。难点在于团队通常将嵌入向量视为“一次性写入”的产物。一旦向量进入数据库,就会被认为是稳定的。事实并非如此。
发生重索引时的策略
当你检测到嵌入模型发生变化时——或者当计划中的迁移迫使你做出改变时——你有几种方法,每种方法都有不同的风险特征。
原位替换是最危险的。你停止写入,重新嵌入所有文档,覆盖现有向量,然后恢复。在这个窗口期,你的索引是旧向量和新向量的混合体:这是一个混合向量空间,其中邻近项是在不兼容的坐标系中计算的。即使你很快完成操作,也没有回滚路径。如果新模型降低了针对你特定数据分布的检索质量,你将无路可走。
蓝绿索引是以存储空间为代价的最安全方法。在旧索引(蓝色)保持运行并提供查询服务的同时,使用新嵌入模型构建一个全新的索引(绿色)。在迁移期间,将传入的数据双写到两个索引中,以保持绿色索引的实时性。一旦绿色索引完成回填并经过验证,就切换查询路径。如果质量下降,立即切回。为了回滚能力,翻倍的存储成本几乎总是值得的。在 800 万份文档的规模下,重新嵌入任务会运行数小时且可能中途失败——你需要能够干净地中止并恢复。
带有特性标志(Feature Flags)的影子索引是生产就绪的折中路径。在现有列旁边添加一个新列或索引(embedding_v2)。通过具有检查点功能的后台任务进行回填,以便在崩溃后恢复——存储最后一次成功嵌入的文档 ID,这样你就可以在不重新处理的情况下恢复。应用特性标志来控制查询路径使用哪个嵌入列。一旦回填完成且在具有代表性的查询集上验证了质量,就翻转标志。回滚是瞬时的。在任何用户受到影响之前,验证都是可能的。
任何迁移方法都适用三个工程要求:
- 幂等性:在已处理的文档上重新运行任务不会损坏索引。
- 检查点:迁移进度是持久化的,因此无需从头开始即可恢复失败。
- 版本标记:数据库中存储的每个向量都带有其模型版本作为元数据,因此你始终知道它属于哪个空间。
