乐于分享
好东西不私藏

Claude Code 源码导读03|Agent Runtime 深挖

Claude Code 源码导读03|Agent Runtime 深挖

Digital Strategy Review | 2026

Claude Code 源码导读 03:从 `AgentTool`、`tasks` 到 `swarm`,真正的 Agent Runtime 长什么样

文 / 果叔 · 阅读时间 / 8 Min

写在前面

前两篇把启动流程和主循环铺开之后,这一篇终于进入 Claude Code 最有辨识度的部分:agent runtime 本身。

我一直觉得,这一层才是 Claude Code 和很多“会调工具的 CLI 助手”真正拉开差距的地方。因为它要解决的已经不是“再开一次模型请求”这么简单,而是怎样把子 Agent 做成一个能调度、能恢复、能隔离、也能协作的运行时对象。

建议把这一层看成一个问题的完整回答:

Claude Code 到底是如何把“再开一个子模型请求”升级成“可调度、可隔离、可恢复、可协作的 Agent 实体”的?

这一层最关键的文件群是:

01

一、AgentTool 是统一入口,不是单一路径

这一节要回答的是:为什么 Claude Code 不把不同 Agent 形态拆成一堆独立入口,而是先收拢成一个 AgentTool。这个选择很重要,因为它决定了模型看到的是“统一委派接口”,还是一坨分散能力点。

src/tools/AgentTool/AgentTool.tsx 的最大价值,在于它对外暴露的是一个统一工具,但对内却可以路由到多种 agent 运行形态。

从源码行为看,它至少覆盖这些分支:

• 普通子 agent

• 后台本地 agent

• teammate

• fork subagent

• worktree 隔离 agent

• remote agent

这说明 Claude Code 的核心设计不是“做很多不同的 spawn API”,而是:

先给模型一个统一的 delegation 入口,再由运行时决定交给哪个后端。

这是非常平台化的设计。

02

二、Agent 在 Claude Code 里首先是 Task

这可能是整套实现最关键的一点。

Task.ts 与 LocalAgentTask / RemoteAgentTask / InProcessTeammateTask 共同说明:

• agent 不是一段附属 transcript

• agent 不是一次函数调用返回值

• agent 是明确的任务实体

1. 任务身份

task 至少拥有:

• id

• type

• status

• description

• toolUseId

• startTime/endTime

• outputFile

• notified

这使得后台 agent、远程 agent、同进程 teammate 都能挂进同一套管理机制里。

2. 为什么这比“子对话”设计强很多

因为一旦 agent 成为 task,系统就天然获得:

• 后台运行

• 通知

• kill / cleanup

• panel 展示

• resume / restore

• sidechain transcript

这正是 Claude Code 能把 agent 做成长期运行实体的根本原因。

03

三、runAgent.ts:同一台执行引擎,驱动所有 Agent 形态

src/tools/AgentTool/runAgent.ts 是 agent runtime 的核心执行器。

这里最值得注意的是: 它并不是重新发明一套新的“agent loop”,而是把 agent 放进同一套 query-based execution model 里。

1. 它要组装什么

启动一个 agent 时,运行时会给它准备:

• prompt messages

• toolUseContext

• canUseTool

• querySource

• model / maxTurns

• tool pool

• allowed tools

• transcriptSubdir

• worktreePath

• 可选的 override system prompt / user context

换句话说,Claude Code 不把 agent 理解为“带 prompt 的子模型”,而是理解为:

拥有独立上下文、独立工具面、独立运行参数的一次受控 query loop。

2. Agent 可以附带自己的 MCP

initializeAgentMcpServers(...) 非常关键。 它允许 agent definition 指定:

• 引用已有 MCP server

• 或内联定义新的 MCP server 配置

启动时挂上,结束时清理。 这意味着 agent 的能力边界可以更细:

• 父会话不必预装所有外部能力

• 某个 agent 可按需扩展自己的操作面

这是“按角色挂能力”的典型实现。

把 Agent 放进统一 Task 体系以后,后台运行、恢复、可视化和权限协调才有了稳固基础。

04

四、Built-in Agent 与自定义 Agent:Claude Code 把角色提升成配置层

loadAgentsDir.ts 很值得细读。因为这里定义了系统如何看待“agent 角色”。

Claude Code 的 agent definition 不只是 prompt,它还可以声明:

• tools

• disallowedTools

• skills

• mcpServers

• hooks

• model

• effort

• permissionMode

• maxTurns

• background

• memory

• isolation

• omitClaudeMd

这意味着 agent 是一个可执行角色描述对象

1. 这带来的直接收益

你可以自然支持:

• built-in agent

• user/project agent

• policy agent

• plugin agent

而且还能让它们按优先级覆盖。

2. 为什么这比“自定义 prompt”强得多

因为系统现在可以对一个 agent 做的不只是“给它一段人设”:

• 还可以约束它能用哪些工具

• 还可以决定它默认跑在前台还是后台

• 还可以决定它是否带 memory

• 还可以决定它是不是 worktree / remote agent

这使得 agent 真正变成了系统对象。

05

五、三个 built-in agent 很能说明设计思想

1. Explore Agent

Explore agent 被明确设计为只读、快速、并发搜索导向的角色。

重点不是它会搜索,而是系统把这些约束写进了角色边界:

• 禁止编辑

• 鼓励并发 read/search

• 甚至会根据环境决定是用专门工具还是走 bash 中的只读命令

2. Plan Agent

Plan agent 的核心不是“会写计划”,而是:

• 明确只读

• 强调探索现有模式

• 以 implementation plan 的结构化输出为目标

它实际上是把“架构分析”从主 agent 中抽出成了可复用的角色。

3. Verification Agent

Verification agent 则更有意思。 它不是普通 reviewer,而是被塑造成一个会主动找失败证据的 adversarial verifier。

这表明 Claude Code 在设计 agent 时,不只是按功能分工,也按行为倾向分工。

06

六、Fork Subagent:不是简单复制上下文,而是做 prompt cache 工程

forkSubagent.ts 是我认为整套系统里最有工程含量的设计之一。

这里的目标非常明确:

• 让 fork child 继承父上下文

• 但又尽量保证请求前缀稳定,从而共享 prompt cache

它的做法包括:

• 保留完整 parent assistant message

• 给所有 tool_use 生成统一 placeholder tool_result

• 把可变的 directive 留在最后

• 尽量复用父会话渲染好的 system prompt bytes

这说明 Claude Code 做 fork,不是停留在“功能有了”,而是在认真优化“规模化使用时的 token 成本”。

07

七、Agent Memory:角色级记忆的范围控制做得很成熟

agentMemory.ts 支持三种 scope:

• user

• project

• local

这其实非常实用。

为什么这点重要

agent 记忆最怕两件事:

• 跨项目污染

• 团队共享与个人偏好混淆

三层 scope 正好把这两个问题拆开了:

• user 适合跨项目经验

• project 适合项目公共知识

• local 适合机器和工作副本相关状态

这不是最花哨的记忆系统,但非常符合真实工程场景。

从 built-in agent 到 fork teammate,再到角色记忆,Claude Code 明显是在用系统设计,而不是 prompt 拼图。

08

八、LocalAgentTask:后台 Agent 如何成为真正的系统实体

LocalAgentTask.tsx 展示了后台本地 agent 的完整生命周期管理。

这里有几个细节很值得注意。

1. 它有自己的 progress tracker

系统会跟踪:

• tool use count

• token count

• last activity

• recent activities

• summary

这意味着后台 agent 不是“黑盒跑着”,而是可观察的。

2. 它有自己的消息与通知机制

后台任务结束时会进入统一的 <task-notification> 通知路径。 于是主会话不用阻塞等待,只要在合适时机消费通知即可。

3. 它有 retain / foreground / disk bootstrap 等 UI 语义

这说明后台 agent 不只是执行对象,它还是可以被用户“切到前台查看 transcript”的对象。

这一步让多 agent 体验从“后台线程”升级成“可交互任务”。

09

九、RemoteAgentTask:Claude Code 把远程执行也纳入了同一任务模型

RemoteAgentTask.tsx 说明 Claude Code 并不把远程 agent 视作完全不同体系。

远程任务同样有:

• taskState

• status

• output

• notification

• restore

• kill / archive

只不过执行后端换成了远程 session polling。

这带来的最大收益是架构统一:

• 对用户来说,它仍是一个 task

• 对 REPL 来说,它仍能进入任务列表

• 对恢复逻辑来说,它仍有 sidecar metadata

也就是说,Claude Code 不是“本地一套,远程一套”,而是一套任务抽象,多个执行后端

10

十、Swarm / In-Process Teammate:最有意思的协作层

spawnInProcessTeammate.ts 和 inProcessRunner.ts 展示了 Claude Code 的另一个强点:团队态 Agent 协作

1. 为什么要做同进程 teammate

如果所有 teammate 都起独立进程,开销高、状态同步麻烦。 如果全部塞进主上下文,又没有隔离。

Claude Code 选了一个很实用的折中:

• 同进程运行

• 有独立 task state

• 有独立 teammate identity

• 用 teammate context 做身份隔离

2. 权限处理非常成熟

createInProcessCanUseTool(...) 的设计很漂亮:

• worker 请求工具调用

• 先过权限判断

• ask 型请求优先走 leader 的统一 ToolUseConfirm UI

• 不可用时再退回 mailbox 同步

这保证了一个重要特性:

多 agent 可以并发执行,但最终权限控制仍然统一回到用户可理解的主界面。

3. 协作不是概念,而是显式机制

这套体系里有很多专门为协作服务的东西:

• teammate identity

• mailbox

• permission bridge

• plan mode required

• team file

• split pane / pane backend

也就是说,Claude Code 不是“能开多个 agent”,而是真的在做 team runtime。

11

十一、一张图看懂 Agent Runtime

12

十二、这一层真正解决了什么问题

如果要用更抽象的话总结这一层,我会说 Claude Code 解决的是这几个问题:

01 如何给模型一个统一的“委派入口”

02 如何让不同类型的 agent 共用同一套核心执行引擎

03 如何让 agent 具备任务身份而不是一次性子调用

04 如何把权限、协作、隔离、记忆都嵌进 agent runtime

05 如何让本地、同进程、远程这些执行形态在架构上保持统一

这正是 Claude Code 比“支持 subagent 的普通 CLI”更强的地方。

下一篇就回到最上层:为什么 REPL.tsx 和 AppStateStore.ts 会长成今天这样,以及它们如何承接前面所有复杂度。