子代理与 swarm

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

作者 David更新于 第 21 篇(共 33 篇)

四个内置 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):

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 次工具往返不该进主上下文。

两个协作工具

工具位置作用
Agentagent/tools/agent/派发单个子代理,可 resume 旧实例、run_in_background 转后台
AgentSwarmfeatures/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 在工具执行前否决:

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:

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

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

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

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,回放时自然恢复,不再需要特判。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,转到后台时就是一个后台任务。

权限继承与防嵌套

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

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

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

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

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 包的 schema 里也有 swarm: { trigger } 与 goal 元数据字段,保证 Web UI 与 TUI 看到一致的模式状态。

下一篇:Goal 与 Plan。

本页目录