核心摘要

当单个 AI Agent 面对复杂任务时,上下文窗口限制、工具过载、缺乏专业化分工等问题会显著降低效果。多智能体系统通过角色专业化、并行处理和协作涌现,突破单一 Agent 的能力天花板。本文深入解析 Eino 框架支持的三种核心协作模式——Router(意图路由)、Supervisor(管理者)和 Swarm(对等协作),并通过一个多 Agent 代码审查系统展示实战落地方案。


目录

  1. 核心要点
  2. 为什么需要多 Agent
  3. Router 模式:意图路由
  4. Supervisor 模式:管理者协调
  5. Swarm 模式:对等协作
  6. Agent 作为 Tool:层级组合
  7. 状态共享与隔离
  8. 三种模式对比
  9. 实战:多 Agent 代码审查系统
  10. 最佳实践
  11. 常见问题
  12. 总结
  13. 相关资源

核心要点

  • Router 模式:一个路由 Agent 对意图分类并分发到领域 Agent,延迟与分类质量需要实测
  • Supervisor 模式:管理者 Agent 负责规划、派发、汇总,Worker Agent 执行具体子任务并汇报结果
  • Swarm 模式:Agent 可以在无固定中心的情况下对等移交,因此更需要明确预算、授权和终止规则
  • Agent as Tool:任何编译后的 Graph 或 Agent 都可以暴露为 Tool,实现层级化的 Agent 架构
  • 状态策略:共享事实(via context)、隔离推理(独立对话历史),平衡一致性与自主性

为什么需要多 Agent

单个 Agent 在面对真实世界的复杂任务时存在明确的能力天花板:

限制因素 表现 多 Agent 解决方案
上下文窗口 信息超载导致遗忘关键细节 每个 Agent 只处理相关子集
工具过载 工具过多时选择准确率下降 每个 Agent 只绑定必要工具
缺乏专业化 通才表现不如领域专家 角色专业化的 System Prompt
串行执行 复杂任务耗时过长 子任务并行处理
单点失败 一次错误影响全局 独立推理、局部失败不扩散

这些限制在 Eino 框架中通过 Graph 编排 + Agent 组合得到系统性解决。在 前一篇文章 中我们构建了单 Agent 应用,现在让我们进入多 Agent 的世界。


Router 模式:意图路由

Router 模式是最简单的多 Agent 协作——一个路由器根据用户输入的意图分类,将请求转发到对应的专家 Agent。

架构图

graph TD A["用户输入"] --> B["Router Agent"] B -->|"代码相关"| C["Code Agent"] B -->|"数据分析"| D["Data Agent"] B -->|"通用问答"| E["General Agent"] C --> F["输出结果"] D --> F E --> F

核心实现

go
package main

import (
    "context"
    "github.com/cloudwego/eino/compose"
    "github.com/cloudwego/eino/schema"
)

func buildRouterGraph(ctx context.Context) (*compose.Runnable[string, *schema.Message], error) {
    graph := compose.NewGraph[string, *schema.Message]()

    // 添加路由节点:对意图进行分类
    graph.AddLambdaNode("router", compose.InvokableLambda(func(ctx context.Context, input string) (string, error) {
        // 调用轻量模型快速分类意图
        classification, err := classifyIntent(ctx, input)
        if err != nil {
            return "general", nil // fallback
        }
        return classification, nil
    }))

    // 添加专家 Agent 节点
    graph.AddChatModelNode("code_agent", codeModel, &compose.ChatModelNodeConfig{
        SystemPrompt: "你是一位资深 Go 开发专家,专注于代码编写、调试和优化。",
    })
    graph.AddChatModelNode("data_agent", dataModel, &compose.ChatModelNodeConfig{
        SystemPrompt: "你是一位数据分析专家,擅长 SQL、数据可视化和统计分析。",
    })
    graph.AddChatModelNode("general_agent", generalModel, &compose.ChatModelNodeConfig{
        SystemPrompt: "你是一位通用助手,擅长回答日常问题。",
    })

    // 设置边和分支
    graph.AddEdge(compose.START, "router")
    graph.AddBranch("router", compose.NewBranch(func(ctx context.Context, intent string) (string, error) {
        switch intent {
        case "code":
            return "code_agent", nil
        case "data":
            return "data_agent", nil
        default:
            return "general_agent", nil
        }
    }))
    graph.AddEdge("code_agent", compose.END)
    graph.AddEdge("data_agent", compose.END)
    graph.AddEdge("general_agent", compose.END)

    return graph.Compile(ctx)
}

适用场景

  • 客服系统:根据问题类型路由到售前/售后/技术支持
  • IDE 助手:区分代码生成、文档查询、项目配置等请求
  • 数据平台:分流 SQL 查询、报表生成、异常分析等任务

Supervisor 模式:管理者协调

Supervisor 模式引入一个"管理者" Agent,负责理解任务全局、制定计划、分配子任务给 Worker Agent,并汇总最终结果。

架构图

graph TD A["用户任务"] --> B["Supervisor Agent"] B -->|"分配研究任务"| C["Researcher Worker"] B -->|"分配写作任务"| D["Writer Worker"] B -->|"分配审核任务"| E["Reviewer Worker"] C -->|"返回调研结果"| B D -->|"返回初稿"| B E -->|"返回修改建议"| B B --> F["汇总输出"]

核心实现

go
package main

import (
    "context"
    "fmt"
    "github.com/cloudwego/eino-ext/devops/adk"
    "github.com/cloudwego/eino/components/tool"
    "github.com/cloudwego/eino/schema"
)

// workerAsTool 将一个 Agent 包装为 Tool,供 Supervisor 调用
func workerAsTool(name, description string, agent *adk.ChatModelAgent) tool.BaseTool {
    return tool.NewTool(
        name,
        description,
        func(ctx context.Context, input string) (string, error) {
            messages := []*schema.Message{
                schema.UserMessage(input),
            }
            result, err := agent.Generate(ctx, messages)
            if err != nil {
                return "", fmt.Errorf("worker %s failed: %w", name, err)
            }
            return result.Content, nil
        },
    )
}

func buildSupervisorAgent(ctx context.Context) (*adk.ChatModelAgent, error) {
    // 创建 Worker Agent
    researcher, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model:        researchModel,
        SystemPrompt: "你是一位技术研究员,负责收集和整理技术资料。输出结构化的调研报告。",
    })

    writer, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model:        writerModel,
        SystemPrompt: "你是一位技术写作专家,根据调研资料撰写高质量技术文章。",
    })

    reviewer, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model:        reviewModel,
        SystemPrompt: "你是一位严格的技术审稿人,检查文章的准确性、完整性和可读性。",
    })

    // 创建 Supervisor Agent,将 Worker 作为 Tool
    supervisor, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model: supervisorModel,
        Tools: []tool.BaseTool{
            workerAsTool("researcher", "调用研究员收集技术资料,输入为研究主题", researcher),
            workerAsTool("writer", "调用写作专家撰写文章,输入为写作要求和参考资料", writer),
            workerAsTool("reviewer", "调用审稿人审核文章,输入为待审核文章内容", reviewer),
        },
        SystemPrompt: `你是一位项目经理,负责协调团队完成技术内容生产任务。
工作流程:
1. 分析用户需求,拆解为子任务
2. 先调用 researcher 收集资料
3. 将资料交给 writer 撰写初稿
4. 让 reviewer 审核初稿
5. 如有问题,让 writer 修改
6. 汇总最终结果返回`,
        MaxSteps: 10,
    })

    return supervisor, err
}

适用场景

  • 内容生产:调研 → 写作 → 审核 → 定稿的完整流水线
  • 代码审查:分析 → 审查 → 修复的迭代循环
  • 项目规划:需求分析 → 方案设计 → 风险评估的多维度评审

Swarm 模式:对等协作

Swarm 模式(灵感来源于 OpenAI Swarm 概念)中,Agent 之间是对等关系,没有中心协调器。每个 Agent 拥有自主决策权,可以将对话控制权移交(handoff)给另一个 Agent。

核心概念

  • 无中心化:没有固定的"管理者",任何 Agent 都可以接管
  • Handoff 机制:当前 Agent 判断某个问题超出自己能力范围时,主动移交给更合适的 Agent
  • 上下文传递:移交时携带必要的对话上下文

核心实现

go
package main

import (
    "context"
    "github.com/cloudwego/eino/components/tool"
    "github.com/cloudwego/eino-ext/devops/adk"
)

// HandoffResult 表示一次移交操作的结果
type HandoffResult struct {
    TargetAgent string
    Context     string
}

// buildSwarmAgents 构建对等协作的 Agent 集合
func buildSwarmAgents(ctx context.Context) (map[string]*adk.ChatModelAgent, error) {
    agents := make(map[string]*adk.ChatModelAgent)

    // 销售 Agent
    salesAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model: model,
        SystemPrompt: `你是销售顾问。处理产品咨询和购买相关问题。
如果用户问技术问题,调用 handoff_to_tech 移交给技术支持。
如果用户要退款,调用 handoff_to_refund 移交给退款专员。`,
        Tools: []tool.BaseTool{
            makeHandoffTool("handoff_to_tech", "移交给技术支持", "tech"),
            makeHandoffTool("handoff_to_refund", "移交给退款专员", "refund"),
        },
    })

    // 技术支持 Agent
    techAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model: model,
        SystemPrompt: `你是技术支持工程师。解决技术问题和 bug 报告。
如果用户想购买或升级,调用 handoff_to_sales 移交给销售。`,
        Tools: []tool.BaseTool{
            makeHandoffTool("handoff_to_sales", "移交给销售顾问", "sales"),
        },
    })

    // 退款 Agent
    refundAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model: model,
        SystemPrompt: "你是退款专员。处理退款申请和订单问题。",
        Tools: []tool.BaseTool{
            makeHandoffTool("handoff_to_sales", "移交给销售顾问", "sales"),
        },
    })

    agents["sales"] = salesAgent
    agents["tech"] = techAgent
    agents["refund"] = refundAgent
    return agents, nil
}

// runSwarm 运行 Swarm 对话循环
func runSwarm(ctx context.Context, agents map[string]*adk.ChatModelAgent, input string) (string, error) {
    currentAgent := "sales" // 默认入口
    currentInput := input

    for i := 0; i < 5; i++ { // 最多 5 次 handoff
        agent := agents[currentAgent]
        result, err := agent.Generate(ctx, []*schema.Message{
            schema.UserMessage(currentInput),
        })
        if err != nil {
            return "", err
        }

        // 检查是否发生 handoff
        if handoff := extractHandoff(result); handoff != nil {
            currentAgent = handoff.TargetAgent
            currentInput = handoff.Context
            continue
        }

        return result.Content, nil
    }
    return "", fmt.Errorf("exceeded max handoff limit")
}

适用场景

  • 客服系统:不同技能的客服代表之间灵活转接
  • 多角色对话:模拟多个角色的讨论和辩论
  • 工作流不确定的场景:无法预先定义执行路径

Agent 作为 Tool:层级组合

Eino 中,符合契约的已编译 Graph 或 Agent 可以暴露为 Tool。这个包装层不是授权边界:必须在模型之外校验工具名、参数、租户/对象权限、来源、预算、取消和副作用。

go
// 将一个完整的 Agent 系统封装为 Tool
func agentAsTool(name, desc string, runnable *compose.Runnable[string, string]) tool.BaseTool {
    return tool.NewTool(name, desc, func(ctx context.Context, input string) (string, error) {
        return runnable.Invoke(ctx, input)
    })
}

// 构建层级结构:顶层 Agent 调用子系统
func buildHierarchicalSystem(ctx context.Context) (*adk.ChatModelAgent, error) {
    // 子系统 1:代码分析 Agent Graph
    codeAnalysisGraph := buildCodeAnalysisGraph(ctx)
    codeAnalysisTool := agentAsTool(
        "code_analysis",
        "分析代码质量、复杂度和潜在问题,输入为代码片段",
        codeAnalysisGraph,
    )

    // 子系统 2:文档生成 Agent Graph
    docGenGraph := buildDocGenGraph(ctx)
    docGenTool := agentAsTool(
        "doc_generation",
        "为代码生成技术文档,输入为代码和上下文描述",
        docGenGraph,
    )

    // 顶层协调 Agent
    coordinator, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model: model,
        Tools: []tool.BaseTool{codeAnalysisTool, docGenTool},
        SystemPrompt: "你是开发助手,可以调用代码分析和文档生成子系统来帮助用户。",
    })

    return coordinator, err
}

层级组合的优势

  • 子系统可以独立开发、测试和迭代
  • 顶层 Agent 的 prompt 保持简洁,只需要理解 Tool 的接口
  • 支持按需加载,不用的子系统不占用资源

状态共享与隔离

多 Agent 协作中,状态管理是核心挑战。Eino 提供灵活的策略:

策略 实现方式 适用场景 优缺点
Context 传递 context.WithValue 只读共享事实 简单直接,但只支持不可变数据
外部存储 Redis / 数据库 可变共享状态 支持并发读写,但引入外部依赖
消息传递 Tool 调用的输入输出 Agent 间通信 解耦好,但有 token 开销
独立历史 每个 Agent 独立维护 对话记忆 推理不干扰,但无法共享经验

最佳实践:共享事实,隔离推理

go
// 通过 Context 共享只读的任务上下文
type TaskContext struct {
    TaskID      string
    UserID      string
    Constraints []string
}

func withTaskContext(ctx context.Context, tc *TaskContext) context.Context {
    return context.WithValue(ctx, taskContextKey, tc)
}

// 每个 Agent 独立维护自己的对话历史
type AgentState struct {
    History []*schema.Message
    // 仅存储该 Agent 的推理过程
}

三种模式对比

维度 Router Supervisor Swarm
拓扑结构 星形(一对多) 层级(管理者-工人) 网状(对等)
协调方式 静态分类 动态规划 自主移交
延迟 取决于分类器和被路由 Agent 取决于规划轮数和 Worker 取决于移交与终止条件
适用复杂度 低-中 中-高
容错性 单子 Agent 失败可 fallback Supervisor 可重新分配 天然隔离
实现难度 简单 中等 较高
典型场景 意图分发、客服路由 项目管理、内容生产 角色扮演、灵活协商

实战:多 Agent 代码审查系统

结合以上模式,构建一个包含 Planner(规划者)、Reviewer(审查者)和 Fixer(修复者)的代码审查系统。

go
package main

import (
    "context"
    "fmt"
    "github.com/cloudwego/eino-ext/devops/adk"
    "github.com/cloudwego/eino/components/tool"
)

func buildCodeReviewSystem(ctx context.Context) (*adk.ChatModelAgent, error) {
    // Reviewer Agent:专注于代码质量审查
    reviewer, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model: reviewModel,
        SystemPrompt: `你是代码审查专家。分析以下维度:
- 逻辑正确性
- 性能隐患
- 安全漏洞
- 代码规范
输出格式:[severity] file:line - description`,
    })

    // Fixer Agent:根据审查意见生成修复代码
    fixer, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model: fixerModel,
        SystemPrompt: `你是代码修复专家。根据审查意见生成修复补丁。
输出标准的 unified diff 格式。确保修复不引入新问题。`,
    })

    // Planner (Supervisor):协调整个审查流程
    planner, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Model: plannerModel,
        Tools: []tool.BaseTool{
            workerAsTool("reviewer", "对代码进行质量审查,输入为待审代码", reviewer),
            workerAsTool("fixer", "根据审查意见修复代码,输入为审查意见和原始代码", fixer),
        },
        SystemPrompt: `你是代码审查项目的协调者。工作流程:
1. 接收用户提交的代码变更
2. 调用 reviewer 进行审查
3. 如果发现问题,调用 fixer 生成修复
4. 再次调用 reviewer 验证修复
5. 输出最终的审查报告和修复建议
如果 reviewer 连续两次都没有发现问题,直接输出通过。`,
        MaxSteps: 8,
    })

    return planner, err
}

// 使用示例
func main() {
    ctx := context.Background()
    system, err := buildCodeReviewSystem(ctx)
    if err != nil {
        panic(err)
    }

    codeChange := `
func processOrder(order *Order) error {
    db.Save(order)
    sendEmail(order.UserEmail, "Order confirmed")
    chargePayment(order.Amount)
    return nil
}
`
    result, _ := system.Generate(ctx, []*schema.Message{
        schema.UserMessage(fmt.Sprintf("请审查以下代码变更:\n%s", codeChange)),
    })
    fmt.Println(result.Content)
}

这个系统体现了 Supervisor 模式的核心特征:Planner 负责流程控制,Reviewer 和 Fixer 作为专业 Worker 执行具体任务。通过 MaxSteps 限制避免无限循环。


最佳实践

1. 从单 Agent 开始,按需拆分

不要过早引入多 Agent。先用单 Agent 验证核心逻辑,当观察到明确的性能瓶颈或能力限制时再拆分。

2. 控制嵌套深度

为 Agent as Tool 设置经过测量的 token、时间、扇出和副作用预算;固定层数或“倍增”结论不能跨模型和 Prompt 泛化。

3. 为每个 Agent 设定清晰边界

每个 Agent 的 System Prompt 应明确定义:职责范围、输入/输出格式、何时移交。

4. 实现优雅降级

go
// Router 中设置 fallback
if !policy.acceptsClassification(confidence, inputSlice) {
    return "general_agent", nil // 阈值应在验证切片上校准
}

5. 利用 Callback 做全链路观测

go
agent.WithCallbacks(
    callbacks.OnStart(func(ctx context.Context, info *callbacks.RunInfo) {
        log.Printf("[%s] started with input: %s", info.Name, info.Input)
    }),
    callbacks.OnEnd(func(ctx context.Context, info *callbacks.RunInfo) {
        log.Printf("[%s] completed in %v", info.Name, info.Duration)
    }),
)

常见问题

Q: Router、Supervisor 和 Swarm 三种模式应该如何选择?

Router 适合意图明确、可分类的请求分发场景;Supervisor 适合需要规划、分配、汇总的复杂任务;Swarm 适合需要灵活协商、无法预定义流程的开放式协作。选择依据是任务是否可预先分类、是否需要中心协调。

Q: Agent as Tool 模式有什么限制?

限制取决于实现:同步子调用可能占用父 Agent,字符串边界需要明确契约,嵌套调用会共同消耗 token、时间和失败预算;应由运行时执行实测边界。

Q: 多 Agent 之间的状态如何共享?

推荐策略:通过 context.Context 传递只读的共享事实,每个 Agent 维护独立的对话历史。需要持久化的中间结果可使用外部存储。核心原则:共享事实,隔离推理。

Q: Eino 的多 Agent 系统支持流式输出吗?

流式能力取决于 Eino revision、Agent API、传输、缓冲、审核、取消和部分失败语义,应使用实际部署版本验证。

Q: 多 Agent 系统如何调试和观测?

Eino 内置 Callback 机制,为每个 Agent 设置唯一 RunInfo.Name,配合 OpenTelemetry 实现分布式追踪,可在可观测平台上看到完整的多 Agent 调用链。


总结

多智能体协作是突破单 Agent 能力限制的核心路径。Eino 通过 Graph 编排、Agent as Tool 和灵活的状态管理机制,原生支持三种协作模式:

  • Router:在分类质量和成本可接受时进行意图分发
  • Supervisor:有序的任务规划与执行,适合复杂多步骤任务
  • Swarm:灵活的对等协作,适合开放式、不确定性高的场景

选择模式时,应在相同工作负载切片和故障预算下比较 Router、Supervisor 与 Swarm。Eino 系列第一篇介绍框架全貌;本文聚焦协作模式的工程权衡。


相关资源