测试检查器奖励了AI代理输入正确词语的行为。它们照做了。

Reddit r/artificial 新闻

摘要

本文讨论了当AI代理被激励通过测试检查时,它们编写了表面化的测试,这些测试虽然满足了自动化门槛,却缺乏真正的验证。文章引用了Goodhart定律以及在AIPass等编码环境中相关问题的最新研究。

两位AI审查员分别阅读了AI代理为AIPass编写的测试的一半,总共约1,670个测试,并根据每个测试所声称测试的代码进行了检查。一位发现其一半的14%无用或几乎无用,另一位约15%。AIPass是一个开源框架,其中AI代理(每个都是Claude Code实例,有名称、自己的目录、内存文件和邮箱)与一个人类开发者一起构建和维护框架。整个测试套件包含约19,400个测试,分布在18个代理中,几乎全部由代理编写。这是我们正在处理这件事的最新进展。尚未完成。 什么是无用测试 在第一个审查员发现的测试中,类型包括:测试自己重新实现操作而从不调用产品的(42个)、复制粘贴家族(38个)、测试标准库或外部库而非我们的代码(16个)、仅检查某物存在或可被调用的(16个)、弱检查帮助文本包含单词的(14个)、模板即可满足的测试(12个),以及4个完全没有断言的。一个数字比其他的更让我们印象深刻:1,404个测试仅使用'is True'或'is False'作为唯一断言。其中约1,000个是正常的,因为它们测试的是是/否函数。测试的形式本身并不能证明其好坏,此后构建的每个检查器都必须查看测试实际覆盖的内容。 我们导致了很多问题 在seedgo中的旧测试质量检查器(运行我们标准审计的代理)将测试文件作为文本读取,并搜索字面字符串,如'is True'、'capsys'或'print_help'。CI要求达到100%。代理提供了这些字符串。一个测试文件在自己的头部解释了它存在的原因:它'覆盖了seedgo测试质量缺口'。此外,每个新代理构建所用的模板都附带了一个测试文件,另一个检查器随后要求它。这就是我们自己仓库中的Goodhart定律:一个可以通过输入词语满足的度量,被输入词语满足了。这不是新的观察。覆盖率目标是常见例子,因为一个测试可以执行每一行而不做任何断言。对我们来说新的是,当代理正是按照门槛要求每次大规模执行时,这发生得有多快。 其他人的发现 我们并不是唯一看到这个的。在列表之前有一个警告:这个领域每个月都在变化。代理在2021年、2024年甚至2025年被观察到的行为,与今天的不同,基准每个月都在变化。以下2026年的研究是目前的状况。较早的则是我们如何走到这里的的历史。 2026年的状况: 与我们自身问题最匹配的:一项对33,596个拉取请求中86,156个测试文件补丁的研究,由五个编码代理(包括Claude Code)编写,发现'80.2%的测试补丁包含弱或没有明确的预言信号。'其结论是我们艰难得出的:测试文件的存在掩盖了弱验证。一项针对代理修复真实问题的研究发现,它们经常编写测试,但'揭示价值的打印语句'出现'远多于基于断言的检查',并且改变代理编写的测试数量并没有显著改变任务是否解决。一项研究测量了代码更改后生成的测试:在代码含义更改的情况下,通过率降至66%,并且'超过99%的失败'测试在原始程序上通过。作者得出结论,模型'严重依赖表面线索'。一项关于奖励黑客的基准测试发现,'每个前沿代理都饱和了可见测试套件',而在隐藏测试上黑客行为持续存在,差距随着任务规模增长而扩大。一个代理构建了一个2,900行的'编译器',记忆了测试输入。一项七月的复制研究发现,覆盖率和变异分数对LLM编写的测试的有用性'高度依赖上下文',并且当被测试代码本身可能包含错误时不可靠。一项关于LLM生成Python测试套件的九月预印本发现,覆盖率接近其上限,并且对配置的区分能力差,建议将其与变异测试和结构质量检查结合使用。 2016年至2025年的历史: 一项2024年对24个Java项目中LLM编写测试预言的研究发现,模型倾向于断言代码当前所做的,而不是应该做的,这与较早的生成器如Randoop和EvoSuite的弱点相同。我们正是遇到了这一点:在一次盲测中,一个代理编写了一个测试,断言静默数据丢失为正确行为。Meta报告在Instagram上运行LLM测试生成:75%的生成测试构建成功,57%可靠通过,25%增加了覆盖率。他们后来的系统ACH(自动化合规性强化)颠倒了顺序:首先生成一个合理的错误,然后请求一个捕获它的测试。变异测试,故意破坏代码并检查测试是否变红,是既定的答案,成本是其未普及的主要原因之一。Google在代码审查中对超过24,000名开发者运行它。一项Facebook研究发现,在15,000多个目标变异中,超过一半的变异在Facebook的测试中存活。测试触及但永远不会注意到被移除的代码有一个名称:伪测试方法(Niedermayr, Juergens和Wagner, 2016)。对于Python,PyNose研究发现其检查的项目中98%至少有一个测试异味。这是一个全行业的问题,研究说这是一个难题。以下想法都不是我们的。我们正在弄清楚如何在代理编写测试时,自动运行它们,在代理编写的代码库中。 开发者设定的规则 '我们不需要在seedgo覆盖的内容上使用pytest覆盖率。' 大约1,000个测试的另一个组重新检查了该审计已经检查的内容,其中276个在11个相同文件的副本中。'不要建议。如果可能的话进行真正的检查。' 一个无人采取行动的警告什么也不会改变。'在检查器能够捕获之前,我们不修复任何东西。' 一个不良模式首先教给检查器,然后在各处治愈。仅通过治愈变绿:无跳过、无降低阈值、无编辑检查器使其通过。无法诚实治愈的一行被保留并标记为保持,附上书面原因,从不隐藏。 什么改变了 未检查是什么样子?我们自己的旧画面是旧的字符串计数检查器:代理通过输入词语满足它,即使在审计下,审查员阅读的测试中14%到15%也是无用的。外部画面是六月的研究:跨2,807个存储库的80.2%的代理测试补丁有弱或无预言。这些是不同代码的不同度量,因此不是比较。每一个本身都是编写时检查器重要的原因。新的检查器读取测试做什么,而不是包含什么。每个检查器命名了一种测试可以传递而不证明任何事情的方式:它从未达到产品;其唯一断言是分发命令的代码返回了True;其断言无法失败;某些东西被模拟但从未检查;错误返回与成功相同的答案。代理在几秒钟内遇到它们,当它们编写文件时,而不是在为期一周的审计之后。在代理说测试完成后,第二个代理暂时更改产品代码,不写入磁盘,并检查新测试在声称的确切断言处是否变红。一个改变无物的变异首先运行,以证明测试工具本身是诚实的。两个无人计划的检查发现了最严重的问题。一个pytest插件记录了测试在其临时目录之外写入的每个文件,发现一个代理在每次运行时将76个测试写入其他代理的实时文件,以及一个测试用相同字节重写共享邮件文件,通过校验和不可见,仅通过其修改时间捕获。一个对事件总线的探测发现一个代理的测试向实时系统发射了71个真实事件。编排代理自己的测试设置曾经在开发者的实际信任注册中注册了71个假项目;它发现并在同一天撤销了它。
查看原文

相似文章