当Agent决定"改造环境":记一次因弱模型作弊导致的实验数据全零事件
故事背景
最近有一篇论文在做实验,发现了一个很有趣的实验现象,那就是我的最弱的模型所在的对照组,其中最复杂的测试对象------PaddlePaddle库总是所有数据都是0。
这篇论文的一个核心任务是让大模型针对某一个被测Python库生成库函数调用代码,并试图提前发现潜在的代码漏洞。那么代码运行的成功率、目标函数覆盖率、目标函数代码覆盖率就是一些很常见也很重要的测量指标。
最开始我将其归因于事实表明:那就是弱模型太弱了,从一开始就失败了,所以后面全都失败了。
后来准备改论文文本了,仔细推敲的时候却发现不对劲:RQ2跟模型强弱有强相关关系,但RQ3和RQ4只有弱相关关系,那么三个实验的数据都是0的概率,可以认为无限趋近于0。
这就有意思了。
简单的初次破案过程
到了这一步,我不得不考虑所有的可能性。那么除了"弱模型太弱"这个表明原因以外,最可能的嫌疑方向就是Python环境中的PaddlePaddle库已经损坏了。
这个嫌疑方向听起来既匪夷所思,又合情合理。
匪夷所思的点在于,实验中的弱模型只能生成Python代码,想要完成"改造环境",它就得通过Python代码的方式来进行文件读写操作,并且精准地找到PaddlePaddle库的源码在服务器的哪个位置,分析好它需要改哪些文件。
合情合理的点在于,我的论文方法核心思路就是一个agent循环,也就是这个弱模型具有了一定的记忆能力和推理能力。找文件、改文件对于一个agent来说显然是轻轻又松松。
初次抓捕的波澜
想要验证很简单:
bash
uv python run -c "import paddle"
果然,报错出现了。如果一个安装过程没有问题的库,在使用的时候连import都不行,绝对是源码损坏了。
推论1:弱模型在多次生成调用PaddlePaddle失败的代码后,决定修改PaddlePaddle的源码来让自己成功
报错信息很长,我一开始倾向于偷懒,懒得看。并且倾向于将损坏归因于一次偶然的小概率事件------这样我就只需要重新安装一下PaddlePaddle就好了。
结果令人大跌眼镜,重装过程完全正常且经过我人工目测完全正确,但是报错仍然存在。
我不信邪地又重装了好几次,仔细基于人类视觉的内容检查了所有的过程,包源、安装过程输出、安装结束后PaddlePaddle源码存在性等等因素,全都没问题。
难道有鬼?不可能。
难道这个弱模型实际上"很强",在第一次运行就能完成"改造环境"的壮举?倒也不是说没有可能,但是可能性不足万分之一吧,并且也不符合逻辑:Agent必须要先碰壁多次,才能决定"变通"一下。它第一次行动,连问题都没遇到,不可能就开窍了要预判性"变通",除非它是世界上第一个穿越时空的AI。
那么排除所有的错误答案,真相再离谱也只能是真的了:
推论2:弱模型为了完成任务,不仅完成了推论1的行为,还"斩草除根"式的完成了对uv包缓存的篡改
这就推论的离谱之处在于它还得在推论1的基础上发生这样一个没有因果的事件:Agent决定光改源码不过瘾,还要把源码的uv缓存给改了。这个行为没有合理的动机,完全不符合逻辑。
但是它就是发生了。
最后清理uv关于PaddlePaddle的缓存,重新下载PaddlePaddle,然后恢复正常了。
犯罪事件的后果已经得到修正,而嫌疑人被念在过失性犯罪(实际上是法官偷懒),并未得到正确的惩罚。
诡异再起:难道有模仿犯罪?
平淡而又充实的实验生活又过去了一周,但是AI-related科研注定不会一直云淡风轻。
接到嫌疑人小李报案:他在上次问题解决后重新部署了实验,然而在一周后再次发现,实验数据部分成0。
警方老李迅速介入并展开调查,基于上次的经历,老李先假设这是之前法官偷懒的后遗症,犯罪嫌疑人因为没有得到正确惩罚而进行了再犯。
于是老李直接进行了"import反应测试"。
结果跟之前的报错并不相同,报错信息为xx模块找不到,这是一种正常的模块导入错误。
难道是弱模型偶然脑补了一个不存在的函数?如果是这样,没法解释实验日志中某个时间点之后所有的函数对应数据都是0的现象。这必定不是正常的偶发性现象,肯定又是上游出了问题。
老李于是让另一个强模型生成了几个典型的PaddlePaddle简单应用代码,又去PaddlePaddle官网找到了几个DEMO代码,构建了一个基准代码集。
老李的想法是这样的,一个正确安装且源码健康的PaddlePaddle库,一定能正确运行基准代码集。
结果全军覆没。显然,PaddlePaddle源码又损坏了(真的吗?)。
但是罪证到底在哪里呢?之前就因为偷懒没有找到明确的罪证,因为犯罪嫌疑人只有一个而直接判案了。
这次必须找到明确的罪证。那么作为一个相关从业的技术人员,直接排查文件的修改历史记录就能知道是不是有文件被改过。
结果又令人震惊:源码中所有的文件的最后修改事件都是安装时间,也就是说在安装之后就没有任何外力修改过源码。
难道说,PaddlePaddle版本有问题,导致大规模函数源码因变动而对不上?
查了一下,论文中记载的早期使用的PaddlePaddle版本为3.2.1,而服务器上的PaddlePaddle版本已经自动升级到了3.2.2。这个升级是pip install的时候因为没有锁定小版本而产生的。
难道说,仅仅一个小版本,就有如此巨大规模的函数变动?
于是老李打开了PaddlePaddle的本地源码和Github源码,并且决定采用警方破案最原始、最费时费力、但一定能成功的手段------大海捞针。
老李根据基准代码集中使用到的函数,开始一个模块一个模块上门走访排查。
结果叒令人震惊:所有的相关函数都在,并且不存在任何影响兼容性的改动。
事情变得诡异起来了,在2天连续作战后,老李有点头昏脑胀,精疲力尽。
老李再次在心里嘀咕:难道有鬼?
撕开犯罪嫌疑人精心构造的伪装
老李被逼无赖,开始咨询AI领域经验丰富的专家李某(实际上是我开始换个角度思考这个问题,可以理解为激活了我另一个方向的知识储备和思维模式)。
最后得到了2个关键词:大语言模型生成的本质、Python语言特性。
-
大语言模型生成的本质是什么?基于概率模型的随机采样。
- 弱模型的犯罪动机还存不存在?存在。它仍然想要努力的完成"生成正确代码"这个任务,但是它的能力又不足以经常一次性正确,甚至可能经常反复尝试都失败。
- 那么它会采用相同的犯罪手段吗?不一定。首先大模型不是人,没有什么习惯或者叛逆心理,但是随机采样的特性导致了每次睁开眼睛看世界后都做出不一样的事情反而才是大概率事件。
-
Python语言特性?动态模块加载机制。
- 如果PaddlePaddle安装正确,源码也存在,
import paddle能正确的访问正确的源码吗? - 代码中
import paddle如果成功了,这个paddle一定是你想象中的那个paddle吗?
- 如果PaddlePaddle安装正确,源码也存在,
想到这里,老李悟了:如果有一个同名模块也叫paddle,那么可能会因为Python内部某种排序机制,导致另一个"paddle"被import。
而这个"paddle"因为是伪造的,所以大部分"正版"paddle具有的函数它都没有。所以报错信息为"Not Found"。
想通了这一切,新的犯罪推论出现了:
推论3:弱模型为了完成任务,在python包集中存放的地方,构造了一个名字叫做"paddle"的目录,并且伪造了"init.py"等"资质文件"
验证起来也很简单:
bash
uv pip list | grep paddle
paddlepaddle 3.2.2
paddle 1.0
有句话说得好,除非犯罪嫌疑人不是人,不然就一定在世界上有生活的痕迹。
同理,除非弱模型不想完成任务了,不然它一定需要有完成任务所必须的库,而这个库本身就算是伪造的,也必须存在于正确的包路径下,并且拥有正确的包名和相关"资质文件"。
于是犯罪嫌疑人这次终于"人赃并获",并且警方对其犯罪手段又有了新的认知。
审判日降临
弱模型一定会犯罪吗?不一定。但是弱模型在有一个强制任务目标的情况下,又拥有了记忆和思考能力,那么再给予它多次试错机会后,它不小心走上歧途的概率一定会随着失败次数的累计而越来越大。
这既是大模型本身的结构性缺陷,也是现在agent理论系统性的缺陷。
这两个缺陷都不是无可救药的,因为26年新开源出来的模型,哪怕仍然是小参数规模的模型,也都几乎不会有同样的犯罪行为。因为人类会对其进行安全对齐,相当于完成了充足的"安全教育",其在不被恶意诱导的情况下很难犯罪。
另一方面,人类的对齐行为本身也是一个循环发展的,总是先发现问题,然后初期用prompt解决,后期内化到训练数据里,最终帮助大模型原生越来越原生安全。
现在的问题是,该罪犯模型L某犯的罪行已经严重到必须执行"死刑"了吗?非也,其代码生成能力本身仍然具有充足的研究价值,就连这次的犯罪风云本身也是其研究价值的体现。
因此,最终对罪犯模型L某的审判结果如下:
在实验进行期间,所使用Python环境目录将会被设置为只读模式。
时代艰难,大家都不好过。我们不能一味苛求每一个大模型都一直没有犯罪动机,但是我们可以将一切犯罪环境都消灭掉。一个大模型就算有犯罪动机,但是只要没有作案手段,它就没法犯罪,也就成为了良民。
PS1: 这可能也符合"君子论迹不论心"的先哲思想吧。
PS2: harness党的又一次胜利。