系列「企业级 AI Agent 实现拆解」E43 篇,Part 10 生产工程篇第一章。Part 9 拆完了单个 Agent 的内部结构。这篇往上一层:多个 Agent 怎么协作?Eino ADK 提供了哪些模式,各有什么取舍?

读完这篇你会知道

  • Agent 接口是什么,为什么它是 ADK 的核心抽象
  • 三种多 Agent 模式:AgentTool / Supervisor / Plan-Execute-Replan
  • 为什么官方源码注释里明确写了 Supervisor 模式"NOT RECOMMENDED"
  • NewAgentTool:把 Agent 包成工具的边界设计
  • AgentEvent 流:内层 Agent 的输出如何穿透到外层

为什么需要多 Agent

单个 ReAct Agent 的问题:

  • 工具太多会让 LLM “迷失”(context pollution),工具调用准确率下降
  • 复杂任务需要不同专业知识(搜索/计算/写作),一个 Agent 难以都擅长
  • 某些任务天然可以并行(研究 + 分析 + 撰写同时进行)
  • 长任务的 context window 容量限制

多 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 循环里"自己想到"要做什么。


三种模式对比

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

DeepFlux 的选择

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

  • 知识库检索kb BC 暴露为一个 Tool,Agent 需要查资料时调用
  • 记忆读写memory BC 作为 Tool,Agent 自主决定何时存储/检索记忆
  • HITL 审批:通过 StatefulInterrupt,穿透到外层等待人工处理

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


小结

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

  • AgentTool:Agent 作为工具被调用,边界最清晰,官方推荐
  • Supervisor:共享 context 的转移模式,直觉上"像指挥系统",但实测效果不如 AgentTool
  • Plan-Execute-Replan:确定性工作流,适合步骤清晰、需要容错的长任务

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


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

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐