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 会长成今天这样,以及它们如何承接前面所有复杂度。
夜雨聆风