多 Agent 协作不是简单的"同时启动几个模型"。
当你让多个 Agent 一起完成一个复杂项目时,真正的问题不是它们能不能同时运行,而是如何让它们像一支团队那样工作:有明确的组织架构、共享的任务状态、可靠的消息通道,以及完整的生命周期管理------从创建到运行再到最终的清理。
Claude Code 的 Agent Teams 解决的就是这个问题。它不是单一功能,而是一套贯穿多 Agent 协作完整生命周期的机制:
- 团队容器(Team)------划定协作边界,建立成员归属
- 成员身份(Teammate)------区别于普通 subagent 的长期运行实体
- 共享任务表(Task List)------记录任务状态、归属和依赖关系
- 消息通道(Mailbox)------成员间的异步通信机制
- 生命周期管理------从创建、运行到最终清理的完整闭环
注意,teammate 和普通 subagent 的关键区别:
- teammate 在同一个 Node.js 进程内长期运行,通过独立的上下文实现隔离,而非任务结束即销毁。这让多个 Agent 能像一个团队一样持续协作。
- subagent 运行完成后立即销毁
理解 Agent Teams,不应把它当作"功能列表"来记忆,而是跟随一条 Agent Team 从创建、运行到最终清理的完整生命周期,看清每个环节如何衔接。

1. 核心概念
在深入实现之前,先明确几个关键概念:
| 概念 | 定位 | 类比 |
|---|---|---|
| team | 团队容器,划定协作边界 | 项目组 |
| teammate | 团队中的成员身份 | 项目组成员 |
| Task List | 共享任务表,记录任务状态和归属 | 项目看板 |
| mailbox | 消息通道,在成员之间传递通知 | 团队群聊/通知 |
| runner | 管理 teammate 生命周期的代码层(非独立进程) | 项目经理(协调者) |
关键区分:
- team vs teammate:team 是容器,teammate 是成员。一个 team 可以有多个 teammate。
- Task List vs mailbox:Task List 是"状态事实",mailbox 是"消息通知"。前者解决"任务归谁",后者解决"告诉谁"。
- teammate vs runner:teammate 是执行任务的 agent,runner 是管理 teammate 生命周期的代码层。runner 负责启动、idle 循环、接收消息、传递 prompt。
2. 创建团队容器
Agent Teams 的生命周期从 TeamCreate 工具开始。这是一个真实的内置工具,定义在 src/tools/TeamCreateTool/TeamCreateTool.ts。
2.1 工具注册:从全局声明到具体实现
TeamCreateTool 通过懒加载注册到全局工具列表,避免循环依赖:
ts
// src/tools.ts
const getTeamCreateTool = () =>
require('./tools/TeamCreateTool/TeamCreateTool.js').TeamCreateTool;
// 条件启用:仅当 Agent Swarms 功能开启时注册
const allTools = [
// ... 其他工具
...(isAgentSwarmsEnabled() ? [getTeamCreateTool(), getTeamDeleteTool()] : []),
// ...
];
它不是一个独立进程或外部服务,而是 Claude Code 内置的 buildTool 实现:
ts
// src/tools/TeamCreateTool/TeamCreateTool.ts
export const TeamCreateTool: Tool<InputSchema, Output> = buildTool({
name: 'TeamCreate',
searchHint: 'create a multi-agent swarm team',
shouldDefer: true, // 让模型优先决定是否调用
isEnabled() {
return isAgentSwarmsEnabled();
},
async description() {
return 'Create a new team for coordinating multiple agents';
},
async validateInput(input) {
/* team_name 必填校验 */
},
async call(input, context) {
/* 核心逻辑 */
},
});
buildTool 是 Claude Code 的工具构造器,负责统一处理输入校验、输出格式化、权限检查等通用逻辑。TeamCreateTool 通过实现 call 方法注入具体的团队创建逻辑。
TeamCreateTool 会被 当前 Agent 调用,模型根据上下文决定是否需要创建团队:
ts
TeamCreateTool.call({
team_name: "my-team", // 团队名称(必填)
description: "...", // 可选描述
agent_type: "researcher" // leader 角色类型(可选)
}, context)
注意两个限制:
- 一个 leader 只能管理一个 team,如果已在团队中再次调用会报错
- teammate 不能调用------只有非 teammate 身份的 Agent 才能创建团队
2.2 核心实现:写入配置、准备 Task List、更新运行时状态
call 方法内部做了五件事:
ts
async call(input, context) {
const { setAppState, getAppState } = context
const { team_name, description, agent_type } = input
// 1. 限制:一个 leader 只能管理一个 team
const existingTeam = getAppState().teamContext?.teamName
if (existingTeam) {
throw new Error('A leader can only manage one team at a time...')
}
// 2. 生成唯一 team name(名称冲突时自动生成新的)
const finalTeamName = generateUniqueTeamName(team_name)
// 3. 写入团队配置到 ~/.claude/teams/{team-name}/config.json
const teamFile: TeamFile = {
name: finalTeamName,
description,
createdAt: Date.now(),
leadAgentId: formatAgentId(TEAM_LEAD_NAME, finalTeamName),
leadSessionId: getSessionId(),
members: [{
agentId: leadAgentId,
name: TEAM_LEAD_NAME,
agentType: leadAgentType,
model: leadModel,
joinedAt: Date.now(),
cwd: getCwd(),
subscriptions: [],
}],
}
await writeTeamFileAsync(finalTeamName, teamFile)
// 4. 准备空的共享 Task List
const taskListId = sanitizeName(finalTeamName)
await resetTaskList(taskListId)
await ensureTasksDir(taskListId)
// 5. 绑定 leader 到 team Task List,后续任务写入共享表
setLeaderTeamName(taskListId)
// 6. 更新 AppState 运行时团队状态
setAppState(prev => ({ ...prev, teamContext: { teamName: finalTeamName, ... } }))
// ...
}
这段代码做了五件事:
| 步骤 | 做了什么 | 存储位置 |
|---|---|---|
| 1 | 写入团队配置 | 磁盘 ~/.claude/teams/{team-name}/config.json |
| 2 | 准备空 Task List 目录 | 文件系统 |
| 3 | 绑定 leader 到 team | 内存 leaderTeamName |
| 4 | 更新运行时团队状态 | 内存 AppState.teamContext |
| 5 | 注册清理任务 | 内存(session 结束时自动清理) |
2.3 关键细节
leader 不是 teammate。源码中有这样一段注释:
ts
// We intentionally don't set CLAUDE_CODE_AGENT_ID for the team lead because:
// 1. The lead is not a "teammate" - isTeammate() should return false for them
// 2. Their ID is deterministic (team-lead@teamName) and can be derived when needed
// 3. Setting it would cause isTeammate() to return true, breaking inbox polling
leader 不会被设置 CLAUDE_CODE_AGENT_ID,所以 isTeammate() 对 leader 返回 false------这是设计上的区分:leader 负责管理,teammate 负责执行。
TeamCreate 不创建 teammate 。它只建立团队容器,真正的 teammate 是后续通过 Agent(name + team_name) 创建的。
TeamCreate 也不创建具体任务 。它只准备一张空的 Task List 目录,真正写入任务是后面调用 TaskCreate 时才发生的。
2.4 团队配置文件 vs 运行时团队状态
TeamCreate 的产物分为两层:

- 团队配置文件(
TeamFile)------持久化到磁盘的 JSON 文件,用于跨会话恢复团队信息 - 运行时团队状态(
AppState.teamContext) ------内存中的临时状态,包含teamName、leadAgentId、teammates(队友列表)等,供当前会话快速访问
团队容器的结构关系可以这样理解:它不是"启动几个 Agent",而是先建立组织架构、共享状态和运行时上下文。容器就绪后,真正的 teammate 才会在下一步通过 Agent 工具创建。
3. 创建 teammate
创建团队的 leader(当前 Agent)通过调用 AgentTool 来拉新成员进团队。
3.1 Leader 调用 AgentTool
AgentTool 有两种用法,取决于有没有 team_name:
- 没有
team_name:创建普通 subagent,任务结束即销毁 - 有
team_name:创建 teammate,加入团队协作
Leader 已经创建了团队,所以调用 AgentTool 时带有 team_name,创建的就是 teammate。
ts
export const AgentTool = buildTool({
name: 'Agent',
async description() {
return 'Launch a new agent';
},
get inputSchema() {
/* ... */
},
get outputSchema() {
/* ... */
},
async call(
{
prompt,
subagent_type,
description,
model: modelParam,
name,
team_name,
mode: spawnMode,
}: AgentToolInput,
toolUseContext,
canUseTool,
assistantMessage,
onProgress?,
) {
const appState = toolUseContext.getAppState();
const teamName = resolveTeamName({ team_name }, appState);
// 有 team_name 和 name 时,创建 teammate
if (teamName && name) {
const result = await spawnTeammate(
{
name,
prompt,
description,
team_name: teamName,
use_splitpane: true,
plan_mode_required: spawnMode === 'plan',
model: modelParam,
agent_type: subagent_type,
},
toolUseContext,
);
return { data: { status: 'teammate_spawned', ...result.data } };
}
// ...
},
});
Task List 只是任务状态表;teammate 是通过 Agent(name + team_name) 显式创建出来的团队成员。
Agent Teams 还有一个组织边界:teammate 不能继续创建 teammate。
ts
if (isTeammate() && teamName && name) {
throw new Error('Teammates cannot spawn other teammates');
}
原因很简单:团队名册是扁平的。leader 负责管理 team,teammate 负责做任务;如果 teammate 继续扩张团队组织结构,成员归属就会变得混乱。teammate 仍然可以用普通 subagent 辅助自己,但不能继续拉新 teammate 进团队。
3.2 生成 teammate 身份和运行环境
Leader 调用 AgentTool 后,系统开始真正创建 teammate。这个过程包括:生成唯一 ID、分配颜色、准备运行环境。
ts
async function handleSpawn(
input: SpawnInput,
context: ToolUseContext,
): Promise<{ data: SpawnOutput }> {
const appState = getAppState();
const teamName = input.team_name || appState.teamContext?.teamName;
const uniqueName = await generateUniqueTeammateName(name, teamName);
const sanitizedName = sanitizeAgentName(uniqueName);
const teammateId = formatAgentId(sanitizedName, teamName);
const teammateColor = assignTeammateColor(teammateId);
const config: InProcessSpawnConfig = {
name: sanitizedName,
teamName,
prompt,
color: teammateColor,
planModeRequired: plan_mode_required ?? false,
model,
};
const result = await spawnInProcessTeammate(config, context);
// ...
}
这段逻辑生成了 teammate 的关键身份信息:

接下来,teammate 不会新开进程,而是在同一个 Node.js 进程里运行。系统会为它创建独立的身份上下文,避免多个 teammate 之间互相干扰。
ts
export async function spawnInProcessTeammate(
config: InProcessSpawnConfig,
context: SpawnContext,
): Promise<InProcessSpawnOutput> {
const { name, teamName, prompt, color, planModeRequired, model } = config;
const { setAppState } = context;
const agentId = formatAgentId(name, teamName);
const taskId = generateTaskId('in_process_teammate');
const abortController = createAbortController();
const parentSessionId = getSessionId();
const identity: TeammateIdentity = {
agentId,
agentName: name,
teamName,
color,
planModeRequired,
parentSessionId,
};
// 创建 teammate 上下文,用于同进程隔离
const teammateContext = createTeammateContext({
agentId,
agentName: name,
teamName,
color,
planModeRequired,
parentSessionId,
abortController,
});
// 创建 task state 并注册到 AppState
const taskState: InProcessTeammateTaskState = {
...createTaskStateBase(
taskId,
'in_process_teammate',
description,
context.toolUseId,
),
type: 'in_process_teammate',
status: 'running',
identity,
prompt,
model,
abortController,
// ...
};
registerTask(taskState, setAppState);
// ...
}
| 对象 | 定位 | 典型使用场景 |
|---|---|---|
teammateContext |
teammate 特有的运行时上下文 | 3 个 teammate 同时运行,都调用 getAgentName()。 teammateContext 让每个调用返回自己的名字(researcher/coder/tester),不会互相混淆。 还用于中断控制(abortController)。 只有 teammate 有这个机制,普通 Agent 没有。 |
taskState |
单个 Agent 的状态 | 每个 Agent(无论是不是 teammate)都有自己的 taskState,记录自己的运行状态(running/idle/completed)、消息等。 Leader 通过 researcher 的 taskState 查看它是否在忙。 普通 Agent、teammate、shell 任务都有各自的 taskState。 |
两者关系:teammateContext 和 taskState 平行存在,前者管"团队身份",后者管"运行状态"。
3.3 启动执行循环
创建身份和 task state 之后,teammate 还没有真正开始工作。真正让它跑起来的是执行循环。
spawn 成功后,系统会立即启动 in-process runner(teammate 的执行循环):
ts
export function startInProcessTeammate(config: InProcessRunnerConfig): void {
const agentId = config.identity.agentId;
void runInProcessTeammate(config).catch(error => {
logForDebugging(
`[inProcessRunner] Unhandled error in ${agentId}: ${error}`,
);
});
}
// 启动时传入的配置
startInProcessTeammate({
identity: {
agentId: teammateId,
agentName: sanitizedName,
teamName,
color: teammateColor,
planModeRequired: plan_mode_required ?? false,
parentSessionId: result.teammateContext.parentSessionId,
},
taskId: result.taskId,
prompt,
teammateContext: result.teammateContext,
toolUseContext: { ...context, messages: [] }, // 注意:空数组,不从 leader 继承历史
abortController: result.abortController,
// ...
});
注意 messages: []。in-process teammate 不直接继承 leader 的完整对话历史,而是从自己的初始 prompt 开始构建上下文。这能避免 teammate 长期持有 leader 的大量上下文,也能让它的会话更像独立成员。
执行循环里,teammate 会建立自己的 agent context:
ts
export async function runInProcessTeammate(
config: InProcessRunnerConfig,
): Promise<InProcessRunnerResult> {
const {
identity,
taskId,
prompt,
teammateContext,
toolUseContext,
abortController,
model,
} = config;
const { setAppState } = toolUseContext;
// 创建 AgentContext 用于分析归因
const agentContext: AgentContext = {
agentId: identity.agentId,
parentSessionId: identity.parentSessionId,
agentName: identity.agentName,
teamName: identity.teamName,
agentColor: identity.color,
planModeRequired: identity.planModeRequired,
isTeamLead: false,
agentType: 'teammate',
invocationKind: 'spawn',
};
// 在 teammateContext 和 agentContext 包裹下运行 agent loop
await runWithTeammateContext(teammateContext, async () => {
return runWithAgentContext(agentContext, async () => {
for await (const message of runAgent({
promptMessages,
toolUseContext,
canUseTool: createInProcessCanUseTool(
identity,
currentWorkAbortController,
),
model,
// ...
})) {
// 处理 agent 输出、工具进度和状态同步
}
});
});
}
这说明 in-process teammate 不是"假 agent"。它仍然跑完整的 agent loop,只是运行在同一个进程里,并通过 runWithTeammateContext() 获得自己的团队身份。
执行循环启动后,teammate 才从"名册里的成员"变成"正在工作的成员":它能接收 prompt,调用工具,更新状态,并在一轮工作结束后回到 idle(空闲等待状态,保持存活但暂不执行)。
teammate 怎么知道要领任务? 答案在 system prompt 和 idle 循环的配合里。
teammate 启动时,system prompt 会被注入一段团队协作指令(TEAMMATE_SYSTEM_PROMPT_ADDENDUM),拼接到原有的 System Prompt 后面,告诉它:你是团队成员,工作通过"任务系统"和 teammate 消息来协调,也能用 SendMessage 工具与其他成员通信。
ts
const fullSystemPromptParts = await getSystemPrompt(
toolUseContext.options.tools,
toolUseContext.options.mainLoopModel,
undefined,
toolUseContext.options.mcpClients,
);
const systemPromptParts = [
...fullSystemPromptParts,
TEAMMATE_SYSTEM_PROMPT_ADDENDUM,
];
ts
// 注入 teammate 的 system prompt 附加指令
export const TEAMMATE_SYSTEM_PROMPT_ADDENDUM = `
# Agent Teammate Communication
IMPORTANT: You are running as an agent in a team. To communicate with anyone on your team:
- Use the SendMessage tool with \`to: "<name>"\` to send messages to specific teammates
- Use the SendMessage tool with \`to: "*"\` sparingly for team-wide broadcasts
Just writing a response in text is not visible to others on your team - you MUST use the SendMessage tool.
The user interacts primarily with the team lead. Your work is coordinated through the task system and teammate messaging.
`;
// 中文翻译:重要提示:你正在作为团队中的 agent 运行。要与团队中的任何人通信:使用 SendMessage 工具,`to: "<name>"` 发给特定 teammate,`to: "*"` 谨慎用于团队广播。仅仅在文本中回复,团队其他成员是看不到的 ------ 你必须使用 SendMessage 工具。用户主要与团队 leader 交互。你的工作通过任务系统(task system)和 teammate 消息来协调。
一轮工作完成后,teammate 不会退出,而是进入 idle 状态,启动一个等待循环 waitForNextPromptOrShutdown。这个循环每 500ms 检查三件事:
- 有没有新消息 ------ 来自 leader 或其他 teammate 的 SendMessage
- 有没有 shutdown 请求 ------ leader 要求结束 teammate
- Task List 里有没有可领取的任务 ------ 通过
tryClaimNextTask检查
ts
// idle 循环里检查 Task List
const taskPrompt = await tryClaimNextTask(taskListId, identity.agentName);
if (taskPrompt) {
return {
type: 'new_message',
message: taskPrompt, // 格式化后的任务描述
from: 'task-list',
};
}
如果 Task List 里有满足条件(pending、无人负责、前置依赖已完成)的任务,tryClaimNextTask 会把它格式化成 prompt,返回给 waitForNextPromptOrShutdown,后者再把这个 prompt 交给下一轮 agent loop 执行。这个过程对 teammate 来说是透明的 ------ 它只需要在 idle 循环里等待,有任务时 runner 会自动把任务内容作为新的 prompt 传递给它。
这也解释了为什么第 3 步叫"Task List 负责共享任务事实" ------ teammate 不是被硬编码去"领任务",而是通过 system prompt 知道有"任务系统"存在,再通过 runner 的 idle 循环自动检查 Task List 获取任务分配。
3.4 登记到成员名册
teammate 运行起来后,还必须被团队其他机制识别。否则它虽然在跑,但 leader 不知道团队里有这个成员,任务和消息也不好路由。
谁来登记 :Leader 调用 AgentTool → spawnTeammate → handleSpawnSplitPane(或 handleSpawnSeparateWindow),在 spawn 流程中完成登记。
成员登记会同时进入两个位置:leader 的运行时团队状态(内存),以及持久化的团队名册(磁盘)。
ts
async function registerTeammateInAppState(
teammateId: string,
sanitizedName: string,
teamName: string,
teammateColor: string,
agent_type: string,
setAppState: SetAppStateFn,
) {
// 1. 登记到运行时团队状态(内存中,供快速访问)
setAppState(prev => ({
...prev,
teamContext: {
...prev.teamContext,
teammates: {
...prev.teamContext?.teammates,
[teammateId]: {
name: sanitizedName,
agentType: agent_type,
color: teammateColor,
tmuxPaneId: 'in-process',
cwd: getCwd(),
spawnedAt: Date.now(),
},
},
},
}));
// 2. 登记到团队名册(持久化到磁盘)
const teamFile = await readTeamFileAsync(teamName);
if (!teamFile) {
throw new Error(`Team "${teamName}" does not exist`);
}
teamFile.members.push({
agentId: teammateId,
name: sanitizedName,
agentType: agent_type,
color: teammateColor,
joinedAt: Date.now(),
tmuxPaneId: 'in-process',
cwd: getCwd(),
subscriptions: [],
});
await writeTeamFileAsync(teamName, teamFile);
}
成员名册的结构关系可以画成这样:

leader、teammate、消息系统、清理逻辑都可以围绕这份成员信息工作。团队不是靠模型记忆维持,而是有一份可查询、可更新的成员名册。
4. Agent 完成工作后如何继续
teammate 跑完一轮 prompt 后,不会直接消失。它会进入 idle 状态,等待下一个输入。这个输入可能来自 Task List(可领取的任务),也可能来自 mailbox(leader 或其他 teammate 的消息,详见 4.2 节)。
mailbox 是团队成员间的消息通道,用于传递指派、通知和协作消息。teammate 通过 runner 每 500ms 轮询读取,消息被读取后从队列中移除。
idle 状态的等待循环按优先级处理多个来源:

下面分别讲 Task List 和 mailbox 这两个协作通道是如何工作的。
4.1 Task List:runner 自动领取任务
当 teammate 完成一轮工作进入 idle 状态时,它的外层 runner(inProcessRunner)会自动检查 Task List,寻找可领取的任务。这个过程对 teammate 是透明的:
tryClaimNextTask开始执行:- 调用
listTasks()获取所有任务 findAvailableTask(tasks)从列表中筛选出可领取的任务(pending、无人负责、前置依赖已完成)claimTask()把任务登记到 teammate 名下- 把任务格式化成 prompt,传给 teammate 执行
- 调用
ts
// runner 的 idle 循环中自动执行
const taskPrompt = await tryClaimNextTask(taskListId, identity.agentName);
if (taskPrompt) {
// 把任务作为新的 prompt 传给 teammate
return { type: 'new_message', message: taskPrompt, from: 'task-list' };
}
注意:claimTask 不是 Agent 可调用的工具,而是 runner 内部函数。teammate 不需要主动"领取"任务(Agent 领取不可靠,必须代码领取),它只需要在 idle 循环里等待,runner 会自动把可领取的任务作为新 prompt 传递给它。
Task List 记录的任务结构如下:

一个任务能被领取,要满足三个条件:还没开始、无人负责、前置依赖已完成。
4.2 mailbox:消息传递和再次唤醒
除了 Task List,teammate 还可以通过 mailbox 接收消息。
mailbox 的实现机制 :每个 teammate 有一个独立的 inbox 文件,存储在 .claude/teams/{team_name}/inboxes/{agent_name}.json。这是一个基于文件系统的消息队列,而非内存广播:
- 点对点写入 :发送方通过
writeToMailbox将消息写入接收方的 inbox 文件,使用文件锁防止并发冲突 - 消息格式 :每条消息包含
from(发送者)、text(内容)、timestamp(时间戳)、read(是否已读),以及可选的color和summary - 广播实现 :
to: "*"时,系统遍历团队成员列表,向每个成员的 inbox 写入同一条消息 - 消息消费 :消息被读取后不会立即删除,而是标记为
read: true,便于追溯历史
谁负责接收消息 :teammate 自己不直接检查 mailbox,而是由它的 runner(inProcessRunner)负责。runner 在一轮工作结束后会进入 waitForNextPromptOrShutdown 循环,每 500ms 轮询检查 mailbox 和其他来源。
接收消息后会发生什么:
- 如果是 shutdown 请求 → 进入收尾流程,准备退出
- 如果是 leader 消息 / 其他 teammate 消息 → 把消息格式化成新的 prompt,传给 teammate 执行下一轮
- 如果 没有任何消息 → 继续等待,保持 idle 状态
runner 在一轮工作结束后,会把 task 标记为 idle,并向 leader 发送 idle 通知:
ts
async function markTeammateIdle(
taskId: string,
identity: TeammateIdentity,
workWasAborted: boolean,
setAppState: SetAppStateFn,
) {
// 标记为 idle
updateTaskState(taskId, task => ({ ...task, isIdle: true }), setAppState);
// 通知 leader
await sendIdleNotification(
identity.agentName,
identity.color,
identity.teamName,
{ idleReason: workWasAborted ? 'interrupted' : 'available' },
);
}
之后,runner 会进入等待循环 waitForNextPromptOrShutdown,按上面流程图的优先级处理各种输入来源。
这就形成了 Agent Teams 的两条协作通道:

Task List 解决"状态是否一致",mailbox 解决"消息是否送达"。两者合在一起,teammate 才能在无人手动提醒时继续推进下一轮工作。
4.3 生命周期循环与关闭
in-process teammate 的生命周期不是"一次 prompt 跑完就结束"。更准确地说,它会在 running 和 idle 之间循环:

如果收到普通消息,它会把消息格式化成新的 user prompt,继续下一轮 runAgent()。如果收到 shutdown request(leader 通过 SendMessage 发送的优雅退出请求),它会把关闭请求交给模型处理,让 teammate 决定如何响应或收尾。
最终退出循环时,runner 会把 teammate task 标记为 completed,并发送终止事件:
ts
async function completeTeammateTask(
taskId: string,
setAppState: SetAppStateFn,
) {
updateTaskState(
taskId,
task => ({
...task,
status: 'completed',
completedAt: Date.now(),
}),
setAppState,
);
emitTaskTerminatedSdk(taskId, 'completed', metrics);
}
如果 leader 要清理整个 team,则会先检查是否还有 active teammate;如果还有,就要求先请求 shutdown。
ts
export const TeamDeleteTool = buildTool({
async call(_input, context) {
const { setAppState, getAppState } = context;
const appState = getAppState();
const teamName = appState.teamContext?.teamName;
// 1. 检查是否还有 active teammate
const teamFile = readTeamFile(teamName);
const nonLeadMembers = teamFile.members.filter(
m => m.name !== TEAM_LEAD_NAME,
);
const activeMembers = nonLeadMembers.filter(m => m.isActive !== false);
if (activeMembers.length > 0) {
return {
success: false,
message: `Cannot cleanup team with ${activeMembers.length} active member(s). Use requestShutdown to gracefully terminate teammates first.`,
};
}
// 2. 清理团队
await cleanupTeamDirectories(teamName);
clearTeammateColors();
clearLeaderTeamName();
setAppState(prev => ({
...prev,
teamContext: undefined,
inbox: { messages: [] },
}));
return { success: true, team_name: teamName };
},
});
生命周期在清理完成后才真正结束。
5. 把整条链路串起来
Agent Teams 的核心流程可以压缩成下面这张图:

这条链路的核心不是"把模型复制几份",而是给每个 agent 补齐团队成员所需的运行上下文:

如果只说"Claude Code 可以启动多个 agent",会漏掉最重要的部分:这些 agent 为什么能像一个团队一样持续协作。
Agent Teams 的答案是:先有团队容器,再有成员身份,再有执行循环,最后用共享任务表和消息通道把成员连接起来。
回到开头的团队协作类比:TeamCreate 像建立项目组,Agent(name + team_name) 像把成员拉进项目组,Task List 像共享任务池,mailbox 像团队通知。这个类比只服务于理解主线;真正的实现边界,仍然是 team、teammate、runner、Task List 和 mailbox 之间的职责分工。
从时序看,一次典型的协作流程如下:

6. 总结
Agent Teams 把多 Agent 协作从"启动几个模型"升级为一套完整的团队生命周期。回顾整条链路:
- TeamCreate 建立团队容器------写入配置文件、准备 Task List 目录、绑定 leader 到团队运行时状态
- Agent(name + team_name) 创建 teammate------在同进程内生成身份、上下文和执行循环
- idle 循环 + Task List 实现自动任务领取------teammate 无需手动指派,runner 自动筛选可领取任务
- mailbox 实现异步消息传递------基于文件系统的双向通信,支持点对点、广播、shutdown 等场景
- TeamDelete 完成清理------检查 active teammate、移除团队目录、释放运行时状态
这套机制的本质是把团队协作的隐性契约变成显式状态:谁负责什么任务、消息发给谁、成员是否还在运行,都有明确的记录和通道,而不是依赖模型自己去记忆和协调。
更多 AI 工程、Agent 和技术实践相关内容,欢迎关注公众号。
