核心摘要
当单个 AI Agent 面对复杂任务时,上下文窗口限制、工具过载、缺乏专业化分工等问题会显著降低效果。多智能体系统通过角色专业化、并行处理和协作涌现,突破单一 Agent 的能力天花板。本文深入解析 Eino 框架支持的三种核心协作模式——Router(意图路由)、Supervisor(管理者)和 Swarm(对等协作),并通过一个多 Agent 代码审查系统展示实战落地方案。
目录
- 核心要点
- 为什么需要多 Agent
- Router 模式:意图路由
- Supervisor 模式:管理者协调
- Swarm 模式:对等协作
- Agent 作为 Tool:层级组合
- 状态共享与隔离
- 三种模式对比
- 实战:多 Agent 代码审查系统
- 最佳实践
- 常见问题
- 总结
- 相关资源
核心要点
- 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。
架构图
核心实现
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,并汇总最终结果。
架构图
核心实现
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
- 上下文传递:移交时携带必要的对话上下文
核心实现
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。这个包装层不是授权边界:必须在模型之外校验工具名、参数、租户/对象权限、来源、预算、取消和副作用。
// 将一个完整的 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 独立维护 | 对话记忆 | 推理不干扰,但无法共享经验 |
最佳实践:共享事实,隔离推理
// 通过 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(修复者)的代码审查系统。
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. 实现优雅降级
// Router 中设置 fallback
if !policy.acceptsClassification(confidence, inputSlice) {
return "general_agent", nil // 阈值应在验证切片上校准
}
5. 利用 Callback 做全链路观测
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 系列第一篇介绍框架全貌;本文聚焦协作模式的工程权衡。