Skip to main content

作用

Subagent 让主 agent 把「可独立处理、上下文重、可并行」的任务委派出去,避免主线程膨胀。
每个 subagent 都是一个临时 HarnessAgent(或 remote stub)实例,拥有独立子会话,最终通过工具结果回传。

何时启用

HarnessAgent.build() 满足以下条件时,才会装载 subagent 能力:
  • 当前 agent 不是 leaf subagent
  • 没有 disableSubagents()
  • 已配置 model
满足后会注册 SubagentsHook(priority=80),并通过 hook 暴露:
  • agent_spawn / agent_send / agent_list
  • task_output / task_cancel / task_list
在每轮 PreReasoningEventSubagentsHook 会向 SYSTEM 注入:
  • 子 agent 使用规则
  • 当前可用 agent_id 列表
  • 当前 session 的异步任务摘要(最多 10 条)

声明来源

buildSubagentEntries(...) 会合并四类来源:
  1. 内置 general-purpose
  2. 编程声明:builder.subagent(SubagentDeclaration)
  3. 文件声明:workspace/subagents/*.mdAgentSpecLoader 非递归加载)
  4. 自定义工厂:builder.subagentFactory(name, factory)builder.subagentFactory(name, description, factory),后者可为编排器提供有意义的描述而非仅有名称(省略或为空白时回退为名称)

声明模型(SubagentDeclaration)

SubagentDeclaration 支持 3 种互斥来源模式:
  1. Definition workspace 模式
    • workspace(path) 指向定义目录(通常含 AGENTS.md
  2. Inline 模式
    • inlineAgentsBody(...) 直接作为系统提示词 base
  3. Remote HTTP 模式
    • url(...) + 可选 headers(...),通过 task protocol 走远端执行
互斥约束(build() 校验):
  • url 不能与 workspace 或非空 inlineAgentsBody 同时出现
  • workspace 与非空 inlineAgentsBody 不能同时出现

运行时工作区五行判定表

WorkspaceMode 决定 runtime workspace root: 补充:
  • tools继承工具的 allowlist:仅过滤父 toolkit,不影响子 agent 后续自动注册的本地工具
  • 同一个 definition workspace 可被多个声明复用
  • workspace.path 相对路径会按 mainWorkspace.resolve(...).normalize() 解析

声明文件(workspace/subagents/<id>.md

文件名(去掉 .md)就是 agent_id,不从 front matter 读取 name
解析规则(AgentSpecLoader):
  • 必填:description
  • 仅扫描 subagents/ 目录第一层 .md 文件(非递归)
  • 如果配置了 workspace.path 且 body 非空:会记录 warning,body 被忽略
  • markdown 声明当前不解析 url/headers(remote 声明建议走编程 API)

编程式配置


内置 general-purpose

内置 general-purpose 不需要写声明文件,会始终加入 entry 列表。
它的目标是「能力镜像主 agent」,核心行为:
  • 共享主 workspace(SHARED 语义)
  • 继承并镜像主 agent 的:
    • toolkit(父工具)
    • hooks
    • execution config
    • compaction / toolResultEviction
    • additional context files / maxContextTokens
    • 各类 disable 开关
  • 固定是 leaf subagent(不能继续 spawn)

防递归与深度保护

双保险:
  1. 所有通过声明/内置生成的子 agent 都会 asLeafSubagent(),leaf 不再注册 SubagentsHook
  2. AgentSpawnTool 还有动态深度上限 MAX_SPAWN_DEPTH = 3

RuntimeContext 透传

agent_spawn / agent_send 调用子 agent 时:
  • 子会话 session_id 为新值(sub-<uuid>
  • userId 从父 RuntimeContext 透传给子 RuntimeContext
这样可保持 USER 维度隔离键一致(例如 namespace/sandbox 隔离依赖 userId 的场景)。

调用工具与关键参数

注意:
  • agent_sendagent_key 必须使用 agent_spawn 返回值中的完整 agent_key: ...(不是 agent_id / session_id / task_id
  • 异步任务刚创建时不要立即轮询;优先先返回用户,再用 task_output(block=false)task_list 查最新状态

异步任务生命周期与存储

默认情况下,主 agent 使用 WorkspaceTaskRepository(除非显式 taskRepository(...) 覆盖)。 生命周期(简化):
  1. putTask(...) 写入 TaskRecord(PENDING) 到 workspace
  2. 提交本地执行 future(local 或 remote)
  3. 执行中更新为 RUNNING
  4. 结束写入 COMPLETED / FAILED / CANCELLED
存储分层:
  • 内存层:localTasks(本节点加速句柄,重启丢失)
  • 持久层:agents/<parentAgentId>/tasks/<sessionId>.json(状态真源)

分布式语义

  • 任务执行粘在创建节点,但任意节点都可通过 workspace 读取状态
  • task_output(block=true) 在跨节点场景下会优雅降级,不会无休止阻塞
  • task_cancel 会把 cancelRequested=true 持久化;执行节点轮询该标记后中止
  • orphan sweeper 会把长时间无心跳的本地任务标记为 FAILED(remote transport 任务不走该判定)
与 filesystem 模式关系:

Remote subagent 行为

当声明配置 url(...) 时:
  • 工厂返回 RemoteSubagentStub(占位,不做本地真实推理)
  • 实际执行通过 TaskRunSpec.RemoteTaskRunSpec + AgentProtocolTaskClient 委派到远端 task HTTP 服务
  • 可同步(timeout_seconds>0)或异步(timeout_seconds=0

实践建议

  1. description 要写清「何时使用 / 输出格式 / 禁止事项」,这是主模型是否委派的关键依据
  2. 子 agent maxIters 通常设得比主 agent 小,避免子线程吞噬过多 token
  3. 会话压缩或恢复后,先用 task_list() 恢复任务全量状态,再做单任务查询

相关文档