🤖HermesBlog
Hermes 官方教程 · 第22篇2026/8/9· Easy Understand Hermes Agent

第22篇:子代理委派——AI 的分身术

Hermes Agent 官方教程第22篇:AI 的分身术

子代理委派:AI 的分身术

第22篇:子代理委派——AI 的分身术

你有没有遇到过这种情况:手头有一堆活儿,但自己只有一双手?Hermes 的 delegate_task 工具就是你的“分身术”——它能召唤出多个 AI 小助手,各干各的,互不干扰,最后把结果汇总给你。

第1步:理解子代理的核心逻辑

子代理就像你临时雇的实习生:它对你的过往对话一无所知,你给它什么资料(goal 和 context),它就基于这些干活。干完后,它只把一份“工作总结”交给你,不会把中间过程全塞进你的脑子里。

⚠️ 关键提醒:子代理是“失忆”的。你必须在调用时把所有背景信息写清楚,否则它只能瞎猜。

# 错误示范:子代理根本不知道“那个错误”是什么
delegate_task(goal="修复那个错误")

# 正确示范:把背景、路径、错误信息全交代清楚
delegate_task(
    goal="修复 api/handlers.py 里的 TypeError",
    context="文件在第47行报错:'NoneType' object has no attribute 'get'。函数 process_request() 依赖 parse_body() 的返回值,但后者在缺少 Content-Type 时返回 None。项目路径 /home/user/myproject,Python 3.11。"
)

第2步:单任务委派

最基础用法——把一件事交给一个子代理:

delegate_task(
    goal="调试测试失败的原因",
    context="错误信息:test_foo.py 第42行断言失败"
)

第3步:并行批量委派

同时派多个子代理干活,默认最多10个(可配置,无硬上限)。它们并行执行,最后汇总成一个结果:

delegate_task(tasks=[
    {"goal": "研究主题A", "context": "重点看近期一手资料"},
    {"goal": "研究主题B", "context": "比较主流解释"},
    {"goal": "修复构建", "context": "项目根目录:/home/user/project"}
])

第4步:结构化输出(output_schema)

每个任务可以带一个可选的 output_schema,它是一个 JSON Schema 对象,子代理的最终答案必须通过它的校验。子代理一开始就会看到这个 schema,把它当作输出契约(提示它“只返回 JSON 值,别写解释、别加代码围栏”);答案返回后由父代理校验,如果没通过,会再给子代理一次有界的纠正机会,并把校验错误原样带上(不会重新粘贴 schema)。任务结果里会多出 schema_valid(true/false),失败时还会有 schema_errors。

就算纠正后还是没对上,子代理的活儿也不会白干:结果依然是 status: completed,原始文本放在 summary 里,同时带上 schema_valid: false、schema_errors 和一条 schema_note 说明这段文本未经校验。父代理直接从原始文本里挑需要的东西就行,不用把一个可能跑了一小时的任务重跑一遍。另外,只要 JSON 本身合法(对象或数组),外面包一层说明文字或代码围栏也能被校验器接受。

delegate_task(
    tasks=[{
        "goal": "Check which of these three endpoints return 200",
        "context": "https://a.example, https://b.example, https://c.example",
        "output_schema": {
            "type": "object",
            "properties": {
                "healthy": {"type": "array", "items": {"type": "string"}},
                "failing": {"type": "array", "items": {"type": "string"}}
            },
            "required": ["healthy", "failing"]
        }
    }]
)

写 schema 时尽量宽松:只要求你真正会读取的字段。没有 output_schema 的任务不受影响。

第5步:给子代理传图片

有些活儿光靠文字说不清——比如用户发来的截图、设计稿、渲染出来的图表。这时可以给任务加一个可选的 images 列表(最多 8 个,支持本地路径、http(s) 链接或 data:image/... 链接):

delegate_task(tasks=[{
    "goal": "Compare the rendered dashboard against the design mock and list layout deviations",
    "context": "The app runs at http://localhost:3000; the repo is at /home/user/dash.",
    "images": ["/home/user/mocks/dashboard-v2.png",
               "https://cdn.example.com/current-render.png"],
}])

图片怎么送进去,跟用户自己贴图走的是同一套逻辑(agent.image_input_mode):

  • 子代理模型支持视觉——图片会作为原生多模态内容出现在子代理的第一轮里:本地文件转成 data URL(和其他文件读取一样受读取守卫约束),远程和 data: 链接原样透传。子代理看到的是真正的像素。
  • 子代理模型不支持视觉——goal 里会多出 [Image attached at: <path>] 提示行,并告诉子代理用 vision_analyze 去看。

传图是尽力而为:读不了的路径会跳过并记一条日志,图片环节出任何问题都会退回纯文本 goal,绝不会把 spawn 搞挂。图片是给子代理“看”的,纯文本文件路径还是照常放 context 里。

第6步:典型应用场景

并行调研:同时查三个技术方向,省时省力。

代码审查+修复:让子代理在全新环境里审查并修复安全漏洞,不污染你的对话上下文。

大规模重构:比如把整个 src/ 目录里的 print() 替换成 logging,这种琐碎又占上下文的活儿,交给子代理再合适不过。

第7步:批量模式细节

当你传 tasks 数组时,Hermes 会返回一个后台句柄,所有子代理跑完后,统一发回一份合并结果。如果父代理本身是“编排者”,它会等自己的子代理全部完成,再综合结果返回。

另外,后台终端进程归属于启动它的那个代理:子代理在委派结束时被关闭,它剩下的进程(包括更早轮次里启动的)也会被终止,但不会影响父代理或兄弟代理的进程。共享同一个终端环境并不等于转移进程所有权。所以子代理在返回最终总结前,应该先等自己的构建、测试等有界后台命令跑完;如果某个 CI 监听或服务器需要在子代理结束后继续运行,请在父会话里启动它——返回一个进程 ID 并不会把所有权交给父代理。

取消操作:普通的后续消息不会取消后台子代理。/stop(网关 /stop、CLI /stop、桌面/TUI 的 Stop 按钮、ACP cancel)或关闭/重置所属会话,会终止该会话正在跑的后台委派;被停掉的子代理仍会返回一条结构化结果(status="interrupted"),summary 里是它最后输出的文本。

卡死的子代理:如果子代理彻底不动了,心跳陈旧监控会盯着它的进度信号(API 调用、工具启动、活动时间戳)。超过阈值(轮次间空闲 450 秒,或在工具里卡住 1200 秒)就会被中断,父代理收到一条 status: "timeout" 的结果。这样即使在一次性运行(hermes chat -Q、Bot Chat 一次性、cron)里,卡住的子代理也不会永远占着这一轮。注意,正在等模型返回也算“有进度”,所以慢速本地模型或长 prefill 不会被误判为卡死。

如果你还想额外加一道上限(比如给无人值守的 cron 委派做成本控制),可以按安装逐个开启(注意:它限制的是空闲时间,不是总运行时长):

# child_timeout_seconds: 1800  # 可选:空闲上限(下限 30 秒)

正数限制的是空闲时间,而不是总运行时长:它指的是子代理在毫无进展(没有完成的 API 调用、没有工具状态变化、没有活动时钟跳动)的情况下最多能撑多久,超过就被放弃。任何一点进展都会重置这个窗口,所以一个正在等几分钟才返回的 completion 的子代理——正是过去会丢掉已完成工作的那种情况——不会因为耗时长而被杀掉;而一个真正停住不动的子代理仍然会被抓住(正在飞行中的请求另有每次调用的陈旧看门狗独立兜底)。设为 0 或负数则关闭这道上限;无论开关如何,下面的心跳陈旧监控都照常生效。

当空闲窗口走到约 80% 时,子代理会通过它的 steer 通道收到一行 [delegation budget warning](在它下一个迭代边界送达),告诉它已经空闲了多久、让它现在就返回总结,这样慢但还能救的子代理可以自己收尾,而不是丢掉上下文。这个警告每个空闲窗口只触发一次,一旦恢复进展就会重新武装。

超时结果里还会带上 timed_out_after_seconds(实际墙钟时间)、last_event_age(等待结束时子代理已经沉默了多久——快速区分“慢供应商”和“失控”的办法)以及 timeout_phase(超时发生在哪个阶段,否则是 after_llm_calls)。这四个字段在非超时错误里都是 null。

后台进程会共享 dock。 代理用 terminal(background=true) 启动的任何东西(构建、测试、开发服务器、CI 轮询器)在 spawn 的那一刻就会出现在子代理行下方的 Processes 区块里——⚙ <command> · 42s · last: <latest output line>——结束时原地翻成 ✔ exit 0 / ✘ exit 1 / ✘ killed,大约 60 秒后离开 dock(对话里的完成通知才是持久记录)。在 Classic CLI 监控器里,进程行排在代理下面:Enter 查看该进程的日志尾部,x 停掉这一个进程;进程不能被 steer。TUI 的 /agents 浮层会在 spawn 树下列出同一个区块(/stop 会结束所有后台进程)。桌面端则把这些进程显示为输入框上方的磁贴。

在 Classic CLI 或 TUI 的输入框里按 Ctrl+R,可以在多行预览和单行阴影摘要之间切换 dock。终端能转发功能键时,F7 仍是可选别名。摘要保留实时计数和展开/还原提示,空间允许时还会加上活动信息。打字和发送都不受影响;打开、关闭监控器会保留你的草稿和插入点。这只是本地显示选择,不会写入配置。

一次性运行的额外限制:hermes chat -q / --oneshot 会话总共最多只能生成 delegation.oneshot_max_children 个子代理(默认 2,0 表示不限)。因为一次性运行没有后续轮次来接收结果,而且基准测试里这类 spawn 大多是“独立复查我自己的工作”,每个子代理都要重新付一次冷启动系统提示、重新读一遍仓库。交互式和网关会话不受影响。

子代理的工具权限:delegate_task 不接受面向模型的 toolsets 参数,每个子代理继承父代理已启用的工具集,模型没法给子代理开父代理没有的能力。有几类工具即使父代理有,子代理也会被拦下:

  • delegate_task —— 叶子子代理(默认角色)不能用;role="orchestrator" 的编排者子代理保留它,受 max_spawn_depth 约束。
  • clarify —— 子代理不能跟用户交互
  • memory —— 不能写共享的持久记忆
  • send_message —— 不产生跨平台副作用
  • cronjob —— 不能以父代理的名义再排活儿
  • start_chat —— 不能以用户的名义开新对话

两种角色都保留 execute_code(编程式工具调用),这样子代理可以批量处理机械性工作,而不是把推理轮次烧在这些琐事上。

第8步:子代理的上下文压缩

子代理也会“忘事”——它的上下文窗口塞满时同样要压缩,而且压缩的触发点跟父代理一致:compression.threshold × 窗口大小(默认 0.50),或者全局 compression.threshold_tokens 上限(如果设了且更低的话)。

如果你想让某个子代理更早、更省地压缩,可以用 delegation.compression_threshold_tokens 给它单独加一道绝对上限(默认 0,也就是关闭)。它只作用于子代理的压缩触发点,取“它”和“比例阈值”里更低的那个生效,不会碰请求内容,也不会影响父代理。注意这个值至少要 16000 才会启用;写成 true 或 "200k" 这类都是配置错误,Hermes 会警告并忽略。

为什么默认不开?官方做过一次 1393 个代理的回放测试:在缓存前缀完整的情况下,200K 和 400K 两档上限的成本差距在 5% 以内,而每一次压缩都是一次丢细节的机会。所以除非你有明确的成本或上下文压力,否则保持默认就好。

# delegation:
#   compression_threshold_tokens: 32000  # 可选:子代理压缩触发上限(≥16000 才生效,默认 0 关闭)

总结:子代理委派 = 上下文隔离 + 并行执行 + 结果汇总。用好它,你就能同时推进多个任务,而不会被海量中间信息淹没。

下一篇预告:第23篇将介绍“工具调用进阶——如何自定义 Hermes 的工具”,敬请期待!

📖 官方文档

本文根据 Hermes Agent 官方文档编写,原文见:官方文档 › user-guide/features/delegation