从今天起,Ploy 的智能体运行在 GPT-5.6 Sol 上,这是 OpenAI 今早发布的模型系列中的旗舰层级。几个月来,鉴于我们对质量有着极高的标准,一直找不到能挑战 Claude Opus 的模型。这种情况随着 GPT-5.6 Sol 的出现而改变。在与 Claude Opus 进行正面交锋测试后,我们已将 GPT-5.6 Sol 设为驱动每个 Ploy 工作区的默认模型。
这比听起来要重大得多。Ploy 的智能体构建并编辑真实的营销网站。它规划页面、读取代码库、编写组件、生成图像、截取自己工作的截图,并判断何时完成。这份工作描述为模型设定了非常高的标准,我们针对每一次前沿发布都进行测试。在 Opus 占据默认位置的四个月里(先是 Opus 4.7,然后是 4.8),我们测试过的任何模型都无法击败它。GPT-5.6 是第一个做到的模型。
这并非说首次评估运行就完美无缺。它确实存在一些失败模式,我们会向你展示。但它的表现极其出色,其前景立竿见影且具体明确:构建完成所需的挂钟时间缩短一半以上,成本降低 27%,在已完成工作上的评分达到或超过我们现有的模型。这样的数据足以让一个模型获得真正的迁移努力。
尽管使用了 Vercel 的 AI SDK(一个通用的 LLM SDK),但从 Claude Opus 4.8 切换到 GPT-5.6 Sol 仍需我们通过一次次评估失败来发现:我们认为是“模型”的那些东西,其实是整个技术栈已经悄然适配的、特定于提供商的行为——比如它如何填充工具参数、它的提示缓存如何工作、以及它如何在轮次之间重放自己的推理过程。
以下是需要做的事情:修复评估框架,然后是工具模式,接着是缓存,最后是推理重放。
第 0 步:在信任任何一个数字之前,先修复你的评估框架。
我们的评估套件让真实智能体在真实固定工作区中运行。涵盖数百个案例,从"从头构建一个首页"到"这个克隆请求是否安全可执行"。构建案例通过一个视觉评判器进行评分,该评判器对照参考设计运行二元检查,包含十个是/否问题,例如"主视觉区域是全幅摄影场景"或"主要行动号召按钮是圆角矩形而非胶囊形状",此外还有内容检查、工具轨迹检查和文件断言。每个失败的案例都会根据其完整追踪记录进行分类:包括实际的工具调用和模型文本,而不仅仅是分数。
在两个模型系列上运行该套件,其带来的惊喜超过了任何单个结果:
你的测试框架是针对你当前使用的模型调优的,而你自己并未意识到这一点。我们的工具调用预算原本是针对 Opus 的顺序式风格设定的;GPT-5.6 则并行发出调用,并在它正确解决的案例上超出了预算。我们的评估执行器不支持批量文件读取,Opus 很少使用这个功能,而 GPT-5.6 则频繁使用。在首次跨模型运行中,大约三分之一的原始失败原因可追溯到测试框架的假设,而非模型行为,并且这些失败在两个模型之间的分布并不均匀。如果你正在用当前模型评估一个挑战者模型,在相信通过率之前,请先对追踪记录进行分类。否则,你实际上是在评判新模型模仿旧模型的能力有多好。
确保在评估中公平地给模型打分。一个数据集如果省略了其 minScore 阈值,就会静默地继承默认值 1.0,因此 GPT-5.6 在一个它得了 0.98 分的主视觉区域上"失败"了,而 Opus 则在一个通过了所有单项检查的案例上"失败"了。两种都可辩护的设计方向;一个不可见的阈值。
第一印象:立即展现出潜力
在清理了测试框架之后,以下是我们重新设计套件中的一个样本,其中智能体根据参考设计重建一个品牌的首页:
| 每次完成构建的平均值 | Claude Opus 4.8 (n=11) | GPT-5.6 (n=10) |
|---|---|---|
| 成本 | $3.06 | $2.22 |
| 挂钟时间 | 8 分 00 秒 | 3 分 42 秒 |
| 输入 token | 2.60M | 1.70M |
| 输出 token | 33.0K | 17.1K |
| 视觉评分 | 0.936 | 0.970 |
这就是承诺的样貌:完成一个成品页面速度快 2.2 倍,成本低 27%,输出 token 数量大约减半。GPT-5.6 编写的代码很精简。在一组对照中,Opus 生成了一个 17,957 字符的 globals.css 文件,内含 174 个 CSS 变量(完整的色阶,大部分未使用),而 GPT-5.6 只写了 2,508 个字符和 45 个变量,就实现了效果相当(有时甚至更好)的渲染页面。
Claude Opus 4.8
GPT-5.6 Sol
设计:锐利、干净,但略显千篇一律
我们对 GPT-5.6 设计工作的整体评价是:它在干净、现代、紧密网格布局方面表现出色,但除非你给予很好的引导,否则它容易趋同于那种外观。在我们为 Opus 4.8 设计的旧测试框架下,GPT 5.6 Sol 倾向于忽略现有的设计系统,转而生成锐利、克制但明显千篇一律的输出。
我们如何解决这个问题的细节,值得单独写一篇博文。凭借我们设计和工程团队的专业知识,我们能够引导模型实现开箱即用无法获得的、世界级的品牌一致性。
第一步:检查你的工具调用
这就是在我们发现之前,一直在暗中破坏结果的那个问题。
我们智能体的代码工具有 25 个顶层参数,其中一个是必填项(action),其余都是可选的。Claude 只发送它用到的两三个参数,并省略其余参数。GPT-5.6 每次都会发送全部 25 个参数,并为它不需要的参数凭空编造出看似合理的值:offset: 0, timeout: 120000, siteId: "00000000-0000-0000-0000-000000000000"。
三天生产环境追踪数据,code(read) 调用携带了所有属性:
| 模型 | 调用次数 | 携带全部 25 个属性 |
|---|---|---|
| gpt-5.6 | 6,635 | 6,635 (100%) |
| claude-opus-4.8 | 2,898 | 4 (0.1%) |
| claude-sonnet-5 | 1,933 | 0 |
问题不在于冗长。而在于一个编造的值与一个有意传入的值无法区分。offset: 0 看起来像一个真实的参数。我们的文件读取实现将其视为真实参数,结果导致 GPT-5.6 有 52% 到 64% 的文件读取返回空内容。该工具在两种情况下都返回 success: true,因此模型无法知道自己读取的是空白文件。它只是用更多的调用次数,完成了更差的工作。
提示词无法解决这个问题。在工具描述指令中加上“省略未使用的参数”:结果仍是 25/25。在每个属性上添加“可选,未使用则省略”的提示:结果还是 25/25。OpenAI 的严格模式:行为完全一致(我们实测过),而且如果采用该模式,我们就必须从每个 schema 中移除 pattern、format 和数组边界校验。这个问题根植于模型输出函数调用的底层机制。你无法通过指令消除它,只能围绕它来设计。
有效的解决方案是在供应商边界处进行 schema 转换。仅针对 OpenAI 系列模型,我们将每个可选属性改为必填但可为空,使用 anyOf: [T, null] 格式,这样模型就有了明确的表达方式来表示“不使用此参数”。然后,在每个工具调用必经的唯一接口处,我们在校验之前将 null 值剔除,因此工具实现完全无需改动。整个流程:模型看到的 schema 允许它诚实表达意图;工具看到的输入则与以往完全相同。
// Before: 25 keys, every one carrying an invented value
{ "action": "read", "file_paths": [...], "offset": 0, "timeout": 120000, ... }
// After: 25 keys, 4 real values, 21 explicit nulls (stripped before the tool runs)
{ "action": "read", "file_paths": [...], "offset": null, "timeout": null, ... } 结果:空文件读取从 52% 降至 0%,智能体完成相同工作所需的工具调用次数减少了约 30%,因为它不再重复读取返回空白内容的文件。
第二步:重建提示词缓存
这是最具启发性的工程差异,因为表面上两家供应商都提供“提示词缓存”,但这个词背后隐藏着两种完全不同的设计。如果你要谨慎迁移一件事,那就是这个:在我们调整之前,GPT-5.6 看起来比 Opus 贵了约 50%。问题不在于模型定价,而在于我们的缓存配置。
我们智能体的提示词以一个约 29K token 的静态前缀开头(工具 schema 加核心系统提示词),该前缀在所有对话中完全相同。在 Claude 上,我们使用 cache_control 标记缓存断点,这个前缀会在整个组织范围内缓存:任何对话、任何工作空间,共享一个缓存条目,无需考虑吞吐量预算。缓存命中率可达 92% 到 96%,缓存机制几乎无需操心。
GPT-5.6 悄然改变了 OpenAI 的缓存模型,让我们措手不及。早期的 GPT 模型会对部分前缀匹配进行隐式缓存,从而免费获得不错的命中率。GPT-5.6 取消了部分前缀匹配:现在的隐式缓存仅以最新消息为键,创建整个提示词的缓存条目。一个共享我们 29K 静态前缀的新对话,其缓存命中率为 0%。每个对话都会按未缓存费率重新计收整个前缀的费用,而且在 GPT-5.6 上,无论你是否使用缓存,每个未缓存的提示词还需支付 1.25 倍的缓存写入附加费。
其预期的机制是显式的:`prompt_cache_breakpoint` 标记加上一个强制性的 `prompt_cache_key`。而这个键正是设计上真正产生分歧的地方,因为它成为了缓存标识的一部分。相同的提示词,不同的键:缓存命中率为零。每个键映射到一个缓存节点,该节点在 OpenAI 将流量分散到其他拥有独立、冷缓存的节点之前,大约能维持每分钟 15 次请求。
这就把“启用缓存”变成了一个实际的设计决策:你打算将键的作用域限定在哪个实体上?
- 按对话设置键意味着新对话永远无法命中共享前缀。首次调用的命中率:0%。(我们测量过这个错误。代价非常高昂。)
- 使用一个全局键意味着每个请求都会哈希到同一个缓存节点,而生产流量会瞬间耗尽每分钟 15 次的预算;请求会溢出到冷节点,你又回到了未命中状态。
- 按工作空间设置键是最佳方案。同一客户工作空间内的所有对话共享缓存条目;每个键的流量保持在较低水平。
我们推出了工作空间作用域的键,并将系统提示词拆分为带断点的层级,镜像了我们已用于 Anthropic 的结构:
request ──► hash(prompt head + prompt_cache_key) ──► cache node (~15 req/min per key)
│
┌──────────────────────────────────────────────────────┴───────────────┐
│ entries on the node, all namespaced by key ws:{workspaceId} │
│ │
│ [ tools + static prefix ]······················ A every session │
│ [ tools + static prefix + workspace context ]·· B same context │
│ [ ····················· + turn 1 + … + latest ] C this session │
└──────────────────────────────────────────────────────────────────────┘ 条目 A 使得会话的首次调用成本低廉。条目 B 能够自我修复:当工作空间记忆发生变化时,请求会错过 B,但仍能命中 A,然后写入一个新的 B。只需一次上下文大小的写入,而无需重新计收完整的 29K 费用。条目 C 是 OpenAI 的隐式完整提示词链,由于我们的提示词严格采用追加模式,因此它在会话内运行良好。
一个后果没有变通办法:在 OpenAI 上,跨工作区共享静态前缀在结构上是不可能的。Anthropic 可以共享它,因为它的缓存是组织范围的,没有键分区。在 GPT-5.6 上,每个工作区在每个空闲窗口都要支付一次 29K 的冷写入费用,大约 0.18 美元。这是一个真实的成本,但有上限且可预测。
变更后的结果:首次调用的缓存命中率从大约 0% 提升到了 83.7%,未缓存的输入 token 总量下降了 28%,并且 GPT-5.6 的每套成本低于 Opus。我们一直盯着的每一个美元的成本差距都是缓存配置错误造成的,而不是模型定价问题。如果你在比较模型的成本,而其中一个模型缓存是冷的,那你实际上是在比较你的配置,而不是模型本身。
第三步:让推理回放自包含
更短了,但它破坏了真实的对话。GPT-5.6 的 Responses API 默认将前一轮的推理作为服务器端项目引用进行回放;我们的对话中途开始间歇性地失败,报错“项目 'rs_...' 未找到”。修复方法是设置 `store: false`,这会让 SDK 请求加密的推理内容,并回放自包含的数据块,而不是指向服务器状态的指针。一个让我们花了一个下午调试的推论是:当服务器端推理状态参与循环时,即使你发送的字节是只追加的,有效的提示词也可能在你上游发生变化。
GPT 5.6 Sol 已准备好部署
亲自试试吧。GPT-5.6 今天发布,并且已经在 Ploy 上上线。你现在就可以免费试用:给它一个网站去构建,看看不到四分钟的构建过程是什么样子。在 ploy.ai 免费开始使用。
Ploy 是自动运行的营销:一个 AI 层,端到端地规划、构建、发布和优化你的网站及营销活动。如果在凌晨两点调试缓存节点扇出听起来很有趣,我们正在招聘。