【AI Agent 与 Super Agent 构建实战】第 22 篇:辩论与共识 — 多 Agent 协商机制

本系列定位:用 Go 语言从零构建各类 AI Agent,覆盖 ReAct、Plan-and-Execute、Multi-Agent、Super Agent 等核心设计模式的完整工程实现。


本篇你将学到

  • Debate 模式的原理:为什么"让 Agent 吵一架"能提升答案质量
  • 多轮协商的收敛算法与终止条件设计
  • 四种共识机制:多数投票、加权评分、仲裁者裁决、LLM 合成
  • 质量评估 Agent 的设计:用独立 Agent 给答案打分
  • 用 Go 实现完整的多 Agent 辩论框架

学完本篇,你将能解决多 Agent 系统的核心难题——“多个 Agent 对同一问题给出不同答案时如何达成共识”,这是第 23 篇 Group Chat 和第 24 篇 AgentForge v0.4 的关键组件。


一、Debate 模式原理

1.1 单 Agent 答案的脆弱性

回顾前面模块的 Agent:一个 LLM 给出一个答案,对错全凭它的"直觉"。但 LLM 有一个已知缺陷——单次采样容易陷入局部最优或被错误推理带偏

第 16 篇的 Tree of Thought 通过"多分支探索 + 自评估"部分缓解了这个问题。Debate 模式是另一条路径:让多个独立 Agent 各自给出答案并相互挑战,通过对抗暴露彼此的漏洞。

多 Agent 辩论

答案1

答案2

答案3

挑战2,3

挑战1,3

挑战1,2

多轮收敛

问题

Agent 1

Agent 2

Agent 3

辩论场

共识答案
经受过对抗检验

单 Agent 单次采样

一次回答

问题

Agent

答案
可能错误且不自知

1.2 Debate 的认知科学依据

Debate 模式的有效性有认知科学支撑:

机制单 Agent 缺失Debate 补足
确认偏误LLM 倾向于维护自己已说的对手会攻击你的薄弱点
视角盲区单一 Prompt 视角受限不同角色 Prompt 提供不同视角
过度自信单 Agent 对错误答案也很自信被挑战后被迫反思或坚持(可观测)
错误传播一步错步步错其他 Agent 可能走对的那一步

1.3 一个直观例子

问题:“Go 中 map 并发读写会怎样?”

  • Agent A(新手视角):“会读到旧值,没问题”——错误
  • Agent B(经验视角):“会 panic: concurrent map read and map write”——正确
  • Agent C(理论视角):“Go runtime 检测到并发访问会 fatal error”——正确且更精确

单 Agent 模式下,如果 A 被采样到,错误答案直接返回。Debate 模式下,B 和 C 会挑战 A:“你确定不会 panic 吗?Go runtime 有并发检测机制。” A 要么改正,要么坚持(暴露其不可靠),最终共识倾向于 B/C 的答案。


二、多轮协商收敛算法

2.1 辩论的生命周期

各 Agent 提交初始答案

公开所有答案,相互批评

基于批评修改答案

下一轮批评

达到最大轮数或收敛

未收敛,投票

已收敛

票数接近,仲裁

票数分明

仲裁者裁决

Proposal

Critique

Revision

ConsensusCheck

Voting

Consensus

Arbiter

2.2 收敛的三个终止条件

辩论不能无限进行下去,必须设计终止条件:

条件含义典型阈值
共识达成超过阈值的 Agent 给出相同(或语义等价)答案≥ 2/3 一致
最大轮数防止死循环的硬上限3-5 轮
稳定性连续 N 轮无 Agent 改变立场连续 2 轮无变化

实际工程中,最大轮数是必须的兜底——前两个条件可能永远不满足。

2.3 收敛算法伪代码

function Debate(question, agents, maxRounds):
    proposals = {}
    # 第一轮:各自提交初始答案
    for agent in agents:
        proposals[agent] = agent.Propose(question)

    for round in 1..maxRounds:
        # 公开所有答案
        publicView = publish(proposals)

        # 相互批评
        critiques = {}
        changed = false
        for agent in agents:
            critique = agent.Critique(publicView)
            critiques[agent] = critique
            # 基于批评决定是否修改
            revised = agent.Revise(proposals[agent], critique)
            if revised != proposals[agent]:
                proposals[agent] = revised
                changed = true

        # 检查共识
        if consensusReached(proposals, threshold=0.67):
            return pickConsensus(proposals)

        # 检查稳定性
        if not changed:
            return pickConsensus(proposals)

    # 达到最大轮数,进入投票
    return vote(proposals, agents)

三、四种共识机制详解

当辩论未自然收敛时,需要机制强制得出结论。

3.1 机制对比

共识机制选择

答案差异小

Agent 能力有差异

票数接近

答案各有道理

辩论未收敛

多数投票
Majority Vote

加权评分
Weighted Score

仲裁者裁决
Arbiter

LLM 合成
Synthesis

机制原理适用场景缺点
多数投票得票最多的答案胜出答案可二分/分类少数正确答案被淹没
加权评分按置信度/历史表现加权Agent 能力差异大权重难定
仲裁者引入第三方 Agent 裁决票数接近、专业性强的题仲裁者也可能错
LLM 合成Orchestrator 综合多答案生成新答案答案各有可取之处成本高、可能跑偏

3.2 多数投票实现

// internal/multiagent/consensus.go
package multiagent

import (
	"sort"
)

// VoteRecord 一张投票
type VoteRecord struct {
	VoterID  string  // 投票 Agent ID
	ChoiceID string  // 选择的答案 ID
	Reason   string  // 投票理由
	Weight   float64 // 权重(默认 1.0)
}

// MajorityVote 多数投票
type MajorityVote struct{}

// Decide 执行投票,返回胜出的答案 ID 和得分
func (m *MajorityVote) Decide(votes []VoteRecord) (winnerID string, score float64) {
	tally := make(map[string]float64)
	for _, v := range votes {
		w := v.Weight
		if w <= 0 {
			w = 1.0
		}
		tally[v.ChoiceID] += w
	}

	var maxScore float64
	for id, s := range tally {
		if s > maxScore {
			maxScore = s
			winnerID = id
		}
	}
	return winnerID, maxScore
}

// WeightedScore 加权评分共识
type WeightedScore struct{}

// Decide 按权重累加,返回得分最高的
func (w *WeightedScore) Decide(votes []VoteRecord) (winnerID string, score float64) {
	return (&MajorityVote{}).Decide(votes) // 加权投票本质相同
}

// RankedResults 返回所有候选的排名(用于分析)
func RankedResults(votes []VoteRecord) []struct {
	ID    string
	Score float64
} {
	tally := make(map[string]float64)
	for _, v := range votes {
		w := v.Weight
		if w <= 0 {
			w = 1.0
		}
		tally[v.ChoiceID] += w
	}
	result := make([]struct {
		ID    string
		Score float64
	}, 0, len(tally))
	for id, s := range tally {
		result = append(result, struct {
			ID    string
			Score float64
		}{id, s})
	}
	sort.Slice(result, func(i, j int) bool {
		return result[i].Score > result[j].Score
	})
	return result
}

3.3 仲裁者模式

当投票结果接近(如 2:2)时,引入一个独立的仲裁者 Agent 做最终判断。仲裁者通常是能力更强或视角不同的 Agent:

// Arbiter 仲裁者接口
type Arbiter interface {
	Arbitrate(question string, proposals map[string]string) (winnerID string, reasoning string, err error)
}

// LLMArbiter 基于 LLM 的仲裁者
type LLMArbiter struct {
	agent MessagingAgent // 复用第 20 篇的消息驱动 Agent
}

func NewLLMArbiter(agent MessagingAgent) *LLMArbiter {
	return &LLMArbiter{agent: agent}
}

func (a *LLMArbiter) Arbitrate(question string, proposals map[string]string) (string, string, error) {
	// 构造仲裁 Prompt(这里简化,实际应注入到 System Prompt)
	payload := map[string]any{
		"question":   question,
		"proposals":  proposals,
		"instruction": "作为仲裁者,评估每个答案的正确性,选出最准确的一个,并说明理由。",
	}
	resp, err := a.agent.bus.Publish(NewMessage("arbiter-system", a.agent.ID(),
		MsgQuery, payload))
	_ = resp
	return "", "", err
}

四、质量评估 Agent

辩论的胜负不应该只看"谁嗓门大",而应该看"谁的答案质量高"。这需要一个独立的质量评估 Agent。

4.1 评估维度

质量评估五维度

权重 0.35

权重 0.25

权重 0.15

权重 0.15

权重 0.10

正确性
Correctness

完整性
Completeness

一致性
Consistency

可验证性
Verifiability

清晰度
Clarity

总分

4.2 评估结果数据结构

// internal/multiagent/evaluator.go
package multiagent

import "fmt"

// Evaluation 一次质量评估
type Evaluation struct {
	ProposalID string             // 被评估的答案 ID
	Scores     map[string]float64 // 维度 -> 分数 [0,1]
	TotalScore float64            // 加权总分
	Feedback   string             // 文字反馈
}

// EvaluatorDimensions 评估维度权重
var EvaluatorDimensions = map[string]float64{
	"correctness":   0.35,
	"completeness":  0.25,
	"consistency":   0.15,
	"verifiability": 0.15,
	"clarity":       0.10,
}

// ComputeTotal 计算加权总分
func (e *Evaluation) ComputeTotal() {
	total := 0.0
	for dim, score := range e.Scores {
		weight := EvaluatorDimensions[dim]
		total += score * weight
	}
	e.TotalScore = total
}

// QualityEvaluator 质量评估器
type QualityEvaluator struct {
	agentID string
}

func NewQualityEvaluator(agentID string) *QualityEvaluator {
	return &QualityEvaluator{agentID: agentID}
}

// Evaluate 评估一个答案(模拟版,实际应调用 LLM)
func (q *QualityEvaluator) Evaluate(proposalID, answer string) Evaluation {
	// 实际实现:构造 Prompt 让 LLM 按五维度打分
	// 这里给出评估结果的数据结构示例
	eval := Evaluation{
		ProposalID: proposalID,
		Scores: map[string]float64{
			"correctness":   0.85,
			"completeness":  0.70,
			"consistency":   0.90,
			"verifiability": 0.80,
			"clarity":       0.75,
		},
		Feedback: "答案核心正确,但缺少边界 case 的讨论",
	}
	eval.ComputeTotal()
	return eval
}

// FormatReport 格式化评估报告
func (e *Evaluation) FormatReport() string {
	report := fmt.Sprintf("答案 %s 评估报告:\n", e.ProposalID)
	report += fmt.Sprintf("总分: %.2f\n", e.TotalScore)
	report += "维度明细:\n"
	for dim, score := range e.Scores {
		weight := EvaluatorDimensions[dim]
		report += fmt.Sprintf("  - %-15s %.2f (权重 %.0f%%)\n", dim, score, weight*100)
	}
	report += fmt.Sprintf("反馈: %s\n", e.Feedback)
	return report
}

五、Go 实现多 Agent 辩论框架

5.1 辩论核心结构

// internal/multiagent/debate.go
package multiagent

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"
)

// DebateConfig 辩论配置
type DebateConfig struct {
	MaxRounds      int           // 最大轮数
	ConsensusRatio float64       // 共识阈值(如 0.67)
	VoteTimeout    time.Duration // 投票超时
	Logger         *log.Logger
}

// DefaultDebateConfig 默认配置
func DefaultDebateConfig() DebateConfig {
	return DebateConfig{
		MaxRounds:      3,
		ConsensusRatio: 0.67,
		VoteTimeout:    30 * time.Second,
	}
}

// DebateAgent 辩论参与者接口
type DebateAgent interface {
	ID() string
	Propose(ctx context.Context, question string) (string, error)
	Critique(ctx context.Context, question string, others map[string]string) (string, error)
	Revise(ctx context.Context, question, myAnswer, critique string) (string, error)
	Vote(ctx context.Context, question string, proposals map[string]string) (VoteRecord, error)
}

// Proposal 一个 Agent 的提案
type Proposal struct {
	AgentID string
	Answer  string
	History []string // 历史版本(用于追踪修改)
}

// DebateSession 一场辩论
type DebateSession struct {
	Question string
	Agents   []DebateAgent
	Config   DebateConfig

	mu         sync.Mutex
	proposals  map[string]*Proposal // agentID -> 提案
	round      int
	converged  bool
	winner     string
	winnerAns  string
	logger     *log.Logger
}

// NewDebateSession 创建辩论会
func NewDebateSession(question string, agents []DebateAgent, cfg DebateConfig) *DebateSession {
	if cfg.Logger == nil {
		cfg.Logger = log.Default()
	}
	return &DebateSession{
		Question:  question,
		Agents:    agents,
		Config:    cfg,
		proposals: make(map[string]*Proposal),
		logger:    cfg.Logger,
	}
}

5.2 辩论主循环

// Run 执行完整辩论流程
func (s *DebateSession) Run(ctx context.Context) (string, error) {
	s.logger.Printf("[Debate] 开始辩论: %s (参与者: %d)", truncate(s.Question, 50), len(s.Agents))

	// 阶段 1:各自提交初始答案
	if err := s.proposeRound(ctx); err != nil {
		return "", err
	}

	// 阶段 2:多轮批评-修改
	for s.round = 1; s.round <= s.Config.MaxRounds; s.round++ {
		s.logger.Printf("[Debate] === 第 %d 轮 ===", s.round)

		changed, err := s.critiqueReviseRound(ctx)
		if err != nil {
			return "", err
		}

		// 检查共识
		if s.checkConsensus() {
			s.converged = true
			s.logger.Printf("[Debate] 共识达成于第 %d 轮", s.round)
			return s.winnerAns, nil
		}

		// 检查稳定性(无 Agent 修改立场)
		if !changed && s.round >= 2 {
			s.logger.Printf("[Debate] 连续无变化,提前终止")
			break
		}
	}

	// 阶段 3:投票
	s.logger.Printf("[Debate] 进入投票阶段")
	return s.voteRound(ctx)
}

// proposeRound 初始提案轮
func (s *DebateSession) proposeRound(ctx context.Context) error {
	var wg sync.WaitGroup
	errCh := make(chan error, len(s.Agents))

	for _, agent := range s.Agents {
		wg.Add(1)
		go func(a DebateAgent) {
			defer wg.Done()
			ans, err := a.Propose(ctx, s.Question)
			if err != nil {
				errCh <- fmt.Errorf("agent %s propose: %w", a.ID(), err)
				return
			}
			s.mu.Lock()
			s.proposals[a.ID()] = &Proposal{
				AgentID: a.ID(),
				Answer:  ans,
				History: []string{ans},
			}
			s.mu.Unlock()
			s.logger.Printf("[Debate] %s 提交初始答案 (%d 字)", a.ID(), len(ans))
		}(agent)
	}
	wg.Wait()
	close(errCh)
	for err := range errCh {
		if err != nil {
			return err
		}
	}
	return nil
}

// critiqueReviseRound 一轮批评-修改
func (s *DebateSession) critiqueReviseRound(ctx context.Context) (bool, error) {
	// 构造公开视图(所有当前答案)
	publicView := s.snapshotProposals()

	var wg sync.WaitGroup
	changed := false
	var changedMu sync.Mutex
	errCh := make(chan error, len(s.Agents))

	for _, agent := range s.Agents {
		wg.Add(1)
		go func(a DebateAgent) {
			defer wg.Done()
			// 批评其他人的答案
			others := make(map[string]string)
			s.mu.Lock()
			for id, p := range s.proposals {
				if id != a.ID() {
					others[id] = p.Answer
				}
			}
			s.mu.Unlock()

			critique, err := a.Critique(ctx, s.Question, others)
			if err != nil {
				errCh <- err
				return
			}

			// 基于批评修改自己的答案
			s.mu.Lock()
			myProposal := s.proposals[a.ID()]
			s.mu.Unlock()
			if myProposal == nil {
				return
			}

			revised, err := a.Revise(ctx, s.Question, myProposal.Answer, critique)
			if err != nil {
				errCh <- err
				return
			}

			if revised != myProposal.Answer {
				s.mu.Lock()
				myProposal.Answer = revised
				myProposal.History = append(myProposal.History, revised)
				s.mu.Unlock()
				changedMu.Lock()
				changed = true
				changedMu.Unlock()
				s.logger.Printf("[Debate] %s 修改了答案", a.ID())
			}
		}(agent)
	}
	wg.Wait()
	close(errCh)
	for err := range errCh {
		if err != nil {
			return changed, err
		}
	}
	return changed, nil
}

// checkConsensus 检查是否达成共识
func (s *DebateSession) checkConsensus() bool {
	// 简化:统计答案相同(或前 50 字相同)的最大比例
	prefixCount := make(map[string]int)
	s.mu.Lock()
	for _, p := range s.proposals {
		prefix := truncate(p.Answer, 50)
		prefixCount[prefix]++
	}
	s.mu.Unlock()

	maxCount := 0
	var maxPrefix string
	for prefix, count := range prefixCount {
		if count > maxCount {
			maxCount = count
			maxPrefix = prefix
		}
	}
	ratio := float64(maxCount) / float64(len(s.Agents))
	if ratio >= s.Config.ConsensusRatio {
		// 找到胜出答案
		s.mu.Lock()
		for _, p := range s.proposals {
			if truncate(p.Answer, 50) == maxPrefix {
				s.winner = p.AgentID
				s.winnerAns = p.Answer
				break
			}
		}
		s.mu.Unlock()
		return true
	}
	return false
}

// voteRound 投票阶段
func (s *DebateSession) voteRound(ctx context.Context) (string, error) {
	proposals := s.snapshotProposals()

	var wg sync.WaitGroup
	votes := make([]VoteRecord, len(s.Agents))
	errCh := make(chan error, len(s.Agents))

	for i, agent := range s.Agents {
		wg.Add(1)
		go func(idx int, a DebateAgent) {
			defer wg.Done()
			v, err := a.Vote(ctx, s.Question, proposals)
			if err != nil {
				errCh <- err
				return
			}
			votes[idx] = v
		}(i, agent)
	}
	wg.Wait()
	close(errCh)
	for err := range errCh {
		if err != nil {
			return "", err
		}
	}

	// 多数投票
	mv := &MajorityVote{}
	winnerID, score := mv.Decide(votes)
	s.logger.Printf("[Debate] 投票结果: %s 胜出 (得分 %.1f)", winnerID, score)

	s.mu.Lock()
	defer s.mu.Unlock()
	if p, ok := s.proposals[winnerID]; ok {
		s.winner = winnerID
		s.winnerAns = p.Answer
		return p.Answer, nil
	}
	return "", fmt.Errorf("winner %s not found in proposals", winnerID)
}

// snapshotProposals 快照当前所有提案
func (s *DebateSession) snapshotProposals() map[string]string {
	s.mu.Lock()
	defer s.mu.Unlock()
	result := make(map[string]string, len(s.proposals))
	for id, p := range s.proposals {
		result[id] = p.Answer
	}
	return result
}

func truncate(s string, n int) string {
	if len(s) <= n {
		return s
	}
	return s[:n]
}

六、实战 Demo:技术选型辩论

下面模拟三个 Agent 对"Go 微服务该用 gRPC 还是 HTTP/JSON"展开辩论。

6.1 模拟辩论 Agent

// cmd/debate_demo/main.go
package main

import (
	"context"
	"fmt"
	"log"
	"math/rand"
	"os"

	"example.com/agentforge/internal/multiagent"
)

// MockDebateAgent 模拟辩论 Agent
type MockDebateAgent struct {
	id     string
	bias   string // 偏好,影响初始立场
}

func (a *MockDebateAgent) ID() string { return a.id }

func (a *MockDebateAgent) Propose(ctx context.Context, question string) (string, error) {
	// 根据 bias 给初始答案
	switch a.bias {
	case "grpc":
		return fmt.Sprintf("推荐 gRPC:%s。理由:性能高、强类型、流式支持", stance("grpc")), nil
	case "http":
		return fmt.Sprintf("推荐 HTTP/JSON:%s。理由:调试方便、生态广、门槛低", stance("http")), nil
	default:
		return "需要根据场景权衡:内部服务用 gRPC,对外 API 用 HTTP", nil
	}
}

func (a *MockDebateAgent) Critique(ctx context.Context, question string, others map[string]string) (string, error) {
	var points []string
	for id, ans := range others {
		points = append(points, fmt.Sprintf("对 %s 的答案 '%s' 的质疑:是否考虑了团队学习成本?", id, truncateStr(ans, 30)))
	}
	return fmt.Sprintf("批评: %v", points), nil
}

func (a *MockDebateAgent) Revise(ctx context.Context, question, myAnswer, critique string) (string, error) {
	// 30% 概率修改(模拟被说服)
	if rand.Float64() < 0.3 {
		return myAnswer + "(修订:补充考虑了批评意见,但仍维持核心立场)", nil
	}
	return myAnswer, nil // 不修改
}

func (a *MockDebateAgent) Vote(ctx context.Context, question string, proposals map[string]string) (multiagent.VoteRecord, error) {
	// 简化:投票给自己的 bias 倾向
	choice := a.id // 默认投自己
	for id := range proposals {
		if contains(proposals[id], a.bias) {
			choice = id
			break
		}
	}
	return multiagent.VoteRecord{
		VoterID:  a.id,
		ChoiceID: choice,
		Reason:   "最符合我的技术判断",
		Weight:   1.0,
	}, nil
}

func stance(s string) string    { return s }
func truncateStr(s string, n int) string {
	if len(s) > n {
		return s[:n]
	}
	return s
}
func contains(s, sub string) bool {
	return len(s) >= len(sub) && (s == sub || indexOf(s, sub) >= 0)
}
func indexOf(s, sub string) int {
	for i := 0; i <= len(s)-len(sub); i++ {
		if s[i:i+len(sub)] == sub {
			return i
		}
	}
	return -1
}

func main() {
	logger := log.New(os.Stdout, "[DebateDemo] ", log.LstdFlags)

	question := "Go 微服务之间通信用 gRPC 还是 HTTP/JSON?"
	agents := []multiagent.DebateAgent{
		&MockDebateAgent{id: "performance-advocate", bias: "grpc"},
		&MockDebateAgent{id: "simplicity-advocate", bias: "http"},
		&MockDebateAgent{id: "pragmatist", bias: "balanced"},
	}

	cfg := multiagent.DefaultDebateConfig()
	cfg.Logger = logger
	cfg.MaxRounds = 3

	session := multiagent.NewDebateSession(question, agents, cfg)
	winner, err := session.Run(context.Background())
	if err != nil {
		log.Fatalf("辩论失败: %v", err)
	}

	fmt.Printf("\n=== 辩论结果 ===\n问题: %s\n胜出答案: %s\n", question, winner)

	// 质量评估
	evaluator := multiagent.NewQualityEvaluator("qa-agent")
	eval := evaluator.Evaluate("winner", winner)
	fmt.Println("\n" + eval.FormatReport())
}

6.2 预期输出(精简)

[DebateDemo] 2026/08/03 14:30:00 [Debate] 开始辩论: Go 微服务之间通信用 gRPC 还是 HTTP/JSON? (参与者: 3)
[DebateDemo] 2026/08/03 14:30:00 [Debate] performance-advocate 提交初始答案 (52 字)
[DebateDemo] 2026/08/03 14:30:00 [Debate] simplicity-advocate 提交初始答案 (52 字)
[DebateDemo] 2026/08/03 14:30:00 [Debate] pragmatist 提交初始答案 (35 字)
[DebateDemo] 2026/08/03 14:30:00 [Debate] === 第 1 轮 ===
[DebateDemo] 2026/08/03 14:30:00 [Debate] performance-advocate 修改了答案
[DebateDemo] 2026/08/03 14:30:00 [Debate] === 第 2 轮 ===
[DebateDemo] 2026/08/03 14:30:00 [Debate] simplicity-advocate 修改了答案
[DebateDemo] 2026/08/03 14:30:00 [Debate] === 第 3 轮 ===
[DebateDemo] 2026/08/03 14:30:00 [Debate] 进入投票阶段
[DebateDemo] 2026/08/03 14:30:00 [Debate] 投票结果: pragmatist 胜出 (得分 2.0)

=== 辩论结果 ===
问题: Go 微服务之间通信用 gRPC 还是 HTTP/JSON?
胜出答案: 需要根据场景权衡:内部服务用 gRPC,对外 API 用 HTTP(修订:补充考虑了批评意见...)

答案 winner 评估报告:
总分: 0.80
维度明细:
  - correctness       0.85 (权重 35%)
  - completeness      0.70 (权重 25%)
  ...

注意:这个 demo 用 Mock Agent 模拟,真实场景下 Propose/Critique/Revise/Vote 应该调用 LLM。框架本身与 LLM 无关——任何实现 DebateAgent 接口的对象都能参与辩论。


七、辩论模式的工程权衡

7.1 什么时候用 Debate

场景是否适合 Debate理由
技术选型决策✅ 强烈推荐多视角对抗避免盲点
算法正确性验证✅ 推荐错误易在对抗中暴露
创意方案生成✅ 推荐不同视角激发新想法
简单事实查询❌ 不划算成本高,单 Agent 足够
实时对话响应❌ 不适合延迟过高(多轮 LLM 调用)
高确定性任务❌ 不需要答案唯一,无需协商

7.2 成本控制

辩论模式是 Token 消耗大户:N 个 Agent × M 轮 × (Propose + Critique + Revise) = N × M × 3 次 LLM 调用。3 个 Agent 辩论 3 轮就是 27 次调用。第 23 篇会讲多 Agent 场景的 Token 成本管理,核心策略:

  1. 限制参与者:3-5 个 Agent 足够,更多收益递减
  2. 早停机制:检测到收敛立即终止,不跑满轮数
  3. 异步并行:同轮内所有 Agent 的 Propose/Critique 并发执行

本篇小结

知识点核心内容
Debate 原理多 Agent 对抗暴露单 Agent 盲点
认知科学依据克服确认偏误、视角盲区、过度自信
收敛三条件共识达成、最大轮数、稳定性
多数投票得票最多胜出,适合可分类答案
加权评分按置信度/历史加权,适合能力差异
仲裁者第三方裁决,适合票数接近
LLM 合成综合多答案生成新答案
质量评估五维度正确性、完整性、一致性、可验证性、清晰度
辩论生命周期Propose → Critique → Revise → 循环 → Vote
并发执行同轮内所有 Agent 并发,跨轮串行
适用场景技术选型、算法验证、创意生成
不适用场景简单查询、实时对话、高确定性任务

下篇预告

第 23 篇:Group Chat 编排 — 群组协作的调度挑战

辩论是"全员发言"的极端形式,但很多场景需要更精细的发言权调度。下一篇实现 Group Chat Manager,覆盖 Round-robin、LLM-Selected、Priority 三种调度策略,解决多 Agent 群组协作的上下文共享与 Token 成本控制难题。


如果本篇内容对你有帮助,欢迎点赞收藏!有任何疑问,欢迎在评论区交流。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐