Ploy 迁 GPT-5.6 快 2.2 倍便宜 27%,我盯着那笔没入账的迁移工程债

cover

哈喽,我是飞飞。

事情是这样的。GPT-5.6 Sol 上线那天,Ploy 就把生产 agent 从 Claude Opus 4.8 切过去了,隔天发了一篇迁移复盘。账面数字很好看:同一份建站评测跑下来,耗时从 8 分钟压到 3 分 42 秒、单次成本从 3.06 美元降到 2.22、视觉分从 0.936 提到 0.970。

我一眼看到的是这些数字。翻到中间那段才留意到,他们为了把这些数字做出来,中间踩了四个大坑。看完发现,那四个坑几乎逐条对得上我这套写作流水线的家底。

快 2.2 倍是真的

先撂话在前面,Ploy 那份账本我信。Opus 撑了他们家默认 slot 整整四个月,先 4.7 后 4.8,中间试遍每个前沿新模型都没打过,直到 GPT-5.6 Sol 出场。

同一份 redesign 评测跑十来个 case 出来的数字不靠一次 A/B 的运气。是他们眼睁睁看着 GPT-5.6 把页面写得更精简:同一份 globals.css,Opus 甩出去 17957 字符、174 个 CSS 变量还有大半没用上,GPT-5.6 只写 2508 字符 45 个变量,效果一样甚至更好。

这些收益不算幻觉,是真的。所以「要不要换」这个问题,账面上答案很清楚:换。但账面之外那些没入账的活,才是我盯着这篇复盘走神的地方。

编造的默认值最坑

先说这个大坑。Ploy 有个叫 code 的工具,25 个顶层参数、1 个必填、24 个可选。Claude Opus 一直是要用哪个填哪个,剩下的省掉。GPT-5.6 上来直接 25 个字段每次全填,不用的它就编一个看起来合理的默认值。offset 填 0、timeout 填 120000、siteId 填一串全零 UUID。

看着都像真的。工具那头也不知道这是它自己填的,欢欢喜喜按 offset:0 开始读文件,读回来一片空。工具返回 success:true,模型一点感觉都没有。三天生产 trace 拉出来一看,GPT-5.6 的 6635 次 code(read) 调用,100% 全带 25 个字段;Opus 4.8 是 2898 次里出现 4 次;Sonnet 5 一次都没有。GPT-5.6 的文件读取里,有 52% 到 64% 是读进来一片空的

Ploy 一开始想在提示词里治它。工具描述加一句「不用的参数请省略」,还是 25/25。每个字段都挂上 OPTIONAL 提示,还是 25/25。上 OpenAI 官方的 strict 模式,一模一样。HN 上后来有人一句话讲透原理,这是它权重里烧进去的偏好,system prompt 出现哪个参数名,它就要去填一个值。提示词治不了训练层的偏置。

Ploy 最后是在 provider 边界做了个 schema 转换。所有可选字段改成 required-but-nullable,让模型有个明确的地方说「这个我不用」,调工具前那层入口再把 null 剥掉。修完,空读从 52% 降到 0%,工具调用总量也少了 30%。真正躲不掉的从来不在模型跑得动多快,在这道空读悄悄发生了三天没人知道。

缓存不是一个东西

Ploy 讲得最实在的是 prompt cache 这段。他们最初看到的账本是 GPT-5.6「贵 50%」,翻回头查完全是缓存配置的锅,跟模型价格没关系。

两家都叫 prompt caching,但根本不是一个东西。Anthropic 那套是 org 级共享,你标个 cache_control 断点,命中率 92% 到 96%,你都不用管它。GPT-5.6 这一代把之前的 partial-prefix 隐式匹配砍掉了,只留显式 breakpoint 加一个 prompt_cache_key。key 是缓存身份的一部分,同一个 prompt 换个 key 就是零命中;每个 key 对应的缓存节点大约 15 请求每分钟顶天了,超了就 fanout 到冷节点。

于是「开个 cache」不再是勾选一个开关,说白了是一道设计题。per-conversation key,每个新会话首次命中 0%。one global key,15 rpm 立刻被打穿。

Ploy 最后选 per-workspace,同一个客户 workspace 内所有会话共享,key 级流量又不至于爆。first-call 命中从 ~0% 涨到 83.7%,未缓存输入 token 降 28%,成本这才终于压到 Opus 之下。

还有一条躲不掉的结构性差异:跨 workspace 共享静态前缀,在 OpenAI 结构上不可能,因为 key 分片就是这么设计的。每个 workspace 空闲一段时间后要付一次冷写,约 0.18 美元。可预测、有账,但躲不掉。

评估口径先被污染

上面这些如果只当技术细节,我盯得最久的其实是 Ploy 复盘一开头那句「先修 harness」。他们跨模型头一次跑,1/3 的失败根本不在模型不行,是 eval 框架的假设错了。

工具调用预算按 Opus 的串行风格设的,GPT-5.6 并行 fan-out 直接爆预算。eval executor 不支持批量文件读,Opus 不咋用、GPT-5.6 疯狂用。有个 minScore 阈值默认继承成 1.0,GPT-5.6 拿到 0.98 的视觉分被判失败,Opus 反而在某些 case 上单项分不高但总分及格。你以为你在跨模型客观 A/B,其实你的 harness 早就把 incumbent 那些习惯当成默认口径了。

我盯着这段挺不是滋味。因为它意味着,我写作流水线里那份 grep 规则,一整套防 AI 味的死规矩,不许中文长破折号、negate-first 对仗全文最多一处、三联否定要拆成散句、单句超 20 字要拆。这些规矩是我照 Claude Code 一稿一稿改出来的,改到第 76 版才勉强不误伤正常疑问句。它写的是「Claude 写字容易犯什么错」的语义地图,跟「AI 中文写字通用地图」这回事还差一层。真换个模型底座,这份 grep 直接失效的比例有多少,我心里没数。这是我这套家底最不敢体检的一层。

换的不是模型是形状

Ploy 那句总结我抄下来贴在自己那份 Skills 与提示词工程 的经验库最上面:所谓的「模型」,其实是你整套 stack 悄悄围绕它长出的一堆 provider 特化行为。

这话具体到我这边就是:Claude Code 读 skill 的顺序、认 frontmatter 的方式、hook 触发的时机、skill: 里的 description 触发准头、content-training 那条自动回写的回路、CLAUDE.md 分层加载的位置,每一样都是我照着 Opus 的脾气抠出来的死规矩。Lindy 那个例子我一直记得:他们把 100% 流量从 Anthropic 切到 DeepSeek V4,账面上是几百万美元一年的节省,但创始人自己说迁移「比预想多干了 100 倍的活」。省下来那几百万,够不够覆盖那 100 倍的活,只有他自己那本账知道。

我这套写作流水线跑了 115 篇。十几个 skill、一份从 12KB 砍到 4KB 的 CLAUDE.md、一摞按每天真用什么裁出来的 memory 文件,全长在 Claude Code 那个 frontmatter/hook/skill 加载机制上。换个底座,光是把 skill 描述重新写到不误触发、把那份 grep 规则重新对新模型的写字口癖调准,我心里粗算下来一周两周下不来。这笔账在「省下多少 token 单价」那本上,一分钱都不记。

我最不敢动的两个位置

我没说不该换。是想说换之前你得知道,你想换的其实不在一个模型 ID,在围着它长了半年的一堆形状。

真要迁,我心里想的两个动作。

头一件是先把评估口径这本账捋出来。我判断一个 skill 好不好用,究竟是在看它把活干成什么样,还是在看它有没有踩中我按 Claude 脾气埋下的那些暗桩。这个口径不重写清楚,跨模型跑出来的头一波数字,跟 Ploy 那 1/3 的假失败一样都是幻觉。

另一件是先挑一条流量最大的 skill,大概是我的 content-writer。让新旧模型各跑一批真活,盯质量、盯风格、盯月底的实扣账单,看那个「便宜 27%」在我这套 grep 规则底下还剩多少。

Ploy 迁完 GPT-5.6 Sol 之后其实还留下一个躲不掉的事没讲透。GPT-5.6 Responses API 默认让服务端记上一轮 reasoning、下一轮传个 item ref 回来,会话中间偶尔就会报 Item rs_... not found。要修得开 store:false,让 SDK 请求把整份 reasoning content 加密塞进 blob。

我特意记住这一条。你别说,它意味着「你发出去的 bytes 是 append-only」这件事,在 server-side state 面前不成立了。上游可能悄悄换掉你实际的 prompt,你都不知道。

我这套写作流水线到底该不该迁?说实话我现在心里没答案。账面上 27% 一年下来算笔钱,可我心里那本迁移工程债也是不小的一笔账。

你那本迁移工程债自己盘过吗,真要换底座,最先卡住你的会是哪一条?

参考资料

  • [[ploy-gpt-5-6-migration]]
  • [[hn-discussion-ploy-migration]]
  • [[tibo-gpt-5-6-context]]

相关洞察

  • [[model-migration-is-engineering-debt]]