一个 Agent 不够用的时候
单个 Agent 一次只能做一件事。当你面对一个需要多线并进的复杂任务时,排队等待不是个好选择。
举个例子:你让 Hermes Agent 「对这个项目做一次全面的代码审查」。一个 Agent 去看的话,要先审核 auth 模块,再审核数据库层,再审核 API 层,再审核前端……挨个来,可能要好几分钟。
但这些审核之间其实没有依赖关系。auth 模块的审核不需要等数据库层审核完才开始。
Hermes Agent 的解决方案是:spawn 子代理(Sub-Agent)。主 Agent 把任务拆分成多个子任务,每个子任务分配一个独立的子代理并行执行,最后汇总结果。
spawn 机制
基本概念
spawn 是 Hermes Agent 创建子代理的方式。主 Agent(parent)可以 spawn 一个或多个子代理(child),每个子代理:
- 有自己独立的 ReAct 循环
- 有自己的执行上下文
- 可以使用工具
- 执行完后把结果返回给主 Agent
子代理之间互相隔离——A 子代理不知道 B 子代理在干什么,也不能直接和 B 通信。所有的协调都通过主 Agent 进行。
一个实际的执行流程
假设你说:「帮我同时检查三台服务器的系统状态」
主 Agent 的处理过程:
1 | 主 Agent 推理: 需要检查三台服务器,任务互相独立,可以并行 |
三台服务器的检查几乎同时完成,而不是串行等待三次。
什么时候用子代理
子代理不是万能的。它适合特定类型的任务:
适合的场景
批量独立操作:同时检查多台服务器、同时处理多个文件、同时测试多个 API 端点。关键词是「独立」——各个子任务之间没有数据依赖。
代码审查:按模块拆分,每个子代理审查一个模块。
数据采集:同时从多个数据源抓取信息。比如你想了解某个技术栈的最新动态,让几个子代理分别搜索不同的信息源。
多方案评估:让不同的子代理用不同的方案解决同一个问题,然后主 Agent 比较各方案的优劣。
不适合的场景
强依赖的串行任务:后一步必须用前一步的结果。这种任务用子代理反而更慢(多了 spawn 和收集的开销)。
需要共享状态的任务:两个子任务需要读写同一个文件或数据库。并行操作可能导致冲突。
简单任务:检查一台服务器的状态,spawn 子代理的开销比直接执行还大。只有任务足够复杂或数量足够多时,并行才有收益。
Worktree 并行
在代码开发场景下,Hermes Agent 的子代理支持 Git worktree 并行。
什么是 worktree 并行
Git worktree 允许同一个仓库同时 checkout 多个分支到不同目录。Hermes Agent 利用这个特性,让多个子代理在同一个仓库的不同 worktree 中并行工作。
实际例子
你说:「我要同时给 auth、payment、notification 三个模块加单元测试」
主 Agent 的处理:
1 | 1. 为每个任务创建一个 Git worktree |
三个模块的测试代码同时编写,不会互相干扰(因为在不同的 worktree 目录里),写完后合并到主分支。
这在大型项目中特别有用。如果你有一个紧急的重构任务需要改动十几个文件,让子代理并行处理不同的文件组,效率能提升好几倍。
子代理的资源控制
并行执行意味着更多的资源消耗。Hermes Agent 提供了控制机制:
最大并发数
1 | agent: |
限制同时运行的子代理数量。超过这个数的子任务会排队等待。
子代理超时
1 | agent: |
单个子代理的最大执行时间。超时后会被强制终止,主 Agent 会收到超时通知。
Token 预算
1 | agent: |
每个子代理的最大 token 消耗。防止某个子代理在一个奇怪的任务上烧掉太多 token。
后端选择
子代理默认继承主 Agent 的后端配置。但你也可以给子代理指定不同的后端:
1 | agent: |
这在安全场景下很有用——主 Agent 用 Local 后端(方便协调),子代理用 Docker 后端(隔离执行)。想了解更多关于后端选择的内容,可以看六大执行后端解析。
子代理之间的通信
前面说了子代理之间不直接通信。但有些场景确实需要子代理之间交换信息。
Hermes Agent 的做法是通过主 Agent 中转:
1 | 子代理 A: 我发现 config.py 里的数据库连接字符串有问题 |
这种间接通信虽然没有直接通信快,但避免了子代理之间的耦合。主 Agent 作为协调者,能做更高层面的判断——比如 A 发现的问题是否真的影响 B。
错误处理
子代理执行过程中可能出错。Hermes Agent 的处理策略:
单个子代理失败:不影响其他子代理。主 Agent 收到失败通知后,可以决定是重试、跳过,还是用其他方式补救。
多个子代理失败:主 Agent 评估整体状况。如果大部分子代理都失败了,可能是系统性问题(比如网络断了),这时候会暂停所有子代理并告知用户。
子代理超时:强制终止并回收资源。主 Agent 可以选择用更大的超时重试,或者把超时的子任务拆得更小。
结果冲突:如果多个子代理的工作成果有冲突(比如都修改了同一个配置项),主 Agent 会识别冲突并让你决定用哪个。
实际使用方式
你不需要显式地「创建子代理」。在大多数情况下,Hermes Agent 会自己判断什么时候需要 spawn 子代理。
当你说「帮我查三台服务器的状态」,Agent 会自己判断:这三个任务独立、可以并行,于是 spawn 三个子代理。
但你也可以显式要求并行执行:
1 | hermes "并行做以下三件事:1. 检查 server-1 状态 2. 备份数据库 3. 清理日志" |
关键词「并行」会触发 Agent 使用子代理。
或者在交互模式中:
1 | 你: /parallel "检查 auth 模块的单元测试覆盖率" "检查 payment 模块的覆盖率" "检查 user 模块的覆盖率" |
/parallel 是一个内置命令,显式地让多个任务并行执行。
性能数据
子代理带来的效率提升取决于任务类型和并发数:
| 场景 | 串行执行 | 3 子代理并行 | 提升 |
|---|---|---|---|
| 3 台服务器巡检 | ~45 秒 | ~18 秒 | 60% |
| 5 个模块代码审查 | ~3 分钟 | ~50 秒 | 72% |
| 10 个 API 端点测试 | ~2 分钟 | ~30 秒 | 75% |
注意这不是线性加速——spawn 和汇总有开销,子代理之间也会竞争 API 调用资源(大部分 LLM API 有 rate limit)。
实际提升通常在 50%-75% 之间,取决于子任务的规模和并发数。
嵌套子代理
子代理自己能不能再 spawn 子代理?可以,但有深度限制:
1 | agent: |
默认限制 2 层。也就是说:主 Agent → 子代理 → 孙代理,但孙代理不能再 spawn。
嵌套子代理适合递归式的任务。比如你说「帮我审查整个项目」,主 Agent 按目录拆分成多个模块,每个子代理拿到一个模块后,又按文件拆分成更小的子任务。
但嵌套太深会导致协调成本爆炸式增长。两层嵌套通常已经够用了。
子代理与技能系统
子代理也能利用技能系统。当子代理执行任务时,它会搜索技能库找匹配的技能。如果找到了,执行效率更高。
反过来,子代理成功完成的任务也可能触发技能生成。但这里有个设计考量:子代理生成的技能是否要存入主技能库?
当前的策略是:子代理成功完成且主 Agent 对结果满意时,才会存入主技能库。这避免了质量不佳的子代理执行结果污染技能库。
和记忆系统的关系
子代理的会话不会独立存入记忆系统。它们的执行轨迹会被合并到主 Agent 的会话中一起归档。
从记忆的角度看,子代理是透明的——你之后回忆这次任务时,看到的是一个完整的过程,不会分成主 Agent 和子代理的片段。
使用建议
让 Agent 自己决定是否并行。大部分情况下不需要你显式指定。Agent 的判断通常是合理的。
控制并发数。并行越多,API 调用越密集。如果你的 LLM API 有 rate limit,太多并发可能导致限流。建议 max_sub_agents 设为 3-5。
关注 token 消耗。子代理多了,token 消耗也线性增长。monitor 好你的 API 用量。
Docker 后端更安全。多个子代理并行操作文件系统可能有冲突。Docker 后端让每个子代理在独立容器中工作,天然避免冲突。
复杂编排考虑写脚本。如果你的并行任务有复杂的依赖关系和分支逻辑,可能写一个编排脚本比纯靠 Agent 推理更可靠。cocoloop 社区有人分享过结合 Hermes Agent 和 Make/Taskfile 的方案,在 Agent 的灵活性和脚本的确定性之间取得平衡。