24|Supervisor 模式:让协调者管理多个专家 - eino教程

发布时间:2026/10/27 10:16:13
24|Supervisor 模式:让协调者管理多个专家 - eino教程

24|Supervisor 模式:让协调者管理多个专家

《Eino 实战:用 Go 构建 AI 应用与智能体》· 第 24 篇
关键词:Supervisor、TransferToAgent、专家分工、上下文共享、控制权转移
前置条件:已完成 22|AgentAsTool 与 23|Workflow Agents。

前两篇讲了两种协作:AgentAsTool(动态委派,子 Agent 隔离)和 Workflow Agents(固定结构)。

还有第三种:有一个明确的“负责人”,它把任务分配给专家,专家完成后回到负责人。这就是 Supervisor 模式。

它的关键机制是控制权转移(Transfer),而不是工具调用——这是与 AgentAsTool 的本质区别。


一、Supervisor 的结构

用户 ↓ Supervisor(协调者) ↙ ↘ writer reviewer (写完交回) (审完交回)

三条规则:

  1. Supervisor 负责分配任务,并持有最终结论。
  2. 子 Agent 只与 Supervisor 通信,子 Agent 之间不直接交互。
  3. 子 Agent 完成后交回控制权给 Supervisor。

第 2 条是有意的约束:它避免了子 Agent 之间的复杂网状调用,让流程可观测、可调试。


二、控制权转移 vs 工具调用

这是本篇最需要理解的一点。

AgentAsToolSupervisor(Transfer)
机制调用工具转移控制权
父 Agent 状态保持运行,等结果返回交出控制权
上下文子 Agent 独立全量共享
返回方式工具结果回到父上下文子 Agent 把控制权转回

用一句话概括:AgentAsTool 是“我叫你去做件事,做完告诉我”;Transfer 是“现在由你负责,做完再叫我”。

后者会造成上下文的完全合并,因此官方注释里对基于 transfer 的模式(包括 Supervisor)明确标注了 “NOT RECOMMENDED”,并建议大多数场景使用AgentAsTool或DeepAgent。

这不代表 Supervisor 不能用。当业务上确实存在“分层指挥”的关系、且需要共享上下文时,它是合适的表达。但要清楚代价:上下文膨胀、调试变难。


三、实现方式

Supervisor 的构建很简单:

sup,err:=supervisor.New(ctx,&supervisor.Config{Supervisor:coordinatorAgent,SubAgents:[]adk.Agent{writer,reviewer},})

它内部做了两件事:

  1. 把每个子 Agent 包装上“确定性转回 Supervisor”的能力。
  2. 调用SetSubAgents建立Supervisor → 子 Agent的层级关系。

第二步——SetSubAgents——是关键:它让 Supervisor 获得transfer_to_agent工具。

转移是怎么发起的

Supervisor 通过工具调用来发起转移。框架为它注入了内置工具:

工具名:transfer_to_agent 参数: {"agent_name": "writer"}

也就是说,虽然机制上是“控制权转移”,触发方式仍然是模型生成工具调用。这让转移决策完全由模型驱动——也是为什么Description必须写清楚(否则 Supervisor 不知道该转给谁)。

子 Agent 完成后,框架通过确定性机制自动转回 Supervisor,不需要模型决定。


四、完整示例

下面这段程序完整演示“Supervisor 转交 → 子 Agent 执行 → 转回 → Supervisor 汇总”的闭环,不访问外部服务:

packagemainimport("context""fmt""log""github.com/cloudwego/eino/adk""github.com/cloudwego/eino/adk/prebuilt/supervisor""github.com/cloudwego/eino/components/model""github.com/cloudwego/eino/schema")// scriptedModel 按脚本返回响应。typescriptedModelstruct{responses[]*schema.Message idxint}func(m*scriptedModel)Generate(_context.Context,_[]*schema.Message,_...model.Option)(*schema.Message,error){ifm.idx>=len(m.responses){returnschema.AssistantMessage("(脚本结束)",nil),nil}r:=m.responses[m.idx]m.idx++returnr,nil}func(m*scriptedModel)Stream(ctx context.Context,in[]*schema.Message,opts...model.Option)(*schema.StreamReader[*schema.Message],error){msg,err:=m.Generate(ctx,in,opts...)iferr!=nil{returnnil,err}sr,sw:=schema.Pipe[*schema.Message](1)gofunc(){defersw.Close();sw.Send(msg,nil)}()returnsr,nil}func(m*scriptedModel)WithTools([]*schema.ToolInfo)(model.ToolCallingChatModel,error){returnm,nil}funcmain(){iferr:=run();err!=nil{log.Fatal(err)}}funcrun()error{ctx:=context.Background()// 协调者:先转交给 writer,子 Agent 会按框架的确定性机制转回协调者,最后协调者总结。coordinator,err:=adk.NewChatModelAgent(ctx,&adk.ChatModelAgentConfig{Name:"coordinator",Description:"协调专家完成任务",Instruction:"你负责把任务转交给合适的专家,专家返回后给出最终结论。",Model:&scriptedModel{responses:[]*schema.Message{// 第一步:以工具调用的形式发起转交。schema.AssistantMessage("",[]schema.ToolCall{{ID:"t1",Type:"function",Function:schema.FunctionCall{Name:"transfer_to_agent",Arguments:`{"agent_name":"writer"}`,},}}),// 子 Agent 返回后:给出最终结论。schema.AssistantMessage("最终结论:请先检查网线,如仍异常请联系网络支持组。",nil),}},})iferr!=nil{returnerr}writer,err:=adk.NewChatModelAgent(ctx,&adk.ChatModelAgentConfig{Name:"writer",Description:"撰写答复内容",Instruction:"你负责撰写答复。",Model:&scriptedModel{responses:[]*schema.Message{schema.AssistantMessage("答复草稿:请先检查网线连接。",nil),}},})iferr!=nil{returnerr}sup,err:=supervisor.New(ctx,&supervisor.Config{Supervisor:coordinator,SubAgents:[]adk.Agent{writer},})iferr!=nil{returnfmt.Errorf("创建 Supervisor 失败: %w",err)}runner:=adk.NewRunner(ctx,adk.RunnerConfig{Agent:sup})iter:=runner.Query(ctx,"请撰写一则答复")n:=0for{event,ok:=iter.Next()if!ok{break}ifevent.Err!=nil{fmt.Println(" [事件错误]",event.Err)continue}n++ifmv:=messageOutput(event);mv!=nil&&mv.Message!=nil&&mv.Message.Content!=""{fmt.Printf(" agent=%-12s content=%q\n",event.AgentName,mv.Message.Content)}}fmt.Println("事件总数:",n)returnnil}funcmessageOutput(event*adk.AgentEvent)*adk.MessageVariant{ifevent==nil||event.Output==nil{returnnil}returnevent.Output.MessageOutput}

实机输出:

agent=coordinator content="successfully transferred to agent [writer]" agent=writer content="答复草稿:请先检查网线连接。" agent=writer content="successfully transferred to agent [coordinator]" agent=coordinator content="最终结论:请先检查网线,如仍异常请联系网络支持组。" 事件总数: 6

这四行输出就是 Supervisor 模式的完整生命周期:

  1. coordinator → writer:协调者发起转交。
  2. writer 产出内容:子 Agent 在自己的环节工作。
  3. writer → coordinator:框架自动转回,不需要模型决定。
  4. coordinator 汇总:拿回控制权,给出最终结论。

注意第 3 步:子 Agent 并不需要显式“归还”控制权,这是 Supervisor 构建时注入的确定性行为。

还有一处细节值得注意:事件里的agent字段清楚地标识了当前是谁在工作。这让多智能体的执行过程在日志里也是可读的。


五、与另外两种方式的对比

AgentAsToolWorkflow AgentsSupervisor
谁决定下一步父 Agent代码结构Supervisor
上下文隔离上游拼入下游全量共享
子 Agent 间通信无无直接通信无,只与 Supervisor
调试友好度高高较低
官方建议推荐有限场景有限场景

选择顺序建议:

  1. 流程固定 → Workflow Agents(或 compose 编排)。
  2. 需要动态委派且希望隔离 → AgentAsTool。
  3. 确实存在分层指挥、且需要共享上下文 → Supervisor。

六、代价与注意事项

1. 上下文会膨胀。
全量共享意味着每个子 Agent 都带着完整历史。多轮转移后,上下文会快速变大。第 18 篇的上下文管理手段在这里尤其必要。

2.Description决定路由质量。
Supervisor 靠描述判断该转给谁。描述含糊会导致转错——而且转错之后流程可能反复来回。

3. 防止无限来回。
Supervisor 可能把任务转给 writer,writer 转回后 Supervisor 又转给 writer。这类循环需要靠提示词约束和迭代上限控制。

4. 成本要提前估算。
每次转移都是一次完整的 Agent 运行。Supervisor + 3 个子 Agent 的结构,实际调用次数可能是单 Agent 的数倍。

5. 鉴权仍在最内层。
子 Agent 里的工具同样需要自己做权限校验(第 11 篇)。控制权转移不改变安全边界。


七、常见问题

Supervisor 不转交,直接自己回答
Instruction没有说明“应该转交给专家”,或子 Agent 的Description不够清晰。

转交了但子 Agent 没有转回
正常情况下框架会自动转回(借助构建时的确定性转移配置)。若异常,检查是否使用了supervisor.New而不是手动SetSubAgents。

在 coordinator 和 writer 之间反复转账
转移循环。约束提示词(例如“每位专家只调用一次”),并设置迭代上限。

看不到子 Agent 的中间过程
EmitInternalEvents默认关闭。Supervisor 场景下因为共享上下文,通常能直接看到关键输出。

上下文太长导致报错
共享上下文在多次转移后膨胀。加入摘要压缩或限制转移次数。


八、小结

  • Supervisor 模式:一个协调者分配任务,子 Agent 只与协调者通信,完成后交回控制权。
  • 核心机制是控制权转移,与 AgentAsTool 的“工具调用”有本质区别。
  • 转移通过内置的transfer_to_agent工具发起;子 Agent 转回是框架的确定性行为。
  • 上下文完全共享,代价是膨胀与调试难度;官方对此类模式持保留意见。
  • 与另外两种方式的选择顺序:固定流程 → Workflow Agents;动态隔离 → AgentAsTool;分层共享 → Supervisor。
  • 鉴权仍在最内层,转移不改变安全边界。

下一篇《Plan-Execute-Replan:让复杂任务拥有可调整的计划》,看如何应对“一次计划不够用”的情况。


参考资料与版本说明

资料核对日期为2026 年 10 月 9 日:

  1. Agent 协作(多 Agent 协作模式)
  2. Eino ADK 概述(预置模式)
  3. Eino 主仓库

本文示例按Eino v0.9.21编写,使用脚本化模型(不访问外部服务),已实机运行,正文输出为完整转移闭环的真实结果。