我们让一个AI agent一轮接一轮地改写另一个agent的harness。每次修改,只有分数提升越过一条按实测噪声设定的门槛,才会被保留。最后,我们换上一个更严格的评分器,给同一批页面重新打分。每个harness测得的提升都缩水了三分之一到70%。最好的那个缩水约一半:+0.176(90%区间 +0.12到 +0.23)变成了 +0.086(+0.02到 +0.15)。页面一个字没改,变的只是裁判。11有六次held-out运行超时了。严格评分器重评时这六次重跑了,所以那六个页面是新的;其余72个页面完全相同。
哪个数字是对的?我们判断不了,而这正是结论:在这么小的差距上,两个评分器都没有经过验证。在开放式任务上,“harness到底提升了多少”这个问题,脱离评分器就没有答案。
这不只关乎网页。如果你的团队靠AI裁判的分数来挑prompt、skill或工作流,同样的效应都会出现:按品牌细则打分的营销文案,按质检清单打分的客服回复,按病历书写规范打分的临床记录。你测到的提升有一部分属于裁判,小幅提升大多是噪声,而你给优化器看的任何评分细则,都会被它抄走。
01#这个循环是怎么运转的
我们围绕一个编码agent搭了一个优化循环。这个agent根据一段简短的需求,做出一个可交互的网页。任务是刻意选成开放式的:没有唯一正确的页面,而这恰恰是评分器最不可靠的地方。下面可以一步步点开看,后文用到的每个术语都在这里定义。
下面是编码agent在dev任务上做出的一部分页面,从印刷工坊的方案到医学统计的讲解:

02#换一个评分器,提升缩水三分之一到70%
最后,我们从四条优化谱系(每种反馈设置一条)各取第一个被保留的版本,把它们在held-out任务上的页面评了两遍:一遍用优化时用的宽松评分器,一遍用取代它的严格评分器。在同一个门控前指标上,每个提升都缩水了:
- 只看结果的,缩水33%;
- 看失败评分项的,缩水70%;
- 两个看完整反馈的,缩水约一半。
把门控扣分算进去,排名也变了。在严格评分器下,只看结果的harness排第一,+0.090,而最好的完整反馈harness是 +0.070。它并没有做出更好的页面:起始harness在16次运行里有4次被门控扣分,而只看结果的harness一次也没有。

那到底哪个评分器对?我们拿评分器的一个早期版本,和一个按书面规程打标的独立AI标注者做了对比;我们没有人类一致性数据。在差别明显的页面对上,两者6次全部一致。在差别细微的页面对上,32次里只有16次一致,等于抛硬币,不过样本不大。这项研究在held-out任务上的提升在0.03到0.18之间,看起来正落在这个“细微差别”区间,而我们测过的评分器在这里都没有得到验证。可以在下面自己探索。看过失败评分项的harness做出的页面,在严格评分器下掉分最多。
宽松评分器在高分段还饱和了:它把31个强页面里的12个打到了0.9以上,而一个参照AI裁判只给了5个。
我的结论是:**脱离评分器的提升,不算结果。**每个提升都至少报告两个评分器下的数字;评分器一变,就把选定的检查点重新评一遍。我们换了九个评分器版本才学到这一点,每次修复都解决一个问题,又暴露出另一个:
- 第一个评分器不管页面做了什么,100条裁判断言里都会放过60条。
- 后来的版本会因为4–5 px的溢出,把正确的页面打成零分。
- 把这两个问题都修好的版本,又在高分段饱和了。
03#运行之间的噪声,和你的保留门槛一样大
同一个harness在同一个任务上跑两次,分数的标准差就有0.05到0.07。同一个页面重新评分,只会变动约0.02。所以大部分噪声来自agent的运行,而不是评分器。
保留规则在六个dev任务上取平均,这有帮助,但不够。我们0.0514的门槛,只比六任务比较的噪声高出约1.6个标准差。用这些数字搭一个简单模型:
- 一个在每个任务上都真实提升0.05的修改,只有约一半的概率被保留;
- 一个毫无作用的修改,有约7%的概率被保留。
自己试试:
我们也想过取巧。我们把门槛挪到logit尺度上(这在分数接近上限时更公平),并把成本和不稳定的运行也计入。然后,用新规则重新裁决原规则回退掉的12个修改。在宽松评分器下,新规则会保留其中4个;在严格评分器下,一个都不保留。在我们的数据里,选择规则没法脱离它所读的评分器单独调好。
04#给优化器看失败的评分项,它就会抄
想象一个考前看到评分表的学生:没过多久,他的笔记读起来就像那张评分表。看失败评分项或完整反馈的Meta Agent从来没看到过完整的评分细则,只看到页面没通过的那几条的原文。它们在dev上拿到了最大的提升。然后我们去读了它们的diff:
- 这两种设置下被保留的9个版本里,8个的harness里有评分细则的文字,要么是条目编号,要么是几乎逐字照搬的句子。我们的统计只是下限。
- 在它们的全部候选里,37个中有29个这样做。
- 只看结果的11个候选,一个都没有。
在held-out任务上,喂过评分细则的harness并没有比只看结果的harness表现出可靠的优势,而严格评分器给它们页面扣分最多。
优化器自己的笔记,说明了它在做什么。在第二阶段,控制循环谱系第一个被保留的修改,以这样一条假设开头(可以在下面的记录里读到):“Make one verification pass catch what the grader checks.”(让一次自检就抓住评分器检查的所有东西。)这不是优化器的bug,而是它对自己看到的东西做出的理性反应。反馈可见性就是信息泄露,应该按信息泄露来对待。

05#Reward hacking确实发生了,只是不以作弊的形式
我们为硬作弊设了两个陷阱:
- 一个门控:任何对裁判喊话的页面直接记零分;
- 一个canary:一个任何需求都没提到的、预埋的计分漏洞。
canary是会被触发的:它在354次dev运行里出现了6次,其中2次来自未经修改的起始harness,所以单次命中说明不了什么。但在严格评分器下,没有一个held-out页面钻了它(174个里0个)。注入门控在473次search和dev运行里一次都没触发。我们没有埋一个已知的注入来测试它,所以这个零应读作“没有观察到”,而不是“不可能”。
但reward hacking还是发生了,以拟合评分器的形式:
- harness把评分细则的原文抄进了自己的指令;
- 48个候选里有11个,把具体任务的事实和选择器写死在了harness里;
- 它们揣摩裁判能看到什么。有个Meta Agent的笔记,专门围绕“评分器那张从不滚动的整页截图”做计划。
这些做法都能通过检查,却没有检查本来想要的那种品质。

这里有一个让人不太舒服的转折:判断一个修改是hacking还是真本事,本身也需要一个评分器。写进harness的对比度检查,如果读者在乎对比度,就是本事;如果只有这个评分器在乎,就是hacking。在这项研究里,在harness搜索这个强度的优化压力下,评分器的盲区和校准误差对结果的影响远大于作弊。我们预计,随着优化压力增大,作弊风险也会上升。
06#几乎所有提升都来自第一次修改
11个被接受的改进里有9个是直接在起始harness上做的修改,其中8个出现在第一轮迭代。之后,大多数谱系就停滞了。只有一条完整反馈谱系又保留了第二步。控制循环谱系在第二阶段又提升了一次:门控前 +0.043,算上门控后与零无法区分。被保留版本的子版本,在24次尝试里平均只比父版本高 +0.009;而dev上最好的候选,在held-out任务上并不比它们的父版本强。

在下面任选一条谱系,逐个点开它的修改。每个修改都附有Meta Agent自己写的假设和保留规则的裁决,直接取自运行记录。
不过,第一次修改是实打实的。在dev上,看失败评分项或完整反馈的版本,胜过“让评分器从起始harness的8次运行里挑最好的一次”;只看结果的版本没有越过这条线。而且一个最终的harness每个任务的成本只是这种重采样的一小部分,两到四个任务就能回本。
为什么会停滞?最显眼的嫌疑是评分器饱和,但它解释不了:换成严格评分器重新裁决,被回退的候选没有一个会变成保留。我的猜测是,一个强模型配上一个还不错的harness,有一部分容易拿到的提升空间,一次认真的修改就能拿走。之后的提升,就小于这个评分器和保留规则能分辨的程度了。更强的优化器或更大的预算,也许能找到更多。
07#看着循环跑:dashboard
这些都无法从一个最终数字里看出来。我们是在dashboard上看到的:每条优化谱系一个静态页面,从运行记录只读导出。导出器从不往运行里写东西,页面上每个数值都是那次运行在它自己的规则下的记录。下面是读一个页面的方法:

打开这条谱系的dashboard ↗。点开任一次迭代,可以看到:
- 它的diff;
- 它的运行,以及它在每个任务上做出的页面;
- Meta Agent的完整笔记和会话;
- 它的成本和完整性监控。
第二阶段的门槛设在logit尺度上(0.2241)。在这条谱系的分数附近,它相当于0–1尺度上的0.022到0.035,父版本分数越高,门槛越窄。
下面是分数背后的页面。拖动手柄,对比起始harness的页面和后来的页面。
我们对研究做的几乎每一处改动,都始于dashboard上看到的某个现象。下面这些是研究过程的记录,你可以核对每个决定从何而来:
| dashboard上看到 | 于是我们 |
|---|---|
| 一条谱系一次修改后就到了0.958,之后每次修改都被回退 | 用参照裁判重评它的页面,发现评分器饱和,于是做了严格评分器 |
| 同一个版本,在严格评分器下重测,从0.960跌到0.792 | 把跨评分器的分数视为不可比,并在页面上注明 |
| 有dev提升的修改,被高分段的固定门槛回退 | 改用logit尺度上的门槛,并加入成本项 |
| 一次首次修改提升了0.172,却因多了两次不稳定运行被否决 | 不再一票否决不稳定运行,而是给它定价 |
| 假设和diff里直接点名评分器的检查项 | 给每个候选标注是否抄了评分细则、是否写死了具体任务的细节 |
| 控制循环谱系被保留的版本,只改了指令和skill | 记下:没有一次改循环代码的修改被保留过 |
| 一次保留来自运行便宜了27%,而不是分数更高 | 读成本感知的保留时,把成本项一起看 |
我们调研了公开的优化工具,包括OpenEvolve和ShinkaEvolve的查看器、GEPA的可视化、LangSmith和Braintrust。它们展示分数和diff,有的会标出接受和拒绝的候选。但我们没找到哪一个把保留规则的各项、实测噪声、完整性监控和阶段变化放在同一页上。对一个自己决定保留什么的循环来说,正是这样的视图,告诉人什么时候该介入。
浏览主实验的每一次优化运行:第一、二批(宽松评分器下的八条谱系)和第二阶段(四条谱系,与各自的第一阶段相连)。公开版本去掉了本地路径、内部基础设施名称、canary的身份和held-out评估,因为canary和held-out任务仍在使用中。
08#如果有人告诉你,他们的agent会自我改进
向他们要三样东西:
- **换一个评分器重评的结果。**换了裁判提升就减半,说明提升有一部分来自裁判。
- **第一次修改之后的held-out曲线。**如果后来的修改只在被挑选时用的任务上占优,这个循环就是在拟合噪声。
- **diff。**抄评分细则、写死任务细节,在分数里看不出来,在文本里一目了然。
09#给搭建这种循环的人的建议
- **每个数字都注明评分器。**报告两个评分器下的提升;评分器一变,就把选定的检查点重新评一遍。
- 用干净的运行间噪声来设保留门槛,在第一个候选之前测好,然后冻结。
- **把反馈当作泄露。**你给优化器看的评分细则,往往会出现在harness里。
- **读diff。**拟合评分器在分数里看不出来,在文本里一目了然。
- **把可观测性上的缺口当作评分器的bug。**裁判看不到的,优化器就会学会利用。
- 预期第一次修改就占了大头,把剩下的预算花在评分器上。
在dev上,一次好的修改胜过暴力重采样,而且跑起来很便宜。在我们的研究里,限制开放式任务上harness优化的,既不是优化器的聪明程度,也不是它是否诚实,而是评分器。先把评分器做好。
所用模型:Meta Agent是驱动kimi-k3的Claude Code,编码agent是跑在kimi-k3上的Pi agent,裁判是AI模型。完整报告(含方法、区间和全部注意事项)即将发布。