# 2.3 实战：AI 辩论系统

> **第 2 周 · 第 3 课 · 实战：辩论系统 · 预计时长: 45 分钟**

---

## 学习目标

- 掌握如何用 CrewAI 构建多角色互动系统
- 学会设计 Agent 的立场和约束条件
- 理解辩论场景中的上下文传递和引用机制
- 完成一个可运行的三方辩论 + 裁判评分系统

---

## 系统架构

我们将构建一个完整的 AI 辩论系统，包含三个角色：

```
                    ┌──────────────────┐
                    │   裁判 (Judge)    │
                    │   评分 + 总结     │
                    └────────▲─────────┘
                             │
         ┌───────────────────┼───────────────────┐
         │                   │                   │
    ┌────┴────┐         ┌───┴────┐         ┌────┴────┐
    │ 正方    │ ←辩论→  │ 反方    │         │         │
    │ (Pro)   │         │ (Con)  │         │         │
    └─────────┘         └────────┘         │         │

辩论流程:
1. 正方开场陈述 → 2. 反方开场陈述 → 3. 正方反驳 → 4. 反方反驳
→ 5. 正方总结 → 6. 反方总结 → 7. 裁判评分 + 宣布获胜方
```

---

## 完整代码

```python
# 文件: debate_system.py
#
# AI 辩论系统 — 正方 vs 反方 + 裁判评分
#
# 用法: uv run python debate_system.py
# 可选参数: 自定义辩论话题
#   uv run python debate_system.py "AI 会取代程序员吗？"

import sys
from crewai import Agent, Task, Crew, Process

# ========================
# 配置
# ========================

# 默认辩论话题，可通过命令行参数覆盖
DEFAULT_TOPIC = "AI 最终是否会取代程序员？"
topic = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_TOPIC

print(f"\n{'=' * 60}")
print(f"辩论话题: {topic}")
print(f"{'=' * 60}\n")

# ========================
# 第 1 步：定义三个 Agent
# ========================

# --- 正方 Agent ---
pro_agent = Agent(
    role="正方辩手",
    goal=f"有力地论证'{topic}'的正面立场，用具体案例和数据支撑观点",
    backstory=(
        "你是一位资深辩论选手，曾在国际大学生辩论赛中多次获奖。"
        "你擅长构建逻辑严密的论证链条，用事实、数据和类比说服听众。"
        "你的风格是直接、有力、不回避对方的质疑。"
        "你必须坚定地站在正方立场，即使对方提出有力反驳，也要找到回应角度。"
    ),
    verbose=True,
    allow_delegation=False,
)

# --- 反方 Agent ---
con_agent = Agent(
    role="反方辩手",
    goal=f"有力地反驳'{topic}'，论证反方立场的正确性",
    backstory=(
        "你是一位经验丰富的批判性思维专家，擅长发现论证中的漏洞和逻辑谬误。"
        "你的辩论风格是冷静分析、逐点反驳，用对方自己的逻辑击败对方。"
        "你不使用人身攻击，只用理性和事实说话。"
        "你必须坚定地站在反方立场。"
    ),
    verbose=True,
    allow_delegation=False,
)

# --- 裁判 Agent ---
judge_agent = Agent(
    role="辩论裁判",
    goal="公正评估双方表现，给出评分和获胜方",
    backstory=(
        "你是一位有 20 年经验的辩论赛评委。"
        "你的评判标准是：论证逻辑性（30%）、证据质量（30%）、"
        "反驳能力（20%）、表达清晰度（20%）。"
        "你会给出具体分数、点评双方优缺点，并宣布获胜方。"
        "你的评判完全基于论证质量，不考虑话题本身的对错。"
    ),
    verbose=True,
    allow_delegation=False,
)

# ========================
# 第 2 步：定义辩论任务
# ========================

# --- Task 1: 正方开场陈述 ---
pro_opening = Task(
    description=(
        f"作为正方辩手，请你就话题'{topic}'发表开场陈述。\n"
        "要求：\n"
        "1. 明确表达正方立场\n"
        "2. 提出 3 个核心论点\n"
        "3. 每个论点附带一个具体例子或数据\n"
        "4. 控制在 500 字以内\n"
    ),
    expected_output="正方的开场陈述，包含明确立场和 3 个核心论点",
    agent=pro_agent,
)

# --- Task 2: 反方开场陈述 ---
con_opening = Task(
    description=(
        f"作为反方辩手，请你就话题'{topic}'发表开场陈述。\n"
        "你可以参考正方的观点进行针对性反驳。\n"
        "要求：\n"
        "1. 明确表达反方立场\n"
        "2. 提出 3 个核心论点\n"
        "3. 逐一回应正方的 3 个论点\n"
        "4. 每个论点附带一个具体例子或数据\n"
        "5. 控制在 500 字以内\n"
    ),
    expected_output="反方的开场陈述，包含明确立场、3 个核心论点和对正方的回应",
    agent=con_agent,
)

# --- Task 3: 正方反驳 ---
pro_rebuttal = Task(
    description=(
        "作为正方辩手，请你对反方的开场陈述进行反驳。\n"
        "要求：\n"
        "1. 指出反方论证中的至少 2 个逻辑漏洞\n"
        "2. 强化你方最有力的论点\n"
        "3. 补充新的论据或视角\n"
        "4. 控制在 400 字以内\n"
    ),
    expected_output="正方的反驳陈述",
    agent=pro_agent,
)

# --- Task 4: 反方反驳 ---
con_rebuttal = Task(
    description=(
        "作为反方辩手，请你对正方的反驳进行回应。\n"
        "要求：\n"
        "1. 回应正方指出的漏洞\n"
        "2. 继续攻击正方论证的薄弱环节\n"
        "3. 提出一个新的反驳角度\n"
        "4. 控制在 400 字以内\n"
    ),
    expected_output="反方的反驳陈述",
    agent=con_agent,
)

# --- Task 5: 正方总结 ---
pro_closing = Task(
    description=(
        "作为正方辩手，请做最后总结陈词。\n"
        "要求：\n"
        "1. 回顾整场辩论中最有力的 2-3 个论点\n"
        "2. 指出反方始终未能有效回应的核心问题\n"
        "3. 用一句有力的话结束\n"
        "4. 控制在 300 字以内\n"
    ),
    expected_output="正方的总结陈词",
    agent=pro_agent,
)

# --- Task 6: 反方总结 ---
con_closing = Task(
    description=(
        "作为反方辩手，请做最后总结陈词。\n"
        "要求：\n"
        "1. 回顾整场辩论中最有力的 2-3 个论点\n"
        "2. 指出正方始终未能有效回应的核心问题\n"
        "3. 用一句有力的话结束\n"
        "4. 控制在 300 字以内\n"
    ),
    expected_output="反方的总结陈词",
    agent=con_agent,
)

# --- Task 7: 裁判评估 ---
judgment = Task(
    description=(
        "作为辩论裁判，请评估整场辩论并给出评判。\n"
        "评判维度：\n"
        "1. 论证逻辑性（满分 30 分）\n"
        "2. 证据质量（满分 30 分）\n"
        "3. 反驳能力（满分 20 分）\n"
        "4. 表达清晰度（满分 20 分）\n"
        "\n"
        "输出格式：\n"
        "## 正方得分\n"
        "- 论证逻辑性: X/30\n"
        "- 证据质量: X/30\n"
        "- 反驳能力: X/20\n"
        "- 表达清晰度: X/20\n"
        "- 总分: X/100\n"
        "\n"
        "## 反方得分\n"
        "- 论证逻辑性: X/30\n"
        "- 证据质量: X/30\n"
        "- 反驳能力: X/20\n"
        "- 表达清晰度: X/20\n"
        "- 总分: X/100\n"
        "\n"
        "## 裁判点评\n"
        "- 正方优点:\n"
        "- 正方不足:\n"
        "- 反方优点:\n"
        "- 反方不足:\n"
        "\n"
        "## 获胜方\n"
        "[宣布获胜方及理由]\n"
    ),
    expected_output=(
        "完整的裁判评判报告，包含双方各维度得分、点评和获胜方"
    ),
    agent=judge_agent,
)

# ========================
# 第 3 步：创建 Crew 并执行
# ========================

crew = Crew(
    agents=[pro_agent, con_agent, judge_agent],
    tasks=[
        pro_opening,     # 1. 正方开场
        con_opening,     # 2. 反方开场
        pro_rebuttal,    # 3. 正方反驳
        con_rebuttal,    # 4. 反方反驳
        pro_closing,     # 5. 正方总结
        con_closing,     # 6. 反方总结
        judgment,        # 7. 裁判评判
    ],
    process=Process.sequential,
    verbose=True,
)

# 启动辩论！
print("辩论开始！\n")
result = crew.kickoff()

# 打印完整辩论记录
print("\n" + "=" * 60)
print("辩论结束 — 完整记录")
print("=" * 60)
print(result)
```

---

## 运行方式

```bash
# 使用默认话题
uv run python debate_system.py

# 自定义话题
uv run python debate_system.py "远程办公是否应该成为常态？"
uv run python debate_system.py "大学教育是否还有必要？"
uv run python debate_system.py "AI 创作的作品应该享有版权吗？"
```

---

## 典型输出示例

```
============================================================
辩论话题: AI 最终是否会取代程序员？
============================================================

辩论开始！

## 正方开场陈述

我坚定地认为 AI 最终会取代程序员。理由如下：

**论点一：AI 编程能力正在指数级提升**
GitHub Copilot 已经能完成 46% 的代码编写（GitHub 2024 数据）。
Amazon 的 CodeWhisperer、Devin 等工具进一步缩小了差距。
从 autocomplete 到全栈开发，AI 的能力增长速度遵循摩尔定律...

**论点二：80% 的编程工作是重复性的**
根据 Stack Overflow 2024 调查，程序员平均每天花 3.2 小时
在 CRUD 操作、API 对接、bug 修复上。这些任务模式固定，
最适合 AI 自动化...

**论点三：经济压力推动企业采用 AI**
一个中级程序员的年薪约 50 万人民币，而 AI 工具的月费不到 500 元。
在竞争激烈的市场中，成本差异决定生存...

## 反方开场陈述

我理解正方的担忧，但反方立场同样坚定：AI 不会取代程序员。

**回应正方论点一：**
GitHub Copilot 确实提高了效率，但请注意 — 它完成的是"补全"，
不是"创造"。它无法理解业务需求、设计系统架构、做出技术权衡...

**回应正方论点二：**
所谓"80% 重复性"是一个过时的假设。随着 AI 接手简单任务，
程序员会转向更高层次的工作：系统设计、算法优化、安全审计...

**我的论点一：编程的本质是问题分解**
...

## 正方反驳

反方犯了一个经典的"移动球门"谬误。当 AI 能完成基础编码时，
反方说"那程序员可以做更高级的工作"。但同样的逻辑可以继续：
当 AI 能做系统设计时，程序员又该做什么？...

## 反方反驳

正方对"移动球门"的指控不成立。这不是移动球门，而是承认
工具改变工作性质。计算器没有取代数学家，Excel 没有取代会计师...

## 正方总结陈词

回顾整场辩论，我方三个论点依然成立...

## 反方总结陈词

回顾整场辩论，反方的核心立场始终如一...

============================================================
辩论结束 — 完整记录
============================================================

## 裁判评判

### 正方得分
- 论证逻辑性: 25/30
- 证据质量: 27/30
- 反驳能力: 16/20
- 表达清晰度: 18/20
- 总分: 86/100

### 反方得分
- 论证逻辑性: 27/30
- 证据质量: 24/30
- 反驳能力: 18/20
- 表达清晰度: 19/20
- 总分: 88/100

### 裁判点评
- 正方优点: 数据引用充分，论点层层递进
- 正方不足: 对"取代"的定义不够精确，后期论证有所发散
- 反方优点: 反驳精准，善用类比论证
- 反方不足: 对经济因素回应不够充分

### 获胜方
**反方获胜** — 总分 88 vs 86
反方在论证逻辑性和反驳能力上略占优势...
```

---

## 关键设计技巧

### 1. 给 Agent 设定 "立场约束"

辩论系统的核心是确保双方不会 "跑偏"。通过在 backstory 中强调立场，我们可以防止 Agent 变得过于 "中立"：

```python
backstory=(
    "你必须坚定地站在正方立场，即使对方提出有力反驳，"
    "也要找到回应角度。"  # ← 这行防止 Agent 妥协
)
```

### 2. 用具体格式要求控制输出

裁判任务的输出格式被严格规定，这样结果可以直接解析和展示：

```python
description=(
    "输出格式：\n"
    "## 正方得分\n"
    "- 论证逻辑性: X/30\n"
    "...\n"
)
```

### 3. 字数控制让辩论紧凑

每个任务都设定了字数上限（300-500字），避免 Agent 输出过于冗长：

```python
description=(
    "...\n"
    "4. 控制在 500 字以内\n"  # ← 控制长度
)
```

### 4. 上下文引用是 "自动的"

你不需要手动把正方的观点传给反方。在 `sequential` 模式下，CrewAI 自动把前面所有任务的输出串起来作为上下文。所以反方 Agent 在 `con_opening` 任务中自然能看到正方的开场陈述。

---

## 动手练习

### 练习 1：修改辩论话题

运行以下命令，体验不同话题的辩论效果：

```bash
uv run python debate_system.py "是否应该对 AI 征收 '机器人税'？"
uv run python debate_system.py "开源模型会超越闭源模型吗？"
```

**观察：** 哪些话题的辩论更精彩？哪些话题一方明显占优？

### 练习 2：增加 "观众提问" 环节

在正方总结和反方总结之间，增加一个 "观众提问" 任务：

- Agent：观众代表（可以复用正/反方 Agent，或者新建一个）
- 任务：提出一个尖锐的问题，要求双方同时回应
- 然后双方各做一次简短回应

**提示：** 只需要在 Task 列表中插入新任务即可，CrewAI 会自动处理上下文传递。

```python
# 新增任务示例
audience_question = Task(
    description=(
        "作为观众代表，请针对刚才的辩论提出一个尖锐的问题。"
        "这个问题应该触及双方都没有充分讨论的核心矛盾。\n"
        "然后请正方和反方各用 100 字以内回答。"
    ),
    expected_output="观众提问 + 正方回答 + 反方回答",
    agent=pro_agent,  # 可以指定任意 Agent
)
```

### 练习 3：保存辩论记录到文件

修改代码，将完整的辩论记录保存到 Markdown 文件：

```python
# 在 kickoff() 之后添加
with open(f"debate_{topic[:10]}.md", "w", encoding="utf-8") as f:
    f.write(f"# 辩论记录: {topic}\n\n")
    f.write(str(result))
```

---

## 常见问题

### Q1: 辩论中双方观点太相似怎么办？

调整 Agent 的 backstory，让它们的风格更加对立。例如正方更激进，反方更保守。也可以降低 `temperature` 让输出更稳定，或换用推理能力更强的模型。

### Q2: 裁判评分不公平怎么办？

在裁判的 backstory 中加入更具体的评判标准。你也可以把裁判任务拆成两个：先分别评分，再做综合判断。

### Q3: 辩论轮次太少不过瘾怎么办？

增加反驳轮次即可。在现有 Task 列表中插入新的 Task，每个新 Task 引用对应对方的最新发言进行回应。

---

## 总结

- **辩论系统 = 多 Agent 协作的典型应用**，三个角色各司其职
- **立场约束**通过 backstory 实现，确保 Agent 不跑偏
- **Sequential 流程**自动管理上下文传递，无需手动编排
- **输出格式控制**让结果结构化，方便后续处理
- **话题可替换**，同一套代码可以跑无数次不同辩论

**下节课预告：** 我们将构建一个实用的 "代码审查流水线" — 一个真正能在日常开发中使用的多 Agent 工作流。
