跳到主要内容

模型迁移指南:如何在不冻结功能开发的情况下更换基础模型

· 阅读需 13 分钟
Tian Pan
Software Engineer

每个生产环境中的 LLM 系统都会面临模型迁移。供应商发布了新版本。你需要降低成本。竞争对手提供了更好的延迟。监管要求需要更换供应商。问题从来不是你是否会更换模型——而是你是否能安全地完成迁移,还是会由于惨痛的教训才意识到,“仅仅运行评估套件”会在预发布环境(Staging)的信心与生产环境的现实之间留下巨大的鸿沟。

大多数团队将模型迁移视为库升级:更换依赖项、运行测试、然后发布。这对于确定性软件有效。但对于概率性系统,这种方式会遭遇灾难性的失败。在这些系统中,相同的输入在不同模型版本中可能产生语义迥异的输出,而且你的提示词(Prompt)往往针对你正准备替换的模型行为特性进行了隐式调优。

为什么模型迁移与软件升级截然不同

当你升级数据库驱动程序时,契约是明确的:同样的查询,同样的结果。LLM 迁移则从三个互相关联的维度打破了这一假设。

提示词与模型的共同适应(Prompt-model co-adaptation)。 你的提示词是随着当前模型一起演进的。每当工程师微调系统提示词以修复边缘情况时,他们其实是在隐式地将该模型的理解风格编码到提示词中。一个在 GPT-4 上能稳定产生结构化 JSON 的提示词,在 Claude 上可能会产生被 Markdown 包裹的 JSON,或者在 Gemini 上添加不必要的评论。这些并不是新模型的 bug —— 它们是为旧模型优化后留下的痕迹。

行为表面积(Behavioral surface area)。 模型不仅仅是在你的评估集上的准确率。它还包括它如何处理歧义、如何果断地拒绝边缘情况、在模式(Schema)未完全指定时如何格式化输出,以及它如何响应对抗性输入。两个在基准测试中得分相同的模型,在 15% 不符合评估分布的生产流量中,表现可能完全不同。

下游耦合。 你的后处理代码、护栏(Guardrails)、输出解析器 —— 它们都学会了期待当前模型的特定模式。一个用三个反引号包裹 JSON、或者用单词拼写数字而不是数字、或者在结构化响应前添加前导语的模型,会以单元测试从未预料到的方式破坏下游系统。

阴影期:切换前进行双写

模型迁移中唯一最重要的技术是阴影部署期(Shadow deployment period)。在真实的生产流量上运行新模型,但将其响应返回给用户。记录一切。对比一切。只有当差异(Delta)被理解且在可接受范围内时,才进行切换。

以下是其实施结构:

第一阶段:并行执行(1-2 周)。 将每个生产请求的副本路由到新模型。使用关联 ID 存储两者的响应。用户只看到现有模型的响应。这会增加你的推理成本,但这是你能买到的最便宜的保险。

第二阶段:自动化对比。 构建超越字符串匹配的对比流水线。你需要旧输出与新输出之间的语义相似度评分、结构一致性检查(新模型的 JSON 是否能正确解析?),以及行为分类(新模型是否拒绝了旧模型处理过的请求,反之亦然?)。

第三阶段:差异分类。 并非所有差异都是退化。新模型在某些输入上可能会产生更好的答案。目标不是零差异 —— 而是零令人惊讶的差异。将差异分为:

  • 改进(Improvements):新模型明显更好
  • 中性变体(Neutral variants):语义等价,表述不同
  • 退化(Regressions):新模型在旧模型成功的地方失败了
  • 新行为(Novel behaviors):新模型执行了既非预期也未被评估覆盖的操作

“新行为”类别是最棘手的。这些是你的评估套件从未预料到的情况,因为旧模型从未触发过它们。

提示词转换是工程问题,而非查找替换

当团队在不同的模型系列之间迁移时 —— 例如,从 OpenAI 到 Anthropic,或者从专有模型到开源模型 —— 提示词层需要真正的重新工程化。每个模型系列对于指令结构、上下文界定以及输出格式规范都有不同的偏好。

OpenAI 模型对带有章节分隔符的 Markdown 格式提示词响应良好。Claude 更喜欢使用 XML 标签来分隔指令和上下文。Gemini 则强调明确的约束放置。这些并不是表面的差异 —— 它们影响着模型遵循复杂多步指令的可靠性。

实际的迁移模式:

  1. 提取意图:从每个提示词中提取意图。这个提示词实际想要实现的目标是什么?剥离模型特定的格式,写下核心要求。
  2. 针对目标模型重新表述:使用目标模型偏好的结构约定。这通常意味着重写,而不是翻译。
  3. 先在最困难的案例上进行测试:不要从理想路径(Happy path)开始。先处理那些在旧模型上需要最多迭代才能搞定的提示词 —— 这些最容易出问题。
  4. 保留逃生舱口:如果你的旧提示词有处理边缘情况的特定指令(“如果用户询问 X,则回答 Y”),验证这些仍然能被正确触发。边缘情况的处理是模型特定调优最集中的地方。

一个常见的错误是构建一个旨在“规范化”跨供应商提示词的抽象层。这听起来很优雅,但在各处的表现都平平。最好的提示词是特定于模型的。接受为每个模型维护提示词变体的成本,以换取每个模型的可靠性。

嵌入迁移:没人预留预算的重索引问题

如果你的系统使用了嵌入(Embedding)——无论是用于 RAG、语义搜索还是分类——模型迁移都会引发第二次迁移,而且往往规模更大:你的整个向量索引将变得不兼容。新的嵌入模型会在不同的语义空间中生成向量。你不能在同一个索引中混合使用新旧嵌入,并指望获得有意义的相似度评分。

双索引策略。 在旧索引运行的同时创建新索引。当旧索引继续处理生产流量时,使用新模型对语料库进行重新嵌入。这需要足够的算力来重新计算所有嵌入,以及足够的存储空间来同时容纳两个索引。

增量重索引与全量重索引。 对于小型语料库(数百万个文档以下),全量重索引更简单也更安全。对于大规模系统,通过对可信源数据库进行变更数据捕获(CDC)来实现增量重索引,可以让你优先处理高流量文档,随后再回填剩余部分。

验证差距。 你如何知道新的嵌入确实更好?衡量检索重合度:针对具有代表性的查询样本,比较两个索引的 top-K 结果。研究表明,在竞争激烈的嵌入模型之间迁移时,顶部结果出现 80-85% 的重合是典型现象。那 15-20% 的差异点正是你需要人工评估的地方,以确定哪个索引的结果才是正确的。

切换与回滚。 在向量存储前端使用别名或路由层,这样切换只需更改配置,而无需部署代码。切换后,将旧索引保持热备状态至少两周。如果真实流量中的检索质量下降,你可以在几秒钟内切回,而不是几小时。

在每个索引旁存储嵌入模型元数据——模型名称、版本、维度和训练日期。当你在六个月后调试检索质量时,你会想确切知道是哪个模型生成了哪些向量。

为什么“只运行评估套件”是必要但不充分的

你的评估套件测试的是你预见到的场景。模型迁移往往会在你未预见到的场景中崩溃。以下是仅靠评估会产生虚假安全感的原因:

分布不匹配。 评估集是经过策划的,而生产流量是杂乱的。评估集过度代表了你想到要测试的情况,而低估了占实际流量 20-30% 的各种古怪输入的长尾部分。一个在评估中得分 95% 的模型,处理长尾输入的方式可能与前代模型完全不同。

多轮会话中的行为漂移。 关于多轮对话中模型切换的研究表明,即使是模型之间的单轮接力——即新模型接手由旧模型开启的对话——也可能导致性能产生 ±4 个 F1 分的波动。如果你的系统具有任何会话连续性,你不仅需要测试单轮准确性,还需要测试跨模型边界的多轮连贯性。

拒绝模式的改变。 每个模型都有不同的拒绝边界。新模型可能会拒绝旧模型能处理的请求,或者处理旧模型会拒绝的请求。你的评估套件和用户都不会立即察觉到所有这些差异。拒绝模式的变化通常表现为“AI 无法提供帮助”的投诉增加,这需要数周时间才能汇总成可见的模式。

输出格式的不稳定性。 即使使用结构化输出模式,不同模型在极端情况下的失败模式也不同。一个模型可能会偶尔多嵌套一层 JSON,另一个模型可能会以不同的方式编码特殊字符,第三个模型可能会在不同的阈值下截断长输出。这些故障往往能通过评估(因为评估使用干净的输入),但会搞崩溃生产环境的解析器(因为生产输入是“脏”的)。

迁移指南:分阶段方法

以下是行之有效的迁移顺序。每个阶段在进入下一阶段前都有明确的准入门槛。

第 1-2 周:提示词转换与单元验证。 为新模型重新设计你的提示词。针对现有的评估套件进行测试。准入门槛:在所有关键指标上,评估得分与旧模型的差距在 2% 以内。

第 2-3 周:影子部署。 在生产流量中以影子模式运行新模型。记录所有响应。准入门槛:自动化对比显示回归率低于你的阈值(通常非关键路径为 3-5%,关键路径 <1%)。

第 3-4 周:金丝雀发布。 将 5% 的生产流量路由到新模型。监控面向用户的指标:任务完成率、错误率、会话时长、显式反馈评分。准入门槛:任何面向用户的指标都没有统计学上的显著退化。

第 4-5 周:渐进式发布。 在一周时间内将流量逐步增加到 25%、50%,最后到 100%。持续监控。在每一步中,回滚路径都是流量路由更改,而不是代码部署。

第 6 周及以后:清理。 停用旧模型。拆除双写基础设施。存档影子对比数据(下次迁移时你会用到它)。更新你的提示词文档以反映新模型的惯例。

对于一次简单的迁移,整个过程需要 4-6 周。如果你还要迁移嵌入模型,请为重索引和检索验证额外预留 2-3 周。如果你要彻底更换供应商(而不仅仅是模型版本),请再增加一周用于 API 集成、身份验证和错误处理逻辑的更改。

为下一次迁移而构建

擅长处理模型迁移的团队,并不是那些拥有最佳评估套件 (eval suites) 的团队 —— 而是那些从一开始就为迁移而设计的团队。

模型无关的接口 (Model-agnostic interfaces)。 将你的 LLM 调用封装在抽象层之后,将提示词 (prompt) 的构建与模型调用分离。这并不是为了让提示词变得“通用”(它们不应该通用),而是为了让替换界面变得清晰:当你更换模型时,你可以准确地看到哪些提示词需要重新设计。

行为基准 (Behavioral baselines)。 持续记录生产环境输入和输出的样本。这些将成为你下一次迁移的对比语料库。你不需要评估它们 —— 存储它们即可。当迁移时刻到来时,你在新模型中重新运行这些输入并进行对比。

带版本的提示词注册表 (Versioned prompt registries)。 追踪哪个提示词版本与哪个模型版本配对。当出现问题时,你需要知道是提示词变了、模型变了,还是两者都变了。这听起来显而易见,但大多数团队会对代码进行版本管理,却将提示词视为存储在环境变量中的配置。

迁移操作手册 (Migration runbooks)。 在记忆犹新时记录每次迁移。哪里出了问题?评估套件漏掉了什么?每个阶段实际上花了多长时间?这些操作手册的价值会不断累积 —— 你的第三次迁移速度将是第一次的两倍,因为你已经知道坑在哪里了。

关于模型迁移,一个令人不安的事实是:它是一项经常性的税收,而不是一次性的项目。基础模型每隔几个月就会更新。供应商的定价每季度都会变动。你的产品团队想要利用的新功能也不断涌现。那些将迁移视为一种运营能力(就像数据库迁移或 API 版本管理一样)而非特殊项目的组织,才是那些在格局变化时能够真正快速行动的组织。

你的下一次模型更换即将到来。问题在于,届时你拥有的是一份实战手册 (playbook),还是一份事后检讨 (postmortem)。

References:Let's stay in touch and Follow me for more thoughts and updates