群发资讯网

推上CommandCodeAI的CEO:Ahmad Awais分享了他们调教De

推上CommandCodeAI的CEO:Ahmad Awais分享了他们调教DeepSeek 的经验:我们是怎么让 DeepSeek 超过 Opus 4.7 的?----------------------我最近一直在想,为什么“开源模型不擅长工具调用”几乎总是 harness 的问题,而不是模型本身的问题。

背景是:我花了两天时间,看了CommandCodeAI 里用 DeepSeek 跑出来的数十亿 token。Command Code 是一个开源 AI CLI。最后我写了一层“工具输入修复层”。

触发点是我看到 DeepSeek Flash 在最简单的 /review 运行里都失败:每一个 shellCommand 和 readFile 调用都会被原样返回一个 Zod 错误对象,模型无法恢复,因为错误信息不是它能读懂、能行动的形式。

到最后,DeepSeek V4 Pro 在我们的内部评测里,已经有 6/10 次打败了 Opus 4.7。

我学到的一些东西,感觉具有普遍性:

1/ 失败模式不是随机的,而是一个很小、有限、可组合的集合

在 DeepSeek Flash、DeepSeek V4 Pro、GLM、Qwen 上,反复出现的几乎都是同样四种错误:

对可选字段传了 null,而不是直接省略该字段;把 ["a","b"] 输出成 JSON 字符串,而不是实际数组;schema 期望数组时,模型却把单个参数包进 {} 里,像是一个“空占位符”;schema 期望数组时,模型传了裸字符串,比如 "foo",而不是 ["foo"]。

四种修复,每种大概 30 到 100 行代码,顺序要小心安排。比如“解析 JSON 数组字符串”必须在“裸字符串包装成数组”之前执行,否则 '["a","b"]' 会变成 ['["a","b"]']。

这基本就是全部目录了。现在只要我听到“这个开源模型不会做工具调用”,我都会先假设它踩中了这四类问题之一。目前来看,这个判断大概 90% 的时候都是对的。

2/ 最好笑的失败模式,也是最能说明问题的

DeepSeek Flash 在被要求编辑或写文件时,有时候会把路径输出成一个 Markdown 自动链接:

filePath: "/Users/x/proj/[notes.md](http:// notes.md)"

我们的 writeFile 工具就老老实实地尝试创建一个真的叫 [notes.md](http:// notes.md) 的文件,直到我们把它拦住。

这不是幻觉。这是后训练阶段的聊天分布“漏”进了工具边界。模型在对话输出里一直被奖励去自动链接,于是它把这个先验也用到了一个完全不该用的场景里。

修复方式就是两行正则:只解开那种退化情况,也就是链接文本等于去掉协议后的 URL。真正的 Markdown 链接,比如 [click](https:// x.com),会原样通过。

这也和它们在 RL 阶段用到的工具条件有关:那些工具和我们写的工具不同,模型当然无法预测。

比起说“工具能力差距”,更有用的说法是“工具混淆”。模型知道路径该怎么写,只是没人足够明确地告诉它:这个路径接下来会传给 fopen,不是显示在聊天气泡里。

所以我们在 schema 层面编码这个提示:用 pathString(),而不是普通的 z.string()。这样所有路径字段的泄漏问题一次性堵住。

3/ 真正重要的设计选择:从“先预处理再校验”,反过来变成“先校验再修复”

我最初的做法很直觉:在 Zod 校验之前跑一遍预处理,把输入正规化,比如去掉 null、解析字符串化数组等等。

它马上就坏了。writeFile 的内容如果刚好长得像 JSON,就会在写入磁盘前被改写。这是静默数据损坏,烟测里很容易漏掉。

后来我改成更保守的方式:

先原样解析输入。如果成功,就直接放行。合法输入永远不碰。如果失败,就遍历校验器自己的 issue 列表。对每一个出错路径,按顺序尝试四类修复,直到某个修复适用。再解析一次。成功就记录 tool_input_repaired:$ {toolName};失败就记录 tool_input_invalid:$ {toolName},并返回一条模型可读的重试消息。

这里的结构性洞察是:

当你做预处理时,你是在编码一个“哪里坏了”的先验。但当你让校验器先报错时,schema 本身就是先验;你只在 schema 实际不认可的精确路径上花修复预算。

校验器已经帮你定位 bug 了。

这和很多地方的“先便宜、后仔细”是同一种形状:先走快速路径,再基于证据回退。

这还顺便给了你免费的逐工具遥测。你可以观察每个 (model, tool) 的修复率,在用户发现之前就注意到某个模型在特定契约上退化了。

4/ 形状不变量和关系不变量,需要不同的修复方式

上面四类修复处理的都是“形状问题”:类型错了、key 缺了、容器错了。

但 read_file 有一个 关系不变量:如果提供了 offset,就必须也提供 limit;反过来也一样。

DeepSeek 经常调用:

readFile({ absolutePath, limit: 30 })

然后收到一个 ERROR:。

这种不能靠输入修复解决,因为每个字段单独看都是合法的,bug 在字段之间的关系里。

所以我改成让函数理解模型的意图:

只有 limit → 默认 offset = 0只有 offset → 默认 limit = 2000,这和常见读文件工具的默认行为一致

然后把这个决定在结果里告诉模型:

注意:未提供 limit;已默认设置为 2000 行。要读取更多或更少行,请同时提供 offset 和 limit 后重试。

不要加 Error: 前缀,这样 TUI 不会把它染红。模型能看到我们做了什么选择,如果猜错了,它下一轮可以自我修正。

透明胜过静默魔法。

能修复就修复;不能修复就扩展语义;无论哪种,都把选择暴露出来。

拉远看

很多看起来像“模型能力”的东西,其实是“契约设计”。

严格 schema 是一种选择,而且有成本。它能过滤噪声,但也会把那些可恢复的噪声一起过滤掉,尤其是那些还没有记住你刚好选的 JSON 契约的模型。

最大的商业模型可以无形中吃掉这个成本,在工具调用上显得很宽容,因为它们在预训练里见过足够多各种各样的契约。开源模型则会很明显地付出这个成本,然后被人 dismiss。

harness 的作用,就是在不同分布之间做调解。

四个小修复,两个处理自动链接的正则,一个关系默认值,一个前缀修改。模型没有变,是契约在正好需要的地方变得更宽容了。

DeepSeek V4 Pro 现在在我们的内部评测里 6/10 次打败 Opus 4.7。

在我看来,“skill issue”更常出在 harness,而不是模型本身。

AI创造营How I AI