委托与多 Agent 编排
本教程共 25 篇 · 第 18 篇 · 更新于 2026-07-26 · 约 14 分钟阅读
18. 委托与多 Agent 编排
本节目标:搞懂 Hermes Agent 怎么把一个大任务拆给多个子 Agent 并行干,以及怎么用 Mixture-of-Agents(MoA)让好几个模型凑在一起出主意。学完你能判断什么时候该委托、什么时候该用 MoA、怎么配它们。
为什么需要委托
先打个比方。你是个项目经理,手头一件事:调研三个技术方向、写一份对比报告。
一种做法是你自己闷头干:先查 A,再查 B,再查 C,最后汇总。中间查到的几十页资料、几十次搜索结果,全堆你脑子里。等你想汇总时,脑子已经被噪声塞满了。
聪明的做法是找三个实习生,一人分一个方向,告诉他们「查完给我一份摘要」。他们各自在各自的工位上查,你只收三份摘要,脑子清清爽爽做汇总。
Hermes Agent 的委托(Delegation)就是干这个的。主 Agent(父 Agent)通过 delegate_task 工具派出子 Agent(Subagent),每个子 Agent 有自己独立的对话上下文、独立的终端会话,干完活只把最终摘要带回来。父 Agent 的上下文始终保持干净。
这一招解决两个核心问题:
- 上下文膨胀:中间搜索结果、文件内容不再污染主对话
- 并行加速:最多 3 个子 Agent 同时干活(默认值,可调)
delegate_task:派一个子 Agent 去干活
delegate_task 是 Hermes Agent 70+ 内置工具之一,属于 delegation 工具集。最简单的用法是单任务委托:
delegate_task(
goal="Debug why tests fail",
context="Error: assertion in test_foo.py line 42"
)
goal 是子任务目标,context 是给子 Agent 的上下文。两个字段都给清楚,子 Agent 才能独立干活。
Warning子 Agent 启动时完全是空白的。它不知道你和父 Agent 之前聊过什么,不知道项目长什么样,连「我们刚才说的那个 bug」是什么都不知道。它唯一的信息来源就是
goal和context。所以这两字段必须把子 Agent 需要的一切都塞进去:文件绝对路径、错误信息、项目结构、测试命令、技术栈版本。
对比一下:
# 错误写法:子 Agent 一头雾水
delegate_task(goal="Fix the error")
# 正确写法:子 Agent 拿到就能开干
delegate_task(
goal="Fix the TypeError in api/handlers.py",
context="""api/handlers.py 第 47 行有 TypeError:
'NoneType' object has no attribute 'get'.
process_request() 接收 parse_body() 的返回值,
但 Content-Type 缺失时 parse_body() 返回 None.
项目路径 /home/user/myproject, Python 3.11."""
)
子 Agent 拿到后会用一个聚焦的系统提示词跑自己的推理循环,完成后再返回结构化摘要:做了什么、改了哪些文件、遇到什么问题。
单任务 vs 批量并行
delegate_task 支持两种模式。
单任务模式:派一个子 Agent 干一件事,适合「这个子任务需要推理,但我自己懒得在主上下文里折腾」。
批量模式:传一个 tasks 数组,同时派多个子 Agent 并行干活。默认最多 3 个并发(可通过 delegation.max_concurrent_children 调整,最低 1,没有硬上限)。
delegate_task(tasks=[
{"goal": "Research topic A", "context": "Focus on recent primary sources"},
{"goal": "Research topic B", "context": "Compare the leading explanations"},
{"goal": "Fix the build", "context": "Project root: /home/user/project"}
])
批量模式的几个细节值得记住:
- 底层用
ThreadPoolExecutor线程池,并发数就是配置的max_concurrent_children - 结果按输入顺序排好返回,不管谁先干完
- 超过并发上限会直接报工具错误,不会偷偷截断
- 顶层批量委托是后台异步的,Hermes 立刻返回一个句柄,等所有子 Agent 干完再统一把结果推回来
在 TUI 里,批量委托会以树状视图实时显示每个子 Agent 的工具调用,每个任务还有完成行。在 Gateway 模式下,进度批量回传给父 Agent 的进度回调。
子 Agent 的上下文隔离
这是委托机制最核心的设计。再强调一遍:
子 Agent 启动时上下文是空的。它看不到父 Agent 的对话历史、之前的工具调用、讨论过的任何内容。
这种隔离带来一个好处:父 Agent 的上下文不会被中间噪声撑爆。子 Agent 搜索了 10 篇文章、读了 5 个文件、跑了 2 次测试,这些过程全留在子 Agent 自己的 messages 里,函数返回后就被丢弃。父 Agent 只收到一条 tool_result,里面是子 Agent 的最终摘要文本。
一句话总结:子 Agent 拥有独立 messages,全部中间过程不会回到父 Agent。
工具继承与限制
子 Agent 的工具集不能自己挑。delegate_task 不接受 model-facing 的 toolsets 参数,子 Agent 直接继承父 Agent 已启用的工具集。这保证子 Agent 拿不到父 Agent 没有的能力——模型没法偷偷给子 Agent 加权限。
但有几类工具即便父 Agent 有,子 Agent 也用不了:
delegate_task:叶子子 Agent(默认)不能再委托,防止递归失控clarify:子 Agent 没有用户交互通道,不能停下来问用户memory:不让子 Agent 写共享持久记忆,避免并行子 Agent 同时写冲突send_message:子 Agent 不该绕过父 Agent 直接给用户发消息code_execution:让子 Agent 一步步推理而不是直接跑代码
execute_code(程序化工具调用)子 Agent 是保留的,这样它们能批量做机械活,少烧推理迭代。
委托深度与嵌套编排
默认情况下委托是扁平的:父 Agent(深度 0)派子 Agent(深度 1),子 Agent 不能再往下派。这是为了防止递归委托失控。
但有些场景需要多阶段,比如「先并行调研,再综合」。这时可以让父 Agent 派一个**编排者(Orchestrator)**子 Agent,它自己还能再派工干活:
delegate_task(
goal="Survey three code review approaches and recommend one",
role="orchestrator", # 允许这个子 Agent 再派自己的工人
context="...",
)
role 参数有两个值:
role="leaf"(默认):子 Agent 不能再委托,等同扁平委托role="orchestrator":子 Agent 保留delegate_task工具,可以再派叶子节点
但 orchestrator 角色默认是空操作,因为 delegation.max_spawn_depth 默认是 1(扁平)。要真正启用嵌套,得把这个值调到 2 以上:
# ~/.hermes/config.yaml
delegation:
max_spawn_depth: 2 # 允许编排者子 Agent 派叶子孙子
max_concurrent_children: 3
# orchestrator_enabled: false # 全局开关,设 false 强制所有子 Agent 都是叶子
Warning深度乘并发等于总并发量。
max_spawn_depth: 3+max_concurrent_children: 3理论上能跑到 3×3×3 = 27 个叶子 Agent 同时干活。每多一层,花费乘一次。调深度之前想清楚值不值。
配置子 Agent 用更便宜的模型
子 Agent 可以用和父 Agent 不同的模型。这点很实用——主推理用贵的旗舰模型,子 Agent 干搜索、读文件这种粗活用便宜的快模型。
# ~/.hermes/config.yaml
delegation:
model: "google/gemini-flash-2.0" # 子 Agent 用便宜模型
provider: "openrouter" # 可选:路由到不同 provider
不配的话,子 Agent 就用父 Agent 的同款模型。
子 Agent 还继承父 Agent 的 API key、provider 配置和凭据池,所以遇到限速时能自动轮换 key。
监控和日志
委托干活时你可以实时盯。TUI 有个 /agents(别名 /tasks)覆盖层,把递归的委托树变成一等公民的审计界面:
- 实时树状视图,按父节点分组展示运行中和刚完成的子 Agent
- 每个分支的成本、token 数、触碰文件统计
- 可以单独杀掉或暂停某个子 Agent,不影响兄弟节点
- 事后回放:子 Agent 返回后还能逐轮翻它的历史
每次 delegate_task 派发还会写一份追加式、人类可读的日志,让你(或父 Agent)能实时看子 Agent 干嘛,不用等汇总:
tail -f ~/.hermes/cache/delegation/live/deleg_ab12cd34/task-0.log
每行带时间戳,展示子 Agent 的助手文本、思考片段、工具调用(-> tool_name({args}))、工具结果和最终状态标记。同目录还有个 manifest.json 描述整个批量(目标、任务数、每任务状态)。日志完成后保留 7 天自动清理。
几个高频委托模式
并行调研:让多个子 Agent 同时查不同主题,父 Agent 最后综合成简报。
代码审查 + 修复:把审查任务交给一个空白上下文的子 Agent,让它不带偏见地看代码。关键是 context 要塞够:项目路径、相关文件、技术栈、测试命令、关注点。
多文件重构:把大重构拆成多块,每个子 Agent 处理代码库的一部分。
Tip每个子 Agent 有自己的终端会话和工作目录,只要它们编辑不同文件就不会互相踩。如果两个子 Agent 可能动同一个文件,那个文件你自己等并行结束后再处理。
先采集后分析:用 execute_code 做机械的数据采集(10+ 次连续工具调用,便宜),再用 delegate_task 做重推理的分析(单次昂贵推理,干净上下文)。这往往是最省钱的组合。
委托 vs execute_code 怎么选
| 维度 | delegate_task | execute_code |
|---|---|---|
| 推理 | 完整 LLM 推理循环 | 只跑 Python 代码 |
| 上下文 | 全新隔离对话 | 没对话,就是脚本 |
| 工具访问 | 所有非禁用工具带推理 | 通过 RPC 调 7 个工具,无推理 |
| 并行 | 默认 3 个并发子 Agent | 单脚本 |
| 适合 | 需要判断、多步求解的复杂任务 | 机械数据处理、脚本化流程 |
| token 成本 | 高(完整 LLM 循环) | 低(只回传 stdout) |
经验法则:子任务需要推理、判断、多步求解——用 delegate_task。子任务只是机械的多步数据处理或脚本流程——用 execute_code。
Mixture-of-Agents:让多个模型凑一起出主意
委托是把任务拆给多个子 Agent,**MoA(Mixture-of-Agents)**是另一种多 Agent 玩法:让多个模型在同一次回复里凑一起出主意。
打个比方,你写了一份方案,找三位资深同事先各自给意见,然后你拿着三份意见综合改出一版终稿。MoA 就是这个流程的自动化。
MoA 是一个虚拟模型 provider。每个命名预设(preset)在 moa provider 下显示为一个可选模型。选中一个 MoA 预设后,预设里的聚合器(aggregator)就是实际干活的模型——它写助手回复、发工具调用。参考模型(reference models)先跑,给聚合器提供分析意见。
MoA 适合那种「难任务、单模型不够、但又想要 Hermes 正常 Agent 循环(工具调用、迭代、中断、持久化)」的场景。
选一个 MoA 预设当模型
MoA 预设在所有模型选择界面都能选,因为它就是个普通 provider:
/model default --provider moa
/model review --provider moa
具体可用面:
- CLI / Gateway / TUI 的
/model:/model <preset> --provider moa,或/model --provider moa选默认预设 hermes model命令和 Dashboard 模型选择器:会出现Mixture of Agentsprovider 行,预设名就是模型名- 桌面 GUI:模型下拉里有个
MoA presets区,选MoA: <preset>就切换
还有个一次性快捷方式 /moa,它把单条 prompt 跑过默认 MoA 预设,然后恢复你之前的模型:
/moa design and implement a migration plan for this flaky test cluster
/moa 整个参数就是 prompt,它不再把第一个词当预设名解析。裸 /moa(不带 prompt)只打印用法。
Note
/moa是一次性便利糖,不是模型切换。要切到 MoA 预设做整场会话,得从模型选择器选。这样设计是为了让普通 prompt 永远不会意外改你的模型。
MoA 在 Agent 循环里怎么跑
当 provider 选成 moa 时,每次主模型调用 Hermes 会做这些事:
- 按名字解析选中的预设
- 跑配置的参考模型(不带工具 schema,只收到对话的 user/assistant 文本,所以参考调用便宜且不会被严格 provider 拒绝)
- 把参考输出作为私有上下文附加给聚合器
- 用正常 Hermes 工具 schema 调聚合器
- 把聚合器响应当作真正的模型响应
- 如果聚合器调了工具,Hermes 正常执行
- 下一轮模型迭代,同样的 MoA 流程在更新后的对话上再跑一遍
因为 MoA 是通过正常模型系统选的,它会自动和 /goal、Gateway 会话、TUI 会话、桌面聊天组合工作。
配置 MoA 预设
预设可以从这几个地方配:Dashboard → Models → Model Settings → Mixture of Agents;桌面应用 → Settings → Model → Mixture of Agents;hermes moa configure [name];或直接写 config.yaml。
配置里存的是显式的 provider/model 对,所以可以混 provider、用同一个 provider 的多个模型:
moa:
default_preset: default
presets:
default:
reference_models:
- provider: openai-codex
model: gpt-5.5
- provider: openrouter
model: deepseek/deepseek-v4-pro
aggregator:
provider: openrouter
model: anthropic/claude-opus-4.8
# 可选:固定采样温度。不写就每个模型用 provider 默认值
# reference_temperature: 0.6
# aggregator_temperature: 0.4
max_tokens: 4096
enabled: true
上面默认预设里:两个参考模型(openai-codex:gpt-5.5、openrouter:deepseek/deepseek-v4-pro),聚合器是 openrouter:anthropic/claude-opus-4.8。
给参考模型加 token 上限提速
每轮里参考模型并行跑,然后聚合器才动手。参考模型的生成时间是每轮延迟的主因——轮的墙钟时间几乎和最慢的参考模型写完的 token 数强相关。默认参考模型不限 token(reference_max_tokens 不设),可能写成长篇大论的建议。
给预设设 reference_max_tokens 就能给参考输出封顶,换来简洁建议。聚合器只需要每位顾问判断的要点,封顶(比如 600)能明显缩短每轮墙钟时间,质量损失很小。它只封参考模型,聚合器(用户能看到的答案)永不被封。
moa:
presets:
fast:
reference_models:
- provider: openrouter
model: anthropic/claude-opus-4.8
- provider: openrouter
model: openai/gpt-5.5
aggregator:
provider: openrouter
model: anthropic/claude-opus-4.8
reference_max_tokens: 600 # 简洁建议 -> 更快的轮
顾问节奏 fanout
默认参考模型每个用户轮跑一次(fanout: user_turn)——它们在轮的第一条消息上给出计划级建议,然后聚合器独自走完剩余工具循环。这是最省钱的节奏:顾问成本不会随轮内工具调用数翻倍。
两种替代节奏用成本换建议新鲜度:
fanout: per_iteration:参考模型每次工具迭代都重跑,建议永远跟最新工具结果同步——但顾问延迟和花费按轮内工具调用数翻倍fanout: every_n:3:折中。参考模型在每个用户轮的第一次迭代跑,然后每第 3 次工具迭代跑一次(任意N >= 2都行)。中间迭代复用上次顾问的缓存建议,所以聚合器每步都有建议——只是每 N 步刷新一次。计数器在每个新用户消息时重置。fanout: {mode: every_n, n: 3}这种映射形式也接受,会被规范化成字符串形式
moa:
presets:
fresh:
reference_models:
- provider: openrouter
model: anthropic/claude-opus-4.8
aggregator:
provider: openrouter
model: openai/gpt-5.5
fanout: per_iteration # 顾问每次工具迭代都刷新
不认识或格式错的值会回退到 user_turn。
Note2026 年 7 月之前默认节奏是
per_iteration。现在默认改成user_turn——最便宜、影响最低的节奏——除非按模式跑分证明更贵的默认值合理。想要每步都建议的预设得显式设fanout: per_iteration。
顾问输出的隐私过滤
顾问输出可能把对话里的敏感数据(邮箱、格式化电话号码、API key、JWT)回显到参考块、MoA trace 记录、聚合器 prompt 里。moa.privacy_filter(默认关闭)给这些表面打码:
moa:
privacy_filter: display # 或 full
display:只给用户可见表面打码——UI 里渲染的参考块和save_traces写的记录。聚合器仍收到原始顾问文本,所以答案质量不受影响full:额外给注入聚合器 prompt 的顾问文本(以及一次性/moa综合输入)打码
凭据形态(API key 前缀、JWT、私钥、DB 连接串)由 Hermes 的中央密钥脱敏器处理;MoA 过滤在其之上再加邮箱和清晰格式的电话号码脱敏。模式刻意保守:纯数字串、行号、时间戳、git SHA、IP 地址永不被碰——只匹配 (555) 123-4567 或 555-123-4567 这种分隔的电话格式。
每个槽位的推理努力
参考和聚合器槽位都能设 reasoning_effort。想给同一个模型不同深度贡献、或想让聚合器比顾问想得更深时有用。合法值和 Hermes 正常推理控制一致:none、minimal、low、medium、high、xhigh、max、ultra。
moa:
presets:
deep_review:
reference_models:
- provider: openai-codex
model: gpt-5.6-sol
reasoning_effort: low
- provider: openai-codex
model: gpt-5.6-sol
reasoning_effort: xhigh
- provider: xai-oauth
model: grok-4.5
aggregator:
provider: openai-codex
model: gpt-5.6-sol
reasoning_effort: high
不写 reasoning_effort 就用该槽位的 provider/Hermes 默认值。
终端管理预设
hermes moa list
hermes moa configure # 更新默认预设
hermes moa configure review # 创建或更新命名预设
hermes moa delete review
MoA 的几个关键性质
- Prompt 缓存不破坏:选 MoA 预设就是普通模型选择,不改历史、不换工具集、不重建系统提示词。长寿命的对话前缀缓存完整保留,切换 MoA 的缓存失效代价和普通
/model切换一样 - 不可递归:预设的聚合器不能是另一个 MoA 预设。递归 MoA 树被刻意挡掉了
- 单个参考失败不致命:某个参考模型凭据失败不会中止整轮。Hermes 把失败放进参考上下文,继续用返回了的模型
- 调用数增加:单次模型迭代可能涉及多个参考调用 + 一个聚合器调用。你付的是多模型视角的钱,不是缓存失效的钱
常见坑
给子 Agent 写模糊目标。「修一下 bug」这种太虚,子 Agent 一头雾水。要写「修 api/handlers.py 第 47 行 process_request() 收到 parse_body() 返回 None 导致的 TypeError」。
不写文件路径。子 Agent 不知道你的项目结构。永远写清相关文件的绝对路径、项目根、测试命令。
以为子 Agent 能续命。顶层委托是异步的,但仍绑定在拥有它的会话和 Hermes 进程上。会话关闭、/stop、/new、进程重启都可能取消或搁置进行中的活。需要扛过这些边界的,用 cronjob 或 terminal(background=True, notify_on_complete=True)。
轻信子 Agent 摘要。子 Agent 说「修好了,测试通过」——自己再跑一遍测试或看 diff 验证一下。摘要是摘录,不是保证。
默认就开嵌套编排。max_spawn_depth 默认是 1 就是有意为之。真需要多阶段再调,调之前算清并发乘积的成本。
把 MoA 当便宜方案。MoA 单轮多花几个参考模型的钱,是为难任务换质量。简单任务用单模型更划算。