Claude Code v2.1.323 加了个 Code Mode,实验性开关,让 Claude 写 JavaScript 一次性调多个工具,而不是一次调一个。我装了这个版本的 CLI 想实测,结果卡在一个很具体的地方:本机的 Claude Code 接的是第三方 DeepSeek 中转,不是官方模型。这篇讲它的机制、跟结构化 tool_calls 的差别、以及这个品类在别处已经怎么做了。

一次一调,是它的默认

先说 Code Mode 要改掉的东西。默认情况下,模型一次调一个工具。它吐出一个 tool call,等结果回来,再决定下一步调什么。一个要串很多工具调用的任务,每一步都是一次模型的 round-trip。我装了 CLI 先看版本。

$ claude --version
2.1.323 (Claude Code)

这个 2.1.323 是它自己打印的。装的方式是 npm install @anthropic-ai/claude-code@2.1.323,装到临时目录,两分钟就位。装的过程没什么好说的,关键是装完之后能干什么。

Code Mode 开起来之后,Claude 不再一个个吐 tool call,而是写一段 JavaScript,把好几个工具调用打包进去,一次跑完。独立的调用用 Promise.all 并行,有依赖的用 await 串,工具暴露成返回 Promise 的 JS 函数,最后把结果合并过滤,返回一个字符串。这段机制我从三个来源交叉核过。docker 的 docker-agent 有同名的 code-mode,ai-sdk 有 @ai-sdk/code-mode 包,两者都把工具包成一个 run_tools_with_javascript 或 code_mode 的单一入口。

它跟 tool_calls 的差别

这里有个判断要讲清。Code Mode 跟结构化 tool_calls 不是一回事,是两种范式。tool_calls 是模型吐结构化 JSON,告诉运行时「调哪个工具、传什么参数」,运行时去执行,把结果喂回模型,模型再看下一步。Code Mode 是模型直接写一段会执行的代码,代码里自己控制循环、条件、并行。

差别在控制权落在谁手里。tool_calls 的循环和分支在模型和运行时之间来回倒,每一步都要模型重新决定。Code Mode 把这段控制逻辑一次性写进脚本,运行时只执行一次,循环和判断都在脚本里完成。代价也很清楚,模型要会写对这段 JS,写错了工具调用就崩。docker 那个实现的文档写得明白:脚本必须返回一个 string,抛异常时响应里带上失败前调过的工具,让模型下一轮改脚本。它是给多步链式任务减 round-trip 的,不是替代单次工具调用的通用方案。

我横向对比一下这个品类在别处的实现。

实现 打包方式 沙箱 备注
Claude Code Code Mode 一段 JS 调工具 未公开 v2.1.323 实验开关,文档 404
docker-agent code-mode run_tools_with_javascript 单一工具 code_mode_tools: true 开启
AI SDK code-mode @ai-sdk/code-mode QuickJS 需 Node.js 22+

这三行是我从各自官方文档抄下来的事实。共同点是都在把「一次一调」改成「写代码打包调」。

我实测卡在哪

我确实想跑 Code Mode,没跑成,卡在两个地方,都值得记。

第一个,开启文档还没上线。release note 里写的文档地址是 code.claude.com/docs/en/code-mode,我抓过去是 404,连文档索引 llms.txt 里都搜不到 code-mode 这个条目。它是刚发、文档还在路上的实验特性。我搜 release 原文,Code Mode 是 opt-in,默认关,组织级还能给它整个关掉。

同一份 release 里还有些插件改动,claude plugin validate 现在会 type-check 插件的 TypeScript hooks 模块,每个 finding 是 warning,加 --strict 就升级成失败。插件还能在 plugin.json 里写 engines["claude-code"] 声明支持的版本区间,出了区间就不装不加载。这些我照 release 原文核对过。

第二个,本机模型不对。我跑 claude -p 试一句,它通了,但打出一个警告。

[claude-code:unrecognized_model] {"model":"deepseek-v4-flash[1m]","query_source":"sdk"}

这个警告说明本机 ~/.claude 的 settings 把模型指向了第三方 deepseek-v4-flash[1m] 中转,不是 Anthropic 官方模型。Code Mode 要 Claude 官方模型写 JS 调工具,接在第三方中转上,这个实验特性大概率开不起来。这里还有个连带发现。那个 [1m] 后缀对应 release 里一条改动,v2.1.323 起,对不认识的 model ID,Claude Code 默认按 1M 上下文估算,而不是旧的 200K。第三方小窗口模型接进来,它会误以为自己有 1M 空间,一直不触发 compact,等会话塞满就每轮都失败。这条我核了 release 原文,是这次改动的真实副作用。release 里还有两条跟 agent 运行直接相关,hooks 跑长的时候每 30 秒发一个 progress heartbeat,另外 CLAUDE_CODE_DISABLE_AGENT_PROGRESS_SUMMARIES 设成 1 就关掉 subagent 进度摘要和写它们的请求。

所以我诚实交代:Code Mode 我装到了 CLI 这一层,版本 2.1.323 确认,机制从官方和同类实现交叉核实,但「让 Claude 真写一段 JS 调工具」这一步没跑到,卡在本机是第三方中转、加上文档没上线。

选型给个判断

给结论。你的 agent 任务以多步链式工具调用为主,比如翻页取全量、跨几个 API 对账、把大结果压成模型要的几列,Code Mode 值得盯着,它把 round-trip 砍掉,省的是延迟和 token。你的 agent 每轮就调一两个独立工具,那 Code Mode 是纯负担,模型还得额外想怎么写脚本。这个分界跟 docker 那个实现的文档判断一致,我认同。

一句话。Code Mode 承认了一件事:让模型每调一个工具就回来一趟,对链式任务是浪费。但它现在还嫩,文档没上线、要官方模型、默认关着,先在低风险活上试,别直接推进关键流程。