# 子代理与 swarm

> agent/coder/explore/plan 四个内置 profile、Agent/AgentSwarm 两个工具、swarm 模式的三种触发与提醒注入，以及防止无限委派的白名单。

- 作者：David（道雾轩）
- 专栏：Kimi Code 源码解读（https://daiw.org/manual/kimi-code.md）
- 最后更新：2026-09-19
- 原文：https://daiw.org/manual/kimi-code/subagents
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

## 四个内置 profile

v0.29 时代 profile 是 `profile/default/` 下的 YAML；现在是 TS 代码里的 `registerAgentProfile()`。`agent`、`coder`、`explore` 在 `packages/agent-core-v2/src/session/agentLifecycle/profile/profiles.ts`，`plan` 由 plan Feature 在 `features/plan/profile/plan.ts` 注册。主代理的注册（`profiles.ts:90`）：

```ts
registerAgentProfile({
  name: 'agent',
  description: 'Default agent',
  tools: AGENT_TOOLS,
  subagents: ['coder', 'explore', 'plan'],
  renderSystemPrompt: (context) =>
    renderSystemPromptResult('', context, { skillActive: skillActiveFor(AGENT_TOOLS) }),
});
```

| profile | 用途 | 工具面 |
| --- | --- | --- |
| `agent` | 主代理 | 全套，含 `Agent`、`AgentSwarm` 与 `mcp__*` |
| `coder` | 写代码 | 唯一带 Write/Edit 的子代理 |
| `explore` | 探索代码库 | 靠提示词约束只读，可用 Bash |
| `plan` | 规划 | 只读，没有 shell，也不能改文件 |

一个 profile 决定 system prompt（共用 `app/agentProfileCatalog/system.md` 模板，子代理再加一段「父代理只看得到你最后一条消息」的角色前缀）、工具白名单与可委派的子代理。用户还能在 `~/.kimi-code/agents/`、`.kimi-code/agents/` 及对应的 `.agents/agents/` 下放自定义 agent 文件，插件也能带 agent。

README 里对应的描述：

> **Subagents for focused, parallel work.** Dispatch built-in `coder`, `explore`, and `plan` subagents in isolated contexts while keeping the main conversation clean.

关键词是 **isolated contexts**——`explore` 可能要读 50 个文件才找到答案，这 50 次工具往返不该进主上下文。

## 两个协作工具

| 工具 | 位置 | 作用 |
| --- | --- | --- |
| `Agent` | `agent/tools/agent/` | 派发**单个**子代理，可 `resume` 旧实例、`run_in_background` 转后台 |
| `AgentSwarm` | `features/swarm/tools/agent-swarm/` | 用 `prompt_template` 加 `items` 一次派发**一群**，上限 128 个 |

`Agent` 的工具描述是现拼的：基础说明之后，按 `TaskList`、`TaskOutput`、`TaskStop` 是否可用，接上 `agent-background-enabled.md` 或 `agent-background-disabled.md`——**后台能力开关会换掉工具描述**，不能用的能力就不出现，否则模型会尝试并失败。实验开关 `subagent_fork` 打开时再追加 `fork` 参数的说明，最后列出当前可委派的 agent 类型与可选模型。

`AgentSwarm` 还有一条硬约束：它必须是一次回复里唯一的工具调用。v1 用 `agent-swarm-exclusive-deny.ts` 权限策略实现，现在是 `features/swarm/agent/swarmService.ts:47` 在工具执行前否决：

```ts
toolExecutor.onBeforeExecuteTool((event) => {
  const agentSwarmCount = event.toolCalls.filter(
    (toolCall) => toolCall.name === 'AgentSwarm',
  ).length;
  if (agentSwarmCount === 0 || (agentSwarmCount === 1 && event.toolCalls.length === 1)) {
    return;
  }
```

## Swarm 模式

`features/swarm/agent/swarm.ts:3`：

```ts
export type SwarmModeTrigger = 'manual' | 'task' | 'tool';
```

**三种触发来源**：用户持久开启（`/swarm on`）、一次性任务（`/swarm <task>`）、模型主动调用 `AgentSwarm`。后两种在回合结束时自动退出。手动审批模式下开 swarm，TUI 会先询问是否切到 auto 或 yolo。

**只有非 `tool` 触发才注入提醒。** `agent/injection/swarmInjection.ts:43`：

```ts
const trigger = this.options.getTrigger();
const active = trigger !== null && trigger !== 'tool';
const rendered = this.renderedState(ctx);
```

模型自己调工具进的 swarm 模式，它**已经知道**自己在干什么，再注入「你现在处于 swarm 模式」是浪费 token；只有用户从外部切换时才需要告知。模式结束时再对应注入一段「Swarm Mode Ended」。

**状态走事件溯源。** v1 的 `SwarmMode` 类要手写 `logRecord`，并另备一个不写记录的 `restoreEnter()` 供回放；现在进出都是持久事件 `swarm_mode.enter`/`swarm_mode.exit`，状态 `swarmKey` 由事件归约而来并声明为 `replayable`，[回放](https://daiw.org/manual/kimi-code/records-replay)时自然恢复，不再需要特判。`enter` 依旧幂等。

## 批次与限流

一群子代理由 `features/swarm/session/agentRunBatch.ts`（648 行）调度：前 5 个立即启动，之后每 700ms 再放一个；遇到 provider 限流就把子代理挂起重排、指数退避并收缩并发，也可用 `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` 设硬上限。子代理与 swarm 默认都有 2 小时超时（`KIMI_SUBAGENT_TIMEOUT_MS`、`KIMI_CODE_SWARM_TIMEOUT_MS`）。每次派发都注册为一个 `SubagentTask`，转到后台时就是一个[后台任务](https://daiw.org/manual/kimi-code/background)。

## 权限继承与防嵌套

v1 靠 `PermissionManager.parent` 链；现在 `session/subagent/subagentService.ts:184` 在创建子代理时直接复制父代理的权限模式：

```ts
created.accessor
  .get(IAgentPermissionModeService)
  .setMode(caller.accessor.get(IAgentPermissionModeService).mode);
```

**子代理不会比父代理更宽松**——否则「派个子代理去做」就成了提权后门。宿主运行时注册的自定义工具（user tool）也一并继承。

防止「子代理再派子代理」靠白名单。`app/agentProfileCatalog/profile-shared.ts:75`：

```ts
export function profileCanDelegate(
  profile: Pick<AgentProfile, 'tools' | 'disallowedTools'>,
): boolean {
  const possesses = (name: string) =>
    (profile.tools === undefined || profile.tools.includes(name)) &&
    !(profile.disallowedTools ?? []).includes(name);
  return possesses('Agent') || possesses('AgentSwarm');
}
```

调用方没显式声明 `subagents` 时，`withoutDelegatingTargets()` 会把自身还能委派的 profile 从候选里剔除；内置的 `coder`、`explore`、`plan` 本就没有 `Agent`、`AgentSwarm` 工具，委派链天然只有一层。

## 记录与状态

swarm 模式进出会发出 `AgentStatusUpdated`（带 `swarmMode` 字段），TUI 据此显示模式指示；[transcript 包](https://daiw.org/manual/kimi-code/transcript)的 schema 里也有 `swarm: { trigger }` 与 goal 元数据字段，保证 Web UI 与 TUI 看到一致的模式状态。

下一篇：[Goal 与 Plan](https://daiw.org/manual/kimi-code/goal-plan)。
