深入浅出 Claude Code(三):从源码理解 Agent 系统,一个人指挥一支队伍
- 内容介绍
- 文章标签
- 相关推荐
今天来带各位佬友讲讲 agent,本文参考官方教学文档和 claudecode 源码而来
各位佬友抓紧把手,咱们直接发车
1. Agent 是什么:独立 context 的工作单元
一个 agent 就是一个独立的 Claude 会话——有自己的 context window、自己的对话历史、自己的工具集。
你平时跟 Claude Code 对话的那个就是"主 agent"。当你(或模型)调用 Agent 工具时,会创建一个子 agent。子 agent 在自己的 context window 里干活,完成后把结果返回给主 agent。

这里有一个关键区别:普通 subagent 从零开始,只有你传入的 prompt 字符串——你不写进去的信息,它看不到。而 Fork 模式继承父 agent 的完整对话历史——之前聊过什么它都知道,不需要你重复。
源码中子 agent 的 context 创建逻辑(utils/forkedAgent.ts):

function createSubagentContext(parentContext, overrides) {
return {
readFileState: cloneFileStateCache(...) // 独立的文件缓存
messages: override?.messages || [] // 普通 subagent:空;Fork:父 agent 的历史
agentId: override?.agentId || createAgentId() // 新 ID
queryTracking: { chainId, depth: parentDepth + 1 } // 深度 +1
}
}
不管哪种模式,每个子 agent 都有独立的文件缓存和 context window。这就是为什么用 agent 能解决长对话"忘事"——子 agent 不会被主 agent 之前对话的内容塞满。
2. 创建 Agent 时发生了什么
当模型调用 Agent 工具时,路径取决于有没有指定 subagent_type(tools/AgentTool/AgentTool.tsx):
Agent tool 调用
├─ 指定了 subagent_type(如 Explore、Plan)→ 用该类型的定义从零开始
├─ 没指定 + Fork 功能开启 → Fork(继承父 agent 的完整对话历史)
└─ 没指定 + Fork 未开启 → General Purpose Agent
日常使用中你接触到的主要是第一种。大部分时候是模型自动调用的——你说"帮我调研一下 auth 模块",Claude 自己判断该用 Explore agent,自动写 prompt、自动派遣,你不需要手动操作。
但不管是自动还是手动触发,子 agent 都是从空白开始工作。主 agent 传给它的 prompt 是它唯一的上下文——主 agent 之前跟你的对话历史、已经读过的文件,子 agent 统统看不到。
这也是为什么你有时候觉得 subagent 的结果不够好——主 agent 写给子 agent 的 prompt 可能没带足够的背景信息。你可以在对话中显式补充:“帮我调研 auth 模块,我们用的是 JWT + Redis session,入口在 src/auth/middleware.ts”,这样主 agent 传给子 agent 的 prompt 会包含这些关键信息。
Fork 模式(feature flag 控制,可能未对外开放)
Fork 是"复制一个分身"——子 agent 继承父 agent 的完整对话历史和 system prompt。你不需要重复背景信息。
源码中 fork 的启用条件(forkSubagent.ts):
function isForkSubagentEnabled(): boolean {
if (feature('FORK_SUBAGENT')) { // 编译时 feature flag
if (isCoordinatorMode()) return false
if (getIsNonInteractiveSession()) return false
return true
}
return false
}
feature('FORK_SUBAGENT') 是编译时常量。如果你从来没感知过 fork,大概率是这个 flag 在当前版本中未开启——整个 fork 路径会被 dead code elimination 删掉。
Fork 还有一个成本优势:复用父 agent 的 system prompt(byte-exact 相同),prompt cache 直接命中,50K tokens 的上下文走 cache read 成本约 1/10。但因为功能可能未开放,这里不展开。
3. 三种内置 Agent
| Agent | 模型 | 工具 | 用途 |
|---|---|---|---|
| Explore | 普通用户: Haiku / Anthropic 员工: 继承主模型 | 只读(Read, Grep, Glob) | 搜代码、找文件、回答 codebase 问题 |
| Plan | 继承主模型 | 只读 | 架构设计、实现方案规划 |
| General Purpose | 继承主模型 | 全部 | 复杂多步骤任务 |
官方文档说 Explore 在需要搜索或理解代码库时被自动委派,调用时分三个 thoroughness 级别:quick(定向查找)、medium(平衡探索)、very thorough(全面分析)。
两个源码级的细节官方没提:
你用的 Explore 默认跑 Haiku,Anthropic 员工跑的是主模型。 源码(built-in/exploreAgent.ts):
model: process.env.USER_TYPE === 'ant' ? 'inherit' : 'haiku'
USER_TYPE === 'ant' 是 Anthropic 内部员工标识。也就是说同样的 Explore agent,他们跑 Opus/Sonnet,你跑 Haiku。Haiku 更快更便宜,但推理能力弱一些。如果你觉得 Explore 给的结果太浅,可以用自定义 agent 覆盖它(后面第 4 节讲怎么做)。
Explore 跳过 CLAUDE.md。 设置了 omitClaudeMd: true——探索型 agent 不需要你的 commit 规范和代码风格规则,省掉这些 token,把空间留给代码内容。
4. 自定义 Agent
两种方式创建:
交互式——输入 /agents,选 Create new agent,可以让 Claude 根据你的描述自动生成定义。选工具、选模型、选颜色,保存就生效。
手动建文件——在 .claude/agents/ 下创建 .md 文件。frontmatter 是配置,正文是 system prompt:
---
name: code-reviewer
description: 审查代码变更,关注安全和性能
tools: Read, Grep, Glob, Bash(git diff:*)
model: sonnet
maxTurns: 15
---
你是一个代码审查专家。收到审查请求后:
1. 用 git diff 查看所有变更
2. 逐文件检查安全漏洞、性能问题、错误处理
3. 给出结构化审查意见
几个关键字段:
description — 不只是文档。Claude 会根据这个描述自动判断何时委派任务给这个 agent。写得模糊就不会被自动调用。
tools — 硬限制,不是建议。源码中 tools 字段被解析为严格白名单(agentToolUtils.ts:resolveAgentTools)——不在列表里的工具对 agent 来说不存在。而且支持内联权限规则:
tools: "Read, Grep, Bash(git diff:*), Agent(Explore)"
Bash(git diff:*) = 只能执行 git diff 开头的命令。Agent(Explore) = 只能派遣 Explore 类型的子 agent。
model — inherit 继承主模型,或指定 sonnet/opus/haiku。
isolation: worktree — 在独立的 git worktree 中运行。完成后无变更自动清理,有变更保留 worktree 和分支。
background: true — 始终后台运行,不阻塞主对话。
memory: project — 给 agent 独立的记忆空间,存在 .claude/agent-memory/{agent-type}/。code-reviewer 的记忆不会和 code-writer 的混在一起。
覆盖内置 Agent
同名 agent 高优先级覆盖低优先级:
企业策略 > 项目 .claude/agents/ > 用户 ~/.claude/agents/ > 插件 > 内置
想让 Explore 用 Sonnet 而不是 Haiku?创建 .claude/agents/Explore.md:
---
name: Explore
description: 快速探索代码库,搜索文件和代码模式
model: sonnet
---
5. 子 Agent 能用什么工具、不能用什么
源码中有三个工具集控制子 agent 的能力边界:
子 agent 禁止使用的工具(constants/tools.ts):
const ALL_AGENT_DISALLOWED_TOOLS = new Set([
TASK_OUTPUT_TOOL_NAME, // 防止递归
EXIT_PLAN_MODE_V2_TOOL_NAME, // 计划模式是主线程的抽象
ENTER_PLAN_MODE_TOOL_NAME, // 同上
ASK_USER_QUESTION_TOOL_NAME, // 需要主线程的用户交互
TASK_STOP_TOOL_NAME, // 需要主线程的状态访问
// 外部用户禁止嵌套 agent:
...(process.env.USER_TYPE === 'ant' ? [] : [AGENT_TOOL_NAME]),
])
最后一行:外部用户的 AGENT_TOOL_NAME 被加入禁止列表。外部用户的子 agent 不能再创建子 agent,架构只能是一层。Anthropic 内部用户(ant)不受此限制。
后台 agent 允许的工具(constants/tools.ts)——范围更窄:
const ASYNC_AGENT_ALLOWED_TOOLS = new Set([
FILE_READ_TOOL_NAME, GREP_TOOL_NAME, GLOB_TOOL_NAME,
WEB_SEARCH_TOOL_NAME, WEB_FETCH_TOOL_NAME,
...SHELL_TOOL_NAMES, // Bash, PowerShell
FILE_EDIT_TOOL_NAME, FILE_WRITE_TOOL_NAME,
NOTEBOOK_EDIT_TOOL_NAME, SKILL_TOOL_NAME,
TOOL_SEARCH_TOOL_NAME,
ENTER_WORKTREE_TOOL_NAME, EXIT_WORKTREE_TOOL_NAME,
])
注意 ASK_USER_QUESTION 不在列表里——后台 agent 不能问你问题,因为它在后台跑,你看不到他。
6. 权限怎么处理
子 agent 需要执行删除文件、运行危险命令等操作时,权限提示怎么办?
取决于 permissionMode 设置:
| 模式 | 行为 |
|---|---|
bubble(Fork 默认) |
权限提示冒泡到主终端,你在主终端批准 |
acceptEdits |
自动允许文件操作 |
plan |
只能规划不能执行,等你确认 |
bypassPermissions |
全部自动批准 |
dontAsk |
全部自动拒绝 |
bubble 是 Fork 的默认模式——子 agent 想做危险操作时,你的主终端会弹出权限请求。
源码中的决策逻辑(runAgent.ts):
const shouldAvoidPrompts =
agentPermissionMode === 'bubble'
? false // bubble 模式:始终显示权限提示
: isAsync // 其他模式:后台 agent 自动避免提示
后台 agent 如果遇到需要审批的操作,会自动拒绝(因为你看不到)。想让后台 agent 自由操作,设置 permissionMode: acceptEdits 或 bypassPermissions。
7. 并行执行和实际上限
在一条消息中同时发起多个 Agent 调用,它们会并行执行:
"帮我同时做三件事:
1. 用 Explore agent 调研 auth 模块
2. 用 Explore agent 调研 payment 模块
3. 用 Explore agent 调研 notification 模块"
模型会在一次回复中生成三个 Agent tool_use,三个子 agent 同时启动。
源码中没有硬编码的 MAX_WORKERS 限制。但实际约束:
- API 并发请求数(取决于你的订阅/API key)
- 本地内存和 CPU——每个 agent 是一个独立的查询循环
- 远程 bridge 模式默认 32 个并发(
SPAWN_SESSIONS_DEFAULT = 32)
Anthropic 官方博客的实战建议:5-8 个并行 agent,每个负责 5-8 个文件。
一个 agent 有约 167K tokens 的工作空间。5 个并行 agent = 835K tokens 的总工作空间。对于大规模重构,这是从"线性处理"到"并行处理"的质变。
8. Agent Teams:让多个 Agent 互相对话
前面讲的 subagent 都是"主 agent 派活 → 子 agent 干活 → 返回结果"的单向模式。子 agent 之间互相看不到,也不能交流。
Agent Teams 是另一种模式——多个 agent 组成团队,共享任务列表,互相发消息讨论。
| Subagent | Agent Team | |
|---|---|---|
| 通信 | 只能向主 agent 汇报 | 队友之间直接消息 |
| 协调 | 主 agent 管理所有工作 | 共享任务列表,自协调 |
| 场景 | 只需要结果的聚焦任务 | 需要讨论和协作的复杂工作 |
| Token 成本 | 较低 | 较高(每个队友独立 context) |
一个实际例子——用竞争假设做调试:
用户反馈 app 在发一条消息后就退出了。
创建 5 个 agent 队友分别调查不同的假设。
让他们互相讨论、尝试推翻对方的理论,像科学辩论一样。
把共识写到 findings.md 里。
5 个 agent 独立调查各自的假设,然后互相质疑——"你说是 WebSocket 断开,但我查了连接日志没有断开记录,你的证据是什么?"这种对抗式调查比单 agent 线性排查更容易找到真正的根因。
目前是实验性功能,默认关闭。开启方式:
// settings.json
{
"env": {
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
}
}
架构组件:
- Team lead——主会话,创建团队、分配任务、综合结果
- Teammates——独立的 Claude Code 实例,各自有完整 context
- Task list——共享任务列表,支持 pending/in_progress/completed 和依赖关系
- Mailbox——agent 间的消息系统
显示模式两种:in-process(同一终端内,Shift+Down 切换队友)或 split panes(需要 tmux/iTerm2,每个队友独立窗格)。
几个限制:
- 一个 lead 只能管一个团队
- 队友不能再创建子团队
- session 恢复不支持 in-process 模式的队友
- 建议 3-5 个队友,每人 5-6 个任务
什么时候该用 Team 而不是 Subagent?当你需要队友之间互相讨论、质疑、协调时。如果只是"去干活然后告诉我结果",subagent 就够了,成本更低。
因篇幅限制,本文不在此处展开讲解,如需要,可以在评论区提一下,后面会单独开一篇
9. 实际怎么用
几个从源码设计意图推导出的使用模式:
大规模改动 → 并行 subagent + worktree
每个子 agent 在独立 worktree 里改自己那几个文件,互不干扰。完成后各自 commit,主 agent 汇总结果。这就是内置的 /batch skill 的底层原理。
需要验证 → 独立 subagent 做 review
实现完功能后,启动一个新 subagent 做 code review。为什么不用主 agent 自己 review?因为主 agent 在实现过程中形成了"这样是对的"的上下文偏见。独立 subagent 没有这个包袱,能更客观地审查。
长对话保持质量 → 拆成多个 agent 阶段
不要在一个 agent 里干到 context window 满。把任务拆成阶段:研究阶段用 Explore agent,规划阶段用 Plan agent,实现阶段用 General Purpose agent。每个阶段是独立的 context,不会互相污染。
快速搜索 → Explore agent
找文件、搜代码不需要启动重量级 agent。Explore 跑 Haiku,只读模式,不加载 CLAUDE.md,启动快、成本低。调用时可以指定 thoroughness 级别:quick(定向查找)、medium(平衡探索)、very thorough(全面分析)。
临时测试 → --agents CLI flag
不想创建文件,可以用 JSON 直接传临时 agent 定义,这个会话结束就消失:
claude --agents '{
"quick-reviewer": {
"description": "快速代码审查",
"prompt": "你是一个代码审查专家,只关注安全问题。",
"tools": ["Read", "Grep", "Glob"],
"model": "haiku"
}
}'
网友解答:
--【壹】--:
前排支持
--【贰】--:
前排学习,追更追更
--【叁】--:
干货啊,支持大佬
--【肆】--:
厉害厉害,学习了
--【伍】--:
真能学到东西,但太懒了不知道啥时候能学进去
--【陆】--:
Agent 中无法再生成subagent,这种有什么解么,有时候 skill接入上游的 pipline, 上游已经 spawn 成agent了,skill里的multi agent就被拍平了
--【柒】--:
太强了大佬,来学习一下
--【捌】--:
佬!入站的意义,全部都想起来了!
--【玖】--:
前排支持,学习!
--【拾】--:
学习了,基于源码的讲解,太透彻了
--【拾壹】--:
mark一下
--【拾贰】--:
题主这三篇帖子都认真看了,很有价值。感谢。
--【拾叁】--:
写的真棒,感谢佬的分享对日常使用有很大的帮助
--【拾肆】--:
已严肃学习并点赞佬的三个深入浅出教程 ,学到好多技巧,给上下文管理增加了很多方法学,也感叹A÷的技术和工程积累。
补充:
- 哈雷佬的指南里提到这个网站可以参考
鉴于没有推进SubAgent的内容,这里给到一个集合网站给予参考
- http://subagents.cc
- 风佬的CCG自带几个agents在~/.claude/agents/ccg
【补档】CCG v2.1.1 : Claude Code 编排三 CLI 协作 | Codex + Gemini + Claude | 加入多种实用skills
--【拾伍】--:
前排学习
--【拾陆】--:
点赞的人越来越少,充分说明了一件事,大部分人都是知识的搬运工,哈哈哈。
还是要写点自己的感悟供大家分享:
- 默认模式下,某些简单工作不用调用 agent,原文也指出了本身 agent 都是从空白开始工作,不如直接调用工具。
- 原来模型用量里面总是有 Haiku 是因为 Explore 默认用 Haiku,我还以为是设置问题。后续试试覆盖内置 Agent ,让 Explore 用 Sonnet 而不是 Haiku,不知道能否设置为 opus 4.6。
- 什么时候该用 Team 而不是 Subagent,这个其实蛮重要的,我记得我曾经看过 Claude 复刻 Linux 就是用了类似的模式吧,可见复杂任务还是需要这个功能的。
- 第九点实在是太重要了,解决了工作流程问题。
--【拾柒】--:
学习了,感谢佬的分享
--【拾捌】--:
支持支持
--【拾玖】--:
前排支持
今天来带各位佬友讲讲 agent,本文参考官方教学文档和 claudecode 源码而来
各位佬友抓紧把手,咱们直接发车
1. Agent 是什么:独立 context 的工作单元
一个 agent 就是一个独立的 Claude 会话——有自己的 context window、自己的对话历史、自己的工具集。
你平时跟 Claude Code 对话的那个就是"主 agent"。当你(或模型)调用 Agent 工具时,会创建一个子 agent。子 agent 在自己的 context window 里干活,完成后把结果返回给主 agent。

这里有一个关键区别:普通 subagent 从零开始,只有你传入的 prompt 字符串——你不写进去的信息,它看不到。而 Fork 模式继承父 agent 的完整对话历史——之前聊过什么它都知道,不需要你重复。
源码中子 agent 的 context 创建逻辑(utils/forkedAgent.ts):

function createSubagentContext(parentContext, overrides) {
return {
readFileState: cloneFileStateCache(...) // 独立的文件缓存
messages: override?.messages || [] // 普通 subagent:空;Fork:父 agent 的历史
agentId: override?.agentId || createAgentId() // 新 ID
queryTracking: { chainId, depth: parentDepth + 1 } // 深度 +1
}
}
不管哪种模式,每个子 agent 都有独立的文件缓存和 context window。这就是为什么用 agent 能解决长对话"忘事"——子 agent 不会被主 agent 之前对话的内容塞满。
2. 创建 Agent 时发生了什么
当模型调用 Agent 工具时,路径取决于有没有指定 subagent_type(tools/AgentTool/AgentTool.tsx):
Agent tool 调用
├─ 指定了 subagent_type(如 Explore、Plan)→ 用该类型的定义从零开始
├─ 没指定 + Fork 功能开启 → Fork(继承父 agent 的完整对话历史)
└─ 没指定 + Fork 未开启 → General Purpose Agent
日常使用中你接触到的主要是第一种。大部分时候是模型自动调用的——你说"帮我调研一下 auth 模块",Claude 自己判断该用 Explore agent,自动写 prompt、自动派遣,你不需要手动操作。
但不管是自动还是手动触发,子 agent 都是从空白开始工作。主 agent 传给它的 prompt 是它唯一的上下文——主 agent 之前跟你的对话历史、已经读过的文件,子 agent 统统看不到。
这也是为什么你有时候觉得 subagent 的结果不够好——主 agent 写给子 agent 的 prompt 可能没带足够的背景信息。你可以在对话中显式补充:“帮我调研 auth 模块,我们用的是 JWT + Redis session,入口在 src/auth/middleware.ts”,这样主 agent 传给子 agent 的 prompt 会包含这些关键信息。
Fork 模式(feature flag 控制,可能未对外开放)
Fork 是"复制一个分身"——子 agent 继承父 agent 的完整对话历史和 system prompt。你不需要重复背景信息。
源码中 fork 的启用条件(forkSubagent.ts):
function isForkSubagentEnabled(): boolean {
if (feature('FORK_SUBAGENT')) { // 编译时 feature flag
if (isCoordinatorMode()) return false
if (getIsNonInteractiveSession()) return false
return true
}
return false
}
feature('FORK_SUBAGENT') 是编译时常量。如果你从来没感知过 fork,大概率是这个 flag 在当前版本中未开启——整个 fork 路径会被 dead code elimination 删掉。
Fork 还有一个成本优势:复用父 agent 的 system prompt(byte-exact 相同),prompt cache 直接命中,50K tokens 的上下文走 cache read 成本约 1/10。但因为功能可能未开放,这里不展开。
3. 三种内置 Agent
| Agent | 模型 | 工具 | 用途 |
|---|---|---|---|
| Explore | 普通用户: Haiku / Anthropic 员工: 继承主模型 | 只读(Read, Grep, Glob) | 搜代码、找文件、回答 codebase 问题 |
| Plan | 继承主模型 | 只读 | 架构设计、实现方案规划 |
| General Purpose | 继承主模型 | 全部 | 复杂多步骤任务 |
官方文档说 Explore 在需要搜索或理解代码库时被自动委派,调用时分三个 thoroughness 级别:quick(定向查找)、medium(平衡探索)、very thorough(全面分析)。
两个源码级的细节官方没提:
你用的 Explore 默认跑 Haiku,Anthropic 员工跑的是主模型。 源码(built-in/exploreAgent.ts):
model: process.env.USER_TYPE === 'ant' ? 'inherit' : 'haiku'
USER_TYPE === 'ant' 是 Anthropic 内部员工标识。也就是说同样的 Explore agent,他们跑 Opus/Sonnet,你跑 Haiku。Haiku 更快更便宜,但推理能力弱一些。如果你觉得 Explore 给的结果太浅,可以用自定义 agent 覆盖它(后面第 4 节讲怎么做)。
Explore 跳过 CLAUDE.md。 设置了 omitClaudeMd: true——探索型 agent 不需要你的 commit 规范和代码风格规则,省掉这些 token,把空间留给代码内容。
4. 自定义 Agent
两种方式创建:
交互式——输入 /agents,选 Create new agent,可以让 Claude 根据你的描述自动生成定义。选工具、选模型、选颜色,保存就生效。
手动建文件——在 .claude/agents/ 下创建 .md 文件。frontmatter 是配置,正文是 system prompt:
---
name: code-reviewer
description: 审查代码变更,关注安全和性能
tools: Read, Grep, Glob, Bash(git diff:*)
model: sonnet
maxTurns: 15
---
你是一个代码审查专家。收到审查请求后:
1. 用 git diff 查看所有变更
2. 逐文件检查安全漏洞、性能问题、错误处理
3. 给出结构化审查意见
几个关键字段:
description — 不只是文档。Claude 会根据这个描述自动判断何时委派任务给这个 agent。写得模糊就不会被自动调用。
tools — 硬限制,不是建议。源码中 tools 字段被解析为严格白名单(agentToolUtils.ts:resolveAgentTools)——不在列表里的工具对 agent 来说不存在。而且支持内联权限规则:
tools: "Read, Grep, Bash(git diff:*), Agent(Explore)"
Bash(git diff:*) = 只能执行 git diff 开头的命令。Agent(Explore) = 只能派遣 Explore 类型的子 agent。
model — inherit 继承主模型,或指定 sonnet/opus/haiku。
isolation: worktree — 在独立的 git worktree 中运行。完成后无变更自动清理,有变更保留 worktree 和分支。
background: true — 始终后台运行,不阻塞主对话。
memory: project — 给 agent 独立的记忆空间,存在 .claude/agent-memory/{agent-type}/。code-reviewer 的记忆不会和 code-writer 的混在一起。
覆盖内置 Agent
同名 agent 高优先级覆盖低优先级:
企业策略 > 项目 .claude/agents/ > 用户 ~/.claude/agents/ > 插件 > 内置
想让 Explore 用 Sonnet 而不是 Haiku?创建 .claude/agents/Explore.md:
---
name: Explore
description: 快速探索代码库,搜索文件和代码模式
model: sonnet
---
5. 子 Agent 能用什么工具、不能用什么
源码中有三个工具集控制子 agent 的能力边界:
子 agent 禁止使用的工具(constants/tools.ts):
const ALL_AGENT_DISALLOWED_TOOLS = new Set([
TASK_OUTPUT_TOOL_NAME, // 防止递归
EXIT_PLAN_MODE_V2_TOOL_NAME, // 计划模式是主线程的抽象
ENTER_PLAN_MODE_TOOL_NAME, // 同上
ASK_USER_QUESTION_TOOL_NAME, // 需要主线程的用户交互
TASK_STOP_TOOL_NAME, // 需要主线程的状态访问
// 外部用户禁止嵌套 agent:
...(process.env.USER_TYPE === 'ant' ? [] : [AGENT_TOOL_NAME]),
])
最后一行:外部用户的 AGENT_TOOL_NAME 被加入禁止列表。外部用户的子 agent 不能再创建子 agent,架构只能是一层。Anthropic 内部用户(ant)不受此限制。
后台 agent 允许的工具(constants/tools.ts)——范围更窄:
const ASYNC_AGENT_ALLOWED_TOOLS = new Set([
FILE_READ_TOOL_NAME, GREP_TOOL_NAME, GLOB_TOOL_NAME,
WEB_SEARCH_TOOL_NAME, WEB_FETCH_TOOL_NAME,
...SHELL_TOOL_NAMES, // Bash, PowerShell
FILE_EDIT_TOOL_NAME, FILE_WRITE_TOOL_NAME,
NOTEBOOK_EDIT_TOOL_NAME, SKILL_TOOL_NAME,
TOOL_SEARCH_TOOL_NAME,
ENTER_WORKTREE_TOOL_NAME, EXIT_WORKTREE_TOOL_NAME,
])
注意 ASK_USER_QUESTION 不在列表里——后台 agent 不能问你问题,因为它在后台跑,你看不到他。
6. 权限怎么处理
子 agent 需要执行删除文件、运行危险命令等操作时,权限提示怎么办?
取决于 permissionMode 设置:
| 模式 | 行为 |
|---|---|
bubble(Fork 默认) |
权限提示冒泡到主终端,你在主终端批准 |
acceptEdits |
自动允许文件操作 |
plan |
只能规划不能执行,等你确认 |
bypassPermissions |
全部自动批准 |
dontAsk |
全部自动拒绝 |
bubble 是 Fork 的默认模式——子 agent 想做危险操作时,你的主终端会弹出权限请求。
源码中的决策逻辑(runAgent.ts):
const shouldAvoidPrompts =
agentPermissionMode === 'bubble'
? false // bubble 模式:始终显示权限提示
: isAsync // 其他模式:后台 agent 自动避免提示
后台 agent 如果遇到需要审批的操作,会自动拒绝(因为你看不到)。想让后台 agent 自由操作,设置 permissionMode: acceptEdits 或 bypassPermissions。
7. 并行执行和实际上限
在一条消息中同时发起多个 Agent 调用,它们会并行执行:
"帮我同时做三件事:
1. 用 Explore agent 调研 auth 模块
2. 用 Explore agent 调研 payment 模块
3. 用 Explore agent 调研 notification 模块"
模型会在一次回复中生成三个 Agent tool_use,三个子 agent 同时启动。
源码中没有硬编码的 MAX_WORKERS 限制。但实际约束:
- API 并发请求数(取决于你的订阅/API key)
- 本地内存和 CPU——每个 agent 是一个独立的查询循环
- 远程 bridge 模式默认 32 个并发(
SPAWN_SESSIONS_DEFAULT = 32)
Anthropic 官方博客的实战建议:5-8 个并行 agent,每个负责 5-8 个文件。
一个 agent 有约 167K tokens 的工作空间。5 个并行 agent = 835K tokens 的总工作空间。对于大规模重构,这是从"线性处理"到"并行处理"的质变。
8. Agent Teams:让多个 Agent 互相对话
前面讲的 subagent 都是"主 agent 派活 → 子 agent 干活 → 返回结果"的单向模式。子 agent 之间互相看不到,也不能交流。
Agent Teams 是另一种模式——多个 agent 组成团队,共享任务列表,互相发消息讨论。
| Subagent | Agent Team | |
|---|---|---|
| 通信 | 只能向主 agent 汇报 | 队友之间直接消息 |
| 协调 | 主 agent 管理所有工作 | 共享任务列表,自协调 |
| 场景 | 只需要结果的聚焦任务 | 需要讨论和协作的复杂工作 |
| Token 成本 | 较低 | 较高(每个队友独立 context) |
一个实际例子——用竞争假设做调试:
用户反馈 app 在发一条消息后就退出了。
创建 5 个 agent 队友分别调查不同的假设。
让他们互相讨论、尝试推翻对方的理论,像科学辩论一样。
把共识写到 findings.md 里。
5 个 agent 独立调查各自的假设,然后互相质疑——"你说是 WebSocket 断开,但我查了连接日志没有断开记录,你的证据是什么?"这种对抗式调查比单 agent 线性排查更容易找到真正的根因。
目前是实验性功能,默认关闭。开启方式:
// settings.json
{
"env": {
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
}
}
架构组件:
- Team lead——主会话,创建团队、分配任务、综合结果
- Teammates——独立的 Claude Code 实例,各自有完整 context
- Task list——共享任务列表,支持 pending/in_progress/completed 和依赖关系
- Mailbox——agent 间的消息系统
显示模式两种:in-process(同一终端内,Shift+Down 切换队友)或 split panes(需要 tmux/iTerm2,每个队友独立窗格)。
几个限制:
- 一个 lead 只能管一个团队
- 队友不能再创建子团队
- session 恢复不支持 in-process 模式的队友
- 建议 3-5 个队友,每人 5-6 个任务
什么时候该用 Team 而不是 Subagent?当你需要队友之间互相讨论、质疑、协调时。如果只是"去干活然后告诉我结果",subagent 就够了,成本更低。
因篇幅限制,本文不在此处展开讲解,如需要,可以在评论区提一下,后面会单独开一篇
9. 实际怎么用
几个从源码设计意图推导出的使用模式:
大规模改动 → 并行 subagent + worktree
每个子 agent 在独立 worktree 里改自己那几个文件,互不干扰。完成后各自 commit,主 agent 汇总结果。这就是内置的 /batch skill 的底层原理。
需要验证 → 独立 subagent 做 review
实现完功能后,启动一个新 subagent 做 code review。为什么不用主 agent 自己 review?因为主 agent 在实现过程中形成了"这样是对的"的上下文偏见。独立 subagent 没有这个包袱,能更客观地审查。
长对话保持质量 → 拆成多个 agent 阶段
不要在一个 agent 里干到 context window 满。把任务拆成阶段:研究阶段用 Explore agent,规划阶段用 Plan agent,实现阶段用 General Purpose agent。每个阶段是独立的 context,不会互相污染。
快速搜索 → Explore agent
找文件、搜代码不需要启动重量级 agent。Explore 跑 Haiku,只读模式,不加载 CLAUDE.md,启动快、成本低。调用时可以指定 thoroughness 级别:quick(定向查找)、medium(平衡探索)、very thorough(全面分析)。
临时测试 → --agents CLI flag
不想创建文件,可以用 JSON 直接传临时 agent 定义,这个会话结束就消失:
claude --agents '{
"quick-reviewer": {
"description": "快速代码审查",
"prompt": "你是一个代码审查专家,只关注安全问题。",
"tools": ["Read", "Grep", "Glob"],
"model": "haiku"
}
}'
网友解答:
--【壹】--:
前排支持
--【贰】--:
前排学习,追更追更
--【叁】--:
干货啊,支持大佬
--【肆】--:
厉害厉害,学习了
--【伍】--:
真能学到东西,但太懒了不知道啥时候能学进去
--【陆】--:
Agent 中无法再生成subagent,这种有什么解么,有时候 skill接入上游的 pipline, 上游已经 spawn 成agent了,skill里的multi agent就被拍平了
--【柒】--:
太强了大佬,来学习一下
--【捌】--:
佬!入站的意义,全部都想起来了!
--【玖】--:
前排支持,学习!
--【拾】--:
学习了,基于源码的讲解,太透彻了
--【拾壹】--:
mark一下
--【拾贰】--:
题主这三篇帖子都认真看了,很有价值。感谢。
--【拾叁】--:
写的真棒,感谢佬的分享对日常使用有很大的帮助
--【拾肆】--:
已严肃学习并点赞佬的三个深入浅出教程 ,学到好多技巧,给上下文管理增加了很多方法学,也感叹A÷的技术和工程积累。
补充:
- 哈雷佬的指南里提到这个网站可以参考
鉴于没有推进SubAgent的内容,这里给到一个集合网站给予参考
- http://subagents.cc
- 风佬的CCG自带几个agents在~/.claude/agents/ccg
【补档】CCG v2.1.1 : Claude Code 编排三 CLI 协作 | Codex + Gemini + Claude | 加入多种实用skills
--【拾伍】--:
前排学习
--【拾陆】--:
点赞的人越来越少,充分说明了一件事,大部分人都是知识的搬运工,哈哈哈。
还是要写点自己的感悟供大家分享:
- 默认模式下,某些简单工作不用调用 agent,原文也指出了本身 agent 都是从空白开始工作,不如直接调用工具。
- 原来模型用量里面总是有 Haiku 是因为 Explore 默认用 Haiku,我还以为是设置问题。后续试试覆盖内置 Agent ,让 Explore 用 Sonnet 而不是 Haiku,不知道能否设置为 opus 4.6。
- 什么时候该用 Team 而不是 Subagent,这个其实蛮重要的,我记得我曾经看过 Claude 复刻 Linux 就是用了类似的模式吧,可见复杂任务还是需要这个功能的。
- 第九点实在是太重要了,解决了工作流程问题。
--【拾柒】--:
学习了,感谢佬的分享
--【拾捌】--:
支持支持
--【拾玖】--:
前排支持
