> For the complete documentation index, see [llms.txt](https://rokurokulab.gitbook.io/roku-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://rokurokulab.gitbook.io/roku-docs/subsystems/sub-agent.md).

# Sub-agent

> create time: 2026-04-21 19:14 modify time: 2026-04-21 19:45

***

### description: Roku 为什么需要 sub-agent、它隔离了什么、让渡了什么，以及目前这块仍然粗糙的部分。

## Sub-agent

sub-agent 是一个从主 agent loop 内部派生出子 agent 的机制，让 LLM 可以把一段"规模稍大、过程噪声较多"的子任务切到一段独立的对话历史里去跑，最后只把一段浓缩结果交还给主 loop。

触发方式是 LLM 自己在 tool call 里选 `Agent` 这个工具名；Roku 不在编排层主动派发 sub-agent，也没有根据启发式规则替 LLM 做决定。这块保持为一个 LLM 可用的能力，而不是一条 runtime 强制的路径。

### 为什么要有这层

主 agent 的 conversation history 在整个请求生命周期内只增不减。如果每次跨文件搜索、多步 diff、一连串工具调用都全量留在主 agent 的历史里，Compact 压力会提前到来，token 账单会变重，而最终对主 agent 真正有用的只是结论而不是过程。

sub-agent 把这种"过程重、结论轻"的子任务隔离出去：子 loop 用独立的消息历史执行——主 loop 看不到它每一步调了什么工具、读了什么文件、用了多少 token；只看到最后那一段字符串。这不是为了隐藏，而是为了让主 agent 的工作上下文保持干净。

这不是一种强制分工。LLM 可以不用 sub-agent，或者在不合适的场景过度使用它。Roku 不试图替 LLM 做这个判断。

### 继承什么、隔离什么

子 loop 继承父 loop 的**执行环境**：工作目录、已绑定的资源、路由决策、session id、模型覆盖、审批门、事件发送通道。这些都是整个请求的共享属性，子 loop 如果独立一套反而会产生不一致。

子 loop 不继承父 loop 的**对话状态**：

* conversation history 从空开始——这正是隔离的核心
* step 计数从 0 开始
* request id 派生为 `<parent>-sub` 以便在日志里区分，但这只是命名约定

memory sections 是传递进来的——子 loop 用与父 loop 相同的 recall 内容，并没有重新触发一次 recall 流程。\[未查明] 这是有意的设计（避免额外 recall 开销）还是实现上还没分开。

这种继承/隔离的划分方式是一个实用选择：共享那些"跨 loop 应该一致"的，隔离那些"跨 loop 应该独立"的。

### 几处用来控制成本的设计

**深度只允许到 1。** 子 loop 里再发起 `Agent` 工具调用会被直接拒绝并以错误字符串返回。这不是"递归深度 N 可配置"，而是硬约束——防止无限嵌套，也避免多层 sub-agent 叠加出难以推理的 token 账单。

**预算是从父 loop 预扣的。** 子 loop 拿到多少步预算，父 loop 就扣掉多少，不管子 loop 实际用了几步都不回填。这是一个保守选择：父 loop 宁可多让出预算也不赌子 loop 会"省着用"，代价是父 loop 可能因为一次大的 sub-agent 调用直接把剩余预算吃光。

**结果截断到 4000 字符。** 子 loop 的最终答复无论多长，返回父 loop 之前都会按 Unicode 字符数截断，末尾附上截断提示。4000 这个值的意义不在具体数字上，而在表达一个设计意图：sub-agent 的结果必须是一段"压缩过的结论"，不能当作一个可以随便灌回主上下文的数据通道。

**某些工具默认禁用。** 子 loop 默认不允许再调 `Agent`（防止嵌套）和 `ask_user`（防止子 loop 停在一个没有明确恢复路径的挂起状态上）。`final_answer` 和 `fail` 仍然可用——子 loop 需要它们来正常终止。

这几点合起来的意思是：sub-agent 是为"短任务、清晰收敛、少量返回"设计的，不是一个通用的并行执行框架。

### 返回语义：只有字符串

子 loop 执行完后，父 loop 拿到的就是一段纯文本加一个 `is_error` 标志。token 用量、中间工具调用、完成原因都不透出。主 loop 的后续决策只基于这段文本，就像对待任何一次普通工具调用的结果。

超时沿用同一条返回路径：120 秒（默认）之后没有结束，就把 "Timed out" 作为错误字符串返回，父 loop 继续向下走，而不是整个请求崩掉。

### 已知局限

**单进程。** sub-agent 和父 loop 跑在同一进程里，是同一个 `execute_tool_loop` 的递归调用（通过 `Box::pin` 处理 async 递归）。没有跨进程调度，没有跨机器分发。这是当前架构的硬约束，不在短期计划里改。

**串行。** 即便 LLM 一次发出多个 `Agent` 工具调用，Roku 依次执行，不并发。工具执行本身就是串行的（见 [agent-loop](/roku-docs/subsystems/agent-loop.md)），sub-agent 没有绕开这点。

**预算不回填。** 如上文所述，子 loop 没用完的步数不会归还父 loop。在预算紧张的场景里要小心。

**审批门直接透传。** 子 loop 用父 loop 同一个审批门。如果父 loop 用的是无条件放行的 `AutoApproveGate`，子 loop 的写操作同样绕过一切风险分级。没有"子 loop 需要更严格审批"的这种配置维度。\[未查明] 这是否是有意留给未来完善。

**`tools` 参数尚未生效。** `Agent` 伪工具的参数 schema 里有一个可选的 `tools` 字段（字符串，逗号分隔的工具名），理论上让 LLM 给子 loop 指定一个更窄的工具面。目前这个字段解析后没有进入实际过滤链路——子 loop 可见工具完全由默认禁用列表决定。\[推测] 这是预留字段，未实装。

***

参见 [agent-loop](/roku-docs/subsystems/agent-loop.md) 了解 sub-agent 在主循环工具执行阶段的调用位置；[approval-and-execution-policy](/roku-docs/subsystems/approval-and-execution-policy.md) 了解子 loop 透传的审批机制。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://rokurokulab.gitbook.io/roku-docs/subsystems/sub-agent.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
