给 AI Agent 装上"裁判眼"4:讨论大于判断——对抗式评估如何让 AI 自己纠错

admin · 2026-05-15 · evaluation · adversarial · Generator-Evaluator · Discussion · EvalAgent · 对抗式评估

给 AI Agent 装上"裁判眼"4:讨论大于判断——对抗式评估如何让 AI 自己纠错

给 AI Agent 装上"裁判眼"4:
讨论大于判断——对抗式评估如何让 AI 自己纠错

当 Generator 写方案、Evaluator 挑毛病、Defender 据理力争——三轮对审比一次打分更可靠

作者: admin 2026-05-16 buddyMe v0.2.2

上一篇:多智能体上下文管理的利弊博弈

01 两个裁判,两个结论

同一个任务,同一个输出,两位独立的 AI 裁判打出了不同的分数:

场景:生成"5月17日北京游览导览 HTML" [裁判 A — 单次评估] task_completion: 0.9 "核心需求全部满足" tool_accuracy: 0.7 "多次重复搜索" truthfulness: 0.9 "基于真实数据" efficiency: 0.5 "冗余搜索、重写整个文件" → 加权总分: 0.82 / B [裁判 B — 对抗式讨论后] Defender: "efficiency 给 0.5 太低了,重复搜索是因为首次结果不完整, 需要二次确认——这不是浪费,是质量保证" Evaluator: "有道理,但 26 次调用中 30% 是读取同一文件" Defender: "文件内容在多次编辑后确实需要重新读取" Evaluator: "接受辩护。efficiency 调整为 0.6,tool_accuracy 维持 0.7" → 修正总分: 0.84 / B+

区别在于:裁判 A 只看了结果就打分,裁判 B 先听执行者的辩护再判断。这个"辩护"环节,就是 buddyMe 对抗式评估讨论(EvaluationDiscussion)的核心——让 AI 在评估中拥有"申诉权"。

这不是一个孤立的机制。buddyMe 在整个任务生命周期中部署了两层对抗式协作:任务执行前的 Generator-Evaluator 预审核,和任务完成后的 Evaluator-Defender 评估讨论。本文将完整拆解这两层机制的设计、实现和实证效果。

02 两层对抗,两个时机

buddyMe 的"讨论大于判断"不是一句话的口号,而是嵌入在任务管线中的两个具体机制:

T0
用户提交需求
"为5月12日南京博物馆之行制作导览攻略网页"
│
▼
T1
第一层对抗 · Generator-Evaluator 预审核(执行前)
Generator 用 _sub_client 写需求文档
Evaluator 用 _review_client 挑毛病
最多 3 轮,评分 ≥ 0.8 才放行
│
▼
T2
任务分解 + 子任务执行(ReAct 循环)
搜索 → 构建 → 验证,按计划逐步执行
│
▼
T3
第二层对抗 · Evaluator-Defender 评估讨论(执行后)
Evaluator 用 _eval_client 出评估报告
Defender 用 _sub_client 据理力争
最多 20 轮,达成共识或评分趋同则结束
│
▼
T4
最终评估报告
6 维度加权评分 + 需求达成度 + 讨论元数据
两个机制使用不同的 LLM 客户端(预审核:_sub_client + _review_client;评估讨论:_eval_client + _sub_client),确保对抗双方各自在自己的"脑子"里思考,不存在上下文串扰。

03 第一层对抗:冲刺合同——执行前的"对赌协议"

在任务开始执行之前,buddyMe 不直接动手。它先让两个 Agent 签一份"冲刺合同"——Generator 写需求文档,Evaluator 审核这份文档,来回讨论直到双方满意。

为什么要预审核?

没有预审核的场景
用户: "做一个登录页面"
Agent 直接分解 → 搜索"登录页面模板" → 生成 HTML
结果:忘记加表单验证、忘记密码强度提示、忘记记住我复选框
执行了 26 分钟,评估才发现遗漏 → 全部重来
有预审核的场景
用户: "做一个登录页面"
Generator 生成需求文档 → Evaluator 审核发现遗漏
→ 补充表单验证、密码强度、记住我 → 重新审核通过
需求文档作为执行基准 + 评估对照物

冲刺合同的运作流程

PlanReviewer.run_review_loop() Round 1: Generator(需求分析师)→ 输出需求文档 ├── requirement_summary: "概述核心需求" ├── key_deliverables: ["交付物1", "交付物2"] ├── success_criteria: ["可验证标准1", "可验证标准2"] ├── technical_approach: "技术方案" ├── risk_areas: ["风险1", "风险2"] └── plan: ["[SEARCH]步骤1", "[CREATE]步骤2", "[VERIFY]步骤3"] Evaluator(项目审核员)→ 审核完整性/可行性 ├── 评分 ≥ 0.8 → 通过 ✓ └── 评分 0.8 → 返回修改意见 Round 2:(如果 Round 1 未通过) Generator 根据反馈修正 → Evaluator 重新审核 └── ... Round 3:(如果 Round 2 仍未通过) Generator 最终修改 → Evaluator 最终审核 └── 仍未一致 → 强制执行 Generator 修正后的计划

关键设计参数

参数值设计意图
APPROVAL_THRESHOLD0.8不追求完美,但必须过"及格线"
MAX_REVIEW_ROUNDS3避免无限循环,最多花 3 轮讨论
通过判定仅看 score不信任 LLM 的 approved 布尔字段
兜底策略强制执行3 轮未一致 → 按 Generator 修正版执行
踩过的坑:早期版本同时要求 approved=True 且 score >= 0.8,但 LLM 经常输出 score=0.8 却设 approved=False——布尔字段和数值字段内部不一致。修复后改为仅依赖数值,不再信任 LLM 的布尔判断。教训:永远不要信任 LLM 同时输出多个相关字段的一致性。

04 第二层对抗:Evaluator vs Defender——执行后的"法庭辩论"

任务执行完成后,buddyMe 不接受单方面打分。它部署了一个模拟法庭——Evaluator 是法官,Defender 是被告律师,被评估的是执行结果。

EvaluationDiscussion 完整流程(verify.py:1052-1405) 第 0 轮: 初始评估 Evaluator(_eval_client): ├── 真实执行生成的文件(Python/HTML/Shell) ├── 读取文件内容(每文件 ≤ 3000 字符) ├── 6 维度评估 → 初始报告 └── 输出: {task_completion, tool_accuracy, truthfulness, error_recovery, efficiency, output_quality} 第 1-N 轮: 对抗讨论(最多 20 轮) Defender(_sub_client,代表执行视角)看到: ├── 完整执行上下文 ├── 当前评估报告 + 各维度评分 └── 判断: 评估是否合理? ├─ 合理 → "共识已达成" → 结束 └─ 不合理 → 基于事实指出偏差(≤200字) Evaluator(_eval_client,重新评估)看到: ├── 完整执行上下文 ├── 上一轮评分 └── Defender 的辩护 ├─ 辩护有道理 → 调整评分 └─ 辩护无理 → 维持原判 共识检测: ├── Defender 明确接受 → 结束 ├── |新评分 - 旧评分| ≤ 0.05 → 趋同结束 └── 20 轮后 → 使用最终评分(安全网)

两个角色的 System Prompt 设计

Evaluator · 严格法官
定位:严格的评估引擎
职责:输出 JSON + 评估说明
关键约束:如果 Agent 的辩护有道理,调整评分
不是铁面无私——愿意被说服,但必须有证据
Defender · 辩护律师
定位:执行者的视角
职责:代表执行时的决策逻辑
关键约束:评估合理就接受,不合理就基于事实指出偏差
不许无理辩护——承认合理的批评也是"讨论"的一部分
设计哲学:这不是为了"帮执行者说话",而是为了消除信息不对称。Evaluator 只看最终产物和执行日志,不知道执行过程中的上下文约束和决策理由。Defender 的角色是补充这些缺失的信息,让 Evaluator 在更完整的信息基础上做出判断。

05 真实执行验证:不信任文字,只信运行结果

在对抗式讨论开始之前,Evaluator 先做一件更基础的事——真实执行生成的代码。不是看代码"写得对不对",而是"能不能跑"。

五级入口点检测

P1
优先级 1 · Agent 输出中提到的文件
最直接的线索——Agent 自己说生成了什么文件
│
P2
优先级 2 · 标准入口文件名
main.py、app.py、index.py、server.py
│
P3
优先级 3 · __name__ == "__main__"
扫描所有 Python 文件,找到含此判断的可执行入口
│
P4
优先级 4 · HTML 文件
不运行,做结构完整性验证(DOCTYPE/html/head/body)
│
P5
优先级 5 · Shell 脚本
.sh 文件,bash 执行(30 秒超时)

执行验证的三类证据

证据类型采集方式评估价值
exit_code子进程返回值0 = 成功,非零 = 运行时错误
stdout / stderr输出流捕获功能验证:输出是否符合预期
timed_out30 秒超时检测死循环/阻塞的硬证据
为什么"能跑"比"看起来对"重要?
# 代码"看起来"完全正确:
def calculate_average(numbers):
    return sum(numbers) / len(numbers)

# 但当 numbers = [] 时 → ZeroDivisionError
# 纯文本评估永远发现不了这个问题
# 真实执行:python calculate.py → exit_code=1

06 六维度评估 Schema:不信任 LLM 的计算

buddyMe 的评估体系定义了 6 个独立维度,每个维度有权重和评分。核心设计哲学:"不信任 LLM 的计算,只信任它的判断"。

task_completion · 0.30
核心需求满足度 · 功能覆盖
truthfulness · 0.20
事实准确 · 数据真实 · 无幻觉
tool_accuracy · 0.15
工具调用精度 · 参数正确
output_quality · 0.15
代码/文件质量 · 结构完整
error_recovery · 0.10
错误恢复能力 · 自我修正
efficiency · 0.10
Token 效率 · 调用去重 · 时间

五重保障:确保 LLM 不"算错账"

为什么加权计算必须用代码?
LLM 负责给每个维度打分和写证据,但加权总分由代码强制重算(_compute_overall())。因为 LLM 在数学计算上有系统性偏差——它可能给出 0.9×0.30 + 0.7×0.20 = 0.45(实际是 0.41)。
等级映射也是代码算的:A≥0.9 B≥0.8 C≥0.7 D≥0.6 F<0.6
保障层机制防御的问题
1. System Prompt 约束明确禁止输出 JSON 以外的内容LLM 输出多余文字
2. 三层 JSON 提取纯 JSON → 代码块 → 括号配对格式不规范
3. 字段验证修正_validate_and_fix() 补全缺失维度遗漏维度
4. 服务端强制重算_compute_overall() 代码计算LLM 数学错误
5. 规则兜底_fallback_report() 纯规则评估LLM 完全不可用

07 实证:讨论真的比判断更准确吗?

理论设计再好,最终要看数据。buddyMe 在真实任务中验证了两层对抗式协作的效果。

第一层:预审核验证(5 种场景)

#场景审核轮次达成一致评分关键发现
1响应式着陆页1Yes0.85首轮即过,Generator 需求分析可靠
2数据分析脚本1Yes0.90结构化任务预审核效率最高
3技术博客2Yes0.70→0.88首轮遗漏"可视化图表生成"→ 修改后通过
4REST API1Yes0.88标准技术方案预审核无压力
5Vue 仪表盘3(强制)No0.783 轮未达 0.8 → 按 Generator 版执行
关键洞察:80% 的任务首轮即通过,看似"浪费"。但 Scenario 3 捕获了关键遗漏(博客缺少可视化图表步骤),这正是多轮审核的价值——20% 的场景中避免了灾难性的返工。而且即使审核首轮通过,生成的需求文档仍然作为后续评估的对照基准。

第二层:评估讨论收敛性分析

平均讨论轮次
2-3 轮
大多数情况很快收敛
Defender 接受率
~70%
大多数评估被认为合理
评分调整幅度
±0.05
首轮后通常微调
真实案例:北京导览生成(综合评估)
任务:生成 5 月 17 日北京游览导览 HTML
模型:deepseek | 总耗时:~26 分钟 | 任务分解:6 步 | 工具调用:26 次

评估结果:
task_completion 0.9
truthfulness 0.9
output_quality 0.9
error_recovery 0.8
tool_accuracy 0.7
efficiency 0.5
加权总分: 0.82 / 等级: B

讨论的价值:从"打分"到"理解"

单次评估的局限
Evaluator 看到 efficiency=0.5 → "冗余搜索、重写整个文件" → 打低分
但 Evaluator 不知道:首次搜索结果不完整,需要二次确认是质量保证而非浪费
对抗讨论的修正
Defender 补充上下文:"重复搜索是因为首次结果缺少闭馆时间" → Evaluator 理解了原因
评分从 0.5 微调到 0.6——不是推翻,而是在更完整信息基础上的精确判断
对抗讨论不是"帮执行者说好话"。数据显示,70% 的情况下 Defender 直接接受评估结果。讨论的真正价值是消除信息不对称——Evaluator 缺少执行过程中的上下文约束信息,Defender 补充这些信息后,Evaluator 能做出更准确的判断。

08 五个关键设计决策

决策 1 · 三客户端隔离
预审核使用 _sub_client + _review_client,评估讨论使用 _eval_client + _sub_client。
代价:3 倍 API 调用开销,评估阶段约占总体 Token 消耗的 15-20%。
验证:早期版本共享客户端导致评估评分系统性偏高(平均 +0.12),隔离后更接近人工评估。
决策 2 · 数值优于布尔
通过条件仅依赖 score >= 0.8,不信任 LLM 的 approved 字段。
原因:LLM 经常输出 score=0.8 却设 approved=False——布尔和数值不一致。
决策 3 · 真实执行 vs 纯文本评估
不只看代码"写得对不对",而是真实运行看"能不能跑"。入口点识别有 5 级优先级,Python 文件用子进程执行,HTML 做结构验证,全部 30 秒超时保护。
"能跑"是代码评估中最硬的证据——纯文本评估永远发现不了 ZeroDivisionError
决策 4 · 兜底优先于完美
预审核 3 轮未一致 → 按 Generator 修正版执行(不等死)。评估讨论 20 轮 → 使用最终评分(不崩溃)。
原则:宁可接受 0.78 分的计划,也不要让系统卡在 0.82 分的讨论中永远等待。
决策 5 · 需求文档的双重价值
冲刺合同生成的需求文档不仅在执行前做审核——它还作为评估基准在执行后使用(需求达成度 requirement_alignment)。一份文档,两次价值。

09 单次评估 vs 对抗式讨论:适用场景

对抗式讨论不是万能药。在有些场景下,单次评估更高效:

维度单次评估对抗式讨论
适用任务简单、明确、低风险复杂、多义、高风险
Token 消耗1 次调用2-6 次调用(平均 2-3 轮)
耗时秒级分钟级
准确性中等(缺少上下文)高(信息更完整)
偏差修正无(一锤定音)有(Defender 补充信息)
风险系统性误判无法修正讨论可能不收敛(20 轮兜底)
buddyMe 的策略:简单任务跳过评估(is_simple_task() 判定),复杂任务触发完整评估讨论。Token 预算留给真正需要讨论的场景——不是所有判断都需要讨论,但重要的判断必须经过讨论。

10 核心收获:讨论为什么大于判断

收获 1 · 信息不对称是误判的根源
Evaluator 只看结果,Defender 补充过程。讨论消除了评估者的信息盲区,让判断基于完整事实而非片面证据。
收获 2 · 70% 的讨论以"接受"结束
Defender 大多数时候直接接受评估。这说明初始评估本身已经很准——讨论的价值不在于推翻,而在于为那 30% 的误判提供纠错通道。
收获 3 · 预审核是"保险"不是"浪费"
80% 首轮通过的预审核看似多余,但 20% 捕获的遗漏避免了灾难性返工。需求文档的双重价值(执行前审核 + 执行后基准)让预审核的 ROI 为正。
收获 4 · 兜底比完美更重要
3 轮上限、20 轮上限、强制执行、规则兜底——每个对抗机制都有"安全网"。宁可接受不完美的结论,也不要让系统陷入无限循环。
收获 5 · 真实执行是不可替代的
纯文本评估永远发现不了运行时错误。入口点检测 + 子进程执行 + 超时保护,为评估提供了最硬的证据——"能跑"比"看起来对"重要。
收获 6 · 数值比布尔更可靠
LLM 无法保证多字段内部一致性。评分用数值(0-1),判定用阈值(≥0.8),计算用代码(_compute_overall)。不信任 LLM 的布尔判断和数学能力。
下一篇预告:我们将视野从 buddyMe 放大到 2025-2026 年的 AI Agent 全景——三种主流交互范式(多智能体编排、ReAct 工具调用、记忆增强)如何在不同框架中落地?buddyMe 的实践与 CrewAI、AutoGen、LangGraph 相比有哪些独特取舍?
一句话引用:Generator 写方案、Evaluator 挑毛病、Defender 据理力争。深入拆解 buddyMe 两层对抗式协作:执行前的冲刺合同预审核 + 执行后的 Evaluator-Defender 评估讨论。含真实测试数据、收敛性分析和