Claude Code Agent 工程深度教学手册

Claude Code Agent 工程深度教学手册
基于 Claude Code 泄露源码(2026-03-31),约 1,915 个 TypeScript 文件、51.2 万行代码的逐模块拆解。 本文档面向想要理解「一个工业级 AI Agent 系统到底是怎么设计的」的工程师和研究者。

第一章 全局架构:一个 Agent 系统的骨架

1.1 技术选型

层面 选择 为什么这么选
运行时 Bun 比 Node.js 快 3-5 倍的启动速度,内置 bundler,支持编译时 feature flag
语言 TypeScript (strict) 类型安全在大型 Agent 系统中至关重要——工具参数、权限、消息类型都需要精确约束
终端 UI React + Ink 把 CLI 当成 SPA 来写,组件化、状态驱动、声明式渲染
CLI 解析 Commander.js 成熟的 CLI 框架,额外类型支持
Schema 验证 Zod v4 工具输入验证、配置验证,TypeScript 类型推断零成本
协议 MCP SDK + LSP 标准协议,可扩展的工具和语言服务集成
API Anthropic SDK 官方 SDK,流式响应、工具调用原生支持

启发性:选择 Bun 而非 Node.js,不仅是速度考量——Bun 的 feature() 宏允许在编译时剥离整个代码分支,这对一个需要在多种环境(内部/外部、Pro/Free)部署的 Agent 系统来说是关键能力。

1.2 启动流程:毫秒级优化

main.tsx 入口
│
├── [Side Effect] startMdmRawRead()         // 启动 plutil 子进程读取 MDM 配置
├── [Side Effect] startKeychainPrefetch()    // 并行读取 macOS 钥匙串
├── [Side Effect] profileCheckpoint()        // 打桩计时
│
├── Commander.js 解析 CLI 参数
│
├── init() ─── 核心初始化(memoized,只跑一次)
│   ├── configureGlobalAgents()              // HTTP 代理
│   ├── configureGlobalMTLS()                // mTLS 证书
│   ├── applyExtraCACertsFromConfig()        // CA 证书
│   ├── setupGracefulShutdown()              // SIGTERM/SIGINT 处理
│   ├── detectCurrentRepository()            // Git 仓库检测
│   ├── ensureScratchpadDir()                // 临时目录
│   └── initializeTelemetry()                // OpenTelemetry(延迟加载 ~400KB)
│
├── initializeGrowthBook()                   // 特性开关
├── loadPolicyLimits()                       // 策略限制
├── loadRemoteManagedSettings()              // 远程设置
│
└── React/Ink render() ──── 进入 REPL 界面

核心设计思想:启动时间 = 用户感受到的「Agent 是否好用」的第一印象。Claude Code 做了三件关键的事:

  1. 并行预取:MDM 读取、Keychain 读取、API 预连接都在 import 语句的副作用中启动,与后续 135ms 的模块加载并行
  2. 延迟加载:OpenTelemetry(~400KB)和 gRPC(~700KB)通过 dynamic import() 推迟到实际需要时
  3. 编译时剔除feature('VOICE_MODE') 等标志在 Bun bundle 时直接变成 false,整个分支被 tree-shake 掉

对比其他 Agent 框架:LangChain、AutoGPT 等框架通常不关注启动性能。对于 CLI 工具而言,每次命令调用都是一次冷启动——如果启动要 2 秒,用户会放弃。Claude Code 把启动优化到了 200ms 以内。


第二章 工具系统:Agent 的手和脚

2.1 工具的统一抽象

每个工具通过 buildTool() 工厂函数创建,必须实现以下接口:

type ToolDef<InputSchema, Output> = {
  name: string                              // 工具名称
  inputSchema: ZodSchema                    // 输入 Schema(Zod 定义)
  outputSchema: ZodSchema                   // 输出 Schema
  description(): Promise<string>            // 给 LLM 看的描述
  prompt(): Promise<string>                 // 给 LLM 看的使用提示

  call(input, context): Promise<Output>     // 实际执行逻辑
  checkPermissions(input): Promise<PermissionResult>  // 权限检查

  renderToolUseMessage()                    // 终端渲染:调用时显示
  renderToolResultMessage()                 // 终端渲染:结果显示
  renderToolUseProgressMessage()            // 终端渲染:进度显示

  isResultTruncated(output): boolean        // 结果是否被截断
  userFacingName(): string                  // 用户看到的名称
}

设计亮点

  • 描述和提示分离description() 是简短的功能说明,prompt() 是详细的使用指南。前者出现在工具列表中,后者只在 LLM 选中该工具后才注入。这节省了大量 token。
  • 权限前置checkPermissions()call() 之前执行。不是「执行了再问」,而是「问了才执行」。
  • 渲染解耦:每个工具自己负责终端展示。BashTool 显示命令和输出,FileEditTool 显示 diff,GrepTool 显示匹配行——这不是框架统一处理的,而是每个工具根据自己的语义定制的。

2.2 工具详解

2.2.1 BashTool — Shell 命令执行

文件src/tools/BashTool/BashTool.tsx(~600 行)

BashTool 是最复杂的工具之一。它不是简单地 exec(command),而是:

  1. 安全解析:通过 parseForSecurity() 对命令进行 AST 解析,检测危险操作
  2. 命令分类:区分搜索命令(grep/find/rg)、读取命令(cat/head/tail)、列目录命令(ls/tree)和写入命令,用于生成不同的摘要和折叠显示
  3. 沙箱支持:通过 SandboxManager 可选地在隔离环境中执行
  4. 超时管理:默认 2 分钟超时,最大 10 分钟,可配置
  5. 进度显示:超过 2 秒的命令会显示进度指示
  6. 自动后台化:在 assistant 模式下,主 Agent 的阻塞命令超过 15 秒会自动转为后台任务
  7. 输出截断:输出过大时会截断并生成预览,完整结果存到磁盘
  8. Git 跟踪:自动检测 git 操作并记录变更
  9. 编码保持:检测文件编码和行尾(CRLF/LF),确保写回时一致
// 命令语义分类——不同命令给 LLM 不同的摘要
const BASH_SEARCH_COMMANDS = new Set(['find', 'grep', 'rg', 'ag', 'ack', 'locate'])
const BASH_READ_COMMANDS = new Set(['cat', 'head', 'tail', 'less', 'wc', 'jq', 'awk'])
const BASH_LIST_COMMANDS = new Set(['ls', 'tree', 'du'])
const BASH_SEMANTIC_NEUTRAL_COMMANDS = new Set(['echo', 'printf', 'true', 'false', ':'])

启发性:大多数 Agent 框架的 Shell 工具就是一个 subprocess.run()。Claude Code 对命令语义的理解深度——安全检查、分类摘要、自动后台化——体现了工业级 Agent 对可靠性的要求。

2.2.2 FileEditTool — 精确文件编辑

文件src/tools/FileEditTool/FileEditTool.ts

不同于 FileWriteTool(全文覆写),FileEditTool 做的是字符串替换:

  1. 读取文件并检测编码、行尾符
  2. 查找 old_string,确保唯一(不唯一则报错要求提供更多上下文)
  3. 替换为 new_string
  4. 写回文件,保持原编码和行尾符
  5. 触发 LSP 诊断清除(因为文件变了,旧诊断不再有效)
  6. 通知 VS Code 文件已更新(通过 MCP 通道)
  7. 记录 file history(用于回退)
  8. 发现 .claude/skills 等目录中的技能文件时,自动激活相关技能

核心设计:「精确替换」而非「diff/patch」。这对 LLM 来说更容易——它只需要写出要替换的原文和替换后的文本,不需要理解 unified diff 格式。代价是需要确保 old_string 的唯一性。

2.2.3 FileReadTool — 智能文件读取

支持读取:

  • 普通文本文件(带行号输出)
  • 图片(转为 base64 给多模态 LLM)
  • PDF(分页读取,最大 20 页/次)
  • Jupyter Notebook(解析所有 cell 和输出)

设计选择:不让 LLM 用 cat 读文件,而是提供专用工具。好处是可以添加行号、限制读取范围、支持非文本格式,并且跟踪哪些文件被读过(用于 FileEditTool 的前置校验——编辑前必须先读过)。

2.2.4 GlobTool 和 GrepTool — 搜索双雄

  • GlobTool:基于文件名模式匹配,返回按修改时间排序的文件路径列表
  • GrepTool:基于 ripgrep 的内容搜索,支持正则、文件类型过滤、上下文行、多行匹配

设计选择:为什么不直接用 BashTool 执行 findgrep?因为:

  1. 专用工具的权限模型更简单(只是读操作,不需要额外许可)
  2. 输出格式可以针对 LLM 优化(比如 GrepTool 的 files_with_matches 模式比 grep -l 的输出更结构化)
  3. head_limitoffset 参数,避免 LLM 被海量搜索结果淹没

2.2.5 WebFetchTool 和 WebSearchTool

  • WebFetchTool:获取 URL 内容,有域名白名单限制
  • WebSearchTool:网络搜索

这两个工具是 Agent 获取外部知识的窗口。

2.2.6 MCPTool — 协议桥梁

文件src/tools/MCPTool/MCPTool.ts

MCPTool 是一个「元工具」——它本身不做什么,而是作为 MCP 服务器工具的代理。关键设计:

export const MCPTool = buildTool({
  isMcp: true,
  name: 'mcp',                    // 会被 mcpClient.ts 覆盖为真实 MCP 工具名
  inputSchema: z.object({}).passthrough(), // 接受任意输入,因为 MCP 工具定义自己的 schema
  async call() { return { data: '' } },   // 也会被覆盖
  // ...
})

MCPTool 的 namedescriptionpromptcall 全部在 mcpClient.ts 中被覆盖。这是一个巧妙的「模板模式」——统一了 MCP 工具在 Claude Code 工具系统中的接入方式。

2.2.7 AgentTool — 子 Agent 生成器(核心中的核心)

文件src/tools/AgentTool/AgentTool.tsx(~800 行)+ runAgent.ts(~400 行)

AgentTool 是整个多 Agent 架构的入口。当主 Agent 调用 AgentTool 时:

  1. 选择 Agent 类型:根据 subagent_type 参数选择内置或用户定义的 Agent
  2. 构建工具池:根据 Agent 定义的 tools 字段筛选可用工具
  3. 创建上下文createSubagentContext() 为子 Agent 创建独立的运行上下文
  4. 执行查询循环:调用 query() 函数——与主 Agent 使用完全相同的查询引擎
  5. 结果回收:子 Agent 完成后,提取结果返回给父 Agent
// runAgent.ts 核心流程
export async function runAgent(options) {
  // 1. 创建子 Agent 上下文(独立的消息历史、工具集、权限)
  const subagentContext = createSubagentContext(toolUseContext, ...)

  // 2. 注册到 perfetto tracing(可选)
  if (isPerfettoTracingEnabled()) registerPerfettoAgent(agentId)

  // 3. 执行 query() —— 和主 Agent 用同一个引擎
  const result = await query(messages, tools, systemPrompt, ...)

  // 4. 记录 transcript
  recordSidechainTranscript(agentId, messages)

  // 5. 清理
  killShellTasksForAgent(agentId)
  cleanupAgentTracking(agentId)

  return result
}

六种内置 Agent

Agent 类型 用途 工具集 关键特点
general-purpose 通用任务 所有工具 默认 Agent,能搜能写
Explore 代码探索 只读工具 严格只读——不能创建、修改、删除任何文件
Plan 架构规划 只读工具 设计实现方案,不执行
claude-code-guide 使用指南 Glob, Grep, Read, WebFetch, WebSearch 回答关于 Claude Code 本身的问题
verification 验证检查 只读 + Bash 运行测试、检查构建
statusline-setup 状态栏配置 Read, Edit 配置用户的状态栏设置

Fork Subagent 机制(实验性):当省略 subagent_type 时,触发隐式 fork——子 Agent 继承父 Agent 的完整对话上下文和系统提示。这使得「分支思考」成为可能:主 Agent 可以同时在多个方向探索,而不丢失上下文。

关键设计约束

  • Fork 子 Agent 不能再 fork(通过检测对话历史中的 FORK_BOILERPLATE_TAG 防止递归)
  • Fork 和 Coordinator 模式互斥——协调器有自己的委派模型
  • Fork 子 Agent 使用父 Agent 的渲染后系统提示(字节精确),避免重新渲染导致 prompt cache 失效

2.2.8 SendMessageTool — Agent 间通信

允许向正在运行的 Agent 发送后续消息。支持多种消息类型:

  • 普通文本消息
  • shutdown_request / shutdown_response — 请求/确认关闭
  • plan_approval_response — 计划审批

通过解析目标地址,可以发送给:

  • 本地 Agent(isLocalAgentTask
  • 团队 Teammate(findTeammateTaskByAgentId
  • 主会话(isMainSessionTask
  • REPL Bridge 中的远程会话

2.2.9 TaskCreateTool / TaskUpdateTool / TaskGetTool / TaskListTool / TaskStopTool / TaskOutputTool — 任务生命周期

完整的任务管理 API:

  • Create:创建异步任务,可以后台运行
  • Update:更新任务状态和进度
  • Get:查询任务当前状态
  • List:列出所有任务
  • Stop:终止运行中的任务
  • Output:获取任务的输出内容

2.2.10 TeamCreateTool / TeamDeleteTool — 团队管理

TeamCreateTool 创建一个 Agent 团队:

  • 生成团队文件(JSON 格式,存储团队成员信息)
  • 分配 team lead
  • 注册颜色(每个 teammate 在终端中有不同颜色)
  • 初始化任务目录

2.2.11 其他工具

  • SkillTool:执行注册的 Skill(详见技能系统章节)
  • ToolSearchTool:延迟工具发现——当工具列表太长时,部分工具会延迟加载,LLM 通过 ToolSearch 按需获取
  • EnterPlanModeTool / ExitPlanModeTool:切换计划模式——在此模式下 Agent 只能思考和搜索,不能修改文件
  • EnterWorktreeTool / ExitWorktreeTool:Git worktree 隔离——子 Agent 在独立的 git 分支中工作,完成后可以合并或丢弃
  • TodoWriteTool:管理用户可见的 TODO 列表
  • SleepTool:主动模式下的等待——Agent 可以「睡眠」等待外部事件
  • ScheduleCronTool:创建定时任务
  • RemoteTriggerTool:远程触发
  • SyntheticOutputTool:生成结构化输出(JSON 等)
  • ConfigTool:读写配置
  • BriefTool:切换简洁输出模式
  • LSPTool:调用 Language Server Protocol 功能
  • PowerShellTool:Windows 环境下的 PowerShell 执行
  • REPLTool:交互式 REPL 环境
  • AskUserQuestionTool:向用户提问并等待回答

2.3 工具系统的设计启发

与 LangChain Tools 对比

  • LangChain 的工具是扁平的函数签名 + 描述字符串。Claude Code 的工具有完整的权限模型、进度报告、渲染逻辑和错误处理。
  • LangChain 的工具互相独立。Claude Code 的工具之间有协作关系(FileEditTool 要求先 FileReadTool,BashTool 追踪 git 操作)。

与 OpenAI Function Calling 对比

  • OpenAI 的 function calling 只定义了输入 schema。Claude Code 还定义了输出 schema、权限模型、渲染逻辑和截断策略。

核心设计原则

  1. 工具是一等公民——不是简单的函数包装,而是有生命周期的实体
  2. 安全优先——每个工具都有独立的权限检查
  3. 对 LLM 友好——描述、提示、结果格式都为 LLM 优化
  4. 对用户友好——每个工具都有定制的终端渲染

第三章 服务层:Agent 的神经系统

3.1 MCP 服务(src/services/mcp/)—— 最复杂的服务

Model Context Protocol 是 Claude Code 扩展能力的核心通道。22 个文件,涵盖:

客户端连接(client.ts

  • 支持三种传输方式:Stdio(进程管道)、SSE(Server-Sent Events)、Streamable HTTP
  • 每个 MCP 服务器连接是一个 Client 实例
  • 连接后自动发现工具(fetchToolsForClient),将 MCP 工具包装为 Claude Code 的 MCPTool

配置管理(config.ts

  • MCP 服务器可以在多个层级配置:全局、项目、用户
  • 支持环境变量扩展(envExpansion.ts

认证(auth.ts + xaa.ts

  • OAuth 2.0 Token 管理
  • Claude.ai 集成认证(claudeai.ts
  • IDP 登录(xaaIdpLogin.ts

通道权限(channelPermissions.ts + channelAllowlist.ts

  • 每个 MCP 通道有独立的权限策略
  • 白名单机制控制哪些工具可以被调用

VS Code 集成(vscodeSdkMcp.ts

  • 通过 MCP 通道与 VS Code 扩展通信
  • 文件变更通知、编辑器状态同步

3.2 API 服务(src/services/api/

与 Anthropic API 的通信层:

  • bootstrap.ts:启动时获取引导数据(模型列表、费率限制等)
  • filesApi.ts:文件上传/下载
  • dumpPrompts.ts:调试用——转储发送给 API 的完整 prompt
  • promptCacheBreakDetection.ts:检测 prompt cache 是否被破坏(MCP 异步连接、插件重载等会改变工具列表,导致 cache 失效)

Prompt Cache 优化是 Claude Code 的核心性能策略之一。Agent 列表曾占全量 cache_creation tokens 的 10.2%——MCP 异步连接、/reload-plugins、权限模式变化都会改变列表内容导致 cache 失效。解决方案是把 Agent 列表从工具描述中移到消息附件中(shouldInjectAgentListInMessages()),这样工具 schema 保持稳定。

3.3 Compact 服务(src/services/compact/)—— 上下文压缩

当对话变长、Token 接近限制时,Compact 服务会:

  1. 运行 preCompactHooks
  2. 使用 forked agent(共享父 Agent 的 prompt cache)对对话历史进行总结压缩
  3. 插入 SystemCompactBoundaryMessage 标记压缩边界
  4. 重新注入关键的附件信息(Agent 列表、延迟工具列表、MCP 指令)
  5. 运行 postCompactHooks

Forked Agent 模式:Compact 不是调用一个独立的 API,而是 fork 当前 Agent 的对话。这意味着压缩 Agent 可以共享父 Agent 的 prompt cache,大幅减少 token 消耗。

3.4 记忆提取服务(src/services/extractMemories/

在每次完整查询循环结束后(模型产生无工具调用的最终响应)自动运行:

  1. 检查是否启用自动记忆(isAutoMemoryEnabled()
  2. 使用 forked agent 分析当前对话
  3. 提取值得持久化的记忆
  4. 写入 ~/.claude/projects/<path>/memory/ 目录

同样使用 forked agent 模式——共享 prompt cache,几乎零额外 token 成本。

3.5 其他服务

服务 职责 设计要点
oauth/ OAuth 2.0 认证 支持 PKCE 流程、Token 刷新
lsp/ Language Server Protocol 管理多个 LSP 服务器实例,提供诊断、补全
analytics/ GrowthBook 特性开关 + 事件日志 支持缓存和阻塞两种查询模式
policyLimits/ 组织策略限制 Enterprise 版限制特定功能
remoteManagedSettings/ 远程托管设置 IT 管理员远程推送配置
teamMemorySync/ 团队记忆同步 在团队成员间同步共享记忆
AgentSummary/ Agent 总结 生成 Agent 执行摘要
PromptSuggestion/ 提示建议 基于上下文推荐下一步操作
autoDream/ 自动后台推理 在空闲时进行预测性推理
tips/ 使用提示 适时显示使用技巧
plugins/ 插件加载 管理插件生命周期

第四章 Query 引擎:Agent 的大脑

4.1 QueryEngine 的核心循环

QueryEngine.ts 约 46,000 行,是整个系统最大的单文件。它实现了 Agent 的「思考-行动-观察」循环:

用户消息 → query()
│
├── 构建 QueryConfig(快照 runtime gates)
├── 创建 BudgetTracker(Token 预算追踪)
│
└── 循环:
    ├── 调用 Anthropic API(流式)
    ├── 解析响应
    │   ├── 文本内容 → 累积到结果
    │   ├── 工具调用 → 执行工具 → 工具结果加入消息
    │   └── 结束标记 → 检查 stopHooks
    │
    ├── stopHooks 检查:
    │   ├── extractMemories(提取记忆)
    │   ├── autoDream(自动推理)
    │   ├── promptSuggestion(提示建议)
    │   ├── taskCompletedHooks(任务完成钩子)
    │   └── tokenBudget(Token 预算检查)
    │
    ├── Token 预算检查:
    │   ├── 消耗 < 90% → 继续
    │   ├── 消耗 >= 90% → 发送 nudge 继续
    │   └── 回报递减(delta < 500 且连续 3 次)→ 停止
    │
    └── 继续/停止决策

4.2 QueryConfig — 查询快照

type QueryConfig = {
  sessionId: SessionId
  gates: {
    streamingToolExecution: boolean  // 是否流式执行工具
    emitToolUseSummaries: boolean    // 是否发射工具使用摘要
    isAnt: boolean                   // 是否 Anthropic 内部用户
    fastModeEnabled: boolean         // 快速模式
  }
}

QueryConfig 在每次 query() 入口快照一次。这是一个重要的设计决策——查询过程中的配置是不可变的,避免了中途配置变化导致的不一致。

4.3 Token 预算管理

type BudgetTracker = {
  continuationCount: number       // 已继续次数
  lastDeltaTokens: number        // 上次增量
  lastGlobalTurnTokens: number   // 上次全局 turn token 数
  startedAt: number              // 开始时间
}

预算决策逻辑:

  • 如果是子 Agent(agentId 存在)或无预算——停止
  • 消耗 < 90% → 停止(还没到需要继续的程度)
  • 消耗 >= 90% → 发送 nudge 消息让模型继续
  • 连续 3 次以上且每次增量 < 500 token → 回报递减,停止

4.4 Stop Hooks — 查询结束后的连锁反应

当一次查询循环结束(模型产生无工具调用的响应),会触发一系列 hook:

  1. extractMemories:提取并保存记忆
  2. autoDream:后台推理
  3. promptSuggestion:生成下一步建议
  4. taskCompletedHooks:通知任务管理系统
  5. teammateIdleHooks:通知团队系统(如果在 swarm 模式中)

第五章 多 Agent 协调:从独行侠到军团

5.1 协调器模式(Coordinator Mode)

通过 CLAUDE_CODE_COORDINATOR_MODE=1 环境变量 + COORDINATOR_MODE feature flag 启用。

在协调器模式下,主 Agent 变成一个纯粹的指挥官

  • 不直接操作文件
  • 不执行 shell 命令
  • 只使用三种工具:AgentTool(生成 Worker)、SendMessageTool(向 Worker 发消息)、TaskStopTool(终止 Worker)

协调器的系统提示(直接来自源码):

You are Claude Code, an AI assistant that orchestrates software engineering tasks across multiple workers.

Your Role: You are a coordinator. Your job is to help the user achieve their goal, direct workers to research/implement/verify code changes, synthesize results and communicate with the user, and answer questions directly when possible — don't delegate work that you can handle without tools.

Worker 的结果通知机制:Worker 完成后,其结果以 <task-notification> XML 格式作为用户消息注入协调器的对话:

<task-notification>
  <task-id>{agentId}</task-id>
  <status>completed|failed|killed</status>
  <summary>{human-readable status summary}</summary>
  <result>{agent's final text response}</result>
  <usage>
    <total_tokens>N</total_tokens>
    <tool_uses>N</tool_uses>
    <duration_ms>N</duration_ms>
  </usage>
</task-notification>

Scratchpad 目录:协调器模式下有一个共享临时目录,Worker 可以在这里读写文件而无需权限提示。这是跨 Worker 知识传递的关键通道。

5.2 Agent Swarms(Team 模式)

更高级的多 Agent 架构。TeamCreateTool 创建一个由多个 teammate 组成的团队:

  1. Team Lead:团队领导,协调团队内部工作
  2. Teammates:团队成员,执行具体任务
  3. Team File:JSON 文件,记录团队成员信息、状态、角色
  4. Mailbox:每个 teammate 有一个信箱,通过文件系统实现异步消息传递
TeamCreateTool
│
├── 生成 team_name
├── 创建 team file (JSON)
├── 分配 lead agent
├── 注册颜色(每个 teammate 终端颜色不同)
├── 初始化任务目录
└── 注册 session 清理回调

团队通信协议

  • SendMessageTool 支持向指定 to 地址发送消息
  • 支持 shutdown_request / shutdown_response 协议——teammate 可以请求关闭,lead 审批
  • 支持 plan_approval_response——teammate 提出计划,等待审批

5.3 Fork Subagent(实验性)

FORK_SUBAGENT feature flag 启用时,省略 subagent_type 参数会触发隐式 fork:

export const FORK_AGENT = {
  agentType: 'fork',
  tools: ['*'],              // 继承父 Agent 所有工具
  maxTurns: 200,
  model: 'inherit',          // 使用父 Agent 的模型
  permissionMode: 'bubble',  // 权限冒泡到父终端
  // ...
}

Fork 子 Agent 的核心创新:

  • 上下文继承:子 Agent 拿到父 Agent 的完整对话历史
  • Prompt Cache 保持:使用父 Agent 渲染后的系统提示字节流,确保 cache 命中
  • 防递归:通过检测 FORK_BOILERPLATE_TAG 防止 fork 嵌套

5.4 与其他多 Agent 框架的对比

维度 Claude Code AutoGPT CrewAI MetaGPT
Agent 间通信 XML 通知 + Mailbox 共享内存 委派链 消息队列
任务管理 内置 Task 工具 + 文件系统 简单目标链 角色基础 SOPWorkflow
资源隔离 Git Worktree + 独立上下文
Prompt Cache 精心优化 不关注 不关注 不关注
权限模型 冒泡/独立/自动多种模式

Claude Code 的独特优势

  1. Prompt Cache 意识:这是其他框架完全忽略的维度。Claude Code 在多 Agent 场景下仍然关注 cache 命中率
  2. Git Worktree 隔离:子 Agent 在独立的 git 分支中工作,互不干扰
  3. 任务通知机制:异步通知而非轮询,效率更高
  4. 权限冒泡:子 Agent 的权限请求可以冒泡到用户终端

不足之处

  1. 协调器模式和 Team 模式并行存在,概念上有重叠
  2. Fork 机制和 Coordinator 互斥,需要在启动时选择
  3. 缺乏正式的 Agent 通信协议——<task-notification> 是硬编码的 XML 格式

第六章 技能系统:可复用的工作流

6.1 Skill 的三层结构

技能来源
├── Bundled Skills(内置技能)—— 编译进 CLI
├── Disk Skills(磁盘技能)—— .claude/skills/ 目录下的 Markdown 文件
└── MCP Skills(MCP 技能)—— 通过 MCP 协议暴露的 prompts

6.2 Bundled Skills(内置技能)

定义格式

type BundledSkillDefinition = {
  name: string
  description: string
  aliases?: string[]
  whenToUse?: string
  argumentHint?: string
  allowedTools?: string[]        // 限制可用工具
  model?: string                 // 指定模型
  disableModelInvocation?: boolean
  userInvocable?: boolean
  isEnabled?: () => boolean      // 动态启用/禁用
  hooks?: HooksSettings
  context?: 'inline' | 'fork'   // 内联执行还是 fork 新 Agent
  agent?: string
  files?: Record<string, string> // 附加的参考文件
  getPromptForCommand(args, context): Promise<ContentBlockParam[]>
}

17 个内置技能

技能 用途 设计要点
batch 批量处理多个任务 循环调用工具
claudeApi / claudeApiContent Claude API 使用指南 参考文档类
claudeInChrome Chrome 浏览器自动化 集成浏览器 MCP
debug 调试辅助 诊断问题
keybindings 快捷键配置 读写 keybindings.json
loop 循环执行命令 反复执行直到条件满足
loremIpsum 生成占位文本 简单工具
remember 存储记忆 写入 MEMORY.md
scheduleRemoteAgents 远程 Agent 调度 配合 ScheduleCronTool
simplify 简化代码/文本 重构辅助
skillify 将工作流封装为技能 元技能——创建新技能
stuck 卡住时求助 诊断并建议下一步
updateConfig 更新配置 修改 settings
verify / verifyContent 验证执行结果 质量保证

6.3 Disk Skills(磁盘技能)

加载流程loadSkillsDir.ts):

  1. 扫描 .claude/skills/ 目录下的 Markdown 文件
  2. 解析 YAML frontmatter(提取 name、description、allowed_tools、model 等)
  3. 注册为 Command(与斜杠命令统一)
  4. 支持参数替换(frontmatter 中定义的参数在 prompt 中用 $1 等占位符)

Frontmatter 示例

---
name: review-pr
description: Review a pull request
allowed_tools: [Read, Grep, Glob, Bash]
model: sonnet
---
# Your instructions here...

6.4 SkillTool 的执行流程

用户/LLM 调用 SkillTool({ skill: "commit" })
│
├── findCommand("commit") —— 查找注册的命令/技能
│
├── 检查权限(根据技能来源——official marketplace 免检)
│
├── 解析 frontmatter hooks
│
├── 决定执行模式:
│   ├── inline(context: 'inline')→ 注入消息到当前对话
│   └── fork(context: 'fork')→ 调用 runAgent() 创建子 Agent
│
├── 如果 fork 模式:
│   ├── 筛选工具集(allowedTools)
│   ├── 解析模型覆盖
│   ├── 构建消息和系统提示
│   └── 执行 query()
│
└── 返回结果

6.5 启发性

技能 vs 工具的边界:工具是原子操作(读文件、执行命令),技能是工作流编排(代码审查 = 读文件 + 分析 + 生成报告)。Claude Code 把这个区分做得很清晰。

用户可扩展性:通过 Markdown 文件定义技能,降低了扩展门槛——不需要写 TypeScript,不需要理解工具系统,只需要写好 prompt。


第七章 Memory 系统:Agent 的长期记忆

7.1 记忆的层级结构

记忆系统
├── MEMORY.md(入口文件)—— 每次对话都会加载,最大 200 行/25KB
├── memory/ 目录 —— 自动提取的记忆文件
│   ├── *.md 文件(每个记忆一个文件)
│   └── 带 frontmatter(type, description, date)
└── Team Memory(团队记忆)—— 通过 TEAMMEM feature flag

7.2 记忆类型分类学

Claude Code 将记忆分为四种类型,每种有明确的定义和使用场景:

类型 含义 存储范围 示例
user 用户角色、偏好、知识背景 仅私有 「用户是数据科学家,目前关注可观测性」
feedback 用户对 Agent 行为的指导 默认私有,项目级可团队 「测试不要 mock 数据库——上次因此出了事故」
project 项目进展、目标、在进行的工作 偏向团队 「Alice 在做认证重构,预计周四完成」
reference 外部参考信息 看内容 「API 文档链接:...」

关键设计原则(直接来自源码注释):

Memories are constrained to four types capturing context NOT derivable from the current project state. Code patterns, architecture, git history, and file structure are derivable (via grep/git/CLAUDE.md) and should NOT be saved as memories.

翻译:记忆只存储不能从项目当前状态推导出的信息。代码模式、架构、Git 历史、文件结构都可以通过搜索获得,不应该存为记忆。

7.3 记忆检索机制(findRelevantMemories.ts

用户查询 → findRelevantMemories()
│
├── scanMemoryFiles() —— 扫描 memory/ 目录
│   └── 读取每个文件的 frontmatter(filename, description)
│
├── 过滤已展示的记忆(alreadySurfaced)
│
├── selectRelevantMemories() —— 调用 Sonnet 模型
│   ├── 系统提示:「你是记忆选择器,从列表中选择对当前查询有用的记忆」
│   ├── 输入:用户查询 + 记忆清单(filename + description)
│   ├── 约束:最多选 5 个
│   └── 额外规则:如果提供了 recentTools 列表,不要选那些工具的使用文档
│       (但仍然选相关的 warnings/gotchas——因为正在用的工具更需要注意事项)
│
└── 返回选中的记忆文件路径 + mtime

为什么用 LLM 做记忆检索而不是向量搜索?

这是一个有意思的设计选择。向量搜索(如 RAG)适合大规模文档检索,但记忆文件通常不多(几十个),用 LLM 直接看清单判断相关性更准确。而且 LLM 能理解「工具使用文档 vs 工具注意事项」这种语义细节。

7.4 自动记忆提取(extractMemories.ts

触发时机:每次查询循环结束(模型无工具调用的最终响应)

query() 完成
│
└── handleStopHooks()
    └── extractMemories()
        │
        ├── 检查 isAutoMemoryEnabled()
        ├── 扫描已有记忆(避免重复)
        │
        └── runForkedAgent()  —— Fork 当前对话
            ├── 共享父 Agent 的 prompt cache
            ├── 系统提示:指导提取哪些信息值得记忆
            ├── 有权使用:FileRead, FileWrite, FileEdit, Glob, Grep, Bash
            └── 输出:新的记忆文件(带 frontmatter)

Forked Agent 的巧妙之处:记忆提取 Agent 不需要重新理解整个对话——它 fork 了父 Agent 的上下文,prompt cache 直接命中,额外 token 成本极低。

7.5 团队记忆同步

在 Team 模式下,记忆分为 private(个人)和 team(团队共享)两个目录。teamMemorySync 服务负责:

  • 检测团队记忆文件变更
  • 同步到团队成员
  • 检查机密泄露(teamMemSecretGuard.ts

7.6 与其他 Agent 记忆方案的对比

维度 Claude Code MemGPT LangChain Memory
存储格式 Markdown 文件 数据库 Python 对象
检索方式 LLM 选择 向量搜索 向量搜索
记忆分类 4 种明确类型 自由格式 自由格式
持久化 文件系统 数据库 可插拔
团队共享 原生支持 不支持 不支持
自动提取 对话结束自动触发 手动/规则

Claude Code 的优势

  1. 记忆类型的分类学设计非常用心——不是笼统的「记住一切」,而是精确定义了什么值得记
  2. 文件系统作为存储——简单、可检查、可版本控制
  3. Forked agent 做提取——零额外成本

不足之处

  1. 无向量搜索——当记忆文件增多到数百个时,LLM 选择可能效率下降
  2. 200 行/25KB 的 MEMORY.md 限制较为刚性

第八章 权限系统:信任的边界

8.1 权限模型

每个工具调用都经过权限检查。权限模式(PermissionMode)有多种:

模式 含义
default 每次都询问用户
plan 只允许只读操作,写操作需要确认
bypassPermissions 跳过所有权限(危险模式)
auto 基于规则自动判断
bubble 冒泡到父 Agent 的终端询问

8.2 权限检查流程(PermissionContext.ts

工具调用 → checkPermissions()
│
├── 1. 工具自身的权限检查
│   └── 返回 PermissionResult: allow | deny | passthrough | ask
│
├── 2. Hook 检查(executePermissionRequestHooks)
│   └── 用户定义的 hooks 可以自动批准/拒绝
│
├── 3. Classifier 检查(awaitClassifierAutoApproval)
│   └── BashTool 特有——AI 分类器判断命令是否安全
│
├── 4. 用户确认(如果前面没有自动决策)
│   └── 终端弹出确认对话框
│
└── 5. 记录决策 + 更新规则
    ├── 如果用户选择「永久允许」→ 写入权限规则
    └── 日志记录

竞态处理createResolveOnce 确保一个权限请求只被解决一次——hook 回调、分类器、用户操作可能并发到达,通过 claim() 原子操作防止重复解决。

8.3 BashTool 的特殊权限

BashTool 是权限最复杂的工具:

  • AST 解析parseForSecurity() 解析 shell 命令的 AST
  • 命令分割splitCommandWithOperators() 理解管道、&&||
  • 通配符匹配matchWildcardPattern() 支持基于模式的权限规则
  • 只读验证checkReadOnlyConstraints() 在 plan 模式下确保命令是只读的
  • Sed 解析parseSedEditCommand() 专门解析 sed 编辑命令判断是否修改文件

第九章 Bridge 系统:IDE 的神经传导

9.1 架构概览

VS Code / JetBrains
    │
    │ (HTTP API + WebSocket)
    │
    ▼
Bridge Main Loop (bridgeMain.ts)
    │
    ├── bridgeApi.ts ────── API 客户端
    ├── jwtUtils.ts ─────── JWT Token 管理与刷新
    ├── sessionRunner.ts ── 会话执行(spawn CLI 子进程)
    ├── pollConfig.ts ───── 轮询配置(指数退避)
    └── capacityWake.ts ─── 容量唤醒
    │
    ▼
REPL Bridge (replBridge.ts)
    │
    ├── replBridgeTransport.ts ── 传输层
    ├── replBridgeHandle.ts ──── 句柄管理
    └── inboundMessages.ts ───── 入站消息处理

9.2 关键设计

31 个文件,比想象中复杂。核心挑战是:IDE 扩展和 CLI 进程是两个独立进程,需要可靠的双向通信。

JWT 认证:IDE 和 CLI 之间通过 JWT Token 互相验证身份,有自动刷新机制。

容量唤醒(capacityWake.ts:当 CLI 进程空闲时降低轮询频率,有新消息时立即唤醒。

可信设备(trustedDevice.ts:设备级别的信任标记,避免每次连接都要认证。


第十章 状态管理:React 在终端中的实践

10.1 Store 模式

// store.ts
function createStore(initialState: AppState, onChange?): AppStateStore {
  let state = initialState
  const listeners = new Set<() => void>()

  return {
    getState: () => state,
    setState: (updater) => {
      const oldState = state
      state = updater(state)
      if (onChange) onChange({ newState: state, oldState })
      listeners.forEach(l => l())
    },
    subscribe: (listener) => {
      listeners.add(listener)
      return () => listeners.delete(listener)
    },
  }
}

与 React 的集成:通过 useSyncExternalStore hook——React 18 的 API,确保外部 store 与 React 渲染同步。

10.2 Context 体系

AppStateProvider
├── MailboxProvider      // Agent 间消息
├── VoiceProvider        // 语音输入(feature flag 控制)
├── KeybindingProvider   // 快捷键
├── ModalContext         // 模态对话框
├── OverlayContext       // 覆盖层
├── NotificationsContext // 通知
└── QueuedMessageContext // 排队消息

第十一章 Vim 模式:状态机的艺术

11.1 状态机设计

type VimState =
  | { mode: 'INSERT'; insertedText: string }
  | { mode: 'NORMAL'; command: CommandState }

type CommandState =
  | { type: 'idle' }
  | { type: 'count'; digits: string }
  | { type: 'operator'; op: Operator }
  | { type: 'operatorCount'; op: Operator; digits: string }
  | { type: 'find'; findType: FindType }
  | { type: 'operatorFind'; op: Operator; count?: number; findType: FindType }
  | { type: 'operatorTextObj'; op: Operator; count?: number; scope: TextObjScope }
  | { type: 'replace' }
  | { type: 'g' }
  | { type: 'indent'; direction: '>' | '<' }

状态转换图

NORMAL/idle ──┬── [d/c/y] ──► operator
              ├── [1-9]   ──► count
              ├── [fFtT]  ──► find
              ├── [g]     ──► g
              ├── [r]     ──► replace
              └── [><]    ──► indent

operator ──┬── [motion]  ──► execute
           ├── [0-9]    ──► operatorCount
           ├── [ia]     ──► operatorTextObj
           └── [fFtT]   ──► operatorFind

每个状态精确地知道它在等待什么输入。TypeScript 的 discriminated union 确保 switch 语句的穷举性。

启发性:Vim 的输入处理本质上就是一个状态机。Claude Code 把这个状态机的类型定义做到了极致——注释里说「The types ARE the documentation」,类型本身就是文档。这是 TypeScript 在复杂交互逻辑中的最佳实践。


第十二章 Keybinding 系统:可配置的交互

12.1 三层合并

默认绑定(defaultBindings.ts)
    ↓ 被用户绑定覆盖
用户绑定(~/.claude/keybindings.json)
    ↓ 某些键不可覆盖
保留快捷键(reservedShortcuts.ts):ctrl+c, ctrl+d

12.2 平台适配

// 图片粘贴快捷键
const IMAGE_PASTE_KEY = getPlatform() === 'windows' ? 'alt+v' : 'ctrl+v'

// 模式切换快捷键
const MODE_CYCLE_KEY = SUPPORTS_TERMINAL_VT_MODE ? 'shift+tab' : 'meta+m'

Windows Terminal 不支持 VT 模式时,shift+tab 不可靠,回退到 meta+m。


第十三章 插件系统:可扩展的边界

13.1 两类插件

内置插件(builtinPlugins.ts

  • ID 格式:{name}@builtin
  • 通过 /plugin UI 启用/禁用
  • 可提供:skills、hooks、MCP servers
  • 状态持久化到用户设置

第三方插件

  • ID 格式:{name}@{marketplace}
  • 从 marketplace 安装
  • 有版本管理和自动更新

13.2 插件加载流程

启动 → initBuiltinPlugins()
│
├── 注册内置插件定义
├── 检查 isAvailable()(动态判断插件是否在当前环境可用)
├── 读取用户设置(哪些插件被启用/禁用)
├── defaultEnabled 作为回退
│
└── 返回 { enabled: LoadedPlugin[], disabled: LoadedPlugin[] }

第十四章 Query Pipeline 的完整图景

把前面各章串起来,一次完整的用户查询经历以下管道:

用户输入 "帮我修复 src/auth.ts 中的 bug"
│
├── 1. 系统提示构建
│   ├── 基础系统提示
│   ├── + 用户上下文(OS、shell、cwd、git 状态)
│   ├── + 记忆(MEMORY.md + 相关记忆文件)
│   ├── + MCP 指令
│   ├── + 活跃 Agent 列表
│   └── + 延迟工具列表
│
├── 2. 工具池组装
│   ├── 内置工具(BashTool, FileReadTool, ...)
│   ├── + MCP 工具(从连接的 MCP 服务器)
│   ├── + 插件工具
│   ├── - 延迟工具(放入 deferred 列表)
│   └── = 最终工具集
│
├── 3. Query 循环
│   ├── API 调用(流式)
│   ├── 模型思考...
│   ├── 模型选择工具:FileReadTool({ file_path: "src/auth.ts" })
│   │   ├── 权限检查 → 通过(只读)
│   │   ├── 执行
│   │   └── 结果返回给模型
│   ├── 模型分析代码...
│   ├── 模型选择工具:FileEditTool({ file_path: "src/auth.ts", old_string: "...", new_string: "..." })
│   │   ├── 权限检查 → 询问用户
│   │   ├── 用户确认
│   │   ├── 执行
│   │   ├── 通知 VS Code 文件已更新
│   │   ├── 记录 file history
│   │   └── 结果返回给模型
│   ├── 模型选择工具:BashTool({ command: "npm test" })
│   │   ├── 安全解析
│   │   ├── 权限检查
│   │   ├── 沙箱执行
│   │   └── 结果返回给模型
│   └── 模型生成最终回复(无工具调用)
│
├── 4. Stop Hooks
│   ├── extractMemories → 提取「用户关注 auth.ts 的 bug」记忆
│   ├── promptSuggestion → 建议「要不要运行完整测试套件?」
│   └── taskCompleted → 通知任务系统
│
└── 5. 渲染
    └── React/Ink 渲染最终回复到终端

第十五章 设计模式总结与反思

15.1 值得学习的设计模式

  1. 并行预取 + 延迟加载:启动性能的黄金组合
  2. 编译时特性开关:Bun 的 feature() 宏实现零成本条件编译
  3. Forked Agent:共享 prompt cache 的子 Agent,几乎零额外成本
  4. 工具作为一等公民:完整的生命周期(定义、权限、执行、渲染、截断)
  5. 记忆分类学:不是「记住一切」,而是精确定义什么值得记
  6. 状态机驱动:用 TypeScript 类型系统保证状态转换的完备性
  7. Agent 列表外置:从工具描述移到消息附件,保护 prompt cache
  8. 权限冒泡:子 Agent 的权限请求透传到用户终端

15.2 工程质量的体现

  1. 类型安全:几乎所有核心数据结构都有精确的 TypeScript 类型
  2. 错误处理TelemetrySafeError 确保错误信息不泄露代码或文件路径到遥测
  3. 优雅退出setupGracefulShutdown() + registerCleanup() 确保资源释放
  4. 调试支持logForDebugging()logForDiagnosticsNoPII() 分级日志
  5. 性能意识:startup profiler、prompt cache 优化、lazy loading
  6. 安全意识:BashTool AST 解析、文件路径验证、JWT 认证

15.3 不足与改进空间

  1. QueryEngine 过大:46,000 行的单文件违反了单一职责原则。源码中已有注释暗示未来会拆分为「纯函数 reducer」模式。
  2. 状态管理碎片化:AppState、bootstrap/state、各种 module-level 闭包状态共存,没有统一的状态层。
  3. 测试覆盖未知:源码中有 testing/ 目录和测试工具,但泄露的代码不包含测试文件。
  4. 概念重叠:Coordinator Mode、Team Mode、Fork Subagent 三种多 Agent 模式并存,用户需要理解它们的区别才能有效使用。
  5. 记忆系统扩展性:纯文件系统 + LLM 选择的方案在记忆量大时可能成为瓶颈。
  6. MCP 耦合:22 个 MCP 相关文件说明协议集成的复杂度不低,新协议的接入成本高。

15.4 对 Agent 工程的启示

如果你要构建自己的 Agent 系统,Claude Code 源码告诉我们:

  1. 性能是功能——用户不会等一个慢 Agent
  2. 安全是底线——每个工具调用都需要权限检查
  3. 记忆要有策略——不是什么都记,而是记「不能从当前状态推导的信息」
  4. 多 Agent 需要通信协议——不只是 spawn,还要有通知、消息、权限冒泡
  5. Prompt Cache 是金矿——在大规模 Agent 系统中,cache 命中率直接决定成本
  6. 工具不是函数包装——需要完整的生命周期管理
  7. 编译时优化很重要——feature flag + tree shaking 可以显著减小 bundle 体积
  8. 状态机是好工具——复杂交互逻辑用状态机 + 类型系统比 if-else 可靠得多

本文档基于 Claude Code 泄露源码(2026-03-31)的深度阅读,力求「每个结论都有源码支撑」。如有疑问,请直接查阅对应的源文件。