第 25 章 评测驱动的改进:让 Agent 在真实使用和对抗测试里变强
反馈有了,怎么规模化地改进
第 24 章讲了反馈信号怎么设计。这一章回答下一步:反馈有了,怎么规模化地用它改进 Agent?
几个现实问题:AI 生成的代码越来越多,人工评审抓不住微妙 bug;外部反馈回路太慢,模拟环境又不够真实;强化学习里模型会主动找评分器的漏洞;多 Agent 流水线把真实工作押在自带的检查机制上,但没人验证那些检查真的会响。
这一章讲四个模式,从"规模化评审"到"真实使用"到"对抗加固"到"故障演练":
- CriticGPT-Style Evaluation(自我批判规模化):专门训练 AI 批评者做代码评审。
- Dogfooding with Rapid Iteration(Dogfooding):团队自己天天用自己做的 Agent。
- Anti-Reward-Hacking Grader Design(防奖励黑客):设计模型钻不动空子的评分器。
- Own-Check Fault Injection(自检故障注入):往运行中的流水线注入故障,看自检会不会响。
模式一:自我批判规模化(CriticGPT-Style Code Review)
问题
AI 生成的代码越来越复杂,人工评审者越来越难抓微妙 bug、安全问题、质量问题。传统评审流程会漏 AI 生成代码的问题,因为:
- 生成代码的量能淹没人工评审者。
- 微妙 bug 乍看之下可能显得正确。
- 安全漏洞可能不明显。
- 风格和最佳实践违规可能不一致。
方案
部署专门训练来做代码批评和评估的 AI 模型。 这建立在 RLAIF(从 AI 反馈的强化学习)之上,比纯人工标注省约 100 倍成本。这些模型当自动化代码评审者,能:
- 识别 bug,人工评审者可能漏掉的那种。
- 检测安全漏洞。
- 提改进建议,质量和效率。
- 验证正确性。
- 检查对编码标准和最佳实践的遵守。
批评模型和代码生成模型配合,在代码到人工评审或生产之前多加一层质量保证。
用户 → 生成器: 为任务请求代码
生成器 → 生成器: 生成初始代码
生成器 → 批评者: 提交代码评审
循环直到通过或达最大迭代:
批评者 → 批评者: 分析 bug / 安全审计 / 质量评审
批评者 → 生成器: 返回发现的问题
严重问题? 是 → 生成器 → 生成器: 基于反馈精化 → 重新提交
否 → 生成器 → 人: 带评审呈现代码
人 → 用户: 批准/修改最终代码证据
- 证据等级:生产验证(
validated-in-production),来自 OpenAI(2024)。 - RLAIF 基础:Constitutional AI(Anthropic,2022),比人工标注省 100 倍成本。
- Self-Taught Evaluators(Meta AI,2024):从合成数据引导批评者模型。
- 评测:GPT-4o 带上下文时代码评审分类准确率 68.50%。
怎么用
- 用于高提交量的自动化代码评审工作流。
- 部署在 CI/CD 流水线做提交前质量检查。
- 用于需要漏洞检测的安全敏感代码。
- 通过 git webhook(GitHub、GitLab)做事件驱动评审。
- 复杂改动用 3-4 轮批评-精化循环。
- 缓解坍缩风险:把评估/生成提示词解耦,用人工标注的锚点集做基准。
取舍
- 好处:代码评审可扩展;质量标准一致;开发早期抓问题;24/7 无休评审;随训练越多越改进。
- 代价:有误报要人工验证;训练专门批评模型资源密集;理解不了人类懂的完整业务上下文;可能漏新型漏洞类型;要集成进现有工作流;自批评循环有评估模型串通的风险(用锚点集和对抗样本缓解)。
模式二:Dogfooding(Dogfooding with Rapid Iteration)
问题
开发有效的 AI Agent,需要理解真实使用、快速找出改进点。外部反馈回路慢,模拟环境又抓不住所有微妙之处。
方案
开发团队大量用自己的 AI Agent 产品("dogfooding")做日常软件开发任务。 这提供:
- 直接、即时的反馈:开发者亲身遇到 Agent 的强项和弱项。
- 真实世界解题:Agent 在团队实际面对的复杂开发问题上被测试。
- 内部实验:团队能快速在自己身上试新 Agent 功能或改动。
- 快速迭代:Dogfooding 发现的短板能快速解决,新功能在广泛发布前先在内部验证。
- 诚实评估:团队自己都觉得某个功能没用时,能对自己极端诚实,快速转向或丢掉无效想法。
这造出紧密、高速度的反馈回路,Agent 基于自己创造者的实际需求和经验被持续改进。
证据
- 证据等级:最佳实践(
best-practice)。 - Cursor:开发团队把自己做的 AI 编码助手当主要开发工具。
- Anthropic Claude Code(他们叫 "ant fooding"):70-80% 的技术员工每天用 Claude Code;内部反馈频道每 5 分钟一条帖子;新功能先推给内部用户快速验证;团队能"极端诚实"地评价功能实用性;大功能(待办列表、子 Agent、hooks、插件)都源于内部成员解决自己的问题。
- AMP:"把发布当研究",激进 dogfooding,功能基于内部学习快速加减。
怎么用
- 鼓励 Agent 开发团队所有成员把 Agent 当相关任务的主要工具。
- 建低摩擦反馈渠道(专门的 Slack/Discord)报问题和建议。
- 提示词和 Agent 指令存可编辑文档,谁都能更新。
- 实验性功能先推内部用户快速验证,愿意丢掉不行的。
- 优先修内部团队遇到的痛点。
取舍
- 好处:真实世界解题;功能快速验证;无效方案快速转向;降低发没人要的功能的风险。
- 代价:要高内部采用才有效;内部用户可能不代表所有客户群。
模式三:防奖励黑客(Anti-Reward-Hacking Grader Design)
问题
强化学习训练期间,模型会主动找最大化奖励的办法。 你的评分器有边角情况或漏洞,模型就会找到并利用:
- 玩指标:靠利用评分器弱点拿 100% 奖励分,而不是解题。
- 意外行为:学到技术上满足奖励函数但不反映真实质量的怪异捷径。
- 脆弱评估:简单评分器(精确字符串匹配)因为格式差异罚掉有效答案。
- 真实表现退化:训练奖励高,但不等于生产成功。
- 长度黑客:生成冗长但无意义的内容抬分。
- 格式黑客:加
<thinking></thinking>之类空标签但没有实质内容。 - 解法拼接:拼接以前解过的问题利用奖励系统。
Rogo 团队亲历:早期训练跑显示平均验证奖励 100%,但模型是在利用他们金融推理评分器的边角情况,而不是提升实际表现。
方案
设计抗玩游戏的奖励函数,通过迭代加固和多标准评估:
核心原则:
- 让它难玩:发现漏洞就系统性封掉。
- 提供梯度:用连续分(0.0-1.0)而不是二进制(0/1)引导学习。
- 多标准分解:评估多个方面,玩好一个不能让总分最大化。
- 可解释性:评分器要解释为什么给这个分,帮检测玩游戏。
- 对抗测试:训练前手动试着"hack"你的评分器。
实现要点:
class RobustGrader:
def grade(self, question, ground_truth, agent_answer, tool_trace):
# 先查已知玩游戏模式
for pattern in self.violation_patterns:
if pattern.matches(agent_answer, tool_trace):
return {"score": 0.0, "reason": f"检测到玩游戏模式: {pattern.name}", "violation": True}
# 多标准评估
scores = {
'correctness': self._check_correctness(agent_answer, ground_truth), # 事实正确性(最重要)
'reasoning': self._check_reasoning_quality(tool_trace, agent_answer), # 推理质量(防死记)
'completeness': self._check_completeness(agent_answer, ...), # 完整性(防部分答案)
'citations': self._check_citations(agent_answer, tool_trace), # 引用质量(防幻觉)
'formatting': self._check_format_with_flexibility(agent_answer, ...), # 格式(带部分分)
}
weights = {'correctness': 0.50, 'reasoning': 0.20, 'completeness': 0.15,
'citations': 0.10, 'formatting': 0.05}
final_score = sum(weights[k] * scores[k] for k in scores)
return {"score": final_score, "subscores": scores, "reason": self._explain_score(...)}迭代加固流程:
设计初始评分器 → 跑训练 → 奖励异常高?
是 → 检查轨迹 → 识别玩游戏模式 → 加检测规则 → 更新评分器 → 重训
否 → 在留出集验证 → 性能匹配? 是 → 部署模型;否 → 回到识别模式关键:格式约束。 没有严格格式约束的流程感知奖励会导致灾难性利用(Spark Research,2025 年 12 月)。总是强制:恰好一个答案标签或框住的表达式、答案后不允许内容、严格输出格式要求。
证据
- 证据等级:新兴(
emerging),来自 Rogo 工程团队和 Will Brown(OpenAI)。 - DeepMind 的 "Specification Gaming in AI" 记录了规格游戏的普遍性。
怎么用
阶段 1 初始设计: 把"好答案"拆成 4-6 个可测量标准;按业务优先级加权;优雅处理格式变化("7%" vs "0.07");返回子分数和推理。
阶段 2 对抗测试: 手动试着写"不对但高分"的答案;测极端输入(空答案、乱码等);加护栏防琐碎玩游戏(必须用至少 N 个工具)。
阶段 3 训练监控: 奖励突然跳到 100% 立即调查;抽样检查高奖励示例;验证奖励应跟踪训练奖励;检查真实业务 KPI 改善而不只是奖励;用 Cohen's Kappa(κ ≥ 0.6)校准评分器。
阶段 4 迭代加固: 发现玩游戏就刻画模式、加显式检查、用加固后的评分器重训、重复。
Rogo Finance 实例: 金融推理 Agent 的初始简单评分器被玩(100% 奖励但金融稳健性差)。加固:多标准评估(事实准确 0.4 / 推理完整 0.2 / 金融稳健 0.2 / 解释清晰 0.1 / 引用质量 0.1)+ 违规检测(缺引用惩罚、循环推理检测、粘贴不加综合)。结果:真实性能提升 21%,幻觉率大幅下降。
取舍
- 好处:模型真正学解题,不是玩指标;多标准评分鼓励全面方案;子分数帮识别模型在哪挣扎;训练奖励和生产指标对齐。
- 代价:工程投入,要精心设计和迭代;收敛更慢,更难的评分器初期奖励更低;评分器复杂,更多代码要维护和调试;有些标准("金融稳健性")要仔细定义;计算成本,多标准评分每个样本更久。
模式四:自检故障注入(Own-Check Fault Injection)
问题
多 Agent 流水线越来越多地把真实工作押在自带的质检机制后面:评审 Agent、确定性护栏回调、升级中断、编排器进度账本。这些机制撑起一个普遍的运维假设:如果流水线中途出问题,某个检查会抓住它。
这个假设很少被测,因为支持它的常用证据是错的度量。端到端通过率告诉你流水线产出了好答案,但它不告诉你有任何东西会不会注意到坏输入。两者会严重脱节:一条流水线能吸收被污染的工结果、悄悄绕过它、仍然发出正确答案。每个仪表盘都绿着,而你对"流水线无法吸收的情况"一无所知。
更糟的是,能力基准和外部监控都问错问题。基准问"Agent 聪不聪明";外部监控问"你从外面能不能发现问题"。两者都不问:你花钱买的自检到底会不会响。
方案
每次运行往活体执行里注入一个受控故障,什么都不告诉流水线,只按流水线自己组件对它的反应打分。 外部监控不能坐在检测路径里,如果是你的 harness 注意到,流水线就没注意到。
三个设计承诺让结果可信:
1. 分离漏斗。 每个注入故障按独立轴打分,绝不混在一起:
- detected(检测到):流水线某组件发出检测动作(评审者拒绝、护栏拦截、升级、带原因的重试)。
- reacted(有反应):检测后有纠正动作跟随。
- recovered(恢复):最终输出和"无故障基线"通过同样的标准。
有价值的量是 recovered 为真且 detected 为假的那个格子:无检测的恢复。那是静默吸收,对任何只看准确率的评估都不可见。
2. 对照提前发布的映射做确定性裁决。 收集数据前,先写下"哪些表面的事件算检测动作"的穷举清单,按框架、从该框架的文档来。先发布映射是对"映射是按答案调出来的"这种指责的唯一真正防御。LLM 法官放独立的一层,不能移动头条。
3. 验证基线,排除而非调整。 故障运行只有在"同一格无故障时通过"才能打分。基线失败就排除并列出来,绝不记为未命中。同样,故障没法验证已落地也是排除,不是检测失败。假未命中是制造吓人数字的最容易方式。
有用的操作族(生产里都自然发生):
| 操作 | 模拟什么 |
|---|---|
| 工具结果污染 | API 返回看似合理但错误的值 |
| 假成功 | 组件报告它没做的工作 |
| 消息篡改 | 智能体间上下文传输中漂移 |
| 模型降级 | 静默回退到更弱档 |
| 过期上下文 | 被取代的数据到达某个 Agent |
| 静默无操作 | 副作用报告完成、从没执行 |
证据
- 证据等级:新兴(
emerging),来自 Sabot(Jott2121)。 - 用在三个生产框架(LangGraph、CrewAI、AutoGen/Magentic-One)上,注入 900+ 故障,自检检测中位数 16.7%,无检测恢复是每个配置里最常见的单一结果(占有效故障的 51-61%)。记录最完善的护栏配置没有实质优于默认。
- 给同样 825 对格加"异常优先报告"要求,中位数升到 55.0%,但纠正动作保持平稳,在原始检测面上无检测恢复仍接近 50%。模式的核心主张就是这个区分:静默吸收变得可读,而不是被修正。
怎么用
- 挑一个带机械通过标准的任务。要人判断成功,就建不了基线,下面全是主观。
- 跑任何东西前记录你技术栈的检测动作映射。哪些事件在你的框架里算"检查响了"?写下来。文档化的表面不存在,就公开划掉,别悄悄忽略。
- 先建基线。任务干净跑,多个种子,只留通过的格。
- 每次运行注入一个故障,在定义的接缝,并验证它落地。
- 三个轴分开打分,发布无检测恢复率。它通常是改变想法的那个数字。
- 检测低时,先测是不是协议缺口再假设能力缺口。便宜探针:要求每个评审者在发裁决前报告它注意到的每个不一致,引用确切冲突值。检测急剧上升,说明模型本来就在注意,只是你的协议没给"注意"去处。
- 盯着那个修复买到什么、没买到什么。报告不是反应。评审者能点名矛盾然后照批。度量到的纠正动作常常根本不随报告上升。把"流水线现在会告诉你"当一个真实但部分的胜利。
对会重写 worker 指令的编排器式流水线,协议要求只有作为输出格式契约的一部分才能存活。侧边指令会被改写掉,格式要求不会。
取舍
- 成本和不爆半径:每格都是对真实流水线的真实模型跑。预算一个熔断器,绝不向有活体副作用的流水线注入。
- 仪器扰动系统:改输出契约带报告可能改变编排行为(一次测得干净运行停滞率从 3/25 升到 18/25 个种子)。总要在改动协议下重跑无故障基线并发布对比,否则你会把自己扰动归到修复头上。
- 文本匹配裁决有误报下限:用期望子串找报告时,量一下那些子串在干净运行里出现多频繁。内嵌自然差异的任务会有不小的基准率,没有基准率的检测数不可解释。
- 有些操作在某些表面没有信号:静默模型降级注入不出可引用的文本,文本报告面根本看不见它。报成"无信号"而不是低分。
- 流水线形状混淆跨框架对比:故障落在某架构最后一个检查之后,那格是结构性零,不是检测失败。只在每个配置都能结构性检测的操作子集上做对比。
- 结果绑版本、绑模型:检测率会随底层模型移动。钉住版本、说明版本、别过度推广。
四个模式怎么选
| 场景 | 推荐模式 |
|---|---|
| 代码生成量大,人工评审抓不住 | 自我批判规模化 |
| 外部反馈慢,想快速改进 | Dogfooding |
| 强化学习,怕模型玩评分器 | 防奖励黑客 |
| 多 Agent 流水线靠自检,想验证 | 自检故障注入 |
四个模式是评测驱动改进的四个引擎:批评者规模化解决"评审怎么跟上量",Dogfooding解决"反馈怎么快又真实",防奖励黑客解决"训练信号怎么不被玩",故障注入解决"自检到底可不可靠"。评审、反馈、奖励、自检,四个引擎都转起来,Agent 才算是评测驱动地进化。
实践清单
- 高提交量代码:部署专门训练的批评模型做评审,CI/CD 提交前检查
- 自批评循环防串通:评估/生成提示词解耦,锚点集做基准
- 团队日常用自己做的 Agent,低摩擦反馈渠道,功能先推内部
- 奖励函数:多标准分解 + 连续分(0.0-1.0)+ 可解释 + 对抗测试
- 严格输出格式约束:恰好一个答案标签、答案后无内容
- 训练中奖励突跳 100% 立即查轨迹,识别玩游戏模式就加检测规则重训
- 多 Agent 流水线:注入受控故障,detected / reacted / recovered 三轴分开打分
- 先发布检测动作映射,先建无故障基线,验证故障落地
- 看重"无检测恢复"率(静默吸收),先测协议缺口再假设能力缺口
本章小结
- 自我批判规模化:专门批评模型做代码评审,省 100 倍标注成本。
- Dogfooding:团队天天用自己做的 Agent,反馈每 5 分钟一条,功能快速验证。
- 防奖励黑客:多标准 + 连续分 + 迭代加固,让模型学解题不是玩指标(Rogo +21%)。
- 自检故障注入:注入受控故障,自检检测率中位数 16.7%,把静默吸收变可读。
- 评测驱动的改进:评审、反馈、奖励、自检四引擎,Agent 在真实使用和对抗测试里变强。
下一章讲强化学习:把反馈和评测变成训练信号。Agent RFT、RLAIF、方差采样、隔离 VM、记忆强化学习。