模型迁移指南:如何在不破坏生产环境的情况下更换基座模型
每一个交付过由大模型驱动的产品的团队都经历过同样的时刻:一个新的基础模型发布了,它拥有更好的基准测试结果、更低的成本,或者两者兼而有之——这时有人会问:“我们能直接把它换掉吗?”答案在预发布环境中总是肯定的,但在生产环境中往往是灾难性的。
“在新模型上能运行”与“在新模型上表现正确”之间的差距就是生产事故多发地。模型迁移之所以失败,不是因为新模型更差,而是因为迁移过程假设了本不存在的行为等效性。不同供应商的提示词格式规范各不相同。不同系列模型对系统提示词(System prompt)的解读也存在差异。旧模型能够优雅处理的边缘情况——通过你从未记录过的习得性怪癖——会变成回归问题暴露出来,而你的评估套件(eval suite)在设计之初并未考虑到这些。
这是一份安全迁移基础模型的指南:双写影子期(dual-write shadow period)、真正有效的行为偏移检测、嵌入兼容性问题,以及决定更换过程是需要两周还是两个月的组织协调。
为什么“只跑一遍评估套件”是必要但不充分的
这种直觉是合理的:你有一个评估套件,新模型在上面得分很高,那就发布吧。但评估套件只编码了你已经知道的失败模式。而模型迁移会暴露出你不知道的那些。
根本问题在于分布(distributional)。你的评估集是一个精选样本——通常是几百到几千个旨在覆盖已知边缘情况的示例。而生产流量是一个持续、不断变化的输入分布,包含了一些评估集作者从未想象过的组合。一个在评估集上得分为 94% 的模型,在真实流量的长尾部分可能只得分 78%,因为行为差异往往集中在你未测试的输入中。
三类偏移经常会逃脱静态评估:
格式和结构偏移。 OpenAI 模型往往更倾向于使用包含大量 Markdown 的提示词,带有章节分隔符、强调和列表。Anthropic 模型对用于划分输入结构的 XML 标签响应更好。一个能让 GPT-4o 生成干净 JSON 的提示词,可能会让 Claude 生成被 Markdown 代码块包裹的 JSON,反之亦然。你的解析代码处理其中一种格式。评估套件测试其中一种格式。而生产环境在另一种格式上崩溃了。
拒绝模式的变化。 每个模型系列都有不同的拒绝边界。一个模型认为是直接事实响应的查询,另一个模型可能会拒绝,或者用过多的免责声明来推诿。这些差异在标准的准确率评估中是不可见的,因为拒绝并不是错误的——它是另一种形式的正确,只是恰好破坏了你的 用户体验。
推理路径的分歧。 两个模型可以通过不同的中间推理得出相同的最终答案。当你的系统依赖于思维链(chain-of-thought)输出时——用于日志记录、下游工具选择或面向用户的解释——答案正确并不意味着行为等效。
评估套件是你的第一道关卡,而不是最后一道。它能捕捉到 60% 显而易见的回归问题。剩下的 40% 需要通过针对实时流量的影子测试来发现。
影子期:用于安全迁移的双写架构
影子测试是指将生产请求同时运行在当前模型和候选模型上,记录候选模型的响应而不向用户展示。这是在行为偏移触达客户之前捕捉它的最有效技术。
架构非常简单:你的 API 网关或路由层复制每个传入请求,并将其并行发送到两个模型。生产模型的响应发送给用户。候选模型的响应发送到比较流水线。你会捕获响应内容、延迟、Token 计数和任何结构化输出,以及有关请求的元数据。
团队通过艰苦教训发现的一些运营现实:
影子测试会让你的 API 支出翻倍。 在影子期内,你每个请求都要支付两次推理费用。请设置预算警报,并计划一到两周的影子期——这段时间足以捕捉一个完整的业务周期流量模式,同时又不会让你损失惨重。
延迟比较需要仔细测量。 候选模型运行时没有用户等待的压力,因此其在影子模式下的延迟数据可能与生产环境不同。分别测量首个 Token 时间(TTFT)和总生成时间,并对仅在影子模式下出现的延迟改进保持怀疑。
自动化比较至关重要,但并不完美。 你需要一个比较流水线来评估两个输出之间的语义相似性、格式一致性和特定任务的正确性。LLM-as-judge 适用于语义比较。确定性检查适用于结构化输出的一致性。这两者都不能捕捉到所有问题——请为随机样本的人工审核预留预算,特别是对于高风险的输出。
影子期会产生一个比较数据集:包含数千个真实生产输入以及来自两个模型的配对输出。这个数据集比任何基准测试都更有价值。它能准确地告诉你新模型在你实际工作负载中的分歧点在哪里。
Shadow 测试期间需要衡量的指标
聚合指标会掩盖重要的信号。将你的分析按以下维度拆分:
- 输入类别。如果你有意图分类,请衡量每个意图的差异程度 (divergence)。回归 (Regressions) 通常聚集在特定的任务类型中,而不是均匀分布。
- 输出长度分布。一个比原来冗长 30% 的模型会增加成本,即使准确度完全相同,也可能会降低用户体验。
- 结构化输出一致率。如果你使用 JSON 模式或函数调用 (function calling),请分别衡量架构验证通过率。在大规模应用中,一致率下降 2% 意味着每天会有数百个失败的请求。
- 错误率和拒绝率。跟踪每个模型拒绝、闪烁其词或产生错误响应的频率。如果一个新模型拒绝了旧模型可以处理的 5% 的查询,那么即使每一个未被拒绝的响应都更好,这也是一种回归。
- 尾部延迟 (Tail latency)。p50 延迟可能会改善,而 p99 却会变差。对于面向用户的应用程序,p99 是决定你的 SLA 是否成立的关键数字。
嵌入模型迁移:重新索引难题
当你要迁移的是嵌入模型 (embedding model) —— 或者当你新的 LLM 需要为 RAG 使用不同的嵌入模型时 —— 迁移的复杂度会增加一个数量级。嵌入在不同模型之间是不可互换的。由 text-embedding-ada-002 生成的向量对于为 text-embedding-3-large 构建的索引来说毫无意义。维度可能不同,语义空间也根本不同。你不能在同一个索引中混合使用旧向量和新向量。
这意味着你需要对整个文档语料库进行重新索引,这会带来三个问题:
零停机要求。你的 RAG 系统不能为了重新嵌入数百万个文档而离线数小时或数天。标准模式是蓝绿索引 (blue-green indexing):在旧索引运行的同时构建新索引,一旦新索引完成并经过验证,就原子化地切换查询路径。这需要足够的底层设施来同时运行两个索引。
切断 (cutover) 之前的验证。新的嵌入模型会改变检索行为。在旧模型下针对给定查询排名靠前的文档,在模型下可能会有不同的排名。在切换之前,针对新索引运行你的检索评估套件,并抽查排名顺序发生重大变化的查询。检索的变化会级联到生成的变化中 —— 检索内容的 5% 偏移可能会导致生成内容的 15% 偏移。
版本控制陷阱。如果你在多个地方存储嵌入 —— 主向量数据库、缓存层、特征存储 (feature store) —— 所有这些地方都需要原子化地更新。部分迁移(即某些查询命中旧嵌入,而其他查询命中新嵌入)会产生极其难以调试的不一致行为。请给你的嵌入打上版本标签,并强制要求查询路径一次只能从一个版本中读取。
计划进行一天嵌入迁移的团队通常最终需要一到两周才能完成。重新索引很快,验证和协调却很慢。
提示词兼容性:没有人预料到的“迁移税”
- https://www.codeant.ai/blogs/llm-shadow-traffic-ab-testing
- https://insightfinder.com/blog/hidden-cost-llm-drift-detection/
- https://medium.com/@komalbaparmar007/llm-canary-prompting-in-production-shadow-tests-drift-alarms-and-safe-rollouts-7bdbd0e5f9d0
- https://arxiv.org/html/2603.03111v1
- https://dev.to/humzakt/zero-downtime-embedding-migration-switching-from-text-embedding-004-to-text-embedding-3-large-in-1292
- https://docs.aws.amazon.com/prescriptive-guidance/latest/gen-ai-lifecycle-operational-excellence/prod-monitoring-drift.html
