1. 从一次「上下文爆炸」说起:Hermes Agent 多 Agent 到底解决什么问题
如果你用 Hermes Agent 跑过稍微复杂一点的任务,大概率遇到过这种情况:让它分析一个中型项目的安全机制、内存机制和 skills 机制,它一头扎进去读了四十多个文件,中间塞满了 read_file 的返回、grep 的命中行、终端输出,等到真正要写总结的时候,上下文窗口已经被中间数据占满,模型开始丢三落四,甚至把前面读过的结论忘掉。
这不是模型不行,是单 Agent 架构的天然瓶颈。一个 Agent 只有一条 conversation、一个 terminal session、一份 toolset,所有中间产物都堆在同一个上下文里。任务越复杂,上下文越脏,推理质量越差。
Hermes Agent 的多 Agent 能力就是冲着这个痛点来的。它的核心不是搞一个独立的调度中心,而是把「委托」做成一个普通工具:delegate_task。模型看到这个工具的描述后,自己判断当前任务要不要拆、拆成几个、每个子任务给什么上下文和工具集。运行时由 delegate_task 创建一个或多个 child AIAgent,每个 child 拥有独立的 system prompt、conversation、terminal session、toolset 和 iteration budget。parent 不接收 child 的完整中间上下文,只拿回 summary、status、tokens、tool_trace 这些结构化结果。
这套设计里最关键的两个概念就是 Subagent 和 delegate_task 的上下文隔离。Subagent 是隔离的执行单元,delegate_task 是创建和管理这些单元的入口。理解它们怎么协作,你就能在自己的 Agent 流程里复用这套模式。
这篇文章面向多 Agent 编排场景,会拆解上下文隔离的设计思路,给出可复制的 Subagent 配置片段和 delegate_task 调用示例,并附上隔离效果的验证步骤。如果你正在用 Hermes Agent 或者自己搭多 Agent 系统,下面的内容可以直接对照落地。
2. TaoToken 前置:给多 Agent 流程准备统一 Key 与 API 通道
多 Agent 场景有个很现实的问题:child agent 会独立发起 API 调用。如果每个 child 都去配一套 provider、base_url、api_key,配置会迅速失控。更麻烦的是,parent 和 child 可能用不同模型,credential 管理一旦分散,排查 401 就会变成噩梦。
我的做法是先用 TaoToken 把 Key 和 API 通道统一起来,让 parent 和所有 child 走同一个入口。这样无论 delegation 里怎么覆盖 model,底层 credential 都是可控的。
2.1 拿到统一 Key
打开 https://taotoken.net/api-keys ,登录后创建一个 API Key。这个 Key 就是后面所有 Agent 共用的凭证。建议按用途命名,比如 hermes-multi-agent,方便以后区分。
创建完成后复制 Key,格式通常以 sk- 开头。注意:这个 Key 只在创建时完整显示一次,务必先存到安全的地方。
2.2 确认 Base URL
TaoToken 的 API 入口是:
https://taotoken.net/api
这个地址要填到 Hermes Agent 的 provider 配置里,作为 OpenAI-compatible endpoint。parent 和 child 都指向它,delegation 里如果覆盖了 base_url,也要保证指向同一个通道,否则 credential 会对不上。
2.3 在 Hermes 配置里接入
Hermes Agent 的 provider 配置一般在 config.yaml 里。找到 provider 相关段落,填入 base_url 和 api_key:
provider:
name: "openai-compatible"
base_url: "https://taotoken.net/api"
api_key: "sk-你的TaoToken密钥"
model: "claude-sonnet-4-5"
如果你用的是环境变量方式,也可以:
export OPENAI_BASE_URL="https://taotoken.net/api"
export OPENAI_API_KEY="sk-你的TaoToken密钥"
配好之后先跑一个最小请求验证通道是否通:
curl https://taotoken.net/api/v1/chat/completions \
-H "Authorization: Bearer sk-你的TaoToken密钥" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"messages": [{"role": "user", "content": "ping"}]
}'
返回里有 choices 数组就说明通道正常。这一步很关键,因为后面 child agent 的调用都依赖这个通道,如果这里不通,delegate_task 创建出来的 child 会直接报错,而且错误信息可能被 summary 包装过,排查起来更绕。
2.4 为什么多 Agent 场景更需要统一通道
child agent 是独立 AIAgent 实例,它会自己发起 LLM 请求。如果 parent 用一套 credential,child 用另一套,会出现几个问题:
第一,成本统计分散。你不知道整个 delegation 树花了多少 token。
第二,模型切换困难。想让 child 用便宜模型做并行搜索,parent 用强模型做综合,如果 credential 不统一,切换时要改多处配置。
第三,排障困难。child 报 401 时,你无法确定是 parent 的 credential 问题还是 child 的覆盖配置问题。
统一到 TaoToken 之后,delegation 里只需要覆盖 model 字段,base_url 和 api_key 保持继承,credential 链路就清晰了。接入文档在 https://taotoken.net/doc ,里面有完整的参数说明。
3. 可复制配置:Subagent 与 delegate_task 的上下文隔离落地
这一节是全文的核心。我会给出可以直接复制的配置片段和调用示例,重点说明上下文隔离是怎么通过参数实现的。
3.1 delegation 配置片段
Hermes Agent 的 delegation 行为由 config.yaml 里的 delegation 段控制。下面是一份适合多 Agent 编排的配置:
delegation:
model: "" # 空表示继承 parent model
provider: "" # 空表示继承 parent provider
base_url: "" # 空表示继承 parent base_url
api_key: "" # 空表示继承 parent api_key
inherit_mcp_toolsets: true # 缩窄 toolsets 时保留 MCP
max_iterations: 50 # 每个 subagent 独立 tool loop 上限
child_timeout_seconds: 600 # child 最大运行时间
reasoning_effort: "" # 空表示继承 parent reasoning level
max_concurrent_children: 3 # 单次 delegate_task 并行上限
max_spawn_depth: 1 # delegation 树深度
orchestrator_enabled: true # 是否允许 orchestrator role
subagent_auto_approve: false # child 危险命令默认拒绝
这份配置里,model、provider、base_url、api_key 都留空,意味着 child 默认继承 parent 的 credential。这正是上下文隔离的一部分:child 不重新解析一套 provider,而是复用 parent 已经验证过的通道。
max_spawn_depth: 1 表示扁平 delegation,parent 可以创建 child,但 child 不能再创建 subagent。如果你需要树状编排,把它改成 2,并配合 role: "orchestrator"。
3.2 delegate_task 调用示例:单任务模式
最简单的用法是单任务模式,提供 goal,可选 context 和 toolsets:
{
"goal": "Analyze Hermes security mechanisms and summarize the implementation design.",
"context": "Repo path: /home/user/projects/hermes-agent. Focus on tools/approval.py, tools/terminal_tool.py, tools/url_safety.py. Respond in Chinese. Return file references and implementation flow.",
"toolsets": ["file", "terminal"],
"role": "leaf"
}
这里 context 是上下文隔离的关键。child 没有 parent 的对话历史,如果 parent 不把 repo 路径、重点文件、输出语言写进 context,child 就不知道这些信息。role: "leaf" 表示这是默认的叶子节点,不能再 delegate。
3.3 delegate_task 调用示例:批量并行模式
需要并行处理多个独立子任务时,用 tasks 数组:
{
"tasks": [
{
"goal": "Analyze Hermes security mechanisms and summarize the implementation design.",
"context": "Repo path: /home/user/projects/hermes-agent. Focus on tools/approval.py, tools/terminal_tool.py. Respond in Chinese.",
"toolsets": ["file", "terminal"],
"role": "leaf"
},
{
"goal": "Analyze Hermes memory system and summarize how memory is extracted, stored, retrieved, and injected.",
"context": "Repo path: /home/user/projects/hermes-agent. Focus on memory-related prompts, USER.md/MEMORY.md, session_search. Respond in Chinese.",
"toolsets": ["file", "terminal"],
"role": "leaf"
},
{
"goal": "Analyze Hermes skills evolution mechanism and summarize how skills are selected, loaded, created, updated.",
"context": "Repo path: /home/user/projects/hermes-agent. Focus on prompt_builder, skills_tool, skill_manager_tool. Respond in Chinese.",
"toolsets": ["file", "terminal"],
"role": "leaf"
}
]
}
批量模式下,每个 task 都会得到自己的 child AIAgent,拥有独立的 conversation 和 terminal session。tasks 数量不能超过 max_concurrent_children,默认 3。
3.4 上下文隔离的实现参数
child AIAgent 创建时,Hermes 传入几个关键参数来实现隔离:
enabled_toolsets = child_toolsets
quiet_mode = True
ephemeral_system_prompt = child_prompt
skip_context_files = True
skip_memory = True
clarify_callback = None
parent_session_id = parent.session_id
iteration_budget = None
逐个解释:
skip_context_files = True 表示不自动注入 AGENTS.md、.cursorrules 等项目上下文文件。这是隔离的第一层:child 不会因为 parent 所在项目而被动加载一堆文件。
skip_memory = True 表示不注入 USER.md、MEMORY.md 等持久记忆。这是隔离的第二层:child 不会读到 parent 的长期记忆,避免子任务被历史结论带偏。
clarify_callback = None 表示 child 不能向用户提问。这是隔离的第三层:并行子线程不会因为等待用户输入而阻塞。
parent_session_id = parent.session_id 用于 session tree 和 tracing 关联,但它不等于共享对话。child 的 conversation 是全新的。
iteration_budget = None 表示 child 使用独立的 iteration budget,不消耗 parent 的额度。
3.5 child 的完整输入由什么组成
child 模型真正看到的输入分三块:
第一块是 system message,由 child AIAgent 的基础 system prompt 加上 delegate_task 构造的 ephemeral child prompt 拼接而成。基础 prompt 包含 agent 身份、工具使用约束、当前时间、环境提示。ephemeral prompt 包含 YOUR TASK: {goal}、CONTEXT: {context}、WORKSPACE PATH: {workspace_path} 以及 summary 格式要求。
第二块是 user message,就是 goal 本身。goal 在 system prompt 和 user message 里各出现一次,确保不同 provider 对 system/user 权重处理有差异时,核心任务仍然明确。
第三块是 tool schemas,根据 child_toolsets 加载。leaf child 的工具集里会剥离 delegate_task、clarify、memory、send_message、execute_code。模型不是看到 prompt 说不能调用,而是 runtime 在 toolset 层直接移除了这些工具,模型根本拿不到对应 schema。
3.6 哪些上下文会传,哪些不会传
用一张表说清楚:
| 内容 | 是否自动传给 child | 说明 |
|---|---|---|
| parent 完整聊天历史 | 否 | child 不知道之前对话,必须靠 context |
| 本轮 goal/context | 是 | goal 写入 child prompt 并作为 user message |
| 工作区路径 hint | 是 | 从 parent 的 cwd/terminal_cwd 推断 |
| 项目 context files | 否 | skip_context_files=True |
| 持久记忆 | 否 | skip_memory=True |
| clarify 能力 | 否 | clarify_callback=None |
| parent toolsets | 部分继承 | child toolsets 与 parent toolsets 取交集 |
| parent provider/model | 默认继承 | 可通过 delegation 配置覆盖 |
| parent session_id | 关联 | 用于 tracing,不等于共享对话 |
| child tool schemas | 是 | 根据 child_toolsets 加载,随请求发送 |
这张表解释了为什么 context 的质量决定 subagent 质量。Hermes 不会把 parent 当前上下文整体复制给 child,避免上下文爆炸,也避免 child 误读 parent 的中间状态。
4. 验证请求:确认上下文隔离真的生效
配置写完不算完,得验证隔离效果。这一节给出可操作的验证步骤。
4.1 验证 child 拿不到 parent 对话历史
先让 parent 读一个文件,然后创建一个 child,让 child 回答「我刚才读了什么文件」。
parent 侧操作:
用户:读一下 /home/user/projects/hermes-agent/config.yaml
parent 会调用 read_file,然后你继续:
用户:创建一个 subagent,问它「parent 刚才读了什么文件」
如果隔离生效,child 会回答它不知道,因为 parent 的对话历史没有传给它。child 只能看到 goal 和 context 里的内容。
反过来,如果你在 context 里写「parent 刚才读了 config.yaml」,child 就能回答出来。这证明信息传递完全依赖 context 字段。
4.2 验证 child 拿不到持久记忆
在 USER.md 里写一条独特信息,比如「用户最喜欢的颜色是靛蓝」。然后创建一个 child,问它「用户最喜欢的颜色是什么」。
如果 skip_memory=True 生效,child 会回答不知道。这条信息在 parent 的持久记忆里,但不会注入 child。
4.3 验证 child 不能调用 delegate_task
创建一个 leaf child,让它在任务里尝试再创建一个 subagent。child 会失败,因为 leaf 的工具集里没有 delegate_task schema。
你可以从返回的 tool_trace 里看到 child 尝试调用的工具列表。如果列表里没有 delegate_task,说明剥离生效。
4.4 验证 tool_trace 只返回摘要
让 child 读一个大文件,然后检查返回的 tool_trace:
{
"tool": "read_file",
"args_bytes": 128,
"result_bytes": 4096,
"status": "ok"
}
注意 result_bytes 是 4096,但实际文件内容不会出现在 parent 上下文里。parent 只看到「child 读了一个文件,结果 4096 字节」,看不到文件内容。这就是上下文隔离在结果汇总层的体现。
4.5 验证并发结果顺序稳定
创建一个包含 3 个 task 的批量调用,每个 task 的耗时不同。检查返回的 results 数组,task_index 应该按输入顺序排列,不会因为并发完成顺序而乱掉。
{
"results": [
{"task_index": 0, "status": "completed", "summary": "..."},
{"task_index": 1, "status": "completed", "summary": "..."},
{"task_index": 2, "status": "completed", "summary": "..."}
],
"total_duration_seconds": 26.2
}
4.6 验证文件状态提醒
让 parent 先读 src/config.py,然后创建一个 child 去修改这个文件。child 完成后,检查返回的 summary 里是否追加了提醒:
[NOTE: subagent modified files the parent previously read — re-read before editing: src/config.py]
这条提醒说明 file_state 机制在工作,它把「parent 的局部上下文可能过期」暴露给 parent 模型。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
多 Agent 场景的报错往往比单 Agent 更隐蔽,因为错误可能发生在 child 侧,但被 summary 包装后返回。这一节对照真实报错给出排查路径。
5.1 401 Unauthorized
这是最常见的 credential 问题。child 报 401 时,先确认三件事:
第一,parent 的 credential 是否有效。用第 2 节的 curl 命令直接测通道。
第二,delegation 里是否覆盖了 api_key 但填了错误的值。检查 config.yaml 的 delegation.api_key,如果非空,确认它和 parent 用的是同一个 TaoToken Key。
第三,base_url 是否一致。如果 delegation 里覆盖了 base_url 但指向了另一个端点,credential 可能对不上。
排查命令:
grep -A 10 "delegation:" config.yaml
确认 base_url 和 api_key 要么为空(继承 parent),要么和 parent 一致。
5.2 local proxy failed
这个报错通常出现在 child 尝试访问网络但代理配置有问题时。注意:Hermes 的 child 使用独立 terminal session,环境变量可能和 parent 不同。
检查 child 的 toolsets 里是否有 web 或 browser。如果有,确认网络访问配置正确。如果不需要网络,把 toolsets 缩窄到 ["file", "terminal"],避免 child 触发网络调用。
5.3 reading choices 相关报错
这类报错通常出现在解析 LLM 响应时。可能的原因:
第一,child 使用的 model 和 parent 不同,响应格式有差异。检查 delegation.model 是否设置了一个不兼容的模型。
第二,reasoning_effort 配置导致响应结构变化。如果 parent 和 child 的 reasoning level 不同,解析逻辑可能不匹配。
排查方法:把 delegation.model 和 delegation.reasoning_effort 都留空,让 child 完全继承 parent,看报错是否消失。如果消失,再逐个覆盖,定位问题参数。
5.4 OAuth 相关报错
如果 parent 用的是 OAuth 类 provider,child 可能无法继承 OAuth token。因为 child 创建时走的是 credential bundle 解析,OAuth 的刷新逻辑可能不适用。
解决方案:在 delegation 里显式配置 base_url 和 api_key,让 child 走 API Key 认证而不是 OAuth。这也是我推荐用 TaoToken 统一通道的原因之一,API Key 认证在 parent 和 child 之间传递更稳定。
5.5 child timeout
报错信息类似:
Subagent timed out after 600s
检查 delegation.child_timeout_seconds。默认 600 秒,低于 30 秒会被提高到 30 秒。如果 child 任务确实需要更长时间,调大这个值。但要注意,child 运行期间 parent 是阻塞的,太长会卡住 parent。
诊断日志在 ~/.hermes/logs/subagent-timeout-<sid>-<ts>.log,里面有 child 最后的活动记录。
5.6 Too many tasks
报错信息:
Too many tasks: 5 provided, but max_concurrent_children is 3.
这说明 tasks 数组长度超过了 max_concurrent_children。要么减少任务数,要么拆成多次 delegate_task 调用,要么调大 max_concurrent_children。
注意:调大并发会线性放大 token 成本。超过 10 时 Hermes 会打 warning。
5.7 child summary 语言不对
如果 child 返回的 summary 是英文,但你要中文,检查 context 里是否写了「Respond in Chinese」。child 默认英文,不会自动继承 parent 的输出语言偏好。
这是一个典型的上下文隔离副作用:语言偏好属于 parent 对话历史的一部分,不会自动传给 child,必须显式写进 context。
5.8 child 声称成功但实际失败
child summary 是 self-report,不是已验证事实。如果 child 说「文件已写入」或「上传成功」,parent 应该自己验证。
对有副作用的操作,要求 child 返回可验证 handle,比如 URL、ID、绝对路径、HTTP status。parent 拿到后自己 fetch、stat、read back,确认无误再告诉用户成功。
6. 语义一致 CTA:把多 Agent 流程接到统一通道上
多 Agent 编排跑通之后,下一步是让它稳定运行。child agent 会独立消耗 token,独立发起请求,独立执行工具。如果 credential 分散、通道不统一,规模一上来就会乱。
我的建议是把 parent 和所有 child 都接到同一个 API 通道上。这样 delegation 里只需要覆盖 model,base_url 和 api_key 保持继承,credential 链路始终清晰。
具体来说:
如果你还在配置阶段,先去 https://taotoken.net/api-keys 拿一个统一 Key,然后按第 2 节的方式填到 config.yaml 里。接入细节看 https://taotoken.net/doc 。
如果你已经跑通了单任务 delegation,想验证不同模型在 child 侧的表现,可以用 https://taotoken.net/chat 快速对比模型输出,确认哪个模型适合做并行 worker。
如果你打算把多 Agent 流程用于长期编码或 Agent 编排,建议了解一下 Coding Plan:https://taotoken.net/coding-plan 。它更适合持续性的开发场景,不用每次单独管理额度。
配置过程中如果遇到 credential 或通道问题,直接对照第 5 节的排查路径走一遍,大部分 401 和 timeout 都能定位到具体参数。
最后提醒一个实操细节:delegation 里的 model 覆盖只改模型,不改权限。child 的 toolsets 仍然受 parent toolsets 交集、blocked tools、role/depth 限制。模型换了,隔离边界不变。这一点在调试时容易混淆,记住「模型是模型,权限是权限」就不会绕进去。



被折叠的 条评论
为什么被折叠?



