推荐这篇文章,Flask 作者 Armin Ronacher 追踪 Pi 的 bug 发现了一个让人不安的事实:新版 Claude 模型(Opus 4.8、Sonnet 5)的工具调用在退化——不是变好了,是变差了。而且他找到了根因:RL 后训练过度适配了 Claude Code 自己的工具 schema,导致替代工具 schema 越来越"离群"。这是所有自己做 agent harness 的人都需要读的文章。
更好的模型,更差的工具调用
一个奇怪的 Pi issue 让我在过去两天掉进了一个深坑。简短版:新版 Claude 模型有时会在调用 Pi 的 edit 工具时,给嵌套的 edits[] 数组加上多余的、编造出来的字段。不是 Haiku 或什么小模型——是 Opus 4.8。编辑本身通常是正确的,但参数不匹配 schema,因为模型发明了不存在的 keys,Pi 拒绝工具调用并要求重试。
这不完全意外——模型偶尔会发出格式不正确的工具调用,特别小的模型。但让我意外的是,这在 Anthropic 的新模型中变得更糟了。Opus 4.8 和 Sonnet 5 都表现出这个问题,而之前的旧模型不这样。换句话说,这个模型家族的 SOTA 模型在某个特定工具 schema 上不如它们的旧兄弟。
工具调用就是文本
如果你没有花太多时间看 LLM 工具调用的内部机制,需要理解的重要一点是:工具调用不是魔法。模型收到一份转录文本、一个系统 prompt 和一个可用工具列表。服务器把这些搅成一个带有特殊标记 token 的大 prompt。因为模型用那个格式的示例训练和强化过,它在生成过程中某一点会发出被 API 或客户端解释为"用这些参数调用这个工具"的东西。
细节是:嵌套数组里面的 JSON 是序列化在 XML 标签里面的。基本顶层字符串参数在线显示,而对象数组通过 JSON 序列化实现。这很重要,因为当模型在一个几百 token 的转义字符串后面要决定 } 还是 ,"..." 时,这正是最高熵的点。
失败
Pi 的 edit 工具支持在一个调用中做多个精确字符串替换,所以参数里有一个 edits 数组。在失败的案例里,模型产生了这样的条目:额外加了 requireUnique: true、oldText2、newText2。反复测试中我看到了一整批编造出来的尾随 keys:type、id、kind、unique、requireUnique、matchCase、in_file、forceMatchCount、children、notes、cost,甚至一个 event.0.additionalProperties 在里面。
最烦人的是,实际 oldText 和 newText 负载在我检查过的无效调用里是字节级正确的。模型确实产生了正确的调用,然后在对象末尾加了垃圾。
这个失败也高度上下文依赖。全新的单轮"编辑这个文件"prompt 完全不会复现。有 agent 历史——模型读过文件、诊断了问题、然后写了多行编辑——就能复现。而且不是所有转录都会这样。打开 strict 工具调用在我的运行中完全消除了问题。
为什么在变差
我最强的假设是这不是随机退化,而是训练 artifact。
旧 Anthropic 模型训练时,它们训练了一些工具,但那个训练还没有 Claude Code 这样用户交付的 harness 作为明显目标。现代 Anthropic 模型大概率不同,因为它们的后训练包括了 Claude Code 或一个看起来非常相似的 harness。模型学到了在那个环境下什么样的工具调用是成功的。它也会学到那个环境容忍什么错误。
Claude Code 自己的工具相对扁平。普通 edit 工具不是 Pi 的嵌套 edits[] 形状,更接近 file_path、old_string、new_string 和一个可选 flag(replace_all)。看 Claude Code 的客户端非常有启发:它包含格式错误工具用的重试路径、参数别名、类型强制转换、Unicode 修复和未知 key 过滤。换句话说,Anthropic 自己的客户端似乎期望和接受相当数量的 slop,并修复它,大部分是静默的。
如果强化学习发生在这样的 harness 里,或一个模拟里,那么稍微格式不正确的工具调用仍然可以完成任务并得到奖励。harness 完全吸收了错误,几乎不存在惩罚"发明一个别名"、"加一个多余字段"或"用一个相近的参数名"的梯度。
更糟的是,模型可能变得极强地适应了标准 Claude Code edit 工具的形状。一个不同的 harness 可以提供语义相同但 schema 不同的工具。这样的工具会越来越离群。训练得更好的模型可能实际上更难对付你,因为它的先验更强。
这不算太意外,但这是一个变迁。Opus 4.5 发布时,它适应其他 edit 工具的能力异常好。我当时相当确信我们在一条好路上——模型只要指令好,更可能适应任何种类的工具形状。现在我有些担心我们在哪条路上。替代工具 schema 可能不只是不熟悉。它们可能被优化特定、宽容的工具生态的后训练隐式惩罚。而且那个生态没有文档。
Slop Harness
Claude Code 是闭源的,但我们可以看压缩后的代码。老实说,它对输入数据非常宽容。
首先,Claude Code 检查模型可见文本里是否有泄露的
Claude# #Agent# #工具调用#