note
- claude code确实在工程层面做到很好(T-T 感觉我和模型越来越远了),比如子agent的设计、分为同步/异步任务等
- Agent = 主循环 + 工具体系 + 权限体系 + 状态管理 + 子任务编排 + UI/体验 + 工程优化
- Sub-Agent 编排 = Fork 继承上下文 + prompt cache 优化 + Resume 状态恢复 + 后台任务管理 + Agent 间通信 + 默认隔离。它把多个 Agent 组织成一个可控的并发运行时
- 五个子agent:GeneralPurpose 负责兜底执行,Explore 负责快速查,Plan 负责先规划,Guide 负责教你用,Verification 负责挑毛病。
- 多Agent编排架构:主 Agent 负责判断任务怎么分配;短任务用同步子 Agent,结果直接返回;长任务用异步后台 Agent,后台执行并通过通知回传;Fork 让子 Agent 继承上下文;Resume 让已有子 Agent 能继续执行;SendMessage 负责补充指令;task-notification 负责完成通知。
文章目录
一、整体架构

Layer 5 ------ CLI / UI 层 :负责命令行参数解析、终端渲染和用户交互。main.tsx 使用 Commander.js 定义了完整的 CLI 接口,REPL.tsx 提供交互式终端体验。SDK 入口则为程序化调用提供接口。
Layer 4 ------ Query Engine 层 :这是系统的大脑。QueryEngine 管理整个对话的生命周期状态,query() 函数实现核心的 API 调用 - 工具执行循环。
Layer 3 ------ Tool System 层 :定义了工具的抽象接口和执行引擎。toolOrchestration.ts 负责并发控制,将工具调用分为"并发安全"和"串行执行"两类:
typescript
// src/services/tools/toolOrchestration.ts
export async function* runTools(
toolUseMessages: ToolUseBlock[],
assistantMessages: AssistantMessage[],
canUseTool: CanUseToolFn,
toolUseContext: ToolUseContext,
): AsyncGenerator<MessageUpdate, void> {
let currentContext = toolUseContext
for (const { isConcurrencySafe, blocks } of partitionToolCalls(
toolUseMessages,
currentContext,
)) {
if (isConcurrencySafe) {
// 并发安全的工具(如 Glob、Grep、FileRead)并行执行
for await (const update of runToolsConcurrently(
blocks, assistantMessages, canUseTool, currentContext,
)) {
yield { message: update.message, newContext: currentContext }
}
}
// 非并发安全的工具串行执行
// ...
}
}
Layer 2 ------ Agent System 层 :支持 Agent 嵌套和任务管理。AgentTool 可以创建子 Agent,每个子 Agent 拥有独立的 QueryEngine 实例,实现递归式的任务分解。
Layer 1 ------ Protocol & Services 层:与外部世界交互的基础设施。包括 Anthropic API 客户端、MCP 协议实现、权限引擎和上下文压缩服务。
二、主agent和子agent
1、Agent定义
一个 Agent 可以用 Markdown 文件定义,frontmatter 写元信息,正文写 system prompt。比如 name、description、tools、model、permissionMode、maxTurns、memory、mcpServers 等。
本质是:用配置描述一个 Agent 的身份、能力边界和运行方式。
2、5个子Agent
1、GeneralPurpose:万能工兵
默认通用子 Agent,适合复杂问题研究、代码搜索、多步骤任务执行。
特点是工具权限最广,基本可以用所有工具。
适合:任务不明确、需要综合处理时兜底。
2、Explore:快速侦察兵
专门做代码/项目探索,只读、不改文件,强调快。
会用搜索、读取、Bash 等工具快速摸清代码结构。
适合:先搞清楚"代码在哪、逻辑在哪、相关文件有哪些"。
3、Plan:架构规划师
专门负责制定实施方案,不直接改代码。
它会基于代码结构和需求,输出修改计划、关键文件、实现步骤。
适合:动手前先规划,避免 Agent 上来就乱改。
4、Claude Code Guide:使用指南助手
专门回答 Claude Code 自身怎么用。
它能结合当前配置、Skill、Agent、MCP 等信息,给出使用建议。
适合:问"某个功能怎么用、某个配置怎么写、MCP/Skill/Agent 怎么接"。
5、Verification:对抗性验证者
专门验证实现是否真的正确,只读、后台运行、不改文件。
它不是帮你"确认没问题",而是主动找漏洞、跑检查、尝试证明实现有问题。
适合:代码改完后做独立验证,检查测试是否充分、逻辑是否有隐藏 bug。

每个子Agent拥有的工具不同,是通过resolveAgentTools对全局工具集中逐步筛选:
plain
所有工具(100个)
↓ 第一层:系统级过滤
移除危险工具(如 TodoWrite)
自定义 agent → 再多移除几个敏感内部工具
异步 agent → 只剩白名单里的少数工具
剩 60 个
↓ 第二层:agent 自己声明的配置
disallowedTools: [Write, Edit] → 再移除这几个
tools: [Glob, Grep, Read] → 只保留这几个
剩 3 个
最终 agent 只能用这 3 个工具
安全隔离,防止越权,比如Explore Agent进行如下配置,Explore Agent 最终只有只读工具(Glob/Grep/Read/Bash),不能做任何写操作,也不能套娃调用其他 agent:
yaml
disallowedTools:
- Agent # 不能派生子 agent
- Write # 不能写文件
- Edit # 不能改文件
基础过滤层代码参考(根据agent类型和运行模式进行裁剪工具列表):
typescript
// src/tools/AgentTool/agentToolUtils.ts
export function filterToolsForAgent({
tools, isBuiltIn, isAsync = false, permissionMode,
}: { tools: Tools; isBuiltIn: boolean; isAsync?: boolean;
permissionMode?: PermissionMode }): Tools {
return tools.filter(tool => {
// MCP 工具始终放行
if (tool.name.startsWith('mcp__')) return true
// Plan 模式特殊放行 ExitPlanMode
if (toolMatchesName(tool, EXIT_PLAN_MODE_V2_TOOL_NAME)
&& permissionMode === 'plan') return true
// 全局禁止列表(如 TodoWrite、某些内部工具)
if (ALL_AGENT_DISALLOWED_TOOLS.has(tool.name)) return false
// 自定义 Agent 额外禁止列表
if (!isBuiltIn && CUSTOM_AGENT_DISALLOWED_TOOLS.has(tool.name)) return false
// 异步 Agent 只能使用白名单工具
if (isAsync && !ASYNC_AGENT_ALLOWED_TOOLS.has(tool.name)) {
// 特例:进程内队友可以使用 Agent 工具(spawn 同步子代)
if (isAgentSwarmsEnabled() && isInProcessTeammate()) {
if (toolMatchesName(tool, AGENT_TOOL_NAME)) return true
if (IN_PROCESS_TEAMMATE_ALLOWED_TOOLS.has(tool.name)) return true
}
return false
}
return true
})
}
3、多Agent编排架构
主 Agent 负责判断任务怎么分配:
- 短任务用同步子 Agent,结果直接返回;
- 长任务用异步后台 Agent,后台执行并通过通知回传;
Fork 让子 Agent 继承上下文;
Resume 让已有子 Agent 能继续执行(后面主 Agent 还可以把这个已有后台 Agent 重新唤醒,让它基于之前状态继续执行。);
SendMessage 负责补充指令;
task-notification 负责完成通知。
主 Agent 像调度中心;Explore/Plan 是即时助手;Fork/Verification 是后台工人;SendMessageTool 是通信管道;task-notification 是任务完成通知。
| 类型 | 图中代表 | 是否阻塞主 Agent | 结果怎么回来 | 作用 |
|---|---|---|---|---|
| 同步子 Agent | Explore、Plan | 阻塞 | 直接返回 | 快速探索、制定计划 |
| 异步子 Agent | Fork 子代、Verification | 不阻塞 | task-notification | 后台并行执行、验证 |
| 通信恢复机制 | SendMessageTool | 不一定 | resume + notification | 给已有后台 Agent 继续发消息 |

三、值得学习的设计点
1、AsyncGenerator:全链路流式管道
Claude Code 不是等模型和工具全部执行完再返回,而是边生成、边执行、边展示进度。
核心是 AsyncGenerator,它可以持续产出中间结果:模型 token、工具调用请求、工具执行进度、工具返回结果、最终回答。
通俗说:不是"做完再说",而是"边做边给你看"。这对 CLI Agent 很重要,因为读文件、跑命令、改代码、执行测试都可能耗时,流式反馈能避免用户觉得系统卡死。
2、工具系统:不是简单 function call
Claude Code 的工具不是普通函数,而是完整工程模块。
一个工具通常包含:输入参数 schema、权限检查、执行逻辑、结果结构、错误处理、UI 展示、进度展示、是否允许并发、是否会修改环境。
比如读文件、搜索代码、执行 Bash、编辑文件,风险和行为都不同。系统需要判断:能不能并发、是否改环境、是否要确认、失败后怎么展示、结果怎么回填上下文。
所以它不是"模型随便调函数",而是"模型调用可管理、可审计、可控风险的工具组件"。
3、权限系统:Agent 能力越强,安全越重要
Claude Code 能读文件、写文件、跑 Bash、调用外部工具,所以必须有权限系统。
基本流程是:模型提出动作,系统判断风险,再决定允许、询问用户、拒绝,或交给后续权限逻辑判断。
常见结果可以理解为:allow 直接允许,ask 询问用户,deny 拒绝执行,passthrough 继续走通用权限判断。
比如读取普通文件可能直接允许;修改代码可能需要确认;删除大量文件、执行高风险命令就应该拒绝或强确认。
关键点:LLM 负责提出计划,系统负责管控边界。可靠 Agent 不是给模型无限权限,而是在模型和真实环境之间加安全闸门。
4、Sub-Agent / Skill:复杂任务拆开做
Claude Code 不是让主 Agent 什么都自己干,而是支持把复杂任务拆成子任务,再交给子 Agent 或 Skill 完成。
简单任务可以直接做,比如读文件并总结。复杂任务通常要拆解,比如重构项目、补测试、分析报错,可能需要阅读结构、定位代码、修改实现、运行测试、修复错误、汇总变更。
核心思想:主 Agent 负责规划和调度,子 Agent / Skill 负责局部执行,最后由主 Agent 汇总结果。
Skill 更像可复用能力包,比如代码搜索、测试修复、文档总结、依赖分析、Git 操作等。
价值:不要把所有能力塞进一个巨大 prompt,而是把稳定能力沉淀成 Skill,把复杂任务拆成可控流程。
5、工程优化:CLI 要快、稳、可发布
Claude Code 不是 demo,而是工程产品,所以除了模型调用,还要考虑性能、体验、安全、状态和发布。
项目里能看到很多工程化设计:Bun 提升启动和执行性能,React + Ink 做终端 UI,Zod 做参数校验,MCP 接外部工具生态,Feature Flag 控制功能开关和发布范围。
同时还要处理会话保存、上下文恢复、上下文压缩、错误恢复、长任务进度展示等问题。
关键点:Agent 不是只有模型能力,还包括工具体系、权限系统、状态管理、UI 体验和工程发布。
Reference
1\] https://github.com/sawzhang/deep-dive-claude-code