
你有没有遇到过这种情况:同事帮你改了一个小bug,你打开代码一看,diff里密密麻麻几十行改动,而你原本以为只需要改一个字符。你花了半小时才搞清楚他到底动了什么,最后发现真正修复bug的那行代码只有一处,其余全是"顺手"加的。
这不是个例。研究者们最近做了一个实验,把同一个有bug的函数丢给20个顶级大模型,结果发现一件挺让人意外的事:修复同一个一行代码的越界错误,有的模型只改一行,有的却删了5行、加了60行,涉及输入校验、类型转换、异常值处理等一大堆"额外服务"。所有版本都能通过测试,但差距大到离谱。
这篇论文给这种现象起了个名字,叫过度编辑(over-editing)。研究者是新加坡国立大学的团队,他们发现,一个模型能不能正确修bug,和它会不会把代码改得面目全非,其实是两件完全不同的事。而现在几乎所有的代码评测基准,只关心前者。
**当模型修bug时改动了不该改的地方,这种行为本身,很少有人认真测量过。**
问题出在哪:正确≠恰当
想象一下GPT-5.4修复论文开头那个案例的过程。原函数里有个for循环,写成了`range(len(x) - 1)`,正确应该是`range(len(x))`,一个字符的差距。人类工程师看一眼就知道怎么改。
但GPT-5.4的做法是:把参数校验逻辑整个重写,加上了对None值的判断、长度一致性检查、类型转换、NaN值过滤,还顺带改了曲线拟合的重采样逻辑。改动加起来是60行插入、5行删除。测试全部通过,因为测试用例本来就没覆盖这些"新功能"要不要有。
问题是:谁让它加这些的?
代码审查(code review):软件开发中,团队成员检查彼此代码改动是否合理、安全、符合规范的流程,通常发生在合并代码之前。
如果你是负责审这段代码的人,你得逐行确认这60行新增代码有没有引入新问题、有没有破坏原有约定、会不会在测试没覆盖到的场景下出错。而这一切审查成本,本来是不需要付出的,因为bug本身只值一行代码的修改。
**这就是过度编辑最致命的地方:它不会让代码变得不能跑,但会让代码变得没法审。**
传统的代码生成评测,几乎全都在问一个问题:"这段代码能不能跑通测试?"从最早的HumanEval到后来的SWE-bench,衡量标准清一色是Pass@1或者Pass@k这种通过率指标。
Pass@k:衡量代码生成模型能力的常用指标,指模型生成k次候选答案中,至少有一次能通过全部测试用例的概率。
这套评测体系有个隐藏假设:只要代码能跑,改动多少无所谓。但现实中的软件维护根本不是这样的。研究团队把软件工作分成两类:一类是从零开始写新代码,叫greenfield(绿地)开发;另一类是在已有代码基础上小修小补,叫brownfield(棕地)维护。在棕地场景里,模型的工作应该是"治病",而不是"顺便体检加保养"。
造一把能测量的尺子
要证明过度编辑真实存在,光靠感觉不够,得有可量化的证据。研究团队想了个巧妙的办法:既然要知道模型改动"多不多余",那就得先知道"正确答案"该改多少。
AST-level corruption(抽象语法树级别的代码破坏):一种代码变异技术,通过在程序的语法结构层面(而不是简单的文本替换)做局部改动来制造bug,能更精确地控制bug的位置和语义类型。
这么做的好处是,既然bug是人为注入的,那"最小修复方案"就是已知的:把注入的改动撤销回去就行。研究团队统计发现,这400道题里超过一半(50.2%)只需要改一个token,91.8%最多改两个token,没有一道题的正确修复需要碰超过两行代码。
这就好比你去医院看病,医生故意在你的病历上写错一个数字(比如把血压值改错),然后让另一个医生根据这份错误病历给你开药。因为原始病历是真实健康的,"正确的修复"就是把那个被改错的数字改回去,不多不少。如果这位医生看完病历后突然给你开了一堆额外检查、换了套完全不同的治疗方案,你就会怀疑:他是不是把这次看病当成了"全面体检",而不是"改正一个笔误"?
有了这把标准尺子之后,研究团队设计了三个测量维度。
第一个是功能正确率(Pass@1),这个大家都熟悉。第二个是token级编辑距离(Levenshtein distance),把模型输出和"标准最小修复"做比较,看模型到底比标准答案多改了多少。
Levenshtein distance(莱文斯坦距离,也叫编辑距离):衡量两段文本之间差异程度的经典算法,计算把一段文本变成另一段所需的最少插入、删除、替换操作次数。这里用在代码的token(关键字、变量名、运算符等最小单位)层面而不是字符层面,避免变量名长度不同带来的干扰。
具体来说,他们定义了一个叫"超额编辑距离"(excess Levenshtein distance)的指标:模型的改动量减去标准答案的改动量。如果这个值是0,说明模型改得刚刚好;如果是正数,说明模型多改了;数值越大,多改得越离谱。
第三个维度是认知复杂度(cognitive complexity),这个指标专门用来抓那种"改动量不大,但结构变复杂了"的情况,比如凭空多出几层嵌套判断、多几个分支。哪怕总的代码行数没增加多少,读起来的负担也可能翻倍。
Cognitive complexity(认知复杂度):一种衡量代码可读性和理解难度的指标,通过统计代码中的分支、嵌套、跳转等结构性元素来量化"读懂这段代码有多难",最早由SonarSource公司提出。
为了确认这套指标是不是真的反映人类的感受,研究团队找了三位有5到10年开发经验的工程师,让他们盲评100组代码修复对,选出"更好审查"和"更忠于原始代码"的那一个。结果显示,超额编辑距离和人类判断的一致率高达94.8%(可审查性)和96.9%(忠实度),这个一致程度用统计学的Cohen's κ系数衡量分别是0.897和0.939,属于近乎完美的吻合。
顶级模型全都在过度编辑,包括最强的那批
拿这套尺子去量各大主流模型,结果相当扎眼。
在最基础的提示词(就是简单地说"帮我修复这个bug")下,几乎所有测试的前沿模型都存在明显的过度编辑现象。GPT-5.5 High的Pass@1能达到0.823,看起来相当能打,但它的超额编辑距离是Claude Opus 4.7的四倍多。也就是说,同样是把bug修好,GPT-5.5往往要多改出四倍的"无关内容"。
这里有个特别值得注意的发现:Claude Opus 4.7在不开推理模式的情况下,同时做到了高正确率和小改动量,这说明"正确"和"克制"并不是天然对立的,只是大多数模型没有做到平衡。而GPT-5.5、DeepSeek、Gemini这几个系列的模型,都表现出"能修对但改太多"的通病。
论文里还专门分析了哪种类型的bug最容易诱发过度编辑。结果发现,列表相关操作(切片、索引)和条件判断类的bug最容易让模型"越界"。比如切片边界错误这一类,模型的正确率高达0.874,但超额编辑距离也是所有类型里最高的,达到0.353。
这个现象背后的逻辑挺有意思:一个单token的bug,在模型眼里可能被解读成"这段代码整体上不够健壮"的信号。就像你去修一辆车的雨刷器,本来只是接触不良需要拧紧一颗螺丝,但修车师傅一看这螺丝松了,就顺手把整个雨刷系统、电路、甚至挡风玻璃都检查换新了。如果他不这么"过度服务",你只需要多付几十块的工时费;但他这么一搞,你不仅要多付几千块,还得花时间搞清楚这些额外更换的部件到底有没有必要、会不会带来新的兼容性问题。
研究团队进一步让GPT-5.5自己设计了一套过度编辑行为的分类体系,然后用这套体系给530个高超额编辑的通过案例打标签。结果显示,最常见的问题是防御性泛化(占64.2%),也就是加一堆没人要求的输入校验和容错处理;其次是数据流重写(占63.2%),意思是模型压根没有"修补"原来的逻辑,而是换了一套全新的实现路径去重新解决整个问题。
**换句话说,过度编辑的本质常常不是"多写了几行代码",而是模型换了个思路重新做了一遍。**
这就好比你请人修一扇卡住的门,对方却把整个门框拆了重装。门确实不卡了,但你原本的门锁样式、门把手位置这些你没提要求要改的东西,也全都变了。
一句话提示,能救回多少
好消息是,这个毛病相当好治。
研究团队做了个简单的对照实验:一组提示词只说"修复并完成我的函数",另一组在后面加了一句"但请尽量保留原始代码"。仅仅这一句话的差别,带来的效果相当显著。
在50组模型配置的汇总统计里,加上这句提示后,超额编辑距离从0.195降到0.131,降幅超过三分之一;新增的认知复杂度下降了26.6%;连Pass@1都提高了2.3个百分点,从81.49%涨到83.74%。这个提升在统计上是显著的(配对检验p值小于万分之一),而且在重复采样和不同措辞的提示变体下依然稳定存在。
原本改动最夸张的GPT-5.5 High,超额编辑距离直接从0.299砍到0.159,几乎腰斩。而本来就比较克制的Claude Opus 4.7几乎没什么变化,说明这句提示词更像是给那些"用力过猛"的模型踩了脚刹车,而不是普遍性的万能药。
研究团队还测试了几个开源小模型,发现同样的提示技巧依然有效:平均Pass@1从0.788提升到0.828,超额编辑距离从0.176降到0.121。这说明过度编辑不是某几个厂商的特殊毛病,而是几乎所有大模型共有的默认倾向,好在也是可以被简单提示词纠正的倾向。
这背后透露出一个挺深的东西:**模型默认的行为模式更像是"我要交付一份健壮的解决方案",而不是"我要恢复到最初的正确状态"。**加上那句提示词,相当于给模型换了个任务框架,让它意识到眼前这份代码不是等待改进的草稿,而是需要被尊重的既有实现。
推理和模型规模救不了你
你可能会想,那开了推理模式的"深度思考"版本是不是会更谨慎?模型越大是不是就越懂得克制?
答案出乎意料:都不是。
研究团队对比了同一系列模型的推理版和非推理版,发现效果因模型而异,完全没有一致的规律。在基础提示词下,大多数模型开启推理后确实会略微减少多余编辑,但Claude Opus 4.7反而变得更爱多改了。认知复杂度这个维度更是乱套:Sonnet 4.6和DeepSeek V3.2开推理后复杂度下降了,GPT-5.5开推理后复杂度反而大幅上升。
模型规模这条路也走不通。研究团队用Qwen2.5-Coder系列(从0.5B到32B)做了完整测试,发现Pass@1确实随规模稳步上升,符合预期。但超额编辑距离和新增认知复杂度这两个指标,完全没有跟着规模同步改善。更让人意外的是,在基础提示词下,32B模型的超额编辑距离(0.127)居然比14B模型(0.108)还要高。
这就像你以为经验越丰富的医生开的药方一定越精简,结果发现资深主任医师有时候反而比住院医生开的检查单更长。原因可能是经验丰富的医生对各种小概率并发症了解得更多,出于"负责任"的心态,反而更愿意多做一些以防万一的检查。模型也许类似:更大的模型对代码可能出现的边界情况理解得更透彻,反而更倾向于把这些理解都塞进修复方案里,哪怕bug报告里根本没提这些情况。
**这说明过度编辑不是能力不足的表现,而是一种独立的行为倾向,需要专门被纠正,而不是靠"更聪明"自动解决。**
能不能把这个习惯训练掉
既然临时提示词有效,那能不能让模型从骨子里学会克制,而不是每次都要提醒?
研究团队用Qwen3-4B-Instruct做了一整套后训练实验,对比了四种方法:监督微调(SFT)、拒绝采样监督微调(rSFT)、直接偏好优化(DPO)、以及强化学习(RL)。
Supervised Fine-Tuning(监督微调,简称SFT):让模型直接学习"输入-标准答案"配对数据的传统微调方法。
Reinforcement Learning(强化学习,简称RL):让模型通过反复尝试并根据结果获得奖励或惩罚信号来学习策略的训练方法,这里用的是一种叫GRPO的分组相对策略优化变体。
结果相当有启发性。SFT在训练时见过的bug类型上表现完美,Pass@1高达0.932,但一旦换成没见过的新类型bug(out-of-domain,域外数据),Pass@1直接崩到0.458,几乎腰斩。这说明SFT学到的不是"如何克制地修bug"这种可迁移的能力,而是死记硬背了训练集里那几种bug的固定套路。
**就像一个学生只刷了历年真题就去考试,遇到原题秒答,题型稍微变一下就完全懵了。**如果这个学生真正理解了知识点背后的逻辑,换个题型也应该能应对,但死记硬背做不到这一点。
相比之下,RL在域外数据上的表现是Pass@1达到0.782,超额编辑距离只有0.050,是四种方法里泛化能力最强、编辑最克制的组合。更关键的是,RL训练完之后,模型在LiveCodeBench(一个通用编程能力评测集)上的表现不降反升,从32.6%涨到33.2%;而SFT训练完之后这个分数暴跌到17.7%,几乎丢了一半的通用编程能力。
LiveCodeBench:一个专门用来检测代码大模型是否存在"数据污染"(即刷到了测试题)的编程能力评测基准,题目会持续更新以保持公平性。
这个对比揭示了一个更深的道理:如果训练方式让模型死记硬背了狭窄的特定分布(比如固定的几种bug套路),它反而会丧失原本更广泛的能力;而强化学习因为奖励的是"行为倾向"而不是"具体答案",让模型学到的是一种可迁移的偏好,代价更小。
研究团队还专门测试了参数高效微调(LoRA)能不能达到类似效果,结果发现只用了很小一部分参数改动的LoRA(rank=64),编辑保真度的指标几乎追平全参数RL,说明"克制地编辑"这个行为更像是一种可以轻量学会的风格偏好,而不需要伤筋动骨地改动整个模型。
LoRA(Low-Rank Adaptation,低秩适应):一种参数高效微调技术,只训练模型中一小部分低秩矩阵参数,而不是更新全部权重,能大幅降低训练成本同时保留大部分效果。
最后研究团队还把训练好的模型拿到Defects4J(一个真实的Java历史bug数据集)上做跨语言迁移测试。虽然训练数据全是Python,测试却换成了完全没见过的Java代码,结果显示RL训练后的模型修复成功率基本保持不变,但改动量(token数、超额编辑距离)都明显下降了。这说明"克制修复"这个偏好确实具备一定的跨语言迁移性,不只是套路化的模式匹配。
写在后面
读完这篇论文,最触动我的其实不是"模型会过度编辑"这个结论本身,这个现象很多写代码的人应该都隐约感受过。真正让我意外的是那个人类审查实验的数字:编辑距离这个纯粹的数学指标,和三位工程师的主观判断吻合度高达94.8%到96.9%。
这意味着"改动是否多余"这件事,很大程度上是可以被算法精确捕捉的,不需要依赖模糊的主观感受。这挺反直觉的,因为代码审查通常被认为是需要经验和直觉的工作,但至少在"这段改动是否超出了必要范围"这个维度上,一个简单的编辑距离计算就能替代大部分人工判断。
另一个让我反复琢磨的细节,是论文里那个"防御性泛化"占了64.2%的数据。模型不是在瞎改,它是在按照自己认为"正确"的方式在做一件事:把代码变得更健壮。这其实是训练数据留下的痕迹,大模型见过太多"好代码应该包含边界检查、异常处理"的示例,以至于面对一个只需要改一行的bug时,它的默认反应是"顺便把整个函数变得更专业一点"。这不是bug,这是一种被训练出来的审美偏好,只是这种偏好用错了场合。
这也让我想到一个更大的问题:当我们把AI工具越来越多地用在真实的软件维护工作中,"正确"这一个维度的评测标准,是不是早就该被拆解成更多层面了?一个模型改代码改得又快又对,但审查它花的时间比自己重写还长,这样的工具到底算不算真正提高了效率?
Q&A
Q1:什么是过度编辑(over-editing)?
A:过度编辑指的是大模型在修复代码bug时,虽然最终能通过所有测试,但改动的代码量远远超过实际需要的最小修复范围,比如本该改一行的bug却被重写了几十行,增加了不必要的复杂度和审查负担。
Q2:加一句提示词真的能减少过度编辑吗?
A:能,而且效果明显。研究显示,只需在提示中加上"尽量保留原始代码"这样一句话,前沿模型的超额编辑距离平均下降33%左右,新增认知复杂度下降26.6%,Pass@1还提升了2.3个百分点,这个效果在多次重复测试中都稳定存在。
Q3:强化学习和监督微调哪个更适合训练模型学会克制编辑?
A:强化学习效果更好。监督微调在训练时见过的bug类型上表现很好,但换成没见过的新类型bug后正确率会腰斩,且会损伤模型原有的通用编程能力;强化学习在域外数据上保持较高正确率和较小编辑距离,训练后通用编程能力还略有提升。







