☰
第6讲:多 Agent 协作——Orchestrator / Supervisor / Debate 三种模式实战
2026/10/13 10:11:04 网站建设 项目流程

一、开篇:为什么要多 Agent?

2026 年的生产实践表明,单一 Agent 在三个场景下必然力不从心:

场景

单一 Agent 的问题

多 Agent 的解法

复杂长流程(如:从需求分析到部署上线)

上下文太长导致遗忘,token 消耗爆炸

分工协作,每个 Agent 专注一段

需要多领域知识(如:同时懂法律+财务+技术)

一个模型不可能精通所有领域

每个 Agent 配备专属知识和工具

质量要求极高(如:医疗诊断、金融风控)

单一判断容易出错,缺乏制衡

交叉验证、辩论纠偏

多 Agent 不是把问题变复杂,而是把复杂问题拆解成多个简单问题,每个简单问题交给最擅长的 Agent。


二、三种协作模式概览

┌─────────────────────────────────────────────────────────────────┐ │ 多 Agent 协作模式 │ │ │ │ 1. Orchestrator(指挥家模式) │ │ ┌──────────┐ │ │ │ 指挥 Agent│────→ 研究员 Agent ────→ 输出 │ │ │ │────→ 代码 Agent ────→ 输出 │ │ │ │────→ 测试 Agent ────→ 输出 │ │ └──────────┘ ←──── 汇总结果 ──── │ │ │ │ 2. Supervisor(监工模式) │ │ ┌──────────┐ │ │ │ 监督 Agent│◄──── 执行 Agent ────→ 输出(需审核) │ │ │ │────→ 反馈修正 │ │ └──────────┘ │ │ │ │ 3. Debate(辩论模式) │ │ ┌──────────┐ ┌──────────┐ │ │ │ Agent A │◄──►│ Agent B │ │ │ │ (正方) │ │ (反方) │ │ │ └──────────┘ └──────────┘ │ │ │ │ │ │ └──────┬───────┘ │ │ ▼ │ │ ┌──────────┐ │ │ │ 裁决 Agent│──→ 最终结论 │ │ └──────────┘ │ └─────────────────────────────────────────────────────────────────┘

2.1 模式选择决策树

你的场景 │ ├─ 任务是线性流程,步骤明确? │ └─ ✅ Orchestrator(串行调度) │ ├─ 需要高质量输出,允许反复修改? │ └─ ✅ Supervisor(审核迭代) │ ├─ 答案有争议空间,需要多角度分析? │ └─ ✅ Debate(辩论求共识) │ └─ 以上都有? └─ ✅ 组合使用(Orchestrator 内部嵌 Supervisor 或 Debate)

三、模式一:Orchestrator(指挥家模式)

3.1 核心架构

用户请求 │ ▼ ┌──────────────────────────────────────────────┐ │ Orchestrator Agent │ │ │ │ 1. 分析用户意图 │ │ 2. 拆解为子任务 │ │ 3. 选择合适的 Sub-Agent │ │ 4. 分发任务并收集结果 │ │ 5. 汇总为最终答案 │ └──────────────────────────────────────────────┘ │ │ │ ▼ ▼ ▼ ┌────────┐ ┌────────┐ ┌────────┐ │ Researcher │ │ Coder │ │ Tester │ │ Agent │ │ Agent │ │ Agent │ └────────┘ └────────┘ └────────┘ │ │ │ └───────────┼───────────┘ ▼ ┌──────────┐ │ 最终输出 │ └──────────┘

3.2 Go 实现

// orchestrator.go package multiagent import ( "context" "encoding/json" "fmt" "sync" "time" ) // SubAgent 子 Agent 定义 type SubAgent struct { Name string Role string Description string Capability string // 能力描述,供 Orchestrator 决策 Handler func(ctx context.Context, task Task) (TaskResult, error) } type Task struct { ID string Description string Input string Dependencies []string // 依赖的任务 ID AssignedTo string } type TaskResult struct { TaskID string Output string Error string Metrics map[string]interface{} } // Orchestrator 指挥者 Agent type Orchestrator struct { agents map[string]*SubAgent llm LLMClient tasks map[string]Task results map[string]TaskResult mu sync.Mutex } func NewOrchestrator(llm LLMClient) *Orchestrator { return &Orchestrator{ agents: make(map[string]*SubAgent), llm: llm, tasks: make(map[string]Task), results: make(map[string]TaskResult), } } // RegisterAgent 注册子 Agent func (o *Orchestrator) RegisterAgent(agent *SubAgent) { o.agents[agent.Name] = agent } // Execute 执行用户请求 func (o *Orchestrator) Execute(ctx context.Context, userRequest string) (string, error) { // 1. 分析请求,拆解为子任务 tasks, err := o.decomposeTasks(ctx, userRequest) if err != nil { return "", fmt.Errorf("decompose tasks: %w", err) } // 2. 为每个任务分配 Agent if err := o.assignAgents(ctx, tasks); err != nil { return "", fmt.Errorf("assign agents: %w", err) } // 3. 按依赖关系执行任务 executed := make(map[string]bool) for len(executed) < len(tasks) { for _, task := range tasks { if executed[task.ID] { continue } // 检查依赖是否全部完成 depsMet := true for _, depID := range task.Dependencies { if !executed[depID] { depsMet = false break } } if !depsMet { continue } // 执行任务 result, err := o.executeTask(ctx, task) if err != nil { // 重试一次 result, err = o.executeTask(ctx, task) if err != nil { return "", fmt.Errorf("execute task %s: %w", task.ID, err) } } o.mu.Lock() o.results[task.ID] = result executed[task.ID] = true o.mu.Unlock() } } // 4. 汇总结果 summary, err := o.summarizeResults(ctx, userRequest) if err != nil { return "", fmt.Errorf("summarize: %w", err) } return summary, nil } func (o *Orchestrator) decomposeTasks(ctx context.Context, request string) ([]Task, error) { agentList := "" for name, agent := range o.agents { agentList += fmt.Sprintf("- %s: %s (%s)\n", name, agent.Description, agent.Capability) } prompt := fmt.Sprintf(`你是一个任务分解专家。请将以下用户请求分解为多个子任务。 可用子 Agent: %s 用户请求:%s 请输出 JSON 格式的任务列表: [ { "id": "task-1", "description": "任务描述", "input": "任务的输入内容", "dependencies": [] } ] 规则: 1. 每个任务应该可以由一个子 Agent 独立完成 2. 明确标注任务间的依赖关系 3. 任务的 input 字段应包含足够的信息供子 Agent 执行`, agentList, request) response, err := o.llm.Chat([]Message{{Role: "user", Content: prompt}}) if err != nil { return nil, err } var tasks []Task if err := json.Unmarshal([]byte(extractJSON(response.Content)), &tasks); err != nil { return nil, fmt.Errorf("parse tasks: %w", err) } return tasks, nil } func (o *Orchestrator) assignAgents(ctx context.Context, tasks []Task) error { for i, task := range tasks { prompt := fmt.Sprintf(`请为以下任务选择最合适的子 Agent。 可用子 Agent: `, task.Description) for name, agent := range o.agents { prompt += fmt.Sprintf("- %s: %s\n", name, agent.Description) } prompt += fmt.Sprintf(`\n任务描述:%s 请只输出 Agent 的名称。`, task.Description) response, err := o.llm.Chat([]Message{{Role: "user", Content: prompt}}) if err != nil { return err } agentName := response.Content if _, exists := o.agents[agentName]; !exists { // 默认分配给第一个 Agent for name := range o.agents { agentName = name break } } tasks[i].AssignedTo = agentName o.tasks[task.ID] = tasks[i] } return nil } func (o *Orchestrator) executeTask(ctx context.Context, task Task) (TaskResult, error) { agent, exists := o.agents[task.AssignedTo] if !exists { return TaskResult{}, fmt.Errorf("agent %s not found", task.AssignedTo) } // 添加上下文(依赖任务的结果) enrichedInput := task.Input for _, depID := range task.Dependencies { if result, ok := o.results[depID]; ok { enrichedInput += fmt.Sprintf("\n\n【上游任务 %s 的结果】\n%s", depID, result.Output) } } taskWithContext := Task{ ID: task.ID, Description: task.Description, Input: enrichedInput, AssignedTo: task.AssignedTo, } return agent.Handler(ctx, taskWithContext) } func (o *Orchestrator) summarizeResults(ctx context.Context, originalRequest string) (string, error) { var summaryBuilder string summaryBuilder = fmt.Sprintf("原始请求:%s\n\n执行结果:\n\n", originalRequest) for _, task := range o.tasks { if result, ok := o.results[task.ID]; ok { summaryBuilder += fmt.Sprintf("### 任务:%s(由 %s 执行)\n", task.Description, task.AssignedTo) summaryBuilder += fmt.Sprintf("%s\n\n", result.Output) } } prompt := fmt.Sprintf(`请根据以下任务执行结果,生成一份面向用户的总结报告。 %s 请用清晰的语言总结完成了哪些工作,以及关键结果。`, summaryBuilder) response, err := o.llm.Chat([]Message{{Role: "user", Content: prompt}}) if err != nil { return summaryBuilder, nil // 降级:直接返回原始汇总 } return response.Content, nil } // ========== 示例子 Agent ========== func ResearcherAgent(ctx context.Context, task Task) (TaskResult, error) { // 模拟研究 Agent return TaskResult{ TaskID: task.ID, Output: fmt.Sprintf("【研究结果】\n针对「%s」的研究结论:\n- 主要发现 1\n- 主要发现 2\n- 数据来源:[模拟引用]", task.Input), }, nil } func CoderAgent(ctx context.Context, task Task) (TaskResult, error) { return TaskResult{ TaskID: task.ID, Output: fmt.Sprintf("```go\n// 根据需求生成的代码\nfunc main() {\n fmt.Println(\"%s\")\n}\n```", task.Input), }, nil } func TesterAgent(ctx context.Context, task Task) (TaskResult, error) { return TaskResult{ TaskID: task.ID, Output: fmt.Sprintf("【测试报告】\n测试用例:%s\n- 通过:5/5\n- 覆盖率:87%%\n- 性能:P99 延迟 45ms", task.Input), }, nil } // ========== 运行示例 ========== func ExampleOrchestrator() { llm := &MockLLMClient{} orch := NewOrchestrator(llm) orch.RegisterAgent(&SubAgent{ Name: "researcher", Role: "研究员", Description: "负责信息检索和分析", Capability: "搜索、阅读、总结", Handler: ResearcherAgent, }) orch.RegisterAgent(&SubAgent{ Name: "coder", Role: "程序员", Description: "负责编写代码", Capability: "Go、Python、前端开发", Handler: CoderAgent, }) orch.RegisterAgent(&SubAgent{ Name: "tester", Role: "测试工程师", Description: "负责测试和质量保障", Capability: "单元测试、集成测试、性能测试", Handler: TesterAgent, }) result, _ := orch.Execute(context.Background(), "研究最新的 GraphRAG 实现方案,然后用 Go 实现一个最小原型,最后编写测试用例") fmt.Println(result) }

四、模式二:Supervisor(监工模式)

4.1 核心流程

Worker Agent 产出 │ ▼ ┌──────────────────────┐ │ Supervisor Agent │ │ │ │ 审核输出质量 │── 合格 ──→ 交付 │ 检查是否符合要求 │ │ 识别问题和改进点 │ │ │ └──────────────────────┘ │ 不合格 ▼ ┌──────────────────────┐ │ 反馈给 Worker │ │ "需要修改:..." │ └──────────────────────┘ │ ▼ Worker Agent 重新产出 │ ▼ ┌──────────────────────┐ │ Supervisor 再次审核 │── 合格 ──→ 交付 │ │ └──────────────────────┘ │ 仍不合格(达上限) ▼ ┌──────────────────────┐ │ 人工介入 │ └──────────────────────┘

4.2 Go 实现

// supervisor.go package multiagent import ( "context" "fmt" "strings" ) // QualityCheck 质量检查结果 type QualityCheck struct { Passed bool Score int // 1-100 Issues []string Suggestions []string } // SupervisorConfig 监督者配置 type SupervisorConfig struct { MaxIterations int // 最大迭代次数 PassThreshold int // 通过阈值(百分比) StrictMode bool // 严格模式 } // Supervisor 监督者 Agent type Supervisor struct { worker *SubAgent llm LLMClient config SupervisorConfig } func NewSupervisor(worker *SubAgent, llm LLMClient, config SupervisorConfig) *Supervisor { if config.MaxIterations <= 0 { config.MaxIterations = 3 } if config.PassThreshold <= 0 { config.PassThreshold = 85 } return &Supervisor{ worker: worker, llm: llm, config: config, } } // ExecuteWithSupervision 在监督下执行任务 func (s *Supervisor) ExecuteWithSupervision(ctx context.Context, task Task) (TaskResult, error) { var lastResult TaskResult var lastCheck *QualityCheck for iteration := 0; iteration < s.config.MaxIterations; iteration++ { // 1. Worker 执行 result, err := s.worker.Handler(ctx, task) if err != nil { return TaskResult{}, fmt.Errorf("worker execution failed: %w", err) } // 2. Supervisor 审核 check, err := s.review(ctx, task, result, iteration) if err != nil { return result, nil // 审核失败则直接返回 worker 结果 } lastResult = result lastCheck = check // 3. 判断是否通过 if check.Passed && check.Score >= s.config.PassThreshold { result.Metrics = map[string]interface{}{ "iterations": iteration + 1, "final_score": check.Score, "passed": true, } return result, nil } // 4. 未通过,准备反馈给 Worker if iteration < s.config.MaxIterations-1 { feedback := s.buildFeedback(check) task.Input = fmt.Sprintf(`【原始任务】%s 【上次输出】 %s 【监督反馈】 %s 请根据以上反馈进行改进。`, task.Input, result.Output, feedback) } } // 达到最大迭代次数仍未通过 lastResult.Metrics = map[string]interface{}{ "iterations": s.config.MaxIterations, "final_score": lastCheck.Score, "passed": false, "issues": lastCheck.Issues, } return lastResult, nil } func (s *Supervisor) review(ctx context.Context, task Task, result TaskResult, iteration int) (*QualityCheck, error) { prompt := fmt.Sprintf(`你是一个质量审核专家。请审核以下任务输出。 任务描述:%s 输出内容: %s 审核标准: 1. 准确性:输出是否正确? 2. 完整性:是否涵盖了所有要求? 3. 清晰度:表达是否清楚易懂? 4. 规范性:是否符合最佳实践? 5. 安全性:是否存在安全隐患? 请输出 JSON 格式的审核结果: { "passed": true/false, "score": 0-100, "issues": ["问题1", "问题2"], "suggestions": ["改进建议1", "改进建议2"] } 评分标准: - 90-100:优秀,可直接交付 - 75-89:良好,有小瑕疵 - 60-74:及格,需要修改 - 0-59:不及格,需要重做 这是第 %d 次迭代。`, task.Description, result.Output, iteration+1) response, err := s.llm.Chat([]Message{{Role: "user", Content: prompt}}) if err != nil { return nil, err } var check QualityCheck // 解析 JSON(简化处理) if strings.Contains(response.Content, "true") { check.Passed = true } else { check.Passed = false } check.Score = 70 // 模拟分数 return &check, nil } func (s *Supervisor) buildFeedback(check *QualityCheck) string { var sb strings.Builder sb.WriteString(fmt.Sprintf("质量评分:%d/100\n\n", check.Score)) if len(check.Issues) > 0 { sb.WriteString("存在的问题:\n") for _, issue := range check.Issues { sb.WriteString(fmt.Sprintf("- %s\n", issue)) } } if len(check.Suggestions) > 0 { sb.WriteString("\n改进建议:\n") for _, suggestion := range check.Suggestions { sb.WriteString(fmt.Sprintf("- %s\n", suggestion)) } } return sb.String() } // ========== 使用示例 ========== func ExampleSupervisor() { llm := &MockLLMClient{} // 创建一个需要监督的 Worker writerAgent := &SubAgent{ Name: "writer", Role: "技术文档撰写员", Description: "负责编写技术文档", Handler: func(ctx context.Context, task Task) (TaskResult, error) { return TaskResult{ TaskID: task.ID, Output: fmt.Sprintf("# 技术文档\n\n## 概述\n本文档介绍%s的实现方案。\n\n## 架构\n采用微服务架构...\n\n## 部署\n使用 Docker Compose...", task.Input), }, nil }, } // 创建 Supervisor supervisor := NewSupervisor(writerAgent, llm, SupervisorConfig{ MaxIterations: 3, PassThreshold: 85, }) result, _ := supervisor.ExecuteWithSupervision(context.Background(), Task{ ID: "doc-1", Description: "编写 GraphRAG 系统的技术文档", Input: "GraphRAG 是一个基于知识图谱的 RAG 系统", }) fmt.Printf("最终输出:\n%s\n", result.Output) fmt.Printf("指标:%v\n", result.Metrics) }

五、模式三:Debate(辩论模式)

5.1 核心流程

┌─────────────────────────────────────────────────────────────────┐ │ Debate 流程 │ │ │ │ 阶段 1:独立分析 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Agent A │ │ Agent B │ │ Agent C │ │ │ │ (技术视角)│ │ (业务视角)│ │ (安全视角)│ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ │ │ │ └───────────────┼───────────────┘ │ │ ▼ │ │ 阶段 2:公开辩论 │ │ ┌──────────────────────────────────────────┐ │ │ │ A: 我认为方案 X 最好,因为性能提升 40% │ │ │ │ B: 但方案 X 的开发成本太高,建议方案 Y │ │ │ │ C: 方案 X 存在安全漏洞,需要补充 │ │ │ │ A: 我同意 C 的观点,可以在 X 上加防护 │ │ │ └──────────────────────────────────────────┘ │ │ ▼ │ │ 阶段 3:裁决 │ │ ┌──────────────────────────────────────────┐ │ │ │ 裁决 Agent │ │ │ 综合各方观点,给出最终结论 │ │ │ └──────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘

5.2 Go 实现

// debate.go package multiagent import ( "context" "fmt" "strings" ) // Debater 辩手 type Debater struct { Name string Role string Viewpoint string // 立场 Handler func(ctx context.Context, topic string, otherArguments []string) (string, error) } // DebateRound 一轮辩论 type DebateRound struct { RoundNumber int Arguments map[string]string // debater name -> argument } // DebateResult 辩论结果 type DebateResult struct { Topic string Rounds []DebateRound Consensus string Winner string FinalReport string } // DebateModerator 辩论主持人 type DebateModerator struct { debaters []*Debater judge *Debater llm LLMClient maxRounds int } func NewDebateModerator(debaters []*Debater, judge *Debater, llm LLMClient, maxRounds int) *DebateModerator { return &DebateModerator{ debaters: debaters, judge: judge, llm: llm, maxRounds: maxRounds, } } // ConductDebate 主持辩论 func (m *DebateModerator) ConductDebate(ctx context.Context, topic string) (*DebateResult, error) { result := &DebateResult{ Topic: topic, Rounds: make([]DebateRound, 0), } // 阶段 1:开场陈述 openingArgs := make(map[string]string) for _, debater := range m.debaters { arg, err := debater.Handler(ctx, fmt.Sprintf("请就以下议题发表你的开场陈述:\n%s\n\n你的立场:%s", topic, debater.Viewpoint), nil) if err != nil { return nil, fmt.Errorf("debater %s opening failed: %w", debater.Name, err) } openingArgs[debater.Name] = arg } result.Rounds = append(result.Rounds, DebateRound{ RoundNumber: 1, Arguments: openingArgs, }) // 阶段 2:多轮辩论 for round := 2; round <= m.maxRounds; round++ { roundArgs := make(map[string]string) for _, debater := range m.debaters { // 收集其他辩手的论点 var otherArgs []string for name, arg := range result.Rounds[round-2].Arguments { if name != debater.Name { otherArgs = append(otherArgs, fmt.Sprintf("%s 说:%s", name, arg)) } } arg, err := debater.Handler(ctx, fmt.Sprintf("辩论主题:%s\n\n你的立场:%s\n\n其他人的论点:\n%s\n\n请回应他们的观点,提出反驳或补充。", topic, debater.Viewpoint, strings.Join(otherArgs, "\n\n")), otherArgs) if err != nil { continue } roundArgs[debater.Name] = arg } result.Rounds = append(result.Rounds, DebateRound{ RoundNumber: round, Arguments: roundArgs, }) // 提前终止检测:如果所有辩手观点趋于一致 if m.checkConsensus(roundArgs) { break } } // 阶段 3:裁决 consensus, winner, report, err := m.judge.Handler(ctx, m.buildJudgingPrompt(topic, result), nil) if err != nil { return nil, fmt.Errorf("judge failed: %w", err) } result.Consensus = consensus result.Winner = winner result.FinalReport = report return result, nil } func (m *DebateModerator) checkConsensus(args map[string]string) bool { // 简单检测:如果所有论点都包含相同的关键词,认为达成共识 keywords := []string{"同意", "赞同", "agree", "+1", "concur"} agreementCount := 0 for _, arg := range args { for _, kw := range keywords { if strings.Contains(arg, kw) { agreementCount++ break } } } return agreementCount >= len(args)-1 // 至少 N-1 人同意 } func (m *DebateModerator) buildJudgingPrompt(topic string, result *DebateResult) string { var sb strings.Builder sb.WriteString(fmt.Sprintf("你是一个中立的裁决者。请审阅以下关于「%s」的辩论,并给出最终结论。\n\n", topic)) for _, round := range result.Rounds { sb.WriteString(fmt.Sprintf("\n=== 第 %d 轮 ===\n", round.RoundNumber)) for name, arg := range round.Arguments { sb.WriteString(fmt.Sprintf("\n%s:\n%s\n", name, arg)) } } sb.WriteString("\n请输出以下三部分(用 --- 分隔):\n") sb.WriteString("1. 共识点:各方达成一致的地方\n") sb.WriteString("2. 获胜方:哪位辩手的观点最有说服力,为什么\n") sb.WriteString("3. 最终报告:面向用户的综合结论和建议\n") return sb.String() } // ========== 预设辩手 ========== func TechnicalDebater(ctx context.Context, topic string, otherArgs []string) (string, error) { return fmt.Sprintf(`从技术角度看,我建议采用方案 A。 理由: 1. 性能最优,经测试 QPS 可达 5000+ 2. 技术栈成熟,社区活跃 3. 扩展性好,支持水平扩展 顾虑: - 学习曲线较陡 - 初期投入较大`), nil } func BusinessDebater(ctx context.Context, topic string, otherArgs []string) (string, error) { return fmt.Sprintf(`从业务角度看,我建议采用方案 B。 理由: 1. 开发周期短,2 周可上线 2. 成本低,只需 2 台服务器 3. 团队现有技术栈即可支持 顾虑: - 性能上限较低 - 长期维护成本可能上升`), nil } func SecurityDebater(ctx context.Context, topic string, otherArgs []string) (string, error) { return fmt.Sprintf(`从安全角度看,两个方案都需要加强。 方案 A 的风险: 1. 依赖的第三方库有已知 CVE 2. 默认配置不安全 方案 B 的风险: 1. 数据传输未加密 2. 缺少审计日志 建议:无论选哪个方案,都必须补充安全加固措施。`), nil } func JudgeDebater(ctx context.Context, topic string, otherArgs []string) (string, error) { return `共识点:各方都认同需要尽快推进,只是在方案选择上有分歧。 获胜方:技术方和安全方的论证更充分,且两者并不矛盾。 最终报告: 经过三轮辩论,建议采用方案 A,但同时采纳安全方的建议进行加固。具体来说: 1. 使用方案 A 作为基础架构 2. 在实施过程中加入安全方提出的加固措施 3. 业务方的快速上线需求可以通过 MVP 分阶段交付来满足 4. 建议下周召开技术评审会,敲定详细实施方案`, nil } // ========== 运行示例 ========== func ExampleDebate() { moderator := NewDebateModerator( []*Debater{ {Name: "技术专家", Role: "技术负责人", Viewpoint: "偏向方案 A(高性能)", Handler: TechnicalDebater}, {Name: "业务专家", Role: "产品经理", Viewpoint: "偏向方案 B(快交付)", Handler: BusinessDebater}, {Name: "安全专家", Role: "安全工程师", Viewpoint: "中立(关注安全)", Handler: SecurityDebater}, }, &Debater{Name: "裁决者", Role: "CTO", Viewpoint: "中立", Handler: JudgeDebater}, &MockLLMClient{}, 3, // 最多 3 轮辩论 ) result, _ := moderator.ConductDebate(context.Background(), "公司要建设新一代 RAG 系统,应该选择方案 A(高性能但成本高)还是方案 B(快速上线但性能有限)?") fmt.Printf("辩论主题:%s\n\n", result.Topic) fmt.Printf("共识:%s\n\n", result.Consensus) fmt.Printf("获胜方:%s\n\n", result.Winner) fmt.Printf("最终报告:\n%s\n", result.FinalReport) }

六、三种模式的对比与选择

维度

Orchestrator

Supervisor

Debate

适用场景​

明确的线性流程

需要质量把控

有争议的决策

Token 消耗​

中(N 个子任务 × 平均轮次)

高(多次审核迭代)

最高(多轮辩论)

延迟​

取决于最长链路

中等(迭代次数可控)

高(串行辩论轮次)

质量保证​

依赖子 Agent 各自的质量

强(有审核机制)

最强(多角度交叉验证)

实现复杂度​

低

中

高

典型 Token 消耗​

5000~15000

8000~25000

15000~50000

选型建议

你的首要目标 │ ├─ 快速完成任务 → Orchestrator │ ├─ 确保输出质量 → Supervisor │ └─ 做出最优决策 → Debate

七、组合模式:Orchestrator + Supervisor

生产环境中最常见的做法是组合使用:

Orchestrator │ ├─ 子任务 1 → Supervisor(Writer Agent) → 审核通过的文档 │ ├─ 子任务 2 → Supervisor(Coder Agent) → 审核通过的代码 │ └─ 子任务 3 → Debate(技术/业务/安全) → 辩论后的决策
// hybrid_orchestrator.go func HybridExecute(ctx context.Context, request string) (string, error) { llm := &MockLLMClient{} // 创建 Orchestrator orch := NewOrchestrator(llm) // 注册带 Supervisor 的子 Agent writer := &SubAgent{ Name: "writer", Handler: func(ctx context.Context, task Task) (TaskResult, error) { sup := NewSupervisor(&SubAgent{ Name: "writer-worker", Handler: func(ctx context.Context, t Task) (TaskResult, error) { // 实际的写作逻辑 return TaskResult{TaskID: t.ID, Output: "文档内容"}, nil }, }, llm, SupervisorConfig{MaxIterations: 2, PassThreshold: 80}) return sup.ExecuteWithSupervision(ctx, task) }, } coder := &SubAgent{ Name: "coder", Handler: func(ctx context.Context, task Task) (TaskResult, error) { sup := NewSupervisor(&SubAgent{ Name: "coder-worker", Handler: func(ctx context.Context, t Task) (TaskResult, error) { // 实际的编码逻辑 return TaskResult{TaskID: t.ID, Output: "代码内容"}, nil }, }, llm, SupervisorConfig{MaxIterations: 3, PassThreshold: 90}) return sup.ExecuteWithSupervision(ctx, task) }, } orch.RegisterAgent(writer) orch.RegisterAgent(coder) return orch.Execute(ctx, request) }

八、关键要点

  1. 多 Agent 不是银弹​ — 80% 的场景一个 Agent 就够了,只有复杂场景才需要多 Agent
  2. Orchestrator 是最常用的模式​ — 从简单开始,大多数业务流程都是线性的
  3. Supervisor 适合质量敏感场景​ — 金融、医疗、法律等领域建议必加
  4. Debate 消耗最大但效果最好​ — 用于重大决策,不要用在日常任务上
  5. Token 预算要提前算好​ — 多 Agent 的 Token 消耗是指数级增长的
  6. 超时和重试是必需品​ — 任何一个子 Agent 挂掉都会阻塞整个流程
  7. 组合使用效果最佳​ — Orchestrator 管流程,Supervisor 管质量,Debate 管决策

九、预告

第 7 讲预告:《大模型后端服务化:Go 实现高并发 LLM Proxy / Router / Fallback》

你将学到:

  • 为什么需要 LLM Proxy?统一鉴权、限流、计费、日志
  • 多模型路由:按成本/能力/延迟动态选择模型
  • Fallback 策略:主模型挂了自动切换到备选
  • 语义缓存:减少重复请求,降低 40%+ 成本
  • 生产级 Go 实现:连接池、重试、熔断、监控

🧰 开发之余的小工具推荐

处理 Base64、JSON 格式化、JWT 解析、Crontab 计算、PDF 合并压缩这些碎片需求,我常用一个纯前端本地工具箱:zz365.top。所有计算在浏览器完成,文件不上服务器,关页即清。免费、无登录、无广告,适合开发者当常驻标签页。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询