Claude 新模型越强,第三方编程工具越难用?Armin Ronacher 揭示 tool calling 退化真相
基于已整理草稿生成的网页版文章,适合先稳定落地,再做局部润色与发布检查。
7 月 4 日,Flask 和 Jinja2 的作者、AI 编程工具 Pi 的开发者 Armin Ronacher 发表了一篇引人深思的文章:Claude 最新的 Opus 4.8 和 Sonnet 5 模型在编程能力上更强了,但在调用第三方编程工具的 edit 功能时,反而比旧模型更容易出错——不是编辑内容写错了,而是模型会凭空"发明"工具 schema 中根本不存在的参数字段,导致整个调用被拒绝。
这看似是一个小 bug,实际上揭示了 AI 编程工具生态中一个越来越紧迫的结构性问题:当模型厂商在自己的编程工具中做强化学习训练,模型会越来越适配自家工具的内部格式,对其他工具的 schema 则越来越"不适应"。
问题是什么
Pi 的 edit tool 使用嵌套的 edits[] 数组格式:每次编辑操作包含 oldText 和 newText 两个字段,支持一次调用做多处替换。
正常调用应该长这样:
```json
{
"path": "some/file.py",
"edits": [
{ "oldText": "旧代码", "newText": "新代码" }
]
}
```
但 Claude Opus 4.8 和 Sonnet 5 在长对话中,会输出这样的调用:
```json
{
"oldText": "旧代码",
"newText": "新代码",
"requireUnique": true
}
```
或者:
```json
{
"oldText": "旧代码",
"newText": "新代码",
"oldText2": "",
"newText2": ""
}
```
Armin 在反复测试中记录到了一整座"虚构字段动物园":type、id、kind、unique、requireUnique、matchCase、in_file、forceMatchCount、children、notes、cost、oldText2、newText2、oldText_2、newText_2,甚至还有 event.0.additionalProperties。
最让人头疼的是:编辑内容本身完全正确。oldText 和 newText 是 byte 级精确的,模型理解了该做什么修改,只是在 JSON 对象末尾多塞了几个不存在的字段。Pi 的 schema 验证检查到多余字段后拒绝整个调用,模型只好重试。
关键发现:新模型更差,旧模型没事
这个问题有几个重要特征:
- 只有新模型出问题:Opus 4.8 和 Sonnet 5 会发明额外字段,Opus 4.5 及更早版本不会。换句话说,模型能力提升了,但这个特定场景下的 schema 遵从度反而退化了。
- 高度上下文相关:在单轮"编辑这个文件"的提示中完全无法复现;只有在长 agentic 对话(模型已经读过文件、诊断了问题、然后编写多行编辑)中才会出现。
- 失败率不低:在一位用户的会话中,Opus 4.8 的失败率约 20%。删除 thinking blocks 可将失败率减半,开启 strict tool invocation 则完全消除。
- Codex 模型没这个问题:OpenAI 的 Codex 系列模型(除尚未获取的 5.6)均未出现此类退化。
根因分析:RL 训练的隐性代价
Armin 的核心假设是:这不是随机退化,而是训练产物。
当 Anthropic 对 Claude 模型做强化学习(RL)后训练时,训练环境很可能是 Claude Code 或一个类似 harness。在这个环境里:
- Claude Code 的 edit schema 是扁平的:它用的是
file_path、old_string、new_string加一个可选的replace_all标志,和 Pi 的嵌套edits[]结构完全不同。
- Claude Code 客户端极其"宽容":通过分析 Claude Code 的压缩代码可以发现,它内置了大量容错机制——静默过滤未知字段、参数别名映射(如
old_str→old_string)、Unicode 修复、malformed 调用自动重试。也就是说,Claude Code 自己的工具调用格式并不严格,模型即使输出"带毛刺"的调用,Claude Code 也会修好并继续运行。
- 宽容环境 + RL = 无惩罚的毛刺:在 RL 训练中,如果"稍微不规范"的 tool call 仍然能完成任务并获得奖励,模型就没有动力精确遵守 schema。反而,模型可能学到"Claude Code 式"的参数形状作为先验。
- 强先验的副作用:Opus 4.8 对 edit 工具有非常强的先验("编辑应该有 file_path、old_string、new_string,可能还有一个额外标志"),但面对 Pi 的
oldText/newText嵌套结构时,这个先验反而成了干扰。模型在写完正确的编辑内容后,在最高熵的位置(几百 token 的转义 newText 字符串结束后的}vs, "..."分叉点)"忍不住"补了一个它认为该有的字段——名字每次都不一样,因为训练数据里根本没有这个名字。
对编程工具生态意味着什么
这个发现对 AI 编程工具生态的影响远超 Pi 一个工具:
模型厂商的 RL 训练正在隐性"绑架"工具生态。 当模型的 post-training 越来越适配自家编程工具的内部格式,第三方工具的 schema 就越来越"偏离分布"。模型可能足够聪明来理解你的 schema,但在生成压力下就是采样不出正确形状。
闭源 harness 加剧了问题。 Claude Code 是闭源的,它的内部容错逻辑、参数别名、重试机制都不对外公开。开发者无法预知哪些 schema 形状会被模型的先验"带偏"。
这不是 Anthropic 独有的问题。 OpenAI 的 Codex 使用 apply_patch 机制而非 search-and-replace,其模型也被训练为擅长这种格式。任何做自家编程工具 + RL 训练的模型厂商,都可能产生类似效应。只是目前 Codex 模型尚未表现出同等程度的退化。
实际建议
- 如果你是编程工具开发者:使用 Claude 模型时,考虑开启 strict tool invocation 来约束输出格式;或者尽量让工具的 schema 形状接近 Claude Code 的扁平格式。
- 如果你是 AI 应用开发者:注意模型的 tool calling 遵从度可能随版本迭代而变化,不能假设"更好的模型 = 更好的 schema 遵从"。
- 如果你是模型厂商:需要在自家工具优化和通用 tool calling 能力之间找到平衡。开源 RL 训练环境、公开 harness 的容错逻辑,可以帮助整个生态更好地适配。
局限
- 此问题目前仅在 Pi 工具中详细记录,其他编程工具的实际受影响程度需自行测试验证。
- Claude Fable 5 未被测试(作者担心 Anthropic 的分类器可能静默降级为 Opus)。
- Anthropic 的 strict mode 对工具定义复杂度有限制,复杂 schema 可能无法使用 strict mode。
- 问题出现的具体频率高度依赖上下文,不同使用场景差异可能很大。
---
*基于 Armin Ronacher 博客原文及 Simon Willison 转述整理。Armin Ronacher 是 Flask、Click、Jinja2 等 Python 核心库的作者,目前开发 AI 编程工具 Pi。*
参考来源
说明:该页面由基础模板稳定生成,后续可继续局部润色样式或补充模块,再进入发布检查。