关于 agent-orchestrator
面向构建多 Agent 系统的开发者,汇总生产环境中的编排设计实践。内容涉及工具调用循环、子 Agent、分阶段工作流、模型路由、记忆与预算控制。
主要功能
- 01共享上下文与子 Agent 协议
- 02工具调用、重试与结果校验
- 03多阶段依赖工作流与人工检查点
- 04LLM 提供方路由与回退
- 05分层记忆与反馈学习
- 06上下文预算、可观测性与护栏
适用场景
- 01设计可调用工具的 Agent 循环
- 02协调需要依赖排序的多阶段任务
- 03为模型提供方配置路由和回退
- 04控制 Agent 的上下文与调用预算
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ssheleg/ agent-stack --skill agent-orchestrator安装后在 Claude Code 中输入/agent-orchestrator确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/context-engineering.mdgovernance.mdgraph-engineering.mdkv-cache.mdllm-proxy-billing.mdmemory-architecture.mdmemory-landscape.mdmemory-lifecycle.mdpatterns.mdpipeline.mdprovider-lifecycle.mdruntime.md详细介绍
Agent Orchestrator — 生产环境最佳实践
来自生产级多 Agent 系统的模式。正文记录的是决策;具体机制就在一个文件之外,且正文控制在 4750 个 token 以内——正文一旦变长,就会挤占本该拆分出去的那一层,而这个正文一直如此,直到 2026-08-16。
触发词
“工具调用”、“LLM 路由器”、“回退链”、“记忆层”、“token 钱包”、“роутер моделей”、“слой памяти”、“граф задач”。
也会根据范围路由到此处。描述中列出的范围一直保留到 0.30.0:工具调用循环、人工检查点流水线、提供方路由、回退/重试、记忆架构、检索与衰减、上下文预算、子 Agent 协调、错误层级;将工作构建为图(并行层、虚假边、汇合前的检查器);转售相关内容:分级钱包、单一加价边界、跨数据库和提供方 API 的 saga、支出差额轮询、预算与循环防护、每租户密钥。
在 0.31.3 中从描述移至此处:“оркестратор”、“суб-агент”、“human in the loop”、“человек в цикле”、“биллинг LLM”。
架构概览
User Question
↓
OrchestratorAgent.run(AgentContext)
├─ Shape check → one loop, or a planned path (§5, references/pipeline.md)
├─ Context loading (a parallel layer: staleness, sources, KB — §13)
├─ History trimming, then context budget allocation
├─ System prompt built from the live capabilities (§10)
└─ Execute:
├─ SIMPLE: LLM → tools → sub-agents → results → LLM → … → answer (§2)
└─ PLANNED: plan → dependency layers → checker → checkpoints → done (§5)
1. Orchestrator 模式
共享上下文对象
向每个子 Agent 传递同一个近似不可变的上下文对象。它包含请求(project_id、user_question、chat_history)、工具机制(llm_router、tracker、workflow_id)、已解析的提供方和模型,以及一个用于流水线标记的 extra 字典。完整的数据类见 references/patterns.md → Orchestrator 的共享上下文和子 Agent 协议。
关键原则:
- 子 Agent 从不修改上下文,只返回类型化结果
- 提供方/模型偏好按用户默认值 → 项目默认值 → 应用默认值的顺序传递
extra字典承载流水线状态、_skip_complexity等标记以及会话 ID
子 Agent 协议
每个子 Agent 都继承同一个基类,该基类只有一个抽象方法 run(context) -> Result,因此 Orchestrator 无需了解任何子 Agent 的内部工作方式。该类位于同一参考章节中。
每个 Agent 都有对应的类型化结果子类(例如,包含 query、results、attempts 的 SQLAgentResult)。
2. 工具调用循环(简单路径)
循环分为六个步骤,每一步都至关重要:
- 优先管理上下文压力——先裁剪上下文;如果窗口即将填满,还要注入收尾指令,然后再发起调用。
- 携带工具调用模型,并启用重试。
- 没有工具调用就表示得到了答案——这是循环唯一的正常退出方式。
- 追加助手回合及其工具调用,不作修改。
- 分发调用——独立工具使用
asyncio.gather,有状态工具则按顺序执行。 - 按
tool_call_id关联并追加每个结果,然后继续迭代。
for 循环上的 else 是防护措施:循环耗尽时,根据已收集的内容尽力组织答案,而不是返回空结果。完整代码见
references/patterns.md → 完整的工具调用循环。
关键细节:
- 并行分发工具:独立工具使用
asyncio.gather,有状态工具按顺序执行(例如,依赖先前查询结果的数据处理) - 注入收尾指令:上下文容量达到约 70% 时,注入系统消息,告诉大模型停止调用工具并给出最终答案
- 循环内裁剪:上下文容量达到约 80% 时,将较早的助手与工具交互对折叠成单行摘要
- token 限制恢复:遇到
LLMTokenLimitError时,将上下文压缩至 60% 并重试一次。如果仍然失败,则返回部分答案 - 最大迭代次数防护:始终设置硬性上限。次数耗尽时,根据目前收集的数据尽力组织答案
- 迭代次数返还:可恢复的提供方错误不计入该防护的次数——费用仍会产生,只在成功路径上核算会低估最糟糕的运行成本
- 预算感知:告知模型剩余预算,否则 300 步的表现会和 30 步一样
3. 元工具(编排器级)
编排器的工具会委派给子 Agent,而非直接执行:
query_database 接受自然语言问题,由其背后的 SQL Agent 负责生成、验证和执行。一个参数,一项职责,调用方也无需知道子 Agent 的存在。
def get_tools(*, has_db=False, has_kb=False, has_mcp=False) -> list[Tool]:
"""Assembled per request from the same capability flags that build the prompt (§10)."""
tools = []
if has_db: tools.extend([QUERY_DB, PROCESS_DATA, MANAGE_RULES, ASK_USER])
if has_kb: tools.append(SEARCH_CODEBASE)
if has_mcp: tools.append(QUERY_MCP)
return tools
有两条规则属于这一层,而非提示词:请求不具备的能力不会对应任何工具;工具接受的每个枚举值都必须在 schema 中封闭定义(ask_user 的 question_type 只能是 yes_no | multiple_choice | free_text,而不是自由文本)。如何描述工具,让模型选对工具——包括说明何时使用它,以及它容易与哪个相邻工具混淆——见
agent-harness/references/tools.md。
4. 子 Agent 重试与验证
每次调用子 Agent 都要同时进行重试和验证,并将二者分开处理:调用抛出异常,与调用返回了不可用内容,需要不同的应对方式。前者重试,后者重新提示或失败。
后续设计应遵循以下决策:
- 在类型层面将错误划分为可重试和致命错误,而不是在调用点划分。无效凭据和服务提供方过载都会抛出异常,但只有一种值得再次尝试。
- 在结果交给用户前验证结果,并依据调用方预期的结构进行检查——是否有行、列名是否正确、是否附有引用。只检查是否抛出异常的验证,无法发现自信却错误的答案。
- 限制尝试次数并返回最佳部分结果,因为相比部分答案,另一种选择并不是更好的答案,而是没有答案且预算已耗尽。
- 达到限制而停止,不等于等待。 继续处理独立工作,并安排在有界且经过授权的情况下恢复已停止的工作线程;并非每次沉默都代表停滞。
保留服务提供方的时序信息、尝试次数与截止时间预算,以及不确定效果的恢复机制。
支出和计费限制仍由人员把关。机制与准入规则见:
references/runtime.md→ 达到限制而停止,不等于等待。
层级结构、循环流程和各领域的验证器见:
references/patterns.md。
5. 多阶段流水线(复杂路径)
如果问题不适合通过单个循环处理——例如多个相互依赖的数据步骤、需要人员在中途审批,或运行必须跨越两条消息之间的间隔继续——编排器应先制定计划,再执行各阶段,而不是调用工具。
这里涉及三个决策;具体机制见
references/pipeline.md。
- 分两层检测复杂度,先采用成本较低的方式:先用关键词启发式判断,仅在启发式无法确定时才调用一次小型模型。为每个问题都调用模型进行分类,会给常见情况增加成本。
- 按依赖层执行,绝不按列表顺序执行(§13)。计划声明了
depends_on,执行时却按列表顺序遍历,就会把任务串行化;而包含多个阶段的层,在任何阶段使用其结果前都应先经过检查器。 - 检查点是一种能释放工作线程的暂停方式。 如果等待人工审批会占用进程,长时间审批就会被悄悄从设计中剔除——这正是一个人机协作系统逐渐不再有人参与的原因。
6. LLM 提供商路由
在提供商前设置路由器,而不是在应用前设置提供商客户端: 按顺序尝试,失败时转到下一个,并向上层返回统一的错误层级, 让调用方无法判断是哪个供应商响应的。
阅读 references/llm-proxy-billing.md → 模型路由与回退,了解
回退链和各提供商的指数退避重试;阅读其中的
防护措施部分,了解预算、循环检测和自动暂停。
三个会让你真金白银付出代价的陷阱:
- 重试循环和回退链会相乘。 三个提供商各重试三次,就会为一个 提示词调用九次;应限制总尝试次数,而不是限制每个提供商的尝试次数。
- 只在故障时运行的健康检查无法恢复。 被标记为不健康的提供商需要定时 探测,否则调用链会永久少用一个提供商,而且无人察觉——请求仍然会成功。
- 模型选择有三个层级——请求、租户、系统默认值——如果租户覆盖值会被请求 参数悄无声息地压过,那么廉价模型就可能按高价模型的费率计费。
- 这三点都假设请求是可移植的;轨迹却不是。 推理内容携带着供应商凭据——有时 还在工具调用中——因此在一轮对话中途切换可能导致 400,而剥除所有推理内容 正是导致这种情况的原因。应在轮次之间切换。
- 能力消耗并不均匀:瓶颈在规划器,因此最强的模型应分配给管理器,而不是分配给 工作量最大的 Agent。
7. 多层记忆系统
四个层级,各自有不同的生命周期,也有各自存在的理由:
| 层级 | 范围 | 生命周期 | 保存内容 |
|---|---|---|---|
| 1 聊天历史 | 每个会话 | 分钟 | 各轮对话,裁剪至令牌预算 |
| 2 工作记忆 | 每个资源 | 天 | 该任务目前已确认的信息 |
| 3 长期经验 | 每个资源 | 月 | 有效的方法及其置信度评分 |
| 4 洞察 | 每个项目 | 永久 | 超越其资源生命周期的结论 |
哪些内容会进入第 3 层和第 4 层,由 references/patterns.md 决定——置信度管理、
经验提取启发式、模糊去重、冲突解决。
这四层描述的是生命周期,而生命周期并不是分类法。 第 3 层和第 4 层都属于 经验性内容;这里没有事实存储,关于用户的过时事实会让 Agent 显得无礼, 关于环境的过时事实则会让它出错。这里没有提及检索,而检索涉及四项决策;第一项 ——是否进行检索——如果失败,就会生成一个凭空而来的自信回答,且错误日志中 不会留下任何记录。
请依据 references/memory-architecture.md
设计记忆层,而不要依据这张表——它还涵盖上下文预算陷阱、第 0 层信息延续和工作区
规模。写入路径和自行构建或采用现有方案的问题,在下方索引中各有对应条目。
8. 自学习反馈循环
三个循环为记忆层提供输入,它们的信号来源各不相同:先失败后修正的尝试、用户的 评价,以及时间。
本节存在的核心规则: 经验必须基于对比来写入——把失败的尝试与成功的尝试 并列比较——绝不能只基于一次成功运行。只从成功中学习的系统,学到的只是自己的习惯。
提取器、置信度计算和晋升查询:
references/patterns.md。
9. 可观测性
一个总线,每个步骤对应一个事件,并在同一总线上以分块形式流式传输答案。两个
特性决定了它是信息流还是装饰:每个事件都带有单调递增 ID,
以便重连的客户端能够续接,而不会错过本次运行;信息流是持久化轨迹的视图,
而不是记录本身——没有存储下来的流,是 agent-evals 无法评估的一次运行。追踪器的
结构:
references/runtime.md。
10. 动态系统提示词
在组装工具(§3)的同一轮中,根据实际存在的能力组装提示词:为每项当前可用的能力命名一个部分;如果有资源映射,也加入其中;然后加入当前的经验,最后加入指南。描述了 Agent 实际并未获得的工具的提示词,会让模型浪费一轮去调用一个不存在的工具。
该文本应该包含什么、详略到什么程度,以及如何列出词汇表以避免 Agent 臆造状态值,都由 agent-harness 技能的 agent-harness/references/system-prompt.md 规定——所有内容集中于一处,而不在这里。这个技能负责的是接线:每次请求都会根据与工具列表相同的能力标志重新构建提示词,因此两者绝不会不一致。只有逐字节完全相同时,重新构建才没有代价;如果会话中途能力发生变化,应追加变更,而不是重写前缀——编辑边界之前的内容会产生什么代价,请参阅 references/kv-cache.md。
11. 澄清请求(ask_user)
暂停并提问,与检查点一样,都是挂起后恢复,只是调用方不同——它们遵循同一套契约,而非两套(references/pipeline.md)。
12. 上下文工程
压缩是一套阶梯式流程,而不是一次调用。 清除旧的工具结果,折叠过大的内容块,精简消息,然后才调用摘要器——每迈一步都重新测量。大多数压力在第一次调用之前就能缓解。
绝不要让 tool_use 孤立。 每个截断点都必须落在 assistant+tool 对之间,否则下一次请求会在任务中途返回 400 错误。
跨越边界时,以有类型的内容块而非散文传递状态——目标、产物、已验证的工作、限制模式。摘要器会保留讨论内容,却丢掉状态,包括那个表示不要写入任何内容的标志。
将大型工具结果移至文件,并保留路径。 裁剪历史记录无法挽救已被一次工具输出填满的上下文窗口。
子 Agent 的价值在于它自己的上下文窗口:它返回的是有类型的摘要,而非对话记录。
13. 工作即图
在循环、流水线或子 Agent 之前:先确定结构。 节点是一个工作单元;边是依赖关系,且边承载数据。完整模型、模型的来源,以及此主机实际执行的内容,详见
references/graph-engineering.md。
四条规则,真正会改变代码的就是这些:
- 为每条边标注类型:数据、控制、授权或资源。 对继承的任何链路运行虚假边测试——只有在箭头不承载四者中的任何一种时才删除它:没有负载、因果约束、权限或共享资源。backup→migration、approval→charge 和 lease→edit 不传输字节,却都是真实依赖;通常每个工作流中,测试找出的只有两三条仅表示某人输入顺序的箭头。分支前,先比较读写集合——只读分支可以并行;两个写入者操作同一事物时,原本就该有一条资源边。
depends_on是一种声明,因此要按层执行。 §5 的执行器按列表顺序遍历plan.stages,而模型却声明了依赖关系——这会把一个特意声明无需串行的计划串行化。对图运行 Kahn 算法;出现环路时应判定计划失败,而不是让运行陷入死锁。- 并行层在汇合前需要检查器。 三个分支运行,其中一个返回幻觉,综合节点却无法分辨:它会整合三个结果,并自信地作答。检查器只判定可用/不可用,不做其他事;汇合节点依赖的是检查器,绝不能直接依赖某个分支。
- 除非能明确说出动态结构的必要原因,否则使用静态结构——这是为了可预测性,而非可审计性。当运行保存了执行记录(已运行的节点/边/事件、策略版本、确定性的预算/深度/节点上限、来源信息)时,就可审计;保存了该记录的动态图同样可审计。设计图本身绝不是证据:图中画出的结构,并不一定是实际运行的结构。
清单 — 构建新的编排器
上述章节是地图。读者无法从标题中推断出的要点都列在这里——这些都是从犯错中学到的:
- 在上下文窗口用量约达 80% 时于循环中裁剪内容,在约 70% 时注入收尾提示,并设置最大迭代次数保护,以整理出部分答案,而不是空手返回
- 可恢复的提供商错误会退还其占用的迭代次数;配置错误不得消耗本用于阻止运行失控的预算
- 重试和回退次数的总量设有上限——三个提供商各重试三次,就会针对一个提示词调用九次
- 按计划探测被标记为不健康的提供商;只在失败时运行的健康检查永远无法恢复,调用链会少运行一次,却无人察觉
- 聊天历史设有下限——为保留旧有认知而裁剪历史的会话,是在选择泛泛而谈,而非保留用户一分钟前说的话
- 每项已声明的依赖都注明其承载的数据;计划按层执行,多于一个节点的层在任何内容使用其结果前都要经过检查器(§13)
- 观察过检查器拒绝人为植入的错误输入,且其判定以评分形式存储——从未拒绝过任何内容的检查器,本身就是一个发现
- 子 Agent 返回的是提炼后的摘要,而非文字记录;返回值与输入成正比的函数调用,只不过是穿了件伪装外衣
- 在一个边界处根据配置或提供商解析模型、上下文窗口和价格——绝不从源码中的供应商 ID 表解析
- 实现前先添加可观测性,调整提示词前先进行评估,否则调整就只是凭经验;只有语料可以等到生产环境
- 负责回答用户问题的 Agent,应按
agent-evals/references/support-quality.md衡量:记录、指标、评分标准、评审器和每日事件
参考资料
每个文件开头都有自己的 在以下情况下加载 行——权威触发条件以该行为准;此表仅作索引。
| 文件 | 在以下情况下阅读 |
|---|---|
references/graph-engineering.md | 你正在决定工作的形态——虚假边、菱形、检查器节点、静态还是动态 |
references/pipeline.md | 单个循环不符合形态——规划的路径、检查点、恢复,以及请求人工介入的中断 |
references/patterns.md | 你需要了解底层的数据模型和算法 |
references/memory-architecture.md | 正在为 Agent 提供记忆,或者记忆运行异常 |
references/memory-lifecycle.md | 记忆的写入路径——哪些内容进入,哪些内容离开 |
references/memory-landscape.md | 你要构建或采用记忆层,并想了解哪些做法已成为成熟实践 |
references/context-engineering.md | 循环即将耗尽上下文窗口 |
references/kv-cache.md | 你正在决定请求中的内容如何安排——静态前缀与轨迹的划分、缓存未命中的代价、运行时边界条件会产生的 2^N 种缓存分布、已命名的失效因素,以及四种常见的优化(它们付出了缓存代价,却一无所获) |
references/runtime.md | Agent 必须在崩溃、暂停、收到第二条消息、定时任务或使用限额导致的停止后继续运行 |
references/governance.md | 问题关乎权限,而非成本——它可以做什么,以及如何证明;事件检查清单(DNS 出站、机密拆分、摘要注入、外部影响、发现的凭证、暴露的 Docker API) |
references/llm-proxy-billing.md | 产品转售大模型访问权限 |
references/provider-lifecycle.md | 问题关乎人员队伍,而非循环——服务提供商生命周期、金丝雀信任、集群预算 |