乐于分享
好东西不私藏

Claude Code 源码解析 – Agent 架构

Claude Code 源码解析 – Agent 架构

想象你要盖一栋房子。你不可能自己一个人搬砖、和泥、设计结构——你需要不同工种的工人:木工、电工、水泥工…

Claude Code 的 Agent 架构就是给 AI 配了一支施工队:有专门探索代码库的 Explore Agent,有专门做计划的 Plan Agent,还有什么都能干的通用 Agent。

一、Agent 定义:Markdown 即配置

Claude Code 的设计者做了一个非常聪明的决定:用 Markdown 写 Agent 配置。这意味着任何人都可以创建自定义 Agent,不需要懂代码,只需要会写 Markdown。

为什么用 Markdown?因为 Markdown 本身就是一种配置语言。它有 frontmatter(---之间的部分),可以放元数据;正文可以放提示词。天然适合定义 Agent。

---
name: MyAgent
description: 当你需要做某件事时使用这个 Agent
model: haiku
maxTurns: 10
---


你是一个专门做 XXX 的 Agent...

这就是一个完整的 Agent 定义。name 是标识符,description 告诉主 Agent 什么时候该调用它,model 指定用什么模型,maxTurns 限制它能思考多少轮。

1.1 Agent 定义结构

从代码层面看,Agent 的定义结构非常清晰。Claude Code 使用 TypeScript 类型系统来约束 Agent 的所有属性。

agentType 是 Agent 的唯一标识符,就像工牌号。whenToUse 是描述文本,告诉系统什么时候应该召唤这个 Agent。toolsdisallowedTools 控制这个 Agent 能用什么工具、不能用什么工具。model 指定使用哪个 AI 模型——可以用快速的 haiku,也可以用强大的 opus。memory 控制 Agent 的记忆范围,是私有还是团队共享。

// loadAgentsDir.ts
type BaseAgentDefinition = {
  agentTypestring           // Agent 唯一标识
  whenToUsestring           // 何时使用这个 Agent
  tools?: string[]            // 允许使用的工具
  disallowedTools?: string[]  // 禁止使用的工具
  model?: string              // 模型选择
  effort?: EffortValue        // 努力程度
  permissionMode?: PermissionMode  // 权限模式
  maxTurns?: number           // 最大回合数
  skills?: string[]           // 预加载的技能
  memory?: 'user' | 'project' | 'local'  // 记忆范围
  background?: boolean        // 是否后台运行
}

这种设计的精妙之处在于:所有属性都是可选的。你只需要定义你关心的属性,其他都走默认值。这让创建 Agent 变得非常简单。

1.2 三种 Agent 来源

Claude Code 的 Agent 有三种来源,就像员工有三种招聘渠道:

内置 Agent(built-in) 是 Claude Code 官方提供的,包括 Explore、Plan 等。这些 Agent 经过精心调优,开箱即用。

插件 Agent(plugin) 是第三方开发者提供的,通过插件系统集成进来。

自定义 Agent 是用户自己创建的,存放在用户配置(~/.claude/)或项目配置(.claude/)中。

// Claude Code 会合并所有来源,同名的 Agent 后加载的覆盖先加载的
// 这意味着你可以用自己的 Agent 覆盖内置 Agent 的行为

二、内置 Agent:开箱即用的专业队

Claude Code 自带几个专业 Agent,相当于配备了一支精干的专家团队。

2.1 Explore Agent — 快速搜索专家

Explore Agent 是专门做代码探索的 Agent。它的核心设计理念是:只读、迅速、不打扰

当你需要在一整个代码库里找一个函数在哪里、某个 API 被谁调用、或者了解一个模块的结构时,就用 Explore Agent。它不会修改任何文件,只会搜索和阅读。

它使用 haiku 模型——这是最快最便宜的模型,因为探索任务不需要深度推理,只需要快速扫描。

// built-in/exploreAgent.ts
export const EXPLORE_AGENT = {
  agentType'Explore',
  whenToUse'Fast agent specialized for exploring codebases...',
  disallowedTools: ['Agent''Edit''Write', ...],
  model'haiku',  // 速度优先
  omitClaudeMdtrue,  // 不需要 CLAUDE.md
  getSystemPrompt() => getExploreSystemPrompt(),
}

注意 disallowedTools——Explore Agent 被禁止使用 Edit、Write、Agent 等工具。这是一种强制约束,从根源上防止 Explore 误操作文件。

omitClaudeMd: true 是另一个精妙的设计。Explore 不需要读取项目的 CLAUDE.md 规范,因为它只做搜索,不做实现。这节省了大量上下文空间。

2.2 Plan Agent — 计划制定者

Plan Agent 专门用于制定计划。当你需要规划一个复杂任务的执行步骤时,可以用它先制定一个详细的计划,然后交给主 Agent 执行。

Plan Agent 和 plan 权限模式配合使用——在 Plan 模式下,所有修改操作都被禁止,只能制定计划。

2.3 General Purpose Agent — 万能工人

默认的主 Agent,什么都能干。它调用子 Agent 完成特定任务,自己负责任务分解和结果汇总。

三、Agent 运行机制:Fork 模式

当主 Agent 需要调用子 Agent 时,Claude Code 使用 Fork 模式。这就像主工程师把任务分配给实习生——主上下文复制一份给子 Agent,但子 Agent 的操作不会影响主 Agent 的状态。

// runAgent.ts
async function runAgent(agentDefinitionAgentDefinition) {
  // 1. 继承主 Agent 的上下文
  const context = createSubagentContext(parentContext)
  
  // 2. 设置独立的工作目录(可选)
  if (agentDefinition.isolation === 'worktree') {
    context.cwd = createIsolatedWorktree()
  }
  
  // 3. 独立的工具权限
  context.tools = resolveAgentTools(agentDefinition)
  
  // 4. 运行子 Agent
  return await query(context)
}

Fork 模式有三个关键步骤:

第一步:复制上下文。主 Agent 的系统提示词、工具列表、记忆等都被复制一份。这保证子 Agent 知道自己在做什么任务。

第二步:隔离工作目录(可选)。如果 Agent 声明了 isolation: 'worktree',就在一个独立的 git worktree 中运行。这防止并发冲突。

第三步:限制工具。根据 Agent 定义中的 toolsdisallowedTools 过滤工具列表。Explore Agent 拿到的工具列表里没有 Edit 和 Write。

3.1 Fork 的优势

为什么不用线程而用 Fork?因为 Fork 更安全。子 Agent 的所有操作都在隔离环境里,不会意外修改主 Agent 的工作状态。任何一个子 Agent 崩溃,都不会影响主 Agent。

3.2 上下文传递

主 Agent 上下文
├── System Prompt(部分传递)
├── 工具列表(按 Agent 定义过滤)
├── 记忆(按 memory scope 决定)
└── MCP Servers(可继承可添加)

主 Agent 的上下文是「只读的参考」,子 Agent 基于它工作,但不会修改它。

四、工具解析:Agent 能用什么

每个 Agent 能用什么工具,是由它的定义决定的。这是一种白名单 + 黑名单的机制。

// agentToolUtils.ts
function resolveAgentTools(agentAgentDefinition): Tools {
  // 1. 从主工具列表开始(全部工具)
  let tools = getMainTools()
  
  // 2. 应用 allowedTools 过滤器(白名单)
  if (agent.tools) {
    tools = tools.filter(t => agent.tools.includes(t.name))
  }
  
  // 3. 应用 disallowedTools 过滤器(黑名单)
  if (agent.disallowedTools) {
    tools = tools.filter(t => !agent.disallowedTools.includes(t.name))
  }
  
  return tools
}

过滤的顺序很重要:先白名单再黑名单。如果你同时指定了 tools: ['Read', 'Edit']disallowedTools: ['Edit'],最终结果只有 Read

这种设计让 Agent 权限的控制变得非常灵活。你可以默认开放所有工具(不指定 tools),然后禁止危险操作(disallowedTools: ['Bash']);或者默认禁止所有工具(tools: ['Read']),然后按需开放。

五、记忆隔离:Agent 的独立记忆空间

每个 Agent 可以有自己的记忆空间,这解决了「Agent 之间记忆污染」的问题。

Claude Code 有三种记忆范围:

user 记忆存放在用户级别,所有 Agent 共享。

project 记忆存放在项目级别,项目成员共享。

local 记忆最特殊——它是会话级别的,只在当前会话内有效,会话结束就消失。

// agentMemory.ts
type AgentMemoryScope = 'user' | 'project' | 'local'

// Agent 可以有自己的记忆空间
const agentMemory = {
  'user''~/.claude/agents/<agentType>/memory/',
  'project''<project>/.claude/agents/<agentType>/memory/',
  'local''<session>/memory/'
}

local 记忆是 Claude Code 的创新。比如你问主 Agent:「刚才 Explore 找到了什么?」主 Agent 不会记得,因为它没有访问 Explore 的 local 记忆。但如果你把 Explore 改成用 project 记忆,主 Agent 就能看到探索结果了。

六、Agent 协作模式

多个 Agent 怎么配合工作?Claude Code 支持三种协作模式。

6.1 主从模式

最常见的模式。主 Agent 负责任务分解,把子任务分发给专门的 Agent,然后汇总结果。

用户 → 主 Agent → 子 Agent (Explore)
                ↓
           子 Agent (Plan)
                ↓
           主 Agent 汇总结果

6.2 并行模式

多个子 Agent 同时工作,主 Agent 等待所有结果后继续。

主 Agent → [Agent A] ← 同时运行
         → [Agent B] ←
         → [Agent C] ←

适合「独立任务并行执行」的场景。比如同时探索三个不同的代码模块。

6.3 验证模式

主 Agent → 完成任务
         → 触发验证 Agent
         → 验证结果
         → 通过/失败

专门的验证 Agent(VERIFICATION_AGENT)检查主 Agent 的输出是否正确。

七、设计思想:专业化与隔离

Claude Code 的 Agent 架构体现了三个核心原则:

专业化原则:每个 Agent 只做一件事。Explore 专攻搜索,Plan 专攻规划,Verification 专攻验证。专业化的 Agent 比通用 Agent 更容易优化——你可以单独调优 Explore,不用担心影响其他功能。

隔离原则:工具隔离(Explore 不能写文件)、记忆隔离(local 记忆不污染全局)、工作目录隔离(worktree 模式独立 git 状态)。隔离让错误不会扩散,让并发成为可能。

组合原则:简单积木可以组合出复杂系统。主 Agent + Explore = 带探索能力的助手;主 Agent + Plan = 带规划能力的助手;主 Agent + Explore + Plan = 全能助手。

总结

Claude Code 的 Agent 架构告诉我们:专业化 + 隔离 = 可维护的复杂系统

用 Markdown 定义 Agent 让任何人都能创建自定义 Agent;Fork 模式让子 Agent 不影响主 Agent;工具过滤和记忆隔离让每个 Agent 各司其职。

如果你在设计多 Agent 系统,问自己:每个 Agent 的边界在哪里?如何保证隔离又支持协作?


源码索引

功能 文件
Agent 定义加载 src/tools/AgentTool/loadAgentsDir.ts
Agent 运行 src/tools/AgentTool/runAgent.ts
内置 Agent src/tools/AgentTool/builtInAgents.ts
Explore Agent src/tools/AgentTool/built-in/exploreAgent.ts
Plan Agent src/tools/AgentTool/built-in/planAgent.ts
工具解析 src/tools/AgentTool/agentToolUtils.ts
记忆管理 src/tools/AgentTool/agentMemory.ts