第13章 多智能体辩论

第13章 多智能体辩论

本章目标

  • 理解多智能体辩论模式的设计思路
  • 学会使用 MsgHub 构建辩论场景
  • 掌握辩论流程的控制和管理
  • 了解辩论结果的汇总与决策方法

13.1 辩论模式概述

13.1.1 什么是多智能体辩论?

多智能体辩论是一种让多个具有不同立场或专业视角的智能体围绕同一话题进行讨论的协作模式。通过不同观点的碰撞,可以获得更全面、更深入的分析结果。

┌─────────────────────────────────────────────────────────────┐
│                    多智能体辩论模式                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                      ┌──────────┐                           │
│                      │   话题    │                           │
│                      └────┬─────┘                           │
│                           │                                 │
│                           ▼                                 │
│   ┌─────────────────────────────────────────────────────┐   │
│   │                   MsgHub                             │   │
│   │  ┌─────────┐   ┌─────────┐   ┌─────────┐           │   │
│   │  │  正方   │◀─▶│  反方   │◀─▶│  评委   │           │   │
│   │  │Proponent│   │Opponent │   │  Judge  │           │   │
│   │  └─────────┘   └─────────┘   └─────────┘           │   │
│   └─────────────────────────────────────────────────────┘   │
│                           │                                 │
│                           ▼                                 │
│                    ┌──────────┐                             │
│                    │ 辩论结论 │                              │
│                    └──────────┘                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

13.1.2 应用场景

场景描述
决策分析正反两方分析方案的利弊
风险评估乐观者 vs 谨慎者评估项目风险
方案评审多个专家从不同角度评审方案
创意头脑风暴多个角色产生和评价创意
事实核查支持者与质疑者验证信息

13.2 基础辩论实现

13.2.1 简单的正反辩论

import io.agentscope.core.ReActAgent;
import io.agentscope.core.formatter.dashscope.DashScopeMultiAgentFormatter;
import io.agentscope.core.memory.InMemoryMemory;
import io.agentscope.core.message.Msg;
import io.agentscope.core.message.MsgRole;
import io.agentscope.core.message.TextBlock;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.pipeline.MsgHub;
import io.agentscope.core.tool.Toolkit;

/**
 * 简单的正反辩论示例
 */
public class SimpleDebateExample {

    public static void main(String[] args) {
        String apiKey = System.getenv("DASHSCOPE_API_KEY");
        
        // ========================================
        // 创建辩论参与者
        // ========================================
        
        // 正方:支持者
        ReActAgent proponent = createDebater(apiKey, "Proponent", """
            你是辩论中的正方代表(Proponent)。
            
            你的任务是:
            1. 坚定支持辩题的正面观点
            2. 提供有力的论据和证据
            3. 反驳反方的观点
            4. 保持逻辑性和说服力
            
            辩论规则:
            - 每次发言控制在 3-4 句话
            - 针对反方观点进行回应
            - 使用具体例子支持论点
            - 保持尊重和专业
            """);
        
        // 反方:反对者
        ReActAgent opponent = createDebater(apiKey, "Opponent", """
            你是辩论中的反方代表(Opponent)。
            
            你的任务是:
            1. 坚定反对辩题的观点
            2. 指出正方论点的漏洞
            3. 提供反面论据
            4. 保持批判性思维
            
            辩论规则:
            - 每次发言控制在 3-4 句话
            - 针对正方观点进行反驳
            - 提出对立的观点和证据
            - 保持尊重和专业
            """);
        
        // 评委
        ReActAgent judge = createDebater(apiKey, "Judge", """
            你是辩论的评委(Judge)。
            
            你的任务是:
            1. 客观评价双方的论点
            2. 指出各自的亮点和不足
            3. 引导辩论深入进行
            4. 在适当时候做出评判
            
            评判标准:
            - 论点的逻辑性
            - 论据的充分性
            - 反驳的有效性
            - 表达的清晰度
            
            每轮发言控制在 2-3 句话,最后一轮给出详细评判。
            """);
        
        // ========================================
        // 设置辩题
        // ========================================
        String topic = "人工智能是否应该被允许参与重要的人类决策(如医疗诊断、法律判决)?";
        
        Msg announcement = Msg.builder()
            .name("System")
            .role(MsgRole.SYSTEM)
            .content(TextBlock.builder()
                .text(String.format("""
                    【辩论开始】
                    
                    辩题:%s
                    
                    正方(Proponent):支持 AI 参与重要决策
                    反方(Opponent):反对 AI 参与重要决策
                    评委(Judge):进行点评和评判
                    
                    辩论将进行 3 轮,每轮各方依次发言。
                    最后由评委给出最终评判。
                    
                    请正方首先陈述观点。
                    """, topic))
                .build())
            .build();
        
        // ========================================
        // 开始辩论
        // ========================================
        try (MsgHub hub = MsgHub.builder()
                .name("辩论场")
                .participants(proponent, opponent, judge)
                .announcement(announcement)
                .build()) {
            
            hub.enter().block();
            
            System.out.println("=".repeat(60));
            System.out.println("辩题: " + topic);
            System.out.println("=".repeat(60) + "\n");
            
            // 进行 3 轮辩论
            for (int round = 1; round <= 3; round++) {
                System.out.println("--- 第 " + round + " 轮 ---\n");
                
                // 正方发言
                System.out.print("[正方] ");
                Msg proMsg = proponent.call().block();
                System.out.println(proMsg.getTextContent() + "\n");
                
                // 反方回应
                System.out.print("[反方] ");
                Msg oppMsg = opponent.call().block();
                System.out.println(oppMsg.getTextContent() + "\n");
                
                // 评委点评
                System.out.print("[评委] ");
                Msg judgeMsg = judge.call().block();
                System.out.println(judgeMsg.getTextContent() + "\n");
            }
            
            // 最终评判
            Msg finalPrompt = Msg.builder()
                .name("System")
                .role(MsgRole.SYSTEM)
                .content(TextBlock.builder()
                    .text("请评委做出最终评判,判定哪方获胜并说明理由。")
                    .build())
                .build();
            
            hub.broadcast(finalPrompt).block();
            
            System.out.println("=".repeat(60));
            System.out.println("【最终评判】");
            System.out.println("=".repeat(60));
            
            Msg finalJudgment = judge.call().block();
            System.out.println(finalJudgment.getTextContent());
        }
    }
    
    private static ReActAgent createDebater(String apiKey, String name, String prompt) {
        return ReActAgent.builder()
            .name(name)
            .sysPrompt(prompt)
            .model(DashScopeChatModel.builder()
                .apiKey(apiKey)
                .modelName("qwen-plus")
                .stream(true)
                .enableThinking(false)
                .formatter(new DashScopeMultiAgentFormatter())
                .build())
            .memory(new InMemoryMemory())
            .toolkit(new Toolkit())
            .build();
    }
}

13.3 结构化辩论框架

13.3.1 辩论配置类

import java.util.List;

/**
 * 辩论配置
 */
public record DebateConfig(
    String topic,              // 辩题
    int rounds,                // 辩论轮数
    List<String> positions,    // 辩论立场
    boolean enableJudge,       // 是否启用评委
    int maxWordsPerTurn        // 每轮最大字数
) {
    public static DebateConfig defaults(String topic) {
        return new DebateConfig(
            topic,
            3,
            List.of("支持", "反对"),
            true,
            200
        );
    }
}

13.3.2 辩论结果类

/**
 * 辩论结果
 */
public record DebateResult(
    String topic,
    String winner,
    String summary,
    List<RoundSummary> rounds
) {}

public record RoundSummary(
    int roundNumber,
    List<DebaterStatement> statements
) {}

public record DebaterStatement(
    String debaterName,
    String position,
    String content
) {}

13.3.3 辩论管理器

import io.agentscope.core.ReActAgent;
import io.agentscope.core.pipeline.MsgHub;
import io.agentscope.core.message.Msg;
import io.agentscope.core.message.MsgRole;
import io.agentscope.core.message.TextBlock;
import java.util.ArrayList;
import java.util.List;

/**
 * 辩论管理器
 * 封装辩论流程的控制逻辑
 */
public class DebateManager {
    
    private final DebateConfig config;
    private final ReActAgent proponent;
    private final ReActAgent opponent;
    private final ReActAgent judge;
    
    public DebateManager(
            DebateConfig config,
            ReActAgent proponent,
            ReActAgent opponent,
            ReActAgent judge) {
        this.config = config;
        this.proponent = proponent;
        this.opponent = opponent;
        this.judge = judge;
    }
    
    /**
     * 执行辩论并返回结果
     */
    public DebateResult execute() {
        List<RoundSummary> roundSummaries = new ArrayList<>();
        
        // 创建开场公告
        Msg announcement = createAnnouncement();
        
        try (MsgHub hub = MsgHub.builder()
                .name("Debate-" + System.currentTimeMillis())
                .participants(proponent, opponent, judge)
                .announcement(announcement)
                .build()) {
            
            hub.enter().block();
            
            // 执行每一轮辩论
            for (int round = 1; round <= config.rounds(); round++) {
                RoundSummary summary = executeRound(hub, round);
                roundSummaries.add(summary);
            }
            
            // 获取最终评判
            String finalJudgment = getFinalJudgment(hub);
            String winner = extractWinner(finalJudgment);
            
            return new DebateResult(
                config.topic(),
                winner,
                finalJudgment,
                roundSummaries
            );
        }
    }
    
    private Msg createAnnouncement() {
        return Msg.builder()
            .name("System")
            .role(MsgRole.SYSTEM)
            .content(TextBlock.builder()
                .text(String.format("""
                    辩论开始!
                    
                    辩题:%s
                    轮数:%d 轮
                    
                    请正方首先陈述观点。
                    """, config.topic(), config.rounds()))
                .build())
            .build();
    }
    
    private RoundSummary executeRound(MsgHub hub, int roundNumber) {
        List<DebaterStatement> statements = new ArrayList<>();
        
        // 正方发言
        Msg proMsg = proponent.call().block();
        statements.add(new DebaterStatement(
            proponent.getName(),
            "支持",
            proMsg.getTextContent()
        ));
        
        // 反方发言
        Msg oppMsg = opponent.call().block();
        statements.add(new DebaterStatement(
            opponent.getName(),
            "反对",
            oppMsg.getTextContent()
        ));
        
        // 评委点评(如果启用)
        if (config.enableJudge()) {
            Msg judgeMsg = judge.call().block();
            statements.add(new DebaterStatement(
                judge.getName(),
                "评委",
                judgeMsg.getTextContent()
            ));
        }
        
        return new RoundSummary(roundNumber, statements);
    }
    
    private String getFinalJudgment(MsgHub hub) {
        Msg prompt = Msg.builder()
            .name("System")
            .role(MsgRole.SYSTEM)
            .content(TextBlock.builder()
                .text("请评委做出最终评判,明确宣布获胜方并详细说明理由。")
                .build())
            .build();
        
        hub.broadcast(prompt).block();
        Msg judgment = judge.call().block();
        return judgment.getTextContent();
    }
    
    private String extractWinner(String judgment) {
        // 简单的获胜方提取逻辑
        if (judgment.contains("正方获胜") || judgment.contains("正方胜")) {
            return "正方";
        } else if (judgment.contains("反方获胜") || judgment.contains("反方胜")) {
            return "反方";
        } else if (judgment.contains("平局") || judgment.contains("不分胜负")) {
            return "平局";
        }
        return "未确定";
    }
}

13.4 高级辩论模式

13.4.1 多方辩论

/**
 * 多方辩论:三个或更多立场
 */
public class MultiPartyDebate {
    
    public static void main(String[] args) {
        String apiKey = System.getenv("DASHSCOPE_API_KEY");
        String topic = "如何应对全球气候变化?";
        
        // 创建三个不同立场的辩手
        ReActAgent environmentalist = createDebater(apiKey, "Environmentalist",
            "你是环保主义者,主张激进的减排政策和绿色能源转型。");
        
        ReActAgent economist = createDebater(apiKey, "Economist",
            "你是经济学家,关注经济发展与环保的平衡。");
        
        ReActAgent technologist = createDebater(apiKey, "Technologist",
            "你是技术乐观主义者,相信技术创新能解决气候问题。");
        
        ReActAgent moderator = createDebater(apiKey, "Moderator",
            "你是主持人,引导讨论并总结各方观点。");
        
        try (MsgHub hub = MsgHub.builder()
                .participants(environmentalist, economist, technologist, moderator)
                .announcement(createMultiPartyAnnouncement(topic))
                .build()) {
            
            hub.enter().block();
            
            // 第一轮:各方陈述
            System.out.println("=== 第一轮:各方陈述 ===\n");
            environmentalist.call().block();
            economist.call().block();
            technologist.call().block();
            moderator.call().block();
            
            // 第二轮:交叉质询
            System.out.println("\n=== 第二轮:交叉质询 ===\n");
            hub.broadcast(Msg.builder()
                .name("System")
                .role(MsgRole.SYSTEM)
                .content(TextBlock.builder()
                    .text("请各方对其他观点提出质疑或补充。")
                    .build())
                .build()).block();
            
            environmentalist.call().block();
            economist.call().block();
            technologist.call().block();
            
            // 第三轮:总结
            hub.broadcast(Msg.builder()
                .name("System")
                .role(MsgRole.SYSTEM)
                .content(TextBlock.builder()
                    .text("请主持人总结各方观点,寻找共识。")
                    .build())
                .build()).block();
            
            moderator.call().block();
        }
    }
}

13.4.2 自由辩论模式

/**
 * 自由辩论:参与者可以随时发言
 */
public class FreeDebate {
    
    public static void freeDebate(
            List<ReActAgent> debaters,
            String topic,
            int maxTurns) {
        
        try (MsgHub hub = MsgHub.builder()
                .participants(debaters)
                .announcement(createFreeDebateAnnouncement(topic))
                .build()) {
            
            hub.enter().block();
            
            int currentTurn = 0;
            int currentDebaterIndex = 0;
            
            while (currentTurn < maxTurns) {
                ReActAgent currentDebater = debaters.get(currentDebaterIndex);
                
                System.out.printf("[%s]: ", currentDebater.getName());
                Msg response = currentDebater.call().block();
                System.out.println(response.getTextContent() + "\n");
                
                // 轮换发言者
                currentDebaterIndex = (currentDebaterIndex + 1) % debaters.size();
                currentTurn++;
            }
            
            // 发送结束信号
            hub.broadcast(Msg.builder()
                .name("System")
                .role(MsgRole.SYSTEM)
                .content(TextBlock.builder()
                    .text("辩论结束,请各位总结自己的核心观点。")
                    .build())
                .build()).block();
            
            for (ReActAgent debater : debaters) {
                debater.call().block();
            }
        }
    }
}

13.5 辩论结果处理

13.5.1 结构化评判

/**
 * 结构化评判结果
 */
public record JudgmentResult(
    String winner,
    int proponentScore,
    int opponentScore,
    List<String> proponentStrengths,
    List<String> proponentWeaknesses,
    List<String> opponentStrengths,
    List<String> opponentWeaknesses,
    String overallAssessment
) {}

/**
 * 获取结构化评判
 */
public JudgmentResult getStructuredJudgment(ReActAgent judge, MsgHub hub) {
    Msg prompt = Msg.builder()
        .name("System")
        .role(MsgRole.SYSTEM)
        .content(TextBlock.builder()
            .text("请以 JSON 格式输出你的评判结果。")
            .build())
        .build();
    
    hub.broadcast(prompt).block();
    
    Msg result = judge.call(null, JudgmentResult.class).block();
    return result.getStructuredData(JudgmentResult.class);
}

13.5.2 投票决策

/**
 * 多评委投票
 */
public class VotingPanel {
    
    public static String conductVote(
            List<ReActAgent> judges,
            Msg debateContext,
            String topic) {
        
        // 使用 FanoutPipeline 并行获取所有评委的投票
        FanoutPipeline votingPipeline = FanoutPipeline.builder()
            .addAgents(judges)
            .concurrent()
            .build();
        
        Msg voteRequest = Msg.builder()
            .role(MsgRole.USER)
            .content(TextBlock.builder()
                .text(String.format("""
                    基于以下辩论内容,请投票支持你认为胜出的一方。
                    
                    辩题:%s
                    
                    请只回答"正方"或"反方"。
                    """, topic))
                .build())
            .build();
        
        List<Msg> votes = votingPipeline.execute(voteRequest).block();
        
        // 统计票数
        int proVotes = 0;
        int conVotes = 0;
        
        for (Msg vote : votes) {
            String content = vote.getTextContent();
            if (content.contains("正方")) {
                proVotes++;
            } else if (content.contains("反方")) {
                conVotes++;
            }
        }
        
        // 返回结果
        if (proVotes > conVotes) {
            return String.format("正方获胜 (票数: %d:%d)", proVotes, conVotes);
        } else if (conVotes > proVotes) {
            return String.format("反方获胜 (票数: %d:%d)", proVotes, conVotes);
        } else {
            return String.format("平局 (票数: %d:%d)", proVotes, conVotes);
        }
    }
}

13.6 最佳实践

13.6.1 辩论设计建议

建议说明
明确的立场每个辩手应该有清晰、一致的立场
控制发言长度避免单方独白,保持对话节奏
引导性问题评委/主持人应该引导辩论深入
记录和总结保留辩论记录以便后续分析
多样化视角选择互补或对立的角色

13.6.2 提示词模板

// 通用辩手提示词模板
String debaterPromptTemplate = """
    你是辩论中的 %s,立场是 %s。
    
    你的任务:
    1. 坚持你的立场,提供有力论据
    2. 回应对方观点,指出其不足
    3. 用事实和逻辑支持你的论点
    
    辩论规则:
    - 每次发言 %d 字以内
    - 针对具体论点进行回应
    - 保持尊重和专业态度
    """;

// 评委提示词模板
String judgePromptTemplate = """
    你是辩论评委。
    
    你的任务:
    1. 客观评价双方表现
    2. 指出各自的亮点和不足
    3. 引导辩论向深处发展
    
    评判标准:
    - 论点的逻辑性和说服力
    - 论据的充分性和相关性
    - 反驳的有效性
    - 表达的清晰度
    """;

13.7 本章小结

本章介绍了多智能体辩论模式:

  1. 辩论架构:正方、反方、评委的角色设计
  2. MsgHub 应用:使用消息中心管理辩论对话
  3. 结构化辩论:配置类、结果类、管理器的封装
  4. 高级模式:多方辩论、自由辩论
  5. 结果处理:结构化评判、投票决策

多智能体辩论是一种强大的协作模式,能够从多角度分析问题,得到更全面的结论。


练习

  1. 实现一个关于"远程工作 vs 办公室工作"的辩论
  2. 创建一个多方辩论场景,包含 4 个不同视角的参与者
  3. 实现结构化评判输出,包含评分和详细点评
  4. 尝试使用 FanoutPipeline 实现多评委并行投票

上一章:第12章-MsgHub消息中心 | 下一章:第14章-Agent-as-Tool

← 返回目录