第22篇-辩论与共识-多Agent协商机制
【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 各自给出答案并相互挑战,通过对抗暴露彼此的漏洞。
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 辩论的生命周期
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 能力差异大 | 权重难定 |
| 仲裁者 | 引入第三方 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 评估维度
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 成本管理,核心策略:
- 限制参与者:3-5 个 Agent 足够,更多收益递减
- 早停机制:检测到收敛立即终止,不跑满轮数
- 异步并行:同轮内所有 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 成本控制难题。
如果本篇内容对你有帮助,欢迎点赞收藏!有任何疑问,欢迎在评论区交流。
更多推荐


所有评论(0)