
一家叫 Ploy 的公司,用 AI agent 自动搭建营销网站,过去四个月一直在用 Claude Opus 4.8 当默认模型。GPT-5.6 Sol 发布当天,他们跑了对比测试,结果构建时间从 8 分钟降到 3 分 42 秒,成本从 3.06 美元降到 2.22 美元,视觉评分从 0.936 涨到 0.970。他们当天就把生产环境整个切了过去。
这事儿听起来像"新模型发布、换个 API key、完事"。实际不是。这篇博客(原文链接)记录了迁移过程中踩的三个大坑,每一个都跟模型本身的能力无关,而是"你以为你在比较模型,其实你在比较你对旧模型养成的惯性"。Hacker News 上 217 分、92 条讨论(讨论帖),评论区的共识很一致:生产环境换模型,远比你想象的难。
先看硬数据
Ploy 的 agent 做的事很重:规划页面、读代码库、写组件、生成图片、截图自检、判断是否完成。他们的评测套件跑几百个真实 case,每个 case 由一个视觉裁判模型打分(10 个二元 yes/no 问题 + 内容检查 + 工具轨迹检查 + 文件断言)。
均值数据(每完成一次构建):
| 指标 | Claude Opus 4.8 (n=11) | GPT-5.6 Sol (n=10) |
|---|---|---|
| 成本 | 3.06 美元 | 2.22 美元 |
| 耗时 | 8 分 00 秒 | 3 分 42 秒 |
| 输入 token | 2.60M | 1.70M |
| 输出 token | 33.0K | 17.1K |
| 视觉评分 | 0.936 | 0.970 |
输出 token 直接砍半。GPT-5.6 写代码比 Opus 精简得多:同一个匹配对比中,Opus 生成了一个 17957 字符的 globals.css,包含 174 个 CSS 变量(大量色阶斜坡,基本没用),GPT-5.6 只写了 2508 字符、45 个变量,渲染效果相当甚至更好。
但 Ploy 团队的第一轮评测跑出来,三分之一的"失败"根本不是模型的问题,是评测框架自己被旧模型驯化了。
坑一:评测框架是给旧模型量身定的
这个发现让我觉得很有普遍意义。
他们的工具调用预算是按 Opus 的"顺序执行"风格设的。GPT-5.6 则喜欢并行调用,直接打爆了预算。评测执行器不支持批量文件读取(Opus 很少用,GPT-5.6 一直在用),所以 GPT-5.6 的批量读取请求被默默丢弃了。
还有一个隐藏更深的问题:某个数据集没写 minScore 阈值,默认值 1.0 生效。GPT-5.6 在一个 banner 设计上拿了 0.98 分,判定"失败"。Opus 通过了每个子检查但整体判"失败"。两个合理的默认值方向,一个隐形的阈值。
Ploy 的教训:换模型前先修你的评测框架,否则你在打分的是"新模型有多像旧模型"。
坑二:GPT-5.6 会给每个工具参数编一个值
这个坑是三个里面最有意思的。
Ploy 的 code 工具有 25 个参数,1 个必填,24 个可选。Claude 的行为是只发用到的两三个参数,其余省略。GPT-5.6 的行为是 25 个全发,每次都发,没用到的参数自己编一个"看起来合理"的值:offset 0、timeout 120000、siteId 全零 UUID。
三天生产环境的数据:
| 模型 | 调用数 | 25 参数全发 |
|---|---|---|
| GPT-5.6 | 6635 | 6635 (100%) |
| Claude Opus 4.8 | 2898 | 4 (0.1%) |
| Claude Sonnet 5 | 1933 | 0 (0%) |
问题不是冗长。问题是"编的值跟真实意图无法区分"。offset 0 看起来像个真参数。Ploy 的文件读取实现把它当成真的处理了,52% 到 64% 的文件读取返回空内容。工具返回 success true,模型以为读到了文件,实际上什么都没拿到。于是它反复重读,工具调用次数虚高。
提示工程修不了这个。 Ploy 试了:在工具描述里写"省略未使用的参数",仍然 25/25。每个参数加"OPTIONAL, omit if unused",仍然 25/25。OpenAI 的 strict 模式也一样,而且 strict 模式还要求砍掉 pattern、format 和数组边界校验。
最终有效的方案是在 provider 边界做一层 schema 变换:对 OpenAI 系模型,把所有可选参数改成 required but nullable(anyOf T 或 null),让模型有一个显式表达"不用这个"的方式。在工具执行前的统一入口处把 null 剥掉,工具实现不用改一行代码。
效果:空文件读取从 52% 降到 0%,同等工作量的工具调用减少约 30%。
坑三:prompt 缓存的设计差异
这是三个坑里工程含量最高的一个。Ploy 团队说"如果你只仔细迁移一样东西,就迁移这个"。
表面上两家都有"prompt 缓存",底层设计完全不同。
Ploy 的 prompt 开头有一个约 29K token 的静态前缀(工具 schema + 系统 prompt),每次对话都一样。在 Claude 上,用 cache_control 标记断点,前缀在整个组织级别共享缓存,命中率 92% 到 96%,不用操心。
GPT-5.6 改了 OpenAI 的缓存模型。之前的 GPT 模型做隐式 partial-prefix 匹配,免费给你不错的命中率。GPT-5.6 砍掉了 partial-prefix 匹配,隐式缓存只按整条 prompt 创建条目。新对话共享那 29K 静态前缀?缓存命中率 0%。而且 GPT-5.6 每个未命中 prompt 还要交 1.25 倍的 cache-write 附加费。
正确的用法是显式标记 prompt_cache_breakpoint 加上必填的 prompt_cache_key。这个 key 是缓存身份的一部分,相同 prompt 不同 key 等于零命中。每个 key 映射到一个缓存节点,节点带宽约每分钟 15 个请求,超了就 fan out 到其他冷节点。
Ploy 采用的配置:
- per-conversation key:新对话永远命中不了共享前缀,首次调用命中率 0%(他们实测了,很贵)
- global key:所有请求打到同一个节点,生产流量直接打爆 15 rpm 预算,溢出到冷节点,回到 miss
- per-workspace key:同一个客户 workspace 的所有对话共享条目,per-key 流量可控,这才是甜点
改完之后,首次调用缓存命中率从 0% 飙到 83.7%,未缓存输入 token 降 28%,GPT-5.6 的单次评测成本降到 Opus 以下。
有一个没法绕的结构性限制:OpenAI 的缓存按 key 分区,跨 workspace 共享静态前缀在架构上不可能。Anthropic 的缓存是组织级无分区,天然共享。GPT-5.6 每个 workspace 每个 idle 窗口付一次 29K 冷写,约 0.18 美元。有成本,但可预测。
Ploy 的原话:"如果你在比较两个模型的成本,其中一个缓存是冷的,你比的是你的配置,不是模型。"
第三个半坑:reasoning replay
GPT-5.6 的 Responses API 默认用服务端 item reference 回放上一轮推理。Ploy 的对话会间歇性报 "Item rs_... not found"。修复方法是设 store false,让 SDK 请求加密的 reasoning content,回放自包含的 blob 而不是指向服务端状态的指针。
这个坑比较小,但有个副作用值得注意:服务端 reasoning state 在回路里时,即使你发送的字节是 append-only 的,有效 prompt 也可能在你不知情的情况下变化。
Hack News 评论区的信号
评论区最有价值的讨论来自 znnajdla:
"我的经验跟这篇一致:OpenRouter 那种承诺 failover 的服务,除了沙箱测试基本没用,因为生产环境的模型不是真正可互换的。任何做严肃 agentic 工作的生产系统,对模型特定怪癖的依赖比你想的多得多。即使另一个模型不出错,性能和效率也是完全不同的故事。system prompt 都应该按模型的说话习惯专门调。"
SwtCyber 的观点也值得记住:
"讽刺的是,在一篇充满基础设施洞察的文章下面,一半评论在抱怨强行写作风格。Claude 帮作者润色了文字又怎样?里面有一份现成的蓝图,能帮你省 30% API 预算并修复空文件读取。"
我的看法
这篇博客最大的价值并非 GPT-5.6 vs Claude Opus 的对比数据上。数据当然好看,但数据会被下一轮模型迭代覆盖。
真正有迁移价值的是这三个教训的通用性:
- 你的评测框架已经默默适应了旧模型,换模型前先修框架
- 模型行为差异不在能力层面,在调用习惯层面(编参数 vs 省参数),这种差异会在你的工具层静默发酵,表现为"莫名变慢"而不是"报错"
- prompt 缓存不是"有就行",两家的设计哲学不同到需要重新做架构决策
Ploy 的迁移故事本质上是 LLM 基础设施成熟的一个信号:模型已经好到值得为它做认真的工程适配了,而不是反过来,让模型适应你的通用框架。Vercel AI SDK 号称"一个 SDK 跑所有模型",实际上你换一个 provider,provider 特定行为会从 schema 层、缓存层、reasoning 层一层层冒出来。