Agent Platform · Detail Design

多 Agent 协作协议

把 Agent 之间的协作从「互相喊话」升级为「显式委托协议」:AgentInvocation、父子 Run、DelegationTrace、Round 0/1/2 与 ResultSink 五件套构成稳态契约。

返回文档目录查看 Agent Teams 设计

显式 AgentInvocation

所有 Agent 间派单走单一入口;不允许直连模型或私下互调

父子 Run 树

每次派单创建独立 child Run,DelegationTrace 串成可回放的协作树

Round 0/1/2 节奏

规划 → 执行 → 汇总三段式;Tier 3 内核完全不感知 Round 概念

详细设计说明

DESIGN DOCUMENT · MULTI-AGENT COLLABORATION PROTOCOL

把多 Agent 协作收敛为「显式协议 + 父子 Run + 必经 ResultSink」

这份文档定义 Agent 之间在 Tier 2 层如何派单、协作、回收结果。核心三件事:用 AgentInvocation 替代隐式互调;用父子 Run + DelegationTrace 保证协作可回放;用 Round 0/1/2 + AnswerObservationProtocol 把 Tier 3 单 Run 内核与 Tier 2 协作语义干净分层。

设计主张

多 Agent 协作不是 Tier 3 内核的能力,而是 Tier 2 Coordinator 的编排责任。每个 Agent 的执行仍是一个独立 Run、独立 RunState、独立审计;协作是把这些 Run 用 DelegationTrace 串成树,让父能等子、子能回结果给父。

AgentInvocationParent/Child RunDelegationTraceRound 0/1/2ResultSinkAnswerObservationProtocol

评审关注点

  • 父子 Run 的终态如何聚合给父
  • Round 2 汇总轮是不是另起 Run
  • 子 Run 边界是否真的隔离
  • Tier 3 是否完全不感知协作语义
  • DelegationTrace 能否单库回放
D1显式 Invocation无隐式互调
D2父子 Run 树每次派单独立 Run
D3执行边界独立子 Run 不复用父环境
D4Round 0/1/2编排在 T2 闭环
D5ResultSink 出口T3 唯一交付点

Agent Platform · 多 Agent 协作协议

状态:v1 草案
日期:2026-05-07
定位:Tier 2 Coordinator + JobDispatcher 上的协作编排协议;Tier 1 暴露 @单 Agent / @协作群两类入口;Tier 3 完全不感知 Round 与 Delegation
关联:与 Agent Teams 设计(协作单元的承载实体)、Harness 内核设计(单 Run 状态机契约)、可观测性设计(Trace 字段扩展)配套
目标:让多 Agent 协作具备「可派单、可等待、可汇总、可回放」四项硬能力,而不引入新的运行时身份

1. 定位与概念

SECTION GOAL

一张图看清 AgentInvocation 住哪一层、Coordinator 与 JobDispatcher 怎么分工、Run 树是如何被 DelegationTrace 串起来的。本章是阅读其余章节的入口。

1.1 总体架构图

下图把三层定位与协作树状态叠加在一张图上:横向 3 个 tier 带,T1 区给出协作工作台暴露的 2 类入口,T2 区显示 Coordinator + JobDispatcher 协同 + Round 0/1/2 节奏,T3 区只跑独立 Run(每个 child Run 一个独立 RunState)。Run 树由 DelegationTrace 串成。

T1 · 协作工作台 入口 + 鉴权 UI / API @单 Agent 派单 单聊 / 直接 mention @协作群 / @team N agent 扇出 AgentInvocation API 两类入口的统一契约 T2 · 协作编排 Coordinator + JobDispatcher ROUND 0 / 1 / 2 Coordinator 展开 mention · 选 strategy 推进 Round · 收 ResultSink 写 DelegationTrace JobDispatcher child Job 入队 · 沙箱预约 caller_extra 透传 parent 独立 Run 资源边界 ResultSink T3 唯一出口 AnswerObs 协议 回写 parent — ROUND TIMELINE — Round 0 · 规划 展开成员 / 拆分子任务 Round 1 · 执行 N 个 child Run 并行 / 串行 Round 2 · 汇总(可选) consolidator 起新 Run 收口 T3 · Run 内核 不感知协作 SINGLE RUN ONLY Parent Run role = caller Child A 独立 RunState Child B 独立 RunState Child C 独立 RunState Consolidator Run Round 2 · 单独 Run 收口 — DELEGATIONTRACE — parent_run_id ↔ child_run_id 的 N 行记录,串起整棵协作树(cost / latency / status 全部沉淀)
关键约束:T1 只暴露入口,T2 Coordinator 编排所有协作语义,T3 永远只跑单 Run 不感知协作。Round 0/1/2 是 T2 的节奏,T3 看到的只是「起一个独立 Run」。

1.2 两个典型时序图

下面两张图分别对应 T1 入口的两类语义:Scenario A 是 @ 单 Agent 派单(Parent 起一个 Child);Scenario B 是 @ 协作群派单(Parent 起 N 个 Child + Round 2 汇总)。点击 lifeline 头部色块跳到对应章节。

Scenario A · @ 单 Agent 派单

最简形态:Parent Run 在执行中决定把一个子任务委托给 Agent B。Coordinator 起 Child Run,DelegationTrace 落两行(请求 / 完成),ResultSink 把结果回填 Parent。没有 Round 2。

T1 · 工作台@AGENT-B T2 · CoordinatorROUND 0 → 1 T3 · Parent RunCALLER T3 · Child Run B独立 RunState DelegationTracePERSISTENCE 1 用户 @AgentB 任务消息 2 起 Parent Run(caller) 3 ↻ Parent 决定派单 → Agent B 4 AgentInvocation 请求 5 写 DelegationTrace · delegation_requested 6 起 Child Run B · caller_extra.parent_run_id 7 ↻ Child 执行 · 独立 RunState · 独立 Trace 8 ResultSink · AnswerObservation 9 写 DelegationTrace · delegation_completed + cost 10 回填 Observation 到 Parent 11 Parent 终态 · 总 cost = 父 + 子 12 SSE 推送给用户
最简形态:1 父 + 1 子,无 Round 2。Parent 在 ④ 发起的 AgentInvocation 在 T3 视角下就是一次普通的 AgentInvoke Tool 调用——状态保持 EXECUTING 阻塞在 Tool 控制器上,直到 ⑩ ResultSink 把 observation 当作 Tool 返回值回填,T3 完全不感知"在等子 Run"。DelegationTrace 落 2 行(请求 + 完成)即足以回放。
Scenario B · @ 协作群派单(Round 2 汇总)

完整三段式:Round 0 Coordinator 展开协作群 / 选 strategy;Round 1 并行起 N 个 child Run;Round 2 全部 ResultSink 收齐后起一个 Consolidator Run 整合。所有 N+1 个子 Run 都挂在同一个 parent_run_id 下。

T1 · 工作台@TEAM T2 · CoordinatorROUND 0/1/2 T3 · Parent RunCALLER T3 · Children A/B/CN 并行 · 独立 RunState T3 · ConsolidatorROUND 2 ONLY TraceDB — ROUND 0 · 规划 — 1 @team:研发组 任务 2 起 Parent Run(caller) 3 ↻ ③.a 查 Team 配置 → 展开 N 成员(按 role 过滤) ↻ ③.b 读 collaboration_strategy → 选派单路径 三种策略:fan-out(本图)/ sequential / lead-driven — ROUND 1 · 执行(N 并行) — 4 3 个 Child Run · caller_extra.parent_run_id 5 写 N 行 DelegationTrace · delegation_requested 6 ↻ N×并行 · 各自独立 Trace 7 N 个 ResultSink 收齐 — ROUND 2 · 汇总(独立 Run) — 8 起 Consolidator Run(仍挂同一 parent) 9 ↻ 整合 N 输出 10 汇总输出 → ResultSink 11 Parent 终态 · 聚合 cost 12 SSE 推送给用户
关键差异:Round 2 另起一个 Consolidator Run(不是在 Coordinator 进程内做整合),保证汇总过程也走完整 Harness 八步、能写自己的 Trace、能被 HITL 拦下。Tier 3 看到的依然是「N+1 个独立 Run」,不知道有 Round 概念。

1.3 为什么要做协作协议

当前缺口:

缺口具体表现影响
Agent 间私下互调无契约Agent A 直接调 Agent B 的工具或读 B 的记忆责任主体混淆;审计链断裂;权限放大
父子关系靠约定没有 parent_run_id 字段,只能靠日志 join跨 Run 回放需要拼日志;成本无法聚合到父
协作群没有汇总轮承载整合逻辑写在 Coordinator 进程里整合过程不走 Harness 八步、不被 HITL 拦、不写 Trace
子 Run 沙箱边界不明有时被理解成"复用父沙箱"权限越权;状态污染;并行竞争
Tier 3 被迫感知 RoundRunState 里塞 round_index 字段内核被业务语义污染;难以演进

本协议解决的具体技术问题:

  1. 把所有 Agent 间派单收敛到一个 AgentInvocation 入口——不再允许任意路径互调
  2. 把父子关系从约定升级为字段——parent_run_id 是 RunTrace 的一等公民
  3. 把 Round 2 汇总变成另起一个独立 Run——汇总也享受 Harness 全套约束
  4. 明确 Tier 3 的 Run 是协作的最小调度单元——内核不感知 Round / Delegation 概念

1.4 三层职责定位

层承担不承担
Tier 1 · 协作工作台 UI暴露 @ 单 Agent / @ 协作群两类入口;mention 解析;权限校验(用户可见的 Agent 列表);聊天侧把 invocation 串成可读时间线不做协作策略决策;不持有父子 Run 关系
Tier 2 · Coordinator 编排展开 mention;选 strategy;推进 Round 0/1/2;通过 JobDispatcher 起 child Run;收 ResultSink;写 DelegationTrace;做 Round 2 起 Consolidator Run;终态聚合给 Parent不存储 Agent / Team 实体(属 T1);不直接调 LLM(属 T3 内核)
Tier 3 · Run 内核每个 child Run 独立八步管道、独立 RunState、独立 RunState;通过 caller_extra 接收 parent_run_id 并落 Trace不感知 Round 概念;不感知 Delegation;不在 RunState 决策里读 parent;不跨 Run 共享上下文
关键边界:Round 0/1/2 是 Tier 2 概念,不向 Tier 3 渗透。Kernel 永远只跑单 Run,不知道这个 Run 是某协作树的第几轮、是不是 consolidator。Round 的影响力通过 Coordinator 在 Round 之间起新 Run 注入;RunState 状态机本身不变。

2. 数据模型

SECTION GOAL

列出协作协议引入的最小持久化与运行时实体,明确与 Run / Team / Trace 的关系。

2.1 AgentInvocation(运行时请求对象)

所有 Agent 间派单的统一入口,不存表,作为 Coordinator 内部消息结构。Tier 1 的 @ 提及和 Parent Run 内的"我要委托"都收敛到这一个对象。

字段类型说明
invocation_iduuid幂等键;重试同一请求不会重复起 Run
caller_kindenumuser_mention / parent_run(区分两类来源)
caller_run_iduuid?parent_run 来源时必填,user_mention 时可空
callee_agent_iduuid被派单的 Agent
group_session_iduuid?协作群场景必填,单聊场景为空
round_indexint0 = 规划,1 = 执行,2 = 汇总;Coordinator 维护,不进 RunState
task_briefstring自然语言任务描述(明文 + 已脱敏)
context_subsetjsonb显式裁剪过的上下文子集,不是父 RunContext 的全量转发
expected_outputjsonb?期望返回 schema(Round 2 consolidator 必填)
budgetjsonb本次 invocation 的成本上限、超时、HITL 阈值

2.2 GroupSession(协作群运行时上下文)

协作群 / @team 场景的共享运行时上下文。每次 @ 协作群都会创建一个新的 GroupSession(不是持久组织实体——那是 Team 的事)。

字段类型说明
iduuid主键
parent_run_iduuid关联的 Parent Run;同一次协作的 N+1 个 child 都挂这下面
team_iduuid?关联的 Team(如果走 @team;ad-hoc 协作群可空)
strategyenumfan-out-broadcast / sequential-relay / lead-driven(来自 Team 配置或全局默认)
membersjsonb展开后的 callee_agent_id 列表 + 角色
round_statejsonb当前 round_index、各 child 的 status / cost / latency
consolidator_run_iduuid?Round 2 起的 Consolidator Run id(无汇总轮则空)
created_at / closed_atts生命周期时间戳

2.3 DelegationTrace(持久化协作记录)

Tier 2 协作语义的可观测性主表。每次 invocation 落两行:delegation_requested + delegation_completed(或 _failed / _timeout)。回放协作树就是按 parent_run_id 查这张表。

字段类型说明
iduuid主键
parent_run_iduuid父 Run;查协作树的入口字段
child_run_iduuid子 Run;与 RunTrace.run_id 对齐
group_session_iduuid?协作群场景下与 GroupSession 关联
round_indexint0 / 1 / 2
caller_agent_id / callee_agent_iduuid派单方向
eventenumrequested / accepted / rejected / completed / failed / timeout
task_brief_hashstr任务描述指纹(防 PII 落库)
context_subset_hashstr传递 context 指纹(用于审计是否泄漏敏感字段)
cost_cents / latency_msint子 Run 实际消耗,回灌父用于聚合
created_atts事件时间

2.4 与现有实体的关系

关系基数说明
Parent Run → Child Run1 : nRunTrace 表新增 parent_run_id 字段;查询用 WHERE parent_run_id=X
GroupSession → Child Run1 : n同一次 @协作群产生的 N+1 个 child 都挂同一 group_session_id
Team → GroupSession1 : n(可选)来自 @team 路径时关联;ad-hoc 协作群 team_id 为空
AgentInvocation → DelegationTrace1 : ≥2每次 invocation 至少落 requested + 一条终态

3. 父子 Run 关系

SECTION GOAL

定义 Parent / Child Run 在沙箱、Trace、终态聚合上的契约,让 Tier 3 内核在不感知协作的前提下仍能被父正确等待与聚合。

3.1 父 Run 等待协议

原则:不扩展 RunState、不让 T3 感知协作。AgentInvocation 在内核里就是一种 Tool 调用——T3 工具调用控制器认得 4 类调用(本地 Skill / 沙箱 Skill / LLM / AgentInvoke),AgentInvoke 这一类的执行路径是「交给 Coordinator → 等 ResultSink 回填」,对 T3 而言只是一次"慢一点的 Tool 调用"。

结果Tool 控制器看到Parent RunState
child 成功 + observation 回填Tool 调用返回正常结果保持 EXECUTING,继续 Plan 下一步
child 失败 + 父策略 = abortTool 调用抛错,不重试EXECUTING → FAILED → TRACING
child 失败 + 父策略 = retry / fallbackTool 调用抛错,控制器按 manifest 重试 / 切 fallback agent保持 EXECUTING
超 budget.deadline 未回填Tool 调用超时EXECUTING → TIMEOUT → TRACING

这样 RunState 仍是 11 态、T3 状态机不变;"在等子 Run"只是 Tool 调用阻塞的一种具体形态,和"在等沙箱命令返回"没本质区别。Coordinator 在 T2 持有 parent_run_id → 待回填 invocation_id 的映射;ResultSink 触发时把 AnswerObservation 投回 Parent 的 Tool 控制器,调用栈自然解阻塞。

3.2 子 Run 执行边界独立性

每个 child Run 都独立持有自己的:

沙箱(按需):只有当 child 调用沙箱类 Skill(如 claude_code_execute / shell_exec)时才申请独立沙箱容器,与 parent 沙箱不共享;纯 LLM / DB / 外部 API 调用的 child 不进沙箱(见 沙箱边界 ↗)。

父和子之间唯一的运行时联系是:Coordinator 在子完成后通过 ResultSink 把 observation 回填给父。其余资源边界严格隔离。

3.3 终态聚合规则

父策略子终态 = SUCCEEDED子终态 = FAILED / REJECTED子终态 = TIMEOUT
abort_on_child_fail(默认)父继续 EXECUTING父 → FAILED父 → TIMEOUT
retry_on_child_fail父继续Coordinator 重起一次 child(最多 N 次)降级为 abort
fallback_on_child_fail父继续父收到 fallback observation 继续父 → TIMEOUT
collect_all(仅 Round 1 协作群)计入 N 个结果之一计入但标记失败计入但标记 timeout

成本聚合:父 Run 终态前,Coordinator 把所有挂在该 parent_run_id 下的 child Run cost 累加到父 RunTrace 的 delegation_total_cost 字段;父自身 cost 仍单独保留。同一棵协作树的 cost 等于 parent.cost + parent.delegation_total_cost。

3.4 防滥用边界

威胁缓解
无限委托链 A → B → A → B → ...Coordinator 检测 cycle(在协作树深度 + agent_id 重复路径);超过 max_delegation_depth(默认 5)拒绝
大流量推给 child 把成本推爆父 budget 透传给 child;child 自身的 budget = min(parent.remaining, child.config);超 budget 直接 REJECTED
跨 User / 跨 Workspace 委托Coordinator 在起 child 前校验 user / workspace 一致;不一致直接拒绝
context_subset 漏 PIICoordinator 按 schema 白名单裁剪;不在白名单的字段不进 child invocation

4. Round 机制

SECTION GOAL

说明 Round 0 / 1 / 2 在 Tier 2 Coordinator 的语义和推进规则,明确每一轮的输入、输出、终止条件。

4.1 Round 0 · 规划

触发:Tier 1 收到 @ 协作群消息,或 Parent Run 内部决定 fan-out 时。

承担方:Coordinator 进程(不起 Run)。

输入动作输出
用户消息 + group_session 或 team_id展开成员列表(按 Team 配置或 mention 命中)members 数组
Team.collaboration_strategy选择本次走 fan-out / sequential / lead-drivenstrategy 枚举
用户消息 + Team.config构造每个 child 的 task_brief 与 budgetN 份 AgentInvocation

终止条件:N 份 AgentInvocation 全部构造完成 → 进入 Round 1。Round 0 失败(如成员展开为空、策略不存在)直接把 Parent 标为 FAILED 不进 Round 1。

4.2 Round 1 · 执行

承担方:JobDispatcher 把 N 个 invocation 入队,每个生成一个独立 child Run;Tier 3 内核完成单 Run 八步执行。

strategy调度模式失败处理
fan-out-broadcastN 个 child 并行入队,全部 ResultSink 收齐进 Round 2父策略 = collect_all:失败计入但标记
sequential-relay按 position 顺序起 child;前一个 ResultSink 出来再起下一个任意一棒失败:链熔断;父按 abort_on_child_fail 处理
lead-driven先起 lead Run 拆子任务;lead 内部再触发 fan-outlead 失败 = 整个 Round 1 失败;executor 失败按 collect_all 收

终止条件:所有 child 都到达终态(SUCCEEDED / FAILED / REJECTED / TIMEOUT)→ 进入 Round 2 或直接终态聚合。

4.3 Round 2 · 汇总(可选)

触发:Team.config.consolidation_required = true(fan-out 默认 true、sequential 默认 false)。

承担方:另起一个独立的 Consolidator Run,挂在同一个 parent_run_id 下。Consolidator 的 callee_agent_id = Team 的 lead 或一个专用 consolidator persona。

输入动作输出
Round 1 的 N 份 ResultSink observationConsolidator 走完整 Harness 八步:装配 context 时把 N 份 observation 一起塞进去整合后的统一输出(按 expected_output schema)

关键差异(对比"在 Coordinator 进程内做整合"):

终止条件:Consolidator 终态 → ResultSink 回填 Parent → Parent 终态聚合。

4.4 Round 计数与内核解耦

round_index 是 Coordinator 维护的字段,存在 GroupSession 与 DelegationTrace 表里;不进 RunState 也不进 RunContext.run_metadata 的决策路径。Tier 3 内核每次只看到「起一个独立 Run」,不知道它属于哪个 Round。这是 D4(Round 0/1/2)+ D3(执行边界独立)+ Tier 3 不感知协作的复合约束。


5. ResultSink 与 AnswerObservationProtocol

SECTION GOAL

定义 Tier 3 child Run 终态如何把结果交回 Tier 2 Coordinator。这是协作树唯一的「子 → 父」语义出口。

5.1 ResultSink · Tier 3 的唯一交付点

每个 child Run 在终态收口阶段(Harness 第八步 TRACING 之前)必经 ResultSink。ResultSink 是 Coordinator 向 Tier 3 注入的回调钩子(不是新协议层),它从 RunContext 拿到三件事:

字段来源用途
terminal_stateRunStateSUCCEEDED / FAILED / REJECTED / TIMEOUT
final_answerPlan/Tool/HITL 终态产物核心输出(文本 / 结构化 / 工具结果摘要)
run_summaryRunTrace 聚合cost / latency / token 用量 / HITL 路径

ResultSink 的写入原子地完成两件事:写 child 自己的 RunTrace 终态行 + 给 Coordinator 投递一条 child_terminal 消息(带 parent_run_id 做路由)。Coordinator 收到消息后才推进 Round 状态。

没有 ResultSink 就没有终态——这是协作协议对 Tier 3 唯一的硬约束。

5.2 AnswerObservationProtocol · 父侧消费协议

Coordinator 收到 child_terminal 后,把 final_answer 包装成一个 AnswerObservation 投回 Parent Run 的 RunContext。Parent 把它当作普通的 observation 继续 Plan/Execute 循环。

字段类型说明
kindenum固定值 agent_invocation_result,让 Parent 的 Plan 能识别
invocation_iduuid对应 Parent 当初发出的 AgentInvocation
callee_agent_iduuid哪个 Agent 回的
terminal_stateenum透传 child 终态
answer_payloadjsonbfinal_answer 的结构化版本(如 expected_output 指定,按 schema 校验)
cost_cents / latency_msint用于父侧聚合
errorjsonb?FAILED / REJECTED 时的错误结构

5.3 写回路径

步骤动作位置
1Child Run 进入终态收口Tier 3 · Harness 第七步前
2ResultSink 原子写 RunTrace 终态 + 投递 child_terminal 消息Tier 3 ↔ Tier 2 边界
3Coordinator 路由消息:按 round_index 决定推进 Round 1 / Round 2 / 父终态Tier 2 · Coordinator
4Coordinator 写 DelegationTrace 终态行(cost / latency 落表)Tier 2 · 持久化
5Coordinator 把 AnswerObservation 投回 Parent RunContextTier 2 → Tier 3
6Parent 的 AgentInvoke Tool 调用收到返回值(observation),工具控制器解阻塞,EXECUTING 继续 PlanTier 3 · Parent Run

5.4 失败语义


6. 与其他模块关系

SECTION GOAL

说明本协议引入后已有模块的修改点,避免双方对边界产生分歧。

模块修改点边界对齐
Agent Teams 设计Team.collaboration_strategy 由本协议消费;Team.config 提供 max_round / consolidation_required / hitl_threshold 等运行时阈值Team 是「协作单元的承载实体」(名词),本协议是「机制」(动词),互不替代
Harness 内核设计工具调用控制器新增 AgentInvoke 第 4 类调用(与本地 Skill / 沙箱 Skill / LLM 并列);RunContext.caller_extra 接收 parent_run_id;ResultSink 作为 Tier 3 收口前的强制钩子RunState 仍是 11 态、内核仍只跑单 Run;不引入 Round / Delegation 概念,"协作"对 T3 只表现为一种慢 Tool 调用
Memory / Context 设计父 → 子的 context_subset 走 schema 白名单裁剪;不直接转发 RunContext;team_memory 召回路径不动Memory scope 仍按 (user, persona, team) 三维隔离;本协议不引入新 scope
可观测性 / ReplayRunTrace 增加 parent_run_id / delegation_total_cost 字段;新增 DelegationTrace 表;Replay 支持按 parent_run_id 拉整棵树所有 trace 字段对齐 RunTrace 现有 schema 风格,不破坏既有查询
治理 / HITLHITL 阈值可在 Team.config 覆盖;Consolidator Run 也走 HITL 通道(Round 2 与 Round 1 共享同一套 Policy)HITL 仍是 Tier 2 的策略层 + Tier 3 的等待态,不为协作再造一套
Skill 版本治理child Run 的 Skill 集合按 callee_agent_id 装配;不继承父的 Skill;context_subset 不带父的 Skill 调用结果(除非显式 expected_output 包含)Skill 层与父子无关,仍按 Agent 维度隔离

核心契约不变量(评审请确认这五条):

  1. 所有 Agent 间派单走 AgentInvocation 单一入口(D1)
  2. 每次派单产生独立 child Run + 独立 RunState(D2 + D3)
  3. Round 0/1/2 是 Tier 2 概念,Tier 3 不感知(D4)
  4. 所有 child 的终态必经 ResultSink(D5)
  5. 跨 User / 跨 Workspace 委托永久禁止;context 严格按 schema 白名单裁剪