OpenCode Sub Agent — 子代理委托与并行工作
Sub Agent(子代理)是 OpenCode 的工作委托(Delegation)机制, 允许 Primary Agent 将特定任务分派给专门的子代理独立执行,实现并行工作、关注点分离和权限隔离。 这是 OpenCode Agent 体系区别于传统单线程 AI 编程助手的核心能力之一。
1. 概述
1.1 什么是 Sub Agent
Sub Agent 是一种 mode 为 "subagent" 的 Agent 实例,
不能由用户直接交互(不可通过 Tab 切换),
而是由 Primary Agent 在 ReAct 循环中通过 task 工具调度执行,
或由用户通过 @agent-name 手动调用。
tool_result 形式返回给 Primary Agent。
1.2 Primary Agent vs Sub Agent
| 维度 | Primary Agent(如 Build/Plan) | Sub Agent(如 Explore/General) |
|---|---|---|
| 交互方式 | 用户直接对话,Tab 切换 | 通过 task 工具或 @mention 间接调用 |
| ReAct 循环 | 主循环(由 prompt.ts:runLoop() 驱动) |
独立子循环,结果序列化返回 |
| 会话上下文 | 主 Session(包含完整对话历史) | 子 Session(只包含本次任务上下文),执行结束即序列化 |
| 工具集 | 全部工具(bash, edit, read, grep, task, ...) | 按权限过滤(如 Explore 只有 read/grep/glob) |
| TODO 管理 | 有 todowrite |
默认禁用(General 无 todo) |
| 嵌套深度 | 受 subagent_depth 配置控制(默认 1) |
作为子节点,subagent 不会自动调用别的 subagent(可配置开启) |
| System Prompt | 模型专属 + 环境信息 + AGENTS.md + skills + tools | Agent 专属 Prompt(替换模型专属 Prompt) |
2. 行为分析(做什么)
以下从行为视角分析 Sub Agent 的功能边界与委托执行流程。
2.1 用例图 — Sub Agent 的使用场景全景
展示 Sub Agent 的两类调用者(Primary Agent / 用户)与其可委托的任务类型。
2.2 活动图 — Sub Agent 委托执行流程
展示从 Primary Agent 决策委托到 Sub Agent 完成返回的完整活动链,覆盖权限门控和深度检查。
2.3 序列图 — Task Tool 调度 Sub Agent 完整序列
以 Build Agent 委托 Explore Agent 搜索 API 端点为例,展示从 task 工具调用到子会话创建、独立 ReAct 循环执行、结果序列化返回的全链路消息流。
序列图关键节点解读
| # | 节点 | 说明 |
|---|---|---|
| 1 | task 工具调用 |
Primary Agent 的 LLM 输出 tool_call: task(subagent_type, prompt, description)。description 必须 3-5 词,prompt 是给 Sub Agent 的具体任务指令。 |
| 2 | permission.task 检查 |
支持 glob 模式匹配 —— 例如 "task": {"*": "deny", "explore": "allow"} 只放行 explore,屏蔽其他 Sub Agent。 |
| 3 | subagent_depth 门控 |
默认 depth=1:Primary→Sub 是允许的,但 Sub 不能再调 Sub。depth=2 允许 Sub 调 Sub 形成链式委托。 |
| 4 | Sub Agent 启动 | 加载 Agent 专属 System Prompt(如 explore.txt),不继承 Primary Agent 的模型专属 Prompt(如 default.txt)。工具集按 Agent 权限过滤。 |
| 5 | 独立 ReAct 循环 | Sub Agent 在自己的子 Session 中执行完整的推理→工具调用→结果观察循环,有独立步数上限(steps)。 |
| 6 | 结果序列化返回 | Sub Agent 结束后的全部输出文本被打包为 tool_result,追加到主 Session 的 messages 中。Primary Agent 收到指令 "Summarize the task tool output above and continue..."(prompt.ts:446)。 |
3. 结构分析(由什么组成)
3.1 组件图 — Sub Agent 调度架构
展示 Sub Agent 调度系统的分层组件架构:Primary Agent → Task Tool Dispatcher(权限门控 + 深度门控)→ Sub Agent Registry → Sub Agent Runtime(Session Manager + ReAct Loop + System Prompt Loader)→ 过滤后的工具层。
4. 内置 Sub Agent 详解
OpenCode 提供 3 个内置 Sub Agent,源码位于 packages/core/src/plugin/agent.ts 和 packages/opencode/src/agent/prompt/*.txt。
4.1 General
| 属性 | 值 |
|---|---|
| 用途 | 复杂搜索、多步任务、并行工作 |
| 工具 | 全工具(bash, edit, read, grep, glob, webfetch, task, skill, question) |
| TODO | 无 todowrite(区分于 Primary Agent) |
| 文件写入 | 可写(有 edit) |
| 典型 Prompt | "General-purpose agent for researching complex questions and executing multi-step tasks." |
Launch multiple agents concurrently)。
4.2 Explore
| 属性 | 值 |
|---|---|
| 用途 | 快速文件搜索、关键词定位、代码库理解 |
| 工具 | 只读 — read, grep, glob |
| 文件写入 | 不可 |
| 速度 | "Fast agent" — 设计用于快速扫描 |
| 典型 Prompt | "You are a file search specialist. You excel at thoroughly navigating and exploring codebases." |
4.3 Scout
| 属性 | 值 |
|---|---|
| 用途 | 外部依赖研究、库源码检查、对照上游实现 |
| 工具 | 只读 — read, grep, glob(可在托管缓存目录中操作) |
| 特殊性 | 可以克隆依赖仓库到 OpenCode 托管缓存目录(tmp/opencode) |
| 典型 Prompt | 只读,用于外部依赖研究 |
5. Task Tool — Sub Agent 的调度入口
task 工具是 Primary Agent 与 Sub Agent 之间的唯一接口。
Primary Agent 的 LLM 产出 tool_call: task(...),由 Runtime 层解析、
创建子会话、注入 Sub Agent Prompt、启动独立 ReAct 循环、最终将结果序列化返回。
5.1 参数 Schema
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
description | string | 是 | 任务简述(3-5 词),用于日志/UI 显示 |
prompt | string | 是 | 给 Sub Agent 的完整任务指令(高度详细的自然语言指令) |
subagent_type | string | 是 | 要调用的 Sub Agent 类型名称(如 "explore"、"general"、"scout" 或自定义名称) |
task_id | string | 否 | 续跑已有任务(复用之前创建的 Sub Agent 会话上下文) |
command | string | 否 | 触发该 task 的命令(用于日志追溯) |
5.2 调度流程
LLM 产出 task tool_call → Permission.check("task", subagent_type) → SessionManager.createChild() 检查 subagent_depth →
加载 Sub Agent System Prompt + 过滤工具集 → 新 ReAct 循环 runLoop() → 结果序列化 → tool_result → 追加到主 Session messages →
注入续跑提示 "Summarize the task tool output and continue"
6. 自定义 Sub Agent
6.1 JSON 配置方式
{
"agent": {
"code-reviewer": {
"description": "Reviews code for best practices and potential issues",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-5",
"temperature": 0.1,
"steps": 10,
"prompt": "You are a code reviewer. Focus on security, performance, and maintainability.",
"permission": {
"edit": "deny",
"bash": "deny"
}
}
}
}
6.2 Markdown 配置方式
放在 ~/.config/opencode/agents/(全局)或 .opencode/agents/(项目级):
---
description: Writes and maintains project documentation
mode: subagent
permission:
bash: deny
steps: 8
---
You are a technical writer. Create clear, comprehensive documentation.
Focus on:
- Clear explanations
- Proper structure
- Code examples
- User-friendly language
6.3 配置选项全览
| 选项 | 类型 | 说明 |
|---|---|---|
description | string | 必填。Agent 用途描述,帮助 LLM 决定何时调用 |
mode | "primary" | "subagent" | "all" | 设置为 "subagent" 即声明为子代理。默认 "all" |
model | string | 指定模型(如 "anthropic/claude-haiku-4-5")。不指定则继承 Primary Agent 的当前模型 |
temperature | float (0.0-1.0) | 控制随机性:0.0-0.2 确定性(评审/分析),0.6+ 创造性(头脑风暴) |
top_p | float (0.0-1.0) | 核采样参数,替代 temperature 控制多样性 |
steps | int | 最大迭代步数。不设则无限循环至 LLM 主动停止 |
prompt | string | 自定义 System Prompt(替代 Agent 默认 Prompt)。支持 "{file:./path.txt}" 引用外部文件 |
permission | object | 工具权限(allow/ask/deny)。参见 8.3 权限速查 |
hidden | bool | 设为 true 则在 @ 自动补全菜单中隐藏,仅能通过 task 工具程序化调用 |
disable | bool | 设为 true 禁用此 Agent |
color | hex | theme keyword | UI 显示颜色(如 "#ff6b6b") |
model,Sub Agent 使用调用它的 Primary Agent 的当前模型。这确保模型一致性,也可通过显式指定更快的模型(如 haiku)来降低成本和延迟。
7. Sub Agent System Prompt
Sub Agent 启动时用自己的专属 System Prompt替换 Primary Agent 的模型专属 Prompt。位于 packages/opencode/src/agent/prompt/*.txt。
| Agent | 文件 | System Prompt 首句 | 关键约束 |
|---|---|---|---|
| General | agent.ts 常量 |
"General-purpose agent for researching complex questions and executing multi-step tasks." | 无 todowrite,可并行启动多个实例 |
| Explore | explore.txt |
"You are a file search specialist. You excel at thoroughly navigating and exploring codebases." | 只读(read/grep/glob),不可修改文件 |
| Scout | scout.txt |
只读,用于外部依赖研究 | 可在 tmp/opencode 托管缓存中克隆依赖仓库 |
| Compaction | compaction.txt |
"You are an anchored context summarization assistant for coding sessions." | mode: primary 但隐藏,系统自动触发;只总结不回答对话 |
| Title | title.txt |
"You are a title generator. You output ONLY a thread title." | ≤50 字符单行 |
| Summary | summary.txt |
"Summarize what was done in this conversation." | 2-3 句,第一人称 |
| Generate | generate.txt |
"You are an elite AI agent architect specializing in crafting high-performance agent configurations." | 输出 JSON schema |
深层含义:这意味着如果默认 Primary Agent 的 Prompt 中有 "keep going until resolved" 等指令,Sub Agent 看不到这些——它完全按自己 Prompt 中的指令行事。这是有意为之:Sub Agent 的范围应当由 Primary Agent 给定的
prompt 参数精确控制。
8. 实战速查手册
8.1 配置键速查
| 配置键 | 位置 | 说明 |
|---|---|---|
agent.<name>.mode | opencode.json / agents/*.md | 设为 "subagent" 声明为子代理 |
agent.<name>.description | opencode.json / agents/*.md | 必填,决定 LLM 何时调度它 |
agent.<name>.model | opencode.json / agents/*.md | 不填则继承 Primary Agent 的模型 |
agent.<name>.steps | opencode.json / agents/*.md | 最大步数(默认 Infinity) |
agent.<name>.temperature | opencode.json / agents/*.md | 0.0-1.0,不填则用模型默认值 |
agent.<name>.hidden | opencode.json / agents/*.md | true 则在 @ 菜单中隐藏 |
agent.<name>.disable | opencode.json / agents/*.md | true 则禁用 |
agent.<name>.permission | opencode.json / agents/*.md | 工具权限控制 |
agent.<name>.permission.task | opencode.json / agents/*.md | 控制该 Agent 可调度哪些 Sub Agent(glob 匹配) |
subagent_depth | opencode.json(全局) | Sub Agent 嵌套深度(默认 1) |
8.2 调用流程速查
| 方式 | 语法 | 适用场景 |
|---|---|---|
| 自动委托 | LLM 自行决定调用 task 工具 | Primary Agent 判断任务适合委托时自动触发 |
| @-mention 手动调用 | @explore 搜索所有 API 端点 | 用户主动要求用特定 Sub Agent |
| 并行调用 | Primary Agent 同时发出多个 task tool_call | 需要并行搜索/分析时 |
| 续跑已有任务 | task_id 参数复用之前会话 | 分阶段执行同一任务 |
8.3 权限速查
| 权限键 | 值 | 行为 |
|---|---|---|
task | "allow" | 允许调用所有 Sub Agent |
task | "ask" | 每次调用 Sub Agent 都弹审批 |
task | "deny" | 禁止调用任何 Sub Agent |
task | {"*": "deny", "explore": "allow"} | 只允许 explore,其他 Sub Agent 被 deny 时从 task 工具描述中移除 |
task | {"orchestrator-*": "allow"} | glob 模式:允许所有 orchestrator- 前缀的 Agent |
permission.task 设为 deny,用户仍可通过 @-mention 手动调用 Sub Agent。权限只约束 Primary Agent 通过 task 工具的自动调度。
9. 源码分析 — 关键实现路径
以下基于 packages/opencode/src/tool/task.ts 和 task.txt 源码,厘清 Sub Agent 的创建、调度与并发模型。
9.1 Child Session 创建
Sub Agent 的底层实体是 child Session,而非操作系统线程。
调用 task 工具时,task.ts:142-158 走 sessions.create({ parentID, ... }) 创建一条子会话记录,
随后通过 BackgroundJob.start()(task.ts:259)将任务以 Effect Fiber(协程)形式调度执行。
| 步骤 | 源码位置 | 行为 |
|---|---|---|
| 1. 权限检查 | task.ts:104-114 |
调用 ctx.ask({ permission: "task", patterns: [subagent_type] }),走 permission.task 规则(glob 匹配) |
| 2. 解析 Agent | task.ts:116-119 |
agent.get(params.subagent_type) 解析目标 Sub Agent 的 prompt / model / tools |
| 3. task_id 续跑或新建 | task.ts:121-158 |
若传 task_id 则复用已有会话;否则 sessions.create({ parentID, ... }) 新建 child Session |
| 4. 权限合并 | task.ts:125-157 |
deriveSubagentSessionPermission() 合并父 deny + 子 restricts,默认添加 todowrite:deny 和 task:deny |
| 5. 模型继承 | task.ts:167-170 |
Sub Agent 若未单独指定 model,则继承 Primary Agent 当前会话的 providerID 和 modelID |
| 6. 执行调度 | task.ts:242-272 |
先尝试 background.extend()(并发扩展已有 job),否则 background.start() 新建后台 job |
| 7. 前台/后台模式 | task.ts:291-333 |
background:true 走异步模式立即返回;默认前景模式用 Effect.raceFirst 阻塞等待结果 |
sessions.create()(session.ts:669)写一条 parentID 非空的 session 记录 →
ops.prompt()(task.ts:188)以该 session 为目标执行 ReAct 循环 →
结果序列化为 <task id="..." state="completed"> XML 注入父会话(task.ts:64-79)→
sessions.remove()(session.ts:608)删父会话时递归删除子会话。
9.2 并发与重入
task.txt:13 明确指示:
结合源码得到以下结论:
| 问题 | 答案 | 源码依据 |
|---|---|---|
| 指派 Sub Agent = 创建线程? | 否。是创建 child Session + Effect Fiber(协程),运行在 Node.js 事件循环上,非 OS 线程。 | task.ts:142-158(sessions.create)+ task.ts:259(background.start) |
| 同一 Sub Agent 可同时重复指派吗? | 可以。每次调用不传 task_id 即创建 全新的独立 child Session,互不干扰。 |
task.ts:121-123(task_id 判断)+ task.ts:142-158(sessions.create) |
| 能否定义一个全能 Sub Agent 并发跑多任务? | 可以。设计一个拥有完整工具集的 subagent(如 General),同一消息发出多个 task tool_call,每个实例独立会话。 |
task.txt:13(concurrent mandate)+ task.ts:242(background.extend 支持并发 job) |
| 后台模式 | background: true 异步执行,父 Agent 不阻塞。需要 OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true。 |
task.ts:97-102 |
| 续跑 | 传 task_id 复用已有 child Session,在上次上下文基础上继续。 |
task.ts:121-123 |
Effect.forkIn(scope)(Fiber)。多个 task tool_call 在同一消息中发出时,每个都走 background.extend() → background.start() 分支,各自获得独立 Fiber 和 child Session。非后台模式下 Primary Agent 通过 Effect.raceFirst(background.wait, background.waitForPromotion)(task.ts:309-312)阻塞等待,因此并发子任务通常结合后台模式使用。
9.3 组件总表
| 组件 | 路径 | 职责 |
|---|---|---|
| Task Tool | packages/opencode/src/tool/task.ts | 调度入口:权限/深度门控 → Session 创建 → BackgroundJob 启动 → 结果回注 |
| Task Tool Prompt | packages/opencode/src/tool/task.txt | LLM 的工具描述文本(含并发指令) |
| Session Service | packages/opencode/src/session/session.ts | create(parentID)、children()、remove() 递归删除 |
| Subagent Permissions | packages/opencode/src/agent/subagent-permissions.ts | deriveSubagentSessionPermission():合并父 deny + 子 restricts |
| Background Job (Core) | packages/core/src/background-job.ts | 核心 job 引擎:start / extend / wait / promote / cancel |
| Background Job (Wrapper) | packages/opencode/src/background/job.ts | 实例级 BackgroundJob.Service 封装 |
| Agent Registry | packages/opencode/src/agent/agent.ts | 内置 Sub Agent 定义(General / Explore / Scout) |
| Agent Config Schema | packages/core/src/config/agent.ts | Agent 配置 schema v2(mode: "subagent" 等) |
| Prompt Files | packages/opencode/src/agent/prompt/*.txt | 各 Sub Agent 专属 System Prompt |
| Session Prompt | packages/opencode/src/session/prompt.ts | 处理 @agent mention、subtask 分发、prompt 拼装 |