Multi-Agent:让多个 AI 分工协作完成复杂任务需要先看清适用场景和关键步骤,避免只记结论却忽略实际限制。
单个 Agent 加工具够用吗?理论上够。但实践中有两个问题:

问题 1:专业度。让一个 Agent 既懂检索、又懂计算、又懂代码审查,prompt 会越写越长,越长越混乱,效果越来越差。把职责拆开,每个 Agent 只做一件事,效果好得多。
问题 2:并行。单 Agent 串行执行,5 个任务得一个个来。多 Agent 可以并发跑,总时间缩短。
eino 提供了两种官方推荐的 Multi-Agent 模式,加一种不推荐但值得了解的模式。
源码:eino/flow/agent/multiagent/host/
用户问题↓[](持有所有 Specialist 的"工具描述")↓通过 ToolCall 选择一个或多个 Specialist[][Specialist B] (并发执行)↓[](如果选了多个 Specialist,汇总结果)↓最终回复
Host 不是普通 ChatModel,它是 ToolCallingChatModel——能输出结构化的 ToolCall,告诉系统"去找哪个 Specialist、传什么参数"。每个 Specialist 的名字和描述被包装成一个"工具"注册到 Host 上,Host 看完用户问题后决定调哪个。
// 源码:eino/flow/agent/multiagent/host/types.go// Host:决策者type Host struct {ToolCallingModel model.ToolCallingChatModelSystemPrompt string// "你是一个任务分发助手,根据用户需求选择合适的专家"}// Specialist:执行者type Specialist struct {AgentMeta // Name + IntendedUse(这两个字段决定 Host 怎么描述它)ChatModelmodel.BaseChatModelSystemPrompt string// "你是一个数学计算专家,只做数学题"Invokablecompose.Invoke[[]*schema.Message, *schema.Message, agent.AgentOption]}// Summarizer:汇总者(可选)type Summarizer struct {ChatModelmodel.BaseChatModelSystemPrompt string// "综合多位专家的回答,给出统一答复"}
// 参考:eino-examples/adk/multiagent/integration-project-managerhostCfg := &host.Config{Host: host.Host{ToolCallingModel: myLLM,SystemPrompt: "你是项目经理,根据任务类型分配给合适的专家。",},Specialists: []host.Specialist{{AgentMeta:host.AgentMeta{Name: "researcher", IntendedUse: "负责资料检索和调研"},ChatModel:researchLLM,SystemPrompt: "你是研究员,擅长搜索和分析信息。",Invokable:researchAgent.Invoke,},{AgentMeta:host.AgentMeta{Name: "coder", IntendedUse: "负责编写和调试代码"},ChatModel:codingLLM,SystemPrompt: "你是工程师,只负责写代码,不做其他事。",Invokable:coderAgent.Invoke,},},Summarizer: &host.Summarizer{ChatModel:summaryLLM,SystemPrompt: "综合研究员和工程师的输出,给出完整报告。",},}multiAgent, _ := host.NewMultiAgent(ctx, hostCfg)result, _ := multiAgent.Generate(ctx, userMessages)
Host 选了一个 Specialist → 直接返回该 Specialist 的结果(不过 Summarizer)。
Host 选了多个 Specialist → Specialist 并发执行,结果送进 Summarizer 汇总。
Host 每次把任务转给 Specialist,会触发一个 HandOff 事件,可以用 Callback 监听:
// 源码:eino/flow/agent/multiagent/host/callback.gotype HandOffInfo struct {ToAgentName string// 转给哪个 SpecialistArgumentstring// 传了什么参数}handler := host.NewMultiAgentCallbackHandler(func(ctx context.Context, info *host.HandOffInfo) context.Context {log.Printf("[HandOff] 转给 %s,参数:%s", info.ToAgentName, info.Argument)return ctx})
源码:eino/adk/prebuilt/planexecute/plan_execute.go
这个模式适合步骤不确定的复杂任务:不知道要几步,每步成功了才知道下一步怎么走,中途可能需要调整计划。
[] →制定计划(步骤列表)[]→执行第一步(用工具)[] →看结果,决定:继续执行 or 宣布完成 如果需要调整,输出新计划;如果完成,输出最终答案
三者形成循环:Planner → (Executor → Replanner) × N,直到 Replanner 宣布完成。
各阶段靠 Session 键值对共享状态,没有显式消息总线:
// 源码:eino/adk/prebuilt/planexecute/plan_execute.goconst (UserInputSessionKey = "UserInput"// 用户原始问题PlanSessionKey= "Plan"// 当前计划(步骤列表)ExecutedStepSessionKey= "ExecutedStep"// 本次执行结果ExecutedStepsSessionKey = "ExecutedSteps"// 所有历史执行结果)// Plan 接口type Plan interface {FirstStep() string// 取出当前要执行的第一步json.Marshalerjson.Unmarshaler}// 默认实现:有序步骤列表type defaultPlan struct {Steps []string`json:"steps"`}
Planner 写 Plan,Executor 读 Plan.FirstStep() 执行并写 ExecutedStep,Replanner 读所有 ExecutedSteps 判断是否完成。
// Planner 强制 LLM 调 plan() 工具输出结构化步骤,不允许输出普通文字var PlanToolInfo = schema.ToolInfo{Name: "plan",Desc: "制定按序执行的步骤列表",ParamsOneOf: NewParamsOneOfByParams(map[string]*schema.ParameterInfo{"steps": {Type: schema.Array,ElemInfo: &schema.ParameterInfo{Type: schema.String},Desc: "按顺序排列的执行步骤",Required: true,},}),}
// 选择 1:任务未完,输出新计划继续var PlanTool = ...// 同 Planner 的 PlanToolInfo// 选择 2:目标达成,输出最终回复退出循环var RespondToolInfo = schema.ToolInfo{Name: "respond",Desc: "当目标已达成时,给出最终回复",ParamsOneOf: NewParamsOneOfByParams(map[string]*schema.ParameterInfo{"response": {Type: schema.String,Desc: "给用户的完整答案",Required: true,},}),}
// 参考:eino-examples/adk/multiagent/plan-execute-replan/cfg := &planexecute.Config{Planner: planexecute.NewPlannerAgent(ctx, &planexecute.PlannerConfig{ChatModelWithFormattedOutput: llm,}),Executor: planexecute.NewExecutorAgent(ctx, &planexecute.ExecutorConfig{Model: llm,ToolsConfig: adk.ToolsConfig{ToolsNodeConfig: compose.ToolsNodeConfig{Tools: []tool.BaseTool{searchTool, weatherTool, bookingTool},},},MaxIterations: 20,}),Replanner: planexecute.NewReplannerAgent(ctx, &planexecute.ReplannerConfig{ChatModel: llm,}),MaxIterations: 10,// 最多重规划 10 次}agent, _ := planexecute.New(ctx, cfg)
执行过程:
Planner: ["查询热门景点", "查询天气", "规划路线", "预订酒店"]Executor:调 searchTool → "故宫、长城、天坛..." → 写 ExecutedStepReplanner: 步骤未完 → 更新计划(移除已完成步骤)Executor:调 weatherTool → "明天晴,适合户外" → 写 ExecutedStepReplanner: 步骤未完 → 继续......Replanner: 所有步骤完成 → 调 respond() → 输出行程 → 退出循环
源码:eino/adk/prebuilt/supervisor/supervisor.go
Supervisor 把整段对话上下文传给 Sub-Agent,Sub-Agent 执行后再把全部上下文还给 Supervisor:
[Supervisor] → 全部对话 + 任务 → [Sub-Agent A][Sub-Agent A] → 全部对话 + 结果 → [Supervisor][Supervisor] → 全部对话 + 任务 → [Sub-Agent B]...
问题:全上下文传递经过实验没有带来更好效果,context 越来越长,每次调用越来越贵。eino 代码注释里明确标注 ⚠️ Not Recommended。
推荐替代方案:
// AgentTool:把 Sub-Agent 包装成工具,按需调用,不共享全上下文agentTool := adk.NewAgentTool(ctx, subAgent)// Parent Agent 通过 ToolCall 调用 Sub-Agent,和调普通工具一样parentCfg := &adk.ChatModelAgentConfig{Model: llm,ToolsConfig: adk.ToolsConfig{ToolsNodeConfig: compose.ToolsNodeConfig{Tools: []tool.BaseTool{agentTool, otherTool},},},}
无论哪种模式,Agent 之间传的都是 schema.Message 列表。Host-Worker 靠 ToolCall 路由,Plan-Execute-Replan 靠 Session 键值对。
// 源码:eino/schema/message.gotype Message struct {RoleRoleType// assistant / user / system / toolContent string// Host → Specialist:派活指令ToolCalls []ToolCall// 模型输出:调哪个 Specialist,传什么参数// Specialist → Host:执行结果ToolCallID string// 对应哪个 ToolCallToolName string// 哪个工具/Specialist 产生的结果}type ToolCall struct {ID stringFunction struct {Namestring// Specialist 的名字(即 AgentMeta.Name)Arguments string// JSON 格式的任务描述}}
框架用 ToolCall.Function.Name 把结果路由到对应 Specialist,开发者不需要手动写路由逻辑。
| 策略 | 原理 | 适用场景 |
|---|---|---|
| LLM 路由(Host-Worker) | Host LLM 通过 ToolCall 决定派给谁 | 任务类型多样,边界模糊 |
| 结构化规划(Plan-Execute-Replan) | Planner 先拆步骤,Executor 按步执行 | 步骤未知,需要迭代调整 |
| AgentTool 调用(推荐替代) | Parent 按需 ToolCall 调 Sub-Agent | 子任务边界清晰,无需共享上下文 |
Host-Worker(推荐)适合:多专家并行,任务类型多样关键:Host 通过 ToolCall 路由,Specialist 并发执行Plan-Execute-Replan(推荐)适合:步骤不确定的复杂任务关键:Session 传状态,Replanner 决定继续还是结束Supervisor(不推荐)问题:全上下文膨胀,实验效果不及预期替代:AgentTool(简单)/ DeepAgent(复杂)
怎么选:
| 场景 | 模式 |
|---|---|
| 问题可能需要多个专家 | Host-Worker |
| 任务复杂、步骤未知、可能失败重试 | Plan-Execute-Replan |
| 子任务边界清晰、轻量 | AgentTool |
| 多层嵌套、复杂协调 | DeepAgent |
Multi-Agent 不是越复杂越好。能用一个 Agent 加工具解决的,不要上 Multi-Agent。上了,优先选 Host-Worker 或 Plan-Execute-Replan,不要默认选 Supervisor。