教程Claude Code系列第 5 / 8 篇

Claude Code 代理团队实战:让三个队友互相质疑着审同一段代码

代理团队是一项实验功能:一个会话当组长,开出几个各有独立上下文的队友,队友之间能直接互发消息。本站实测了一个三人的评审团队:三个队友互发了 20 条消息,推翻了组长清单里的一条错误结论。也记下了协调上的毛病:有人没等别人的发现就交了报告,行号要组长复核。整个会话估算 1.51 美元。

发布 · 约 12 分钟读完 · 经人工审核()· 本站的内容怎么来的

本站已实测,测试日期:2026-10-12。

本页目录(12 节)
  1. 什么时候用它,什么时候不用
  2. 打开这个功能
  3. 开一个团队
  4. 看队友在干什么,直接和它说话
  5. 这次评审的经过
  6. 协调上的毛病
  7. 关掉队友
  8. 花了多少
  9. 几条实用的建议
  10. 已知的限制
  11. 这次实测没有覆盖到的
  12. 下一步

这篇教程解决一个问题:一件事想让几个 Claude 同时从不同角度去做,而且希望它们互相看对方的结论、互相挑错,该怎么组织。

子代理能把活分出去,但每个子代理只向派它的主对话汇报,彼此不说话。worktree 能同时开几个会话,但它们互不知道对方的存在。代理团队(agent teams)补的是这一块:一个会话当组长,开出几个队友,每个队友是一个独立的 Claude Code 实例,有自己的上下文,队友之间可以直接互发消息,你也可以绕过组长直接和某个队友说话。

先说清楚它的状态:官方文档写明这是实验功能,默认关闭,在恢复会话、任务协调、关闭这几处有已知的限制。

本站用它做了一次三人的代码评审,下面是全过程。

实测环境
日期 2026-10-12
版本 Claude Code 2.1.296
系统 Ubuntu 24.04
模型 组长 Opus 5.5,三个队友 Sonnet 5.5
连接方式 通过酷站AI 中转站,不是直连官方
示例仓库 Express 的源码,v5.3.0。这次克隆下来没有装依赖,所以测试跑不了,评审全靠读代码

什么时候用它,什么时候不用

和子代理的区别,官方文档的对照:

子代理 代理团队
上下文 各自独立,结果交回给派它的一方 各自独立,完全自主
沟通 把结果交回去 队友之间直接互发消息
协调 主对话管所有的事 靠消息自己协调,另有一份共享的任务清单
适合 只要结果的、目标明确的活 需要讨论和配合的复杂工作
花费 较低 较高,每个队友都是一个完整的实例

文档列的几类合适的任务:调研和评审(几个人各看一面,再互相质疑)、各管一块的新模块、用几个互相竞争的假设去查一个 bug、跨前端后端和测试的改动。

不合适的:有先后顺序的任务、要改同一个文件的任务、互相依赖很多的任务。这些用一个会话或者子代理更有效。文档的原话是,代理团队有协调的开销,token 用得明显更多。

第一次用,文档建议从不写代码的任务开始:审一个 PR、调研一个库、查一个 bug。我们照这个建议选了评审。

打开这个功能

设一个环境变量。只想这一次用,启动时带上:

CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 claude

想一直开着,写进 settings.json:

{
  "env": {
    "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
  }
}

两条要知道的,来自官方文档:

  • 打开之后,普通的委派也会变。 Claude 有时会自己给子代理起名字;这个功能开着的时候,有名字的子代理会作为队友启动。所以你没要求组队,也可能冒出一个团队来。不想要这种行为,把变量设回 0。
  • 只在交互式会话里有效。 claude -p 不会开队友,有名字的子代理在那里照旧当普通的子代理跑。

开一个团队

不需要任何配置文件,用一段话说清楚要几个队友、各管什么、怎么配合:

组一个代理团队,评审 lib/response.js 里 res.sendFile 的实现和 test/res.sendFile.js 里它的测试。
开三个队友,都用 Sonnet,名字分别叫 security、errors、coverage:
security 看安全问题(路径穿越、root 选项、点文件);
errors 看错误处理(回调什么时候被调用、连接中断、文件不存在);
coverage 看测试有没有漏掉重要的行为。
只读代码,谁都不要改文件。每个队友得出发现之后,发给另外两个队友,请他们质疑。
最后由你汇总成一份不超过八条的清单,每条写明文件和行号,并标出哪些是两个以上队友都认同的。

这段话里有几处是照着官方的建议写的:

  • 给每个队友起名字。 之后要点名某个队友、或者让队友之间互相找,都靠名字。
  • 每人一个不重叠的角度。 文档解释过为什么:一个评审者容易盯着一类问题看,分开之后安全、错误处理、测试覆盖才都能看透。
  • 指定模型。 队友用 Sonnet,组长用 Opus,省一些。
  • 把背景写进这段话。 队友会自动加载项目的 CLAUDE.md、MCP 服务器和 skill,但不继承组长的对话历史,它知道的只有组长开它时给的那段话。

发出去之后:

● 3 background agents launched (↓ to manage)
   ├ @security
   ├ @errors
   └ @coverage

● 三个队友(security、errors、coverage,都用 Sonnet)已经开始工作,全部只读。每个人得出发现后
  会发给另外两人,请他们质疑。三份最终报告都到齐后,我会核对行号,再汇总成不超过八条的清单。

输入框下面多出一个面板,列着组长和三个队友,各自的用时和用量在跳:

  ● main
  ◯ security  Security review of sendFile                    17s · ↓ 21.0k tokens
  ◯ errors    Error-handling review of sendFile              13s · ↓ 20.7k tokens
  ◯ coverage  Test coverage review of sendFile                7s · ↓ 19.4k tokens

确认开出来的真是团队

官方文档提醒:Claude 有时会用普通的子代理代替团队,而子代理也出现在同一个面板里,光看面板分不出来。

可以看团队的配置文件。它在 ~/.claude/teams/ 下,以“session-”加会话 ID 的前八位命名:

{
  "name": "session-60aa4fe0",
  "members": [
    {"name": "team-lead", "agentType": "team-lead"},
    {"name": "security", "agentType": "general-purpose", "model": "sonnet"},
    {"name": "errors", "agentType": "general-purpose", "model": "sonnet"},
    {"name": "coverage", "agentType": "general-purpose", "model": "sonnet"}
  ]
}

有这个文件,成员里有 team-lead,就是团队。文档说明这个文件是运行时的状态,不要手改,也不要事先写好放在那里,会被覆盖。

看队友在干什么,直接和它说话

面板的操作:

按键 作用
↓ 把焦点从输入框移到面板
↑ ↓ 在面板里选
Enter 打开选中的那个的会话
Esc 取消选中。正在看某个队友的会话时,Esc 会打断它当前这一轮

选中 security 回车,屏幕换成了它的会话:最上面是一条 Message from @team-lead,下面是它在读代码、跑 grep,输入框的提示变成了 Message @security…。

在这里打字,消息直接发给这个队友,不经过组长。我们补了一个要求:

❯ 补充一个要求:也确认一下 dotfiles 选项的默认值是什么,写进你的发现里。

它当时正忙,面板上这一行显示 1 queued,表示消息排着队。后来它的报告里有了这一条:

● Teammate @security finished
  默认值:`dotfiles` 的默认值是 `'ignore'`,也就是对 dotfile 返回 404。依据是 `send/index.js:114-116`,
  选项为 `undefined` 时取 `'ignore'`。

要回到组长的会话,按 ↓ 把焦点移到面板,选中 main 回车。不要按 Esc 退出来,那会打断队友正在做的事。

官方文档还有一种显示方式:每个队友占一个独立的窗格,要在 tmux 或 iTerm2 里用,启动时加 --teammate-mode auto。我们用的是默认的方式,没有试窗格。

这次评审的经过

整个过程 7 分钟出头。组长的会话里陆续出现队友交回的报告,中间有几件事值得记下来。

队友之间确实在互相说话

我们从会话记录里数了发消息的次数(只数了调用,没看内容):

谁发的 发给谁 条数
security errors、coverage 各 4 条
errors security、coverage 各 3 条
coverage security、errors 各 3 条
coverage 组长 1 条
组长 三个队友 共 4 条

队友之间一共 20 条。这是子代理做不到的。

一条错误的结论被推翻了

这是这次最能说明团队价值的一幕。组长先给过一版清单,第一条是:encodeURI 不编码 %,所以文件名里带 % 的文件会返回 400。

coverage 没有接受这个说法,自己用 node 跑了一下。security 和 errors 随后复核,security 撤回了它原来的那条发现。组长自己也重跑了一遍:

● Bash(node -e "console.log(encodeURI('/a/100%.txt'), encodeURI('/a/%2e%2e%2f'))")
  ⎿  /a/100%25.txt /a/%252e%252e%252f

● 我之前给你的清单第 1 条是错的,需要撤回。那条说"encodeURI 不编码 %,所以文件名带 % 的文件会
  返回 400"。coverage 用 node 实测推翻了它,security 和 errors 随后确认,我自己也跑了一遍:
  encodeURI('/a/100%.txt') 得到的是 /a/100%25.txt。……这一条只剩"给特殊字符文件名补回归测试"
  的价值,优先级低,不再列入。

如果只有一个评审者,这条看上去很有道理的结论多半就留在清单里了。官方文档讲“互相竞争的假设”那个用例时说的就是这件事:一个代理找到一个说得通的解释就容易停下,几个独立的调查者互相找茬,留下来的结论才更可能是对的。

最后的清单

组长汇总的八条,每条有位置,并标了谁认同(节选):

│ 1 │ lib/response.js:404          │ opts.etag = this.app.enabled('etag') 直接改写调用者传入的
│   │                              │ options 对象,还会覆盖用户自己设的 etag。没有测试覆盖。    │ 三人 │
│ 3 │ lib/response.js:413          │ 没传回调时,ECONNABORTED 和 syscall === 'write' 的错误被
│   │                              │ 直接吞掉,不交给 next。……但没有测试锁定这个行为。          │ 三人 │
│ 4 │ test/res.sendFile.js:845-899 │ root 选项的测试只有 ../ 两种情况。缺少:%2e%2e%2f 编码穿越、
│   │                              │ %00 空字节、root 下的点文件、符号链接逃出 root……          │ 三人 │
│ 8 │ lib/response.js:379          │ 函数入口取的是 req.next。在 router 之外调用、又没传回调时,
│   │                              │ next 是 undefined,一出错就会抛 TypeError。严重性低。      │ errors、security │

八条里六条三人都认同,两条两人认同。它还单独列了“讨论中确认没问题”的结论和“被降级、没有列入”的几条,并说明没有发现可以利用的安全漏洞。

这份清单我们没有逐条去验证结论对不对。行号抽查了四处(lib/response.js 的 379、404、410、413 行),都和清单里写的代码对得上。

协调上的毛病

团队不是开出来就自己转得很顺。这次看到的几处:

有人没等别人的发现就交了报告。 errors 第一个交,交的时候还没收到另外两人的质疑。security 交的时候更直接:

● Teammate @security finished
  没有收到 errors 和 coverage 的回应,所以下面每条发现的队友意见都是"未回复"。

● security 交报告时,errors 和 coverage 的发现还没送到它那里。我让三人补上这一轮互相质疑。

组长发现了,要求补一轮。三个队友都是各干各的,谁先做完谁先交,“互相质疑”这一步要靠组长盯着才真的发生。

队友给的行号不准。 组长核对之后自己说的:

● errors 这次给的两处行号更正也不对,正确位置是 !path 在 lib/response.js:382、opts.etag 在 :404。
  汇总时我会按实际行号写。

我们在提示词里要求了“每条写明文件和行号”,组长因此去复核了。没有这一步,错的行号会直接进最终的清单。

报告太长被截断。 有一次队友的报告超过了长度上限:

● Teammate @errors finished
  [result truncated — this drain's results exceeded 16000 characters; ask the agent for it via SendMessage]

同一个队友反复“finished”。 每个队友都交了好几次“最终报告”,每收到一轮质疑就更新一次。组长要分辨哪一版才算数。

有队友跑到项目外面去了。 这个仓库没装依赖,security 想看 send 这个包的源码,就到服务器上另一个目录的 node_modules 里去读了。auto 模式下没有人拦它。这在我们的示例环境里无害,但说明队友和组长一样,活动范围取决于权限设置,不取决于你以为的“项目目录”。

出过一次接口报错。 security 中途显示过 API error · Retrying in 8s · attempt 2/10,重试之后恢复了,没有影响结果。原因我们没有查。

官方文档列的已知问题里,和这些对得上的有:任务状态可能滞后、队友遇到错误可能停下而不是恢复、组长有时会不等队友就自己动手或者过早认为事情做完了。文档给的应对都是一句话的事:告诉组长“等队友做完再继续”或者“继续”。

关掉队友

点名让它关:

❯ 请 coverage 队友关闭。

│ coverage has shut down.

组长发的是一个关闭请求,队友可以同意,也可以拒绝并说明理由。

整个会话退出之后,我们看了一下留下了什么:~/.claude/teams/ 下这个团队的目录被删掉了,~/.claude/tasks/ 下同名的目录还在。这和文档的说法一致:团队配置随会话结束清理,任务清单留在本地,按会话记录同样的保留期限清理。

花了多少

  Total cost:            $1.51
  Total duration (API):  12m 26s
  Total duration (wall): 7m 9s
  Usage by model:
       claude-opus-5-5:  50 input, 9.9k output, 875.3k cache read, 73.0k cache write ($0.74)
     claude-sonnet-5-5:  128 input, 38.3k output, 1.5m cache read, 96.7k cache write ($0.77)

两个数放在一起看:模型一共工作了 12 分 26 秒,实际只过了 7 分 9 秒,差出来的就是并行省下的时间。三个 Sonnet 队友合计 0.77 美元,组长一个人 0.74 美元,组长花在协调、复核和汇总上的并不比队友少。

这是 Claude Code 按官方价格估算的数字,不是中转站实际扣的金额。作为对照,子代理那篇里一个评审员审一个测试文件,整个会话是 0.36 到 0.63 美元。团队贵在每个队友都是一个完整的实例,而且消息来回的每一轮都要再读一遍上下文。

官方文档关于规模的建议:多数情况从 3 到 5 个队友开始;token 的花费随人数线性增长;三个目标明确的队友,往往比五个各自为战的强。

几条实用的建议

来自官方文档,加上这次的体会:

  • 要它们互相质疑,就在提示词里写明,并且要求组长在所有人都回应之后再汇总。 这次没写后半句,结果多跑了一轮。
  • 要求结论带文件和行号,组长才有东西可以复核。
  • 两个队友不要改同一个文件。 文档说那样会互相覆盖。这次是只读的任务,没有这个问题。要动手改的任务,按文件把活分开。
  • 不要放着不管。 隔一会儿进某个队友的会话看一眼,方向不对就直接跟它说。
  • 权限的确认会冒到组长这里来。 队友沿用组长的权限模式。用 Manual 模式的话,三个队友的确认框都在组长的会话里弹,很烦。文档建议先在权限设置里把常用的操作预先批准。
  • 可以用子代理的定义当队友的角色。 在 .claude/agents/ 里定义过的角色(比如只读的评审员),开队友时说“用某某类型开一个队友”就能复用,它的工具限制和模型都会带过去。这个我们没有试。

已知的限制

官方文档列的,选几条最容易碰到的:

  • 恢复会话不会把队友带回来。 /resume 和 /rewind 之后,组长可能还在给已经不存在的队友发消息。告诉它重新开。
  • 一个会话只有一个团队,不能跨会话共用。
  • 队友不能再开队友,只有组长能管理团队。
  • 组长是固定的,不能把某个队友提成组长。
  • 权限模式在开队友时不能单独指定,开出来之后可以逐个改。

这次实测没有覆盖到的

  • 只做了只读的评审。 几个队友同时改代码的情况没有试,那里的文件冲突和任务认领才是协调最难的部分。
  • 共享的任务清单没有用上。 任务目录在整个过程中是空的,这次的协调全靠消息。
  • 独立窗格的显示方式、用子代理定义开队友、让队友先出计划、TeammateIdle 这类 hook 都没有试。
  • 清单的八条结论没有逐条验证。
  • 仓库没有装依赖,所以没有一个队友能跑测试,结论都来自读代码。这是我们准备环境时的疏忽,不是功能的限制。
  • 只跑了一次。 队友什么时候交报告、互相发多少条消息,每次都会不一样。
  • 通过中转站跑多模型的团队只验证了这一次。 组长和队友用不同的模型,除了一次自动恢复的接口报错,没有遇到问题。

下一步

来源

通过 API 中转站使用这些模型?到 Veridrop 免费检测中转站给你的是不是它声称的模型,或者看看中转站排行榜前 100 名。

相关文章