让所有模型都变得平庸的抽象层
在你的代码库中的某个地方,存在一个网关,让你只需更改一个字符串就能将 claude-sonnet 替换为 gpt-5。你的架构评审对此赞不绝口。你的 CTO 因此睡得更香。然而,它正在悄悄让你付出代价:损失了 90% 的缓存折扣、Schema 强制输出,以及那些区分优秀生产模型与平庸模型的推理努力(reasoning-effort)调节旋钮。
这就是统一 LLM API 未被宣传的代价。每一个承诺“一行代码切换供应商”的抽象层,都是通过将每个供应商的功能投射到它们共有的子集来实现的——而那些落在这个子集之外的功能,恰恰是供应商竞争最激烈的地方。Prompt 缓存语义、结构化输出强制、扩展思考预算、服务端工具执行:这些才是决定你实际成本和质量曲线的关键杠杆,而你的网关可能正在默默地将它们弃之不用。
结果就是一种奇怪的平衡:团队为了避免押错模型而采用了路由层,作为交换,他们让每个模型都在其能力最低的配置下运行。“我们可以随时切换”变成了“我们正在以最差的状态使用每个模型”。
最 小公分母比你想象的还要小
大多数网关暴露的统一接口是 OpenAI Chat Completions API 的某种变体,因为它是事实上的通用语言。任何符合 OpenAI 格式的请求都能顺利通过。其他的一切都必须经过翻译、模拟或直接被忽略。
考虑一下三大主流 API 系列之间究竟有哪些不同:
- Prompt 缓存。Anthropic 使用显式的
cache_control标记,带有 1.25 倍的写入溢价和 90% 的读取折扣;OpenAI 在匹配的前缀上自动缓存,且不收取写入费用;Bedrock 的 Converse API 则有自己的指令格式和 TTL 规则。这些并非表面差异——指令格式、响应的 usage 字段,甚至缓存触发的时机都各不相同。一个将请求规范化为统一形状的网关,必须在请求发出时翻译成三种原生方言,并在返回时协调三个不同的 usage 对象。许多网关并没有这样做,它们只是简单地剥离了这些标记。 - 结构化输出。每个供应商都使用不同的参数名称、不同的请求形状和不同级别的实际 Schema 强制执行来实现受限解码。有些在解码器层面强制执行 JSON Schema;有些仅保证“有效的 JSON,但形状不确定”。一个将所有请求映射到
response_format: json_object的网关,在没有告知你的情况下,已经将你原本有 Schema 保证的调用降级为了“祈祷并解析”式调用。 - 推理控制。努力程度调节旋钮(Effort knobs)、思考预算和交替推理,在不同供应商之间的命名和形式各不相同,有些甚至只存在于特定代的模型中。在困难任务上,
effort: low和effort: high之间的差异可能超过你所做的任何其他调优决策——而这正是翻译层要么以无类型方式传递,要么干脆拒绝传递的那类参数。
其中每一项的价值都超过了路由层本身。在每一轮都要重放对话前缀的代理式(agentic)工作负载中,仅 Prompt 缓存就能将输入成本降低一个数量级。如果你的网关吞掉了缓存标记,你每次调用都要支付全额费用,而账单条目永远不会告诉你原因。
在网关出现之前,可移植性就已是神话
更深层次的问题在于,网关为你提供的保障——避免被锁定在单一供应商——实际上并不能通过 API 兼容性来解决。API 是迁移过程中成本最低的部分。
Prompt 是模型特定的产物。关于跨模型 Prompt 迁移的研究称之为“模型漂移”:针对一个模型设计的 Prompt 在另一个模型(甚至是更强大的模型)上重放时,表现会明显下降。在一个基准测试中,为 GPT-4o 调优的 Prompt 在迁移到 o3 时,HumanEval 得分为 92%——而 o3 在使用为其专门编写的 Prompt 时,在同一任务上能达到 98%。Prompt 并没有失效,它只是悄悄地丢掉了 6 个百分点。将这种情况乘以系统中的每一个 Prompt,“我们在周末更换了模型”就变成了“我们同时向所有功能发布了一个隐蔽的性能退化”。
而且 Prompt 仅仅是第一层。工具调用约定各不相同。拒绝边界各不相同。默认的冗长度也不同——一个模型可能在“技术上更正确”,但却让用户淹没在吹毛求疵中,除非你的评估衡量的是可接受度而非原始准确度,否则你的评测(evals)将无法捕捉到这一点。迁移供应商意味着重新运行评估、重新调优 Prompt、重新校准输出解析器,并重新了解失败模式。一行代码更换模型是真实的,但它也大约只占总工作量的 10%。
因此,诚实的核算是:网关为你提供了 API 的可移植性(你可能每一两年才需要一次),却在期间的每一次请求中都让你付出了功能降级的代价。除非你是刻意权衡,否则这是一笔亏本买卖。
具体示例:全额买单的智能体循环
这是“抽象税”如何在当前最重要的工作负载——智能体循环(agentic loop)中叠加的。
智能体对话在每一轮都会重放其整个前缀:系统提示词(system prompt)、工具定义以及不断增长的对话记录,在模型每次决定下一步行动时,这些都会被重新发送。一个 20 轮的会话,如果拥有 5,000 token 的系统和工具块,且对话记录每轮增长 1,000 token,那么相同的前缀会被重传 20 次。通过厂商原生缓存(provider-native caching),第 2 到第 20 轮读取该前缀可以享受 90% 的折扣。如果没有它,你每轮都要支付全额费用——整个会话的输入账单将是正常情况下的 5 到 8 倍,具体取决于对话记录的增长情况。
现在,在中间加入一个翻译层。如果网关剥离或损毁了缓存标记,或者以某种方式标准化了请求,导致轮次之间的 token 前缀发生变化(这会彻底破坏前缀匹配缓存),那么折扣就会悄无声息地消失。没有任何报错。 响应完全相同。唯一的症状是使用量对象中的缓存读取 token 为零,以及一份比实际需要高出数倍的账单,而这往往被归咎于“智能体就是很贵”。
同样的循环不仅损失金钱,还会损失质量。智能体的可靠性取决于 Schema 强制的工具调用(第 7 轮的一个格式错误的参数会导致之后的一切脱轨)和推理能力控制(计划步骤需要高投入,机械步骤则不需要)。这两者都是厂商原生特性。通过“最小公分母”接口运行的智能体,每轮花费更多,失败频率却更高——这处于曲线最糟糕的一点。
何时值得支付这笔“税”
这并不意味着“删掉你的网关”。它意味着你要清楚它的哪些工作证明了这笔支出的合理性。路由层在以下情况体现其价值:
- 你确实在生产环境中同时运行多个模型——用廉价模型进行分类,用前沿模型进行生成,用备用链应对停机。此时,统一接口是承重基础设施,而非保险。
- 你需要中心化治理:各团队预算控制、审计日志、PII 脱敏、密钥管理。这些是网关擅长解决的问题,解决一次胜过在每个服务中分别解决。
- 流经它的调用是通用型调用。总结这张工单、分类这封邮件、提取这些字段。对于任何胜任的模型都能达标的工作负载,“最小公分母”方案是可行的——这就是通用商品的定义。
- 故障转移(Failover)比峰值质量更重要。如果厂商停机对你的产品是生存威胁,那么来自备份模型的 中等质量输出总比没有输出要好。
但这笔税在你的核心路径上是不值得支付的——比如智能体循环、长文本 RAG 流水线,以及那些占据你大部分账单的工作负载。这正是厂商原生特性发挥作用的地方:缓存能节省真金白银,Schema 强制执行能防止解析失败,而推理预算能提升核心质量指标。
逃生舱模式
实际的架构并非“到处都是网关”或“到处都是原生 SDK”。它是一种带有明确边界的两层策略:
第一层——通用流量走网关。高吞吐、低差异化的调用,其可移植性和中心化治理的价值高于最后 10% 的性能表现。在这里有目的地接受“最小公分母”。
第二层——核心路径走厂商原生接入。你的核心智能体循环直接与厂商自己的 API 格式通信——可以是直接连接,如果网关支持,也可以通过网关的“透传模式”(passthrough mode)。优秀的网关确实支持这一点:LiteLLM 会将无法识别的参数直接转发给厂商,并提供原生格式的透传端点,正是因为全量翻译注定是徒劳的。要有意识地利用这些“逃生通道”,而不是将它们视为不规范的权宜之计。
两条规则让这种模式具有可行性。首先,让逃生舱在代码审查中清晰可见——为每个厂商原生特性编写类型化的封装函数(如 with_prompt_cache(...),with_schema(...)),而不是通过 extra_body 字段私下传递原始字典。当你最终迁移时,你可以通过 grep 查找这些封装函数,从而获得一份真实的厂商耦合清单,而不是在生产环境中才发 现问题。其次,审计网关丢弃了什么。记录离开网关的请求,而不仅仅是进入网关的请求,并进行对比。检查使用量对象,确认缓存读取 token 是否真正出现。大多数宣称“通过网关启用了缓存”的团队,从未验证过哪怕一次缓存读取是否真的生效。
如果保险才是真正的目标,那就买真正的保险:通过每月针对第二个厂商运行一小部分阴影流量,保持评估集(evals)在备选厂商上也能通过。这才能告诉你真实的切换成本——而那所谓的“一行代码切换”永远做不到这一点。
可移植性是一种能力,而非一种架构
“一行代码切换模型”只是个演示 Demo,不是战略。真正的可移植性存在于你的评估套件、提示词迁移手册以及厂商耦合特性的清单中——统一 API 无法提供这些,而你可以在发挥每个模型最大实力的同时构建这些能力。
所以,反转默认的问题。不要问“我们如何保持可移植性?”,而要问“哪些调用值得使用厂商能提供的最佳特性,哪些调用是通用商品?”。路由通用调用,核心路径走原生接入,并使边界足够清晰,让你始终清楚迁移的实际成本。被坑的团队并不是那些与厂商耦合的团队——她们是那些多年来对每次请求都支付“抽象税”,却在迁移当天发现,提示词工程自始至终才是最难部分的人。
- https://www.truefoundry.com/blog/provider-agnostic-prompt-caching-llm-gateway
- https://www.truefoundry.com/blog/litellm-vs-openrouter
- https://www.requesty.ai/blog/structured-outputs-across-llm-providers-the-compatibility-mess
- https://www.requesty.ai/blog/switching-llm-providers-why-it-s-harder-than-it-seems
- https://arxiv.org/html/2512.01420v1
- https://docs.litellm.ai/docs/completion/provider_specific_params
- https://docs.litellm.ai/docs/pass_through/intro
- https://www.prompthub.us/blog/prompt-caching-with-openai-anthropic-and-google-models
- https://openrouter.ai/docs/guides/best-practices/prompt-caching
- https://www.coderabbit.ai/blog/the-end-of-one-sized-fits-all-prompts-why-llm-models-are-no-longer-interchangeable
