首页
看点啥
插画图片
首页 看点啥 多 Agent 编排:Eino ADK 三种协作模式(第57篇-E43)

多 Agent 编排:Eino ADK 三种协作模式(第57篇-E43)

2026-07-20 0

读完这篇你会知道


为什么需要多 Agent

单个 ReAct Agent 的问题:

多 Agent 编排:Eino ADK 的三种协作模式(第57篇-E43)

多 Agent 的解法是分而治之:把一个大任务拆给多个专注的 Agent,通过某种协调机制组合结果。


Agent 接口:ADK 的核心抽象

Eino ADK 的多 Agent 体系围绕一个极简接口构建:

 复制代码type Agent interface {
    Name(ctx context.Context) string
    Description(ctx context.Context) string    Run(ctx context.Context, input *AgentInput, options ...AgentRunOption) *AsyncIterator[*AgentEvent]
}

AgentInput 只有两个字段:

 复制代码type AgentInput struct {
    Messages        []*schema.Message  // 输入消息
    EnableStreaming  bool               // 是否流式
}

AgentEvent 是执行中产生的事件流:

 复制代码type AgentEvent struct {
    AgentName string       // 产生事件的 Agent 名
    RunPath   []RunStep    // 从根到当前 Agent 的执行路径
    Output    *AgentOutput // 消息输出(模型生成 or 工具结果)
    Action    *AgentAction // 动作(退出/中断/转移/继续)
    Err       error
}

AgentAction 包含 Agent 可以触发的所有动作:

 复制代码type AgentAction struct {
    Exit            bool                  // 正常退出
    Interrupted     *InterruptInfo        // HITL 中断
    TransferToAgent *TransferToAgentAction // 转移给另一个 Agent(不推荐)
    BreakLoop       *BreakLoopAction       // 跳出循环
    CustomizedAction any                   // 自定义
}

这套接口足够薄——只要实现了 Run,任何东西都能成为 Agent:一个 ReAct Agent、一个 Supervisor、一个确定性工作流,甚至一个简单的 LLM 调用。


模式一:AgentTool(官方推荐)

把 Worker Agent 包成一个工具,让 Orchestrator Agent 通过 tool_calls 来调用它。

 复制代码// 创建专门的 Worker Agent
searchAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
    Name:        "research_agent",
    Description: "搜索互联网获取信息",  // LLM 用这个描述决定何时调用
    Instruction: "你是一个研究专员...",
    Model:       model,
    ToolsConfig: adk.ToolsConfig{...},
})// 把 Worker Agent 包成工具
searchTool := adk.NewAgentTool(ctx, searchAgent)// Orchestrator 把所有 Worker Tool 加进自己的工具集
orchestrator, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
    Name:  "orchestrator",
    Model: model,
    ToolsConfig: adk.ToolsConfig{
        ToolsNodeConfig: compose.ToolsNodeConfig{
            Tools: []tool.BaseTool{searchTool, mathTool, writeTool},
        },
    },
})

工作原理:

 复制代码Orchestrator LLM → tool_calls: [{name:"research_agent", args:{"request":"..."}}}]
                                          ↓
                          searchAgent.Run(ctx, &AgentInput{Messages: [...]})
                                          ↓ (完整的 ReAct 循环)
                          搜索工具 → 返回结果
                                          ↓
                          返回 string 给 Orchestrator
                                          ↓
Orchestrator LLM 收到工具结果 → 继续决策

边界隔离(关键设计):

 复制代码// AgentTool 对 Action 的处理是有边界的
// 内层 Agent 的这些动作不会传播给父 Agent:
//   - Exit: 只退出内层 Agent,不退出 Orchestrator
//   - TransferToAgent: 在工具边界内消化
//   - BreakLoop: 同上
// 只有 Interrupted (HITL) 会通过 CompositeInterrupt 穿透给父 Agent

这个设计很重要:Worker Agent 的内部决策("我完成了")不会意外终止 Orchestrator 的执行。

事件穿透(可选):

如果 ToolsConfig.EmitInternalEvents = true,Worker Agent 产生的 AgentEvent(包括模型流式输出、工具结果)会实时穿透到外层 Runner,用户可以实时看到内层 Agent 的思考过程。


模式二:Supervisor(不推荐,但要理解)

官方源码注释里有一段很罕见的坦诚:

 复制代码// NOT RECOMMENDED: Agent transfer with full context sharing between agents has not proven
// to be more effective empirically. Consider using ChatModelAgent with AgentTool
// or DeepAgent instead for most multi-agent scenarios.

Supervisor 模式的结构:

 复制代码sv := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
    Name:        "supervisor",
    Instruction: `你管理两个 Agent:research_agent 和 math_agent。
                  分配任务给合适的 Agent,不要同时调用多个。`,
    Model:       model,
    Exit:        &adk.ExitTool{},  // 结束信号
})// supervisor.New 做了两件事:
// 1. 给每个 sub-agent 注入 DeterministicTransferTo(supervisor)
//    → sub-agent 跑完后必须把控制权还给 supervisor
// 2. 用 SetSubAgents 把 sub-agents 注册为 supervisor 可以 "transfer to" 的目标
result, _ := supervisor.New(ctx, &supervisor.Config{
    Supervisor: sv,
    SubAgents:  []adk.Agent{searchAgent, mathAgent},
})

为什么 NOT RECOMMENDED?

Agent transfer 模式本质上是"共享完整 context 的消息传递":

 复制代码Supervisor → (完整对话历史) → SubAgent A → (完整对话历史) → Supervisor → ...

每次转移都携带完整历史,越来越长,LLM 越来越难以关注当前任务。实际测试中,把 Worker 包成 AgentTool 效果更好——因为边界更清晰,每个 Worker 只看到自己需要的信息。

Supervisor 模式适合用于理解历史遗留设计,或者在特殊场景下需要 sub-agent 感知完整历史时用。


模式三:Plan-Execute-Replan(结构化工作流)

对于需要严格顺序的复杂任务(旅行规划、代码编写、多步研究),用预定义的工作流拆分职责:

 复制代码// 三个专职 Agent
planAgent, _ := agent.NewPlanner(ctx)    // 规划师:输出结构化计划
executeAgent, _ := agent.NewExecutor(ctx) // 执行者:按计划执行每一步
replanAgent, _ := agent.NewReplanAgent(ctx) // 重规划师:执行失败时调整计划// planexecute.New 把三者组成一个确定性循环:
// Plan → Execute → (成功 → Done) or (失败 → Replan → Execute → ...)
entryAgent, _ := planexecute.New(ctx, &planexecute.Config{
    Planner:       planAgent,
    Executor:      executeAgent,
    Replanner:     replanAgent,
    MaxIterations: 20,
})

执行循环:

 复制代码用户输入 → Planner:生成步骤列表 [step1, step2, step3]
                    ↓
           Executor:执行 step1 → 成功
                    ↓
           Executor:执行 step2 → 失败
                    ↓
           Replanner:分析失败原因 → 修改计划
                    ↓
           Executor:执行调整后的 step2' → 成功
                    ↓
           所有步骤完成 → 返回结果

这个模式的优点是可预测:每一步都有明确的输入输出,失败可以定点重试,不依赖 LLM 在一次 ReAct 循环里"自己想到"要做什么。


三种模式对比

AgentToolSupervisorPlan-Execute-Replan
推荐度 推荐️ 不推荐 推荐
边界清晰度高(工具边界)低(共享 context)高(确定性步骤)
灵活性高(LLM 决定调用)低(预定义流程)
Context 增长慢(每次调用独立)快(历史累积)受控(分步独立)
HITL 支持 穿透到父 Agent
适合场景通用 Agent 协作特殊历史共享需求长任务、需要回滚

DeepFlux 的选择

DeepFlux 的 Agent BC(server/internal/agent)使用了 AgentTool 模式:

这种设计的好处是每个 Worker(kb/memory/tool)有完整的边界,可以独立扩容、独立测试,不会因为某个 Worker 的历史积累污染其他 Worker 的 context。


小结

Eino ADK 的多 Agent 体系核心是一个极简的 Agent 接口,三种协作模式本质上是三种组合方式:

选模式的原则很简单:能用 AgentTool 就用 AgentTool,需要严格顺序就用 Plan-Execute,只在真正需要共享完整历史时才考虑 Supervisor


代码来源:eino/adk/interface.go · eino/adk/agent_tool.go · eino/adk/prebuilt/supervisor/supervisor.go

喜欢(0)

上一篇

7 agent

7 agent

下一篇

SERP API + Claude function calling:从 tool use 到 agent 的完整实现

SERP API + Claude function calling:从 tool use 到 agent 的完整实现
猜你喜欢