跳到主要内容

提供商抽象税:构建无需重写即可切换模型的 LLM 应用

· 阅读需 12 分钟
Tian Pan
Software Engineer

一家医疗初创公司从某个主流前沿模型迁移到了同一供应商提供的新版本。结果是:为了恢复功能对等(feature parity),耗费了 400+ 个工程小时。新模型每次响应生成的 token 数量是原来的五倍,抵消了预期的成本节省。它开始提供未经请求的诊断建议——这带来了合规性风险。而且它破坏了下游的所有 JSON 解析器,因为它把响应包裹在了 Markdown 代码块语法中。同一供应商,不同的模型,却是推倒重来。

这就是供应商抽象税(provider abstraction tax):它不是切换供应商的成本,而是不为此做规划所产生的累积成本。它不是一次性的迁移事件,而是一个持续的消耗——你在升级三周后发现的行为退化、无法跨模型迁移的提示词工程工作,以及因为某个供应商分别计算输入和输出 token 的速率限制而导致静默失败的重试逻辑。直接在单一供应商之上构建系统的团队会无形中积累这种债务,直到收到弃用通知或价格变动通知时,账单才会一次性结清。

税费究竟积累在哪里

供应商之间的表面不兼容是真实存在的,但也是可以处理的。OpenAI 将系统指令放在 messages 数组中;Anthropic 要求将其作为顶层的 system 字段。OpenAI 将工具调用参数作为需要 JSON.parse() 的 JSON 字符串返回;Anthropic 则将其作为预解析的对象返回。Gemini 在生成配置中使用 response_schema 字段,而不是任何类似于工具模式(tool schema)约定的东西。这些差异只需要一个下午就能梳理清楚,用一周时间就能完成规范化。

更深层的税收在于行为。量化提示词敏感性的研究发现,仅格式变化(空格、指令顺序、单个词)就能导致高达 76 个准确率百分点的波动。GPT-3.5 在代码翻译任务中,不同提示词模板的表现差异高达 40%。实际的影响是:一个为 Claude 调优数周的提示词,在不改变文本的情况下,在 GPT-4 上的输出可能会明显变差。不是灾难性的变差——而是微妙的、静默的变差。这种退化往往能通过自动化评估,因为评估本身也是针对原始模型的输出风格进行调优的。

在智能体流水线(agentic pipelines)中,这种差异会产生复合影响。单轮评估显示 97% 的通过率,但当同一个模型在五个链式步骤中运行时,问题就变了:3% 的失败案例不会保持孤立,它们会产生级联反应。在模型升级后进行回归测试的团队经常发现,生产环境中的总失败率远高于测试套件建议的通过率,因为多步组合暴露了扁平化评估永远无法察觉的误差累积。

模式不匹配问题

工具调用(Tool calling)是抽象最具体化失效的地方。三大主流供应商采用了结构完全不同的方法:

  • OpenAI 在工具定义中使用 "parameters" 键,并原生支持 parallel_tool_calls
  • Anthropic 使用 "input_schema",会静默剥离 minimummaxLengthpattern 等模式约束(转而将它们放入描述文本中),并且在提供工具时,每条请求会增加 313–346 个 token 的系统提示词开销。
  • Gemini 使用通过 generation_config 配置的 types.Schema 对象——这种模式在协议层级上与其他两者不兼容。

这意味着为 OpenAI 编写的、执行 JSON.parse(call.function.arguments) 的工具处理器,在指向 Anthropic 时会立即崩溃,因为后者返回的是已解析的对象。修复只需一行代码——但前提是你得发现它。在拥有 50 个工具定义的生产规模服务中,这种失效模式是隐蔽的:某些工具调用正常,另一些则报错神秘的类型错误,而根源需要数小时才能追踪到。

结构化输出的强制执行机制也各不相同。OpenAI 和 Gemini 提供服务端模式校验。Anthropic 使用基于工具使用的强制执行。Mistral 保证语法有效的 JSON,但将结构校验留给客户端代码。实际结论是:Pydantic(或同等工具)的客户端校验不是可选的——它是唯一能在跨供应商场景下统一工作的安全网。

现有的抽象库究竟解决了什么

LiteLLM、LangChain、AISuite 和 Vercel AI SDK 都试图掩盖这些差异。它们的覆盖范围和权衡取舍各不相同。

LiteLLM 是在运维层面最完备的选择:它在 OpenAI 兼容接口背后支持 100+ 个供应商,处理成本追踪、速率限制负载均衡和回退路由。其记录的生产环境失效模式是在持续负载下的性能下降和内存泄漏。它适用于原型开发和中等流量;在大规模场景下需要显著的增强。

LangChain 允许通过配置更改来切换供应商,但其抽象模型是有代价的:一家初创公司在从 LangChain 迁移到原生 OpenAI SDK 后,由于 LangChain 的 token 开销,API 成本降低了 40%。另一家公司发现,与手动实现 RAG 相比,它产生了 2.7 倍的成本。更深层次的问题是调试的不透明性——当链式调用隐藏了发送给 API 的内容时,你无法精准地修改提示词行为或添加自定义重试逻辑。团队通常使用 LangChain 制作原型,然后在生产环境中从头重写。

AISuite(来自 Andrew Ng 的团队,2024 年)采取了相反的方法:设计极其简约,更改一个字符串即可切换供应商,不支持流式传输,没有速率限制监控,没有 token 追踪。如果你想要在没有基础设施复杂性的情况下实现移植性,并且可以接受这些限制,它会很有用。

Vercel AI SDK (TypeScript) 在主流供应商之间提供了统一的 generateText/streamText API,两行代码即可切换供应商。它拥有针对 TypeScript 应用最成熟的生产方案,其 SDK 6 版本增加了稳定的智能体原语(agentic primitives)。

这些库都无法解决行为差异。它们规范了 API 表面,但没有规范模型本身。

行为测试套件并非可选

对抗供应商切换成本最持久的投资是构建一个可以在任何供应商上运行的行为测试套件。这与单元测试套件不同,也与生产监控不同。

LLM 应用的行为测试套件包含三个层级:

黄金数据集测试将模型输出与精选的预期响应或 LLM-as-judge 评估进行比较。每个测试用例包括输入、预期行为以及不依赖于精确字符串匹配的通过/失败标准。当你更换供应商时,在发布任何内容之前,针对新模型运行同一套件并衡量差异。

格式契约测试验证结构化保证:模型在被要求时返回有效的 JSON,工具参数被正确解析,响应长度在限制范围内,没有 markdown 代码块包裹本应是原始 JSON 的响应。尽管这些测试本身的信号强度较低,但它们能立即捕捉到最常见的迁移故障模式。

代理链式测试端到端地运行多步场景,并验证最终结果是否正确。这些测试能揭示单轮评估容易忽略的错误累积问题。在做出迁移决策之前,一个包含五个步骤的工作流应该在每个候选模型上至少运行 50 次,因为故障分布是不均匀的——某些提示词组合在第 3 步失败,而另一些在第 5 步失败,只有在大规模测试时,方差才会显现。

Promptfoo、Braintrust 和 LangSmith 都支持针对多个供应商并行运行相同的测试配置,这使得在 CI 中进行此类跨供应商比较变得具有实际意义。

适配器层的提示词规范化

提示词规范化层的目标是让你的业务逻辑远离特定供应商的惯用法。一个设计良好的适配器负责处理:

  • 系统提示词的位置:将系统指令从 messages[0](OpenAI 格式)移动到顶层 system 字段(Anthropic 格式),或者其他供应商的等效字段。
  • Schema 约束迁移:当针对 Anthropic 时,将 JSON Schema 约束(minimumpatternmaxLength)从 Schema 字段移动到描述文本中,以免它们被静默丢弃。
  • 工具参数解析:在交给应用代码之前,将工具调用参数规范化为一致的格式(始终是已解析的对象,绝不是 JSON 字符串)。
  • 输出格式强制执行:将供应商特定的 JSON 模式标志或结构化输出机制转换为统一参数,并在每个响应上使用 Pydantic 验证作为回退层。
  • 预填/输出种子替代方案:Anthropic 将助手响应预填为 { 以强制仅 JSON 输出的能力,在 OpenAI 中没有直接对应的功能;适配器应根据供应商的不同,替换为严格的系统指令或结构化输出参数。

核心架构原则是业务逻辑永远不应包含 if provider == "anthropic" 分支。该分支属于适配器。如果它泄露出去,说明你并没有进行抽象,而只是在不同的位置复制了依赖。

何时选择单一供应商是正确决策

在某些情况下,抽象税并不值得支付。

正在迭代产品市场契合度(PMF)的早期产品,不应将工程周期浪费在可移植性脚手架上。在最初的六到十二个月里,产品需求的变化速度超过了供应商弃用的速度。直接基于一个供应商构建,针对该模型的行为特征进行深度优化,并在产品定型后再重新审视可移植性问题。

微调在设计上就会将你锁定在某个供应商。如果你的质量要求需要微调,可移植性的论点就会部分失效:你不是在抽象一个模型,而是在专门化一个模型。只有当你愿意在新的供应商上进行微调时(这是第二次微调工作,而不是一次配置更改),对模型无关抽象的投资才能收回成本。

供应商特有功能——Claude 的扩展思考(extended thinking)、OpenAI 的结构化输出强制执行、Gemini 的原生多模态集成——有时能提供跨供应商无法复制的质量或成本优势。使用它们是合理的;有意识地这样做,并在适配器层留有逃生舱口,比假装依赖不存在要好。

迁移成本等式

2025–2026 年的模型弃用周期大约是每一代模型十二到十八个月。不做抽象工作的团队在每次强制迁移上会耗费两到五个工程师日,运行跨越 40 到 200 个提示词的回归套件,并重新工程化行为差异。随着各大供应商每年发布四到八次重大更新,这种成本会迅速累加。

投资于行为测试套件和适配器层的团队虽然预付了成本,但会将其分摊到随后的每一次迁移中。跨越点通常是第二次迁移。如果你已经迁移了两次,测试套件就已经回本了。

另一种选择——在弃用模型过保后继续使用——会产生另一种成本。随着供应商将基础设施投资转移到新版本,旧模型会积累稳定性问题。在第一年 LLM 支出超出预算 3 倍以上的企业团队中,有 68% 的团队是由于意外而非设计做出了这种权衡。

现在该构建什么

生产级 LLM 应用的最小可行抽象不是一个框架——而是三个特定的基础设施组件:

第一,一个处理上述特定供应商差异的适配层。它应该是你代码库中的一个轻量化模块,而不是对某个框架的依赖。框架本身会增加迁移风险。

第二,一套行为测试套件,至少包含 50 个黄金数据集样本,覆盖你最关键的用户旅程。在每次代码合并请求(PR)时,在 CI 中针对当前供应商运行该测试;并在做出任何迁移决定之前,针对备选供应商运行该测试。

第三,将供应商配置为单个环境变量。如果切换供应商需要的操作超出了更改一个环境变量和(可能)一个特定供应商参数的范畴,那么适配层就是不完整的。

拥有这三样东西的团队将模型升级视为一次带有测试运行的配置更改。而没有这些东西的团队则将其视为一个项目。这种“税收”是真实存在的——问题在于你是分期小额持续缴纳,还是在你最没有精力应对时一次性全部补缴。

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