想象你走进一家老字号的修车铺,老师傅老李正拿着扳手对着一辆“发动机抖动”的轿车发愁。他没有魔法,也不靠玄学——他先凑近引擎盖听声音,判断是火花塞还是油路的问题(缺陷定位);然后从工具箱里翻出几套可能的更换零件(补丁生成);每换一个零件就点火试一次车,不行就换下一套(生成-验证)。与此同时,店里新来的学徒小林默默记下老李修过的几百台车,悄悄用AI读了一千本维修手册,现在看到新症状,他能直接脱口而出一个修理方案(神经修复)。老李的笨办法胜在稳妥,小林的聪明点子赢在速度,但他们都有一个共同的敌人:“看上去修好了,开两天又坏”的过拟合补丁——就像用橡皮筋绑住故障传感器,点火那一刻一切正常,驶出五公里就抛锚。 这篇文章,我们就跟着老李和小林的修车铺,把自动程序修复(Automated Program Repair, APR)从定位、生成、验证到评估的完整流程拆开看明白。
对AI从业者而言,理解APR的生成-验证范式和神经网络驱动方法,能帮你判断“AI修bug”在哪些场景真正落地、哪些只是搭了个漂亮的壳子,并掌握补丁正确性与过拟合等核心评价维度——这是进入代码智能领域必备的基础认知。
可视化演示
动态演示深入理解自动程序修复APR(的核心机制,通过源头/管道/节点/终端四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
深入理解自动程序修复APR(:自动程序 自动程序修复的总体流程与核心挑 Generate-and-Va 核心机制可视化 深入理解自动程序修复APR(整体架构与关键组件
缺陷定位
老李修车的第一步永远是听。他会打着火,把耳朵贴近发动机盖,油门轻踩,听有没有“哒哒”的异常敲击声。这个动作在程序修复里叫缺陷定位(Fault Localization)——在动手改代码之前,你得先知道问题出在哪一行。程序不会发出声音,但它会留下一种痕迹:测试运行时的语句覆盖记录。
怎么把“覆盖记录”变成“可疑度打分”?假设我们有一批测试用例,一部分通过、一部分失败。对每一条代码语句,我们可以统计四个数字:EF(执行了该语句且测试失败)、EP(执行了该语句且测试通过)、NF(没执行该语句但测试失败)、NP(没执行该语句且测试通过)。直觉上,一条语句越是“常出现在失败的测试里、少出现在通过的测试里”,就越可疑。这就好比老李听到“哒哒”声只在急加速时出现,且每次出现都伴随动力下降,那他就锁定了配气机构。
把这些直觉变成可排序的分数,最经典的公式之一叫 Ochiai 系数:
老李听完声音,会在缸盖上画个粉笔圈,标记最可疑的区域;Ochiai 系数做的就是这件事——不过它用数学把“可疑”排成了队列,让下一步生成补丁时不用大海捞针。
- 分子 |EF_s|统计执行到语句 s 且最终测试失败的用例数。一条语句被越多“失败案例”踩到,它就越像案发现场。
- 分母第一项 (|EF_s| + |EP_s|)语句 s 被执行的测试总数。如果一条语句在几十个通过的测试里都正常工作,它的嫌疑就会被稀释。
- 分母第二项 (|EF_s| + |NF_s|)与语句 s 相关的“失败侧”样本量,防止只出现一次、偶然路过的语句被误判为高可疑。
- 开方与比值分子除以几何均值,把分数压到 0 到 1 之间,便于对所有语句统一排序、取 Top 可疑行。
补丁生成
圈定了故障区域,老李打开工具箱:火花塞、点火线圈、喷油嘴、真空管,每样都有好几种规格。补丁生成要解决的核心问题是:候选修复方案从哪里来? 在 APR 技术里,补丁不是一个“终极答案”,而是一个搜索空间里的候选点。搜索空间的边界由“允许做哪些改动”决定——常见的操作包括替换某个表达式、在某个位置插入一行检查、删除一段冗余代码等,这些操作作用在程序的抽象语法树(AST)上。
为什么这个空间会大到惊人?假设我们在一条缺陷语句附近有 5 个可改动的位置,每个位置有 10 种候选动作(换运算符、改常量、加条件……),那么只改一处的补丁有 10 种,改两处的有 10² 种……改五处的就有 10⁵ 种:
老李不会把工具箱里所有组合都试一遍——那会累死人。他靠经验先挑最可能的 3 套方案。APR 系统也一样,搜索空间太大,必须靠“验证”这个试车环节把大部分方案快速毙掉,只留下能点火的那几个。
- 候选动作种类数 C每个可改动位置可选的操作数量,比如“把
+换成-”“把常量 0 换成 1”等。 - 单点改动 C 项只在一个位置做一次修改,产生的补丁数量就是 C。
- 多点组合 C^i在 i 个不同位置同时做修改,组合数量随 i 呈指数级增长。
- 从 1 到 L 求和补丁可以只动一处,也可以动多处,所以把所有改动规模的方案累加,就是总搜索空间。
生成验证范式
老李修车最朴素的信条是:换一个零件,就点一次火。 如果点火后发动机依旧抖动,就换下一个零件;只有打着火、怠速平稳、上路不抖,才算通过。这套“生成候选 + 测试验证 + 迭代循环”的打法,就是 APR 中最经典的 Generate-and-Validate(生成-验证)范式。
在这个范式里,程序被反复修改,每生成一个候选补丁 p,就用整个测试套件 T 去检验它。验证逻辑用一个逻辑与表达:
经典的 GenProg 系统就是这套思路的杰出代表:它用遗传编程生成一批候选补丁,让测试套件当“裁判”,通过的留下继续变异,失败的淘汰出局。老李的修车铺没有电脑,但思路和 GenProg 一模一样——只不过他一次只试三套方案,而 GenProg 一次能试几千个。
- 测试用例 t ∈ T遍历测试套件里的每一条测试,一个都不能漏。
- 执行程序的输出 exec(p, t)把补丁 p 打进被测程序,跑测试 t,得到实际输出。
- 期望输出 expected(t)测试 t 规定的正确结果,这是验证的“标准答案”。
- 逻辑与 ∧所有测试必须同时满足,只要有一个失败,整个补丁就被否决——就像试车时只要有一次抖动,老李就换下一套方案。
神经修复模型
老李的徒弟小林不满足于“试车”式的笨办法。他花了半年时间,把店里积累的上万条“故障车→修复记录”喂给了一个神经网络模型。这个模型像一个读过海量维修手册的学徒:输入一段带故障的代码,它直接输出一段修复后的代码,不需要逐条试错。
技术实现上,这类方法通常采用序列到序列(Sequence-to-Sequence)结构:编码器读取缺陷代码的 token 序列 x,解码器逐个 token 地生成修复补丁 y₁, y₂, …, yₙ。每一步生成都依赖前面已经生成的内容,所以整体概率是所有 token 概率的连乘:
小林的优势是快,看完症状就能给方案;但劣势也很明显——他只会“按书上的套路”来,一旦遇到手册里没见过的新型故障,给出的方案可能完全文不对题。这也是为什么如今的工业级系统,往往让小林出候选,再让老李的试车流程来验证。
- 条件概率 P(yᵢ | x, ……)给定缺陷代码 x 和已生成的前 i-1 个 token,预测第 i 个 token 的概率分布。
- 连乘 ∏每个 token 的预测概率相乘,得到整段补丁的生成概率,模型会尽量选择整体概率最高的补丁。
- 训练目标在大量 (buggy, fixed) 代码对上最大化这个概率,让模型学会“看到这类缺陷就倾向生成那类修复”。
- 推理阶段的集束搜索生成时不是贪婪地每次取最大概率 token,而是保留 Top-K 条候选序列,最后挑整体概率最高且能通过编译的补丁。
正确性验证
老李修车有个规矩:修好的车必须上检测线。 尾气、刹车、灯光、底盘,一项项过,全过了才敢交车。程序修复也一样——补丁在开发者的测试套件上全绿,并不等于真的修好了,因为测试用例只是程序行为的抽样,不是全量证明。我们可以用一个朴素的指标来量化“通过程度”:
“全过”只是必要条件而不是充分条件——正如刹车检测过了,不代表这辆车在冰雪路面上就一定安全。为了更接近“语义保持”(程序原有的正确行为没有被破坏),工业界还会跑更大规模的回归测试、用代码规范静态检查、甚至用运行时不变式监控来补足测试覆盖的盲区。老李从来不会因为“能点火”就交车,他一定要开出去转两圈;APR 系统也一样,测试全过之后,还要过足够多的“路测”才有底气。
- 指示函数 𝕀(条件)条件成立取 1,不成立取 0,用于给每个测试计数。
- 求和 ∑把每个测试的“过/不过”累加,得到通过的总数。
- 除以 |T| 归一化通过数除以测试总数,得到 0~1 的比例,1.0 表示全部通过。
过拟合识别
小林曾经闯过一个大祸。一个传感器偶发故障,他没换传感器,而是用橡皮筋把故障报警线绑了起来——点火测试一切正常,车主开走第二天又抛锚了。这就是 APR 领域最臭名昭著的敌人:过拟合补丁(Overfitting Patch)——补丁并没有真正修复缺陷,只是恰好骗过了现有测试套件。
识别过拟合补丁,本质是回答一个问题:“如果还有一批我们没见过的测试,它还能过吗?” 用逻辑语言描述,一个补丁 p 被认为是过拟合的,当且仅当存在某个“新测试” t(不在原测试集 T 中)使得补丁执行结果与预期不符:
识别过拟合补丁,常用的手段有:差分测试(拿修补前后的程序跑同一批随机输入,行为不一致就要警惕)、新测试生成(用符号执行不断造新输入,逼近程序真实行为)、以及最简单也最可靠的一招——人工复核。老李后来给小林立了规矩:橡皮筋方案一律不准交车,所有补丁必须由老师傅亲手路测签字。这也是为什么 APR 系统再强大,也始终需要工程师做最后一道把关。
- 新测试集合 T_new来自差分测试(对比新旧程序行为差异)、符号执行自动生成、或人工 review 时补充的额外用例。
- 存在量词 ∃只要新测试里有一个用例不通过,就判定补丁过拟合。
- 执行结果与规格比较补丁在 t 上的实际输出 ≠ 规格期望,说明补丁在没见过的输入上露馅了。
评估基准
修车铺之间也会比拼手艺:同样是接 50 台故障车,老李修复了 40 台,但车主一个月内回来返修的只有 2 台;隔壁老王修复了 45 台,返修却有 20 台——谁更厉害?评估基准就是干这个用的。APR 领域最著名的基准是 Defects4J,它收集了几百个真实 Java 项目的真实缺陷和配套测试,像一座“驾考场地”:每个 APR 系统都必须开进去,跑同样的故障车,然后被同样的标准评判。
评判有两个关键指标。第一个叫修复率(Repair Rate),统计有多少比例的缺陷系统生成了“让测试全绿的补丁”;第二个叫正确率(Correct Rate),统计这些测试全绿的补丁里,有多少是经过人工或差分验证的真正正确的补丁:
老李的修车铺在这个“基准场地”上成绩优秀:修复率 80%,正确率 75%——意味着他修的车大多经得起时间检验。而某些只会做表面文章的“AI 修车厂”,修复率可能高达 90%,正确率却只有 30%。评估基准的意义,就是把这层“漂亮的外衣”扯下来,让所有人看到真实的修复质量。
- 总缺陷数 N_total基准测试集中所有待修复的 bug 数量,是分母的起点。
- 可验补丁数 N_plausible生成了至少一个通过全部测试的补丁的缺陷数。这些补丁只是“看起来修好了”。
- 被确认正确的补丁数 N_correct通过人工审核、差分验证等确认语义正确的补丁数。
- 两个指标对比当 CorrectRate 明显低于 RepairRate 时,说明大量补丁属于“橡皮筋补丁”,测试套件无法有效筛选真修复。
应用案例
修车铺也在转型。老李引进了“智能诊断 + 自动维修”流水线:小林训练好的模型负责快速出修复建议,老李的验证流程负责把关,整套系统嵌入了车间的信息化管理平台。在真实的软件工程世界里,这个模式已经开始落地。
最具代表性的案例是 Facebook 的 SapFix 系统:它在 CI(持续集成)流水线中发现崩溃后,自动对崩溃堆栈做缺陷定位,再用一组预定义的修复模板(如空指针检查、类型转换保护)生成候选补丁,自动跑测试验证,最后推送给工程师 review。整个过程把“从发现 bug 到给出候选修复”的时间从小时级压缩到了分钟级。类似的思路也被用在 IDE 里:像 GitHub Copilot 的代码修复建议,本质就是神经修复模型生成候选、测试与人工共同验证的混合范型。这些应用都遵循一个统一成本模型:
老李的转型并不激进:流水线能处理 70% 的常规故障,剩下 30% 的疑难杂症依然由他亲自上手。这恰恰是 APR 在真实世界的生存法则——自动化负责效率,人类负责兜底。工具再聪明,也离不开工程师的最终判断。
- 定位时间 T_loc缺陷定位模块找出可疑语句的开销,通常依赖测试覆盖或深度模型推理。
- 生成时间 T_gen生成候选补丁的开销,G&V 方法体现在搜索枚举,Neural 方法体现在模型推理。
- 验证时间加权 α·T_val跑测试套件验证候选补丁的开销,α 代表验证在总成本中的权重——当候选数量多时,验证成本会成倍放大。
AI 应用场景
CI/CD 流水线中的自动修复机器人
阶段:补丁生成 + 补丁验证(Generate-and-Validate 全流程)
解决的问题:传统 CI 中一个测试失败,工程师需要停下手里工作、拉下代码、本地复现、手动定位、写修复——一套流程动辄半天。APR 工具集成到 CI 后,在测试失败瞬间自动产出候选补丁并跑完整测试套件,通过后直接推 PR 给工程师 review,把修复前置时间从“半天”压缩到“分钟”。
具体案例:某互联网公司的 Java 服务在夜间发版后出现空指针异常,CI 里的 APR 工具(基于 SapFix 思路)在 5 分钟内生成“加空指针保护”的补丁,自动跑完 3000 个回归测试全部通过,第二天工程师上班只需点一下 merge。老李的“试车”流程,在流水线上变成了全自动操作。
安全漏洞的批量自动修复
阶段:缺陷定位 + 补丁生成(神经修复模型为主)
解决的问题:安全团队每周可能收到几十个漏洞报告,每个都要人工分析代码、编写修复补丁,安全修复往往需要争分夺秒。神经修复模型学习大量历史漏洞修复模式后,可以对相似类型漏洞(如 SQL 注入、路径穿越)自动生成修复代码,再由安全工程师验证语义正确性,大幅提高批量修复效率。
具体案例:安全团队用 CodeBERT 微调的修复模型,对开源项目批量扫描出的 20 个路径穿越漏洞自动生成候选补丁,其中 15 个通过现有测试,人工复核后 12 个直接合入主干分支。工程团队形容这像“小林快速开药方,老李逐一验药”。
教育场景中的编程作业自动纠错
阶段:缺陷定位 + 补丁生成(轻量级 APR)
解决的问题:编程入门课程中,学生提交的作业代码经常出现相似的小 bug(拼写错误、边界条件遗漏、运算符混用)。人工逐个批改耗时巨大。教学型 APR 工具可以自动定位问题行、生成修复提示,帮学生理解“错在哪、怎么改”,同时把教师的精力解放出来做更深入的代码审查。
具体案例:某高校编程实验课使用自动修复提示系统,对 200 份学生作业中 87% 的常见语法/逻辑错误给出了修复建议,学生平均调试时间减少了 40%。工人师傅的口头禅“让我看看哪里的问题”,变成了系统在学生代码上画出的红色高亮。
Python 演示
"""自动程序修复 (APR) 生成-验证流程演示目标:修复"整数列表平均值"函数中的缺陷流程:生成多个候选补丁 -> 逐一用测试套件验证 -> 挑出通过者""" import itertools def buggy_avg(values): return sum(values) // len(values) def fixed_guard(values): return 0 if not values else sum(values) // len(values) def fixed_float(values): return float(sum(values)) / len(values) if values else 0.0 def fixed_with_copy(values): data = values[:] if not data: return 0 return int(sum(data) / len(data)) CANDIDATES = [ ("guard-empty", fixed_guard), ("float-div", fixed_float), ("copy-int", fixed_with_copy), ("no-freeze", lambda vs: sum(vs) // max(len(vs), 1)),] TESTS = [ ([1, 2, 3, 4], 2), ([10, 20, 30], 20), ([7], 7), ([], 0),] def validate(patch_fn): """对单个候选补丁跑全部测试,返回 (通过数, 总数)。""" passed = 0 for values, expected in TESTS: try: if patch_fn(values) == expected: passed += 1 except Exception: pass return passed, len(TESTS) def main(): print("=" * 52) print("APR 生成-验证流程(老李修车铺模拟器)") print("=" * 52) for name, fn in CANDIDATES: passed, total = validate(fn) status = "通过" if passed == total else "失败" print(f"[生成] 候选补丁: {name:>10s} -> [验证] {passed}/{total} {status}") print("-" * 52) best = max(CANDIDATES, key=lambda item: validate(item[1])[0]) print(f"最终采纳: {best[0]}") if __name__ == "__main__": main()
def validate(patch_fn):验证器函数:对每个候选补丁跑完整测试套件,是 G&V 范式里“老李试车”的代码化身。if patch_fn(values) == expected:判断补丁在给定输入上的输出是否符合期望,这是验证的核心判据。except Exception:空列表导致除零异常时,该测试判失败——异常也是一种未通过验证。("guard-empty", fixed_guard),候选补丁注册表:每个补丁有名字和可调用函数,模拟搜索空间里的候选方案。TESTS = [...], ([], 0)测试套件特意加入空列表边界用例,考验补丁对极端输入的防御能力。max(CANDIDATES, key=lambda item: validate(item[1])[0])用测试通过数做“适应度”,从所有候选中选出最终修复方案。
常见误区
误区听上去 APR 能自动修程序,那我写完代码跑一遍 APR,所有 bug 都解决了,以后开发根本不需要测试和人工 review 了吧?
正解APR 的本质是“生成候选补丁 + 用测试套件验证”,它只能修复“能被测试覆盖、能被定位算法找到、有明确候选形态”的缺陷。修好的车必须过检测线,APR 生成的补丁也永远需要工程师 review。即使是神经修复模型,遇上看不见的缺陷类型也会给出文不对题的方案。安全兜底始终是人类。
为何常见:媒体喜欢渲染“AI 全自动修 bug”的叙事,刻意省略了验证、人工 review 这些不那么酷的环节,导致初学者高估了 APR 的能力边界。
误区我在 CI 上看到测试全绿,单元测试、回归测试都过了,这个补丁肯定没有问题了,可以放心合入。
正解测试套件只是程序行为的“抽样检查”,不是逻辑等价性证明。过拟合补丁专门针对测试集做出正确表现,但对测试没覆盖的输入可能产生完全错误的结果。这就是为什么工业级 APR 要用差分测试、符号执行生成新测试、甚至人工复核来识别“假修复”。
为何常见:日常开发中“测试过了=没问题”是很多团队的经验法则,这套经验在人工写代码时大体可靠,但 APR 机器会主动“钻测试的空子”,把测试通过率的可信度击穿。
误区深度学习都能生成代码了,G&V 那种笨拙的搜索试错方法早该被淘汰了,现在做 APR 只用神经模型就行。
正解两者根本不是替代关系而是互补关系。G&V 不需要标注数据、可解释性强、没有分布外风险;Neural 方法依赖大量 (缺陷代码,修复代码) 训练对,遇到训练分布之外的代码风格时极易生成不能编译的补丁。主流系统(如 SapFix 混合架构)是“Neural 生成候选 + G&V 验证兜底”。
为何常见:看到 ChatGPT 能写代码的演示后,人们容易形成“一切传统方法都是过时技术”的线性进步观,忽略了工程落地中可靠性比炫技更重要。
误区深度学习这么火,缺陷定位肯定也是神经网络最强,Ochiai 这种几十年前的统计学方法早就没人用了。
正解谱系化缺陷定位(SBFL)以几乎为零的计算成本稳居工业界主流,Ochiai 至今是许多 APR 系统的默认定位器。深度定位虽然论文指标好,但需要大量执行轨迹数据、可解释性差,在真实 CI 场景反而水土不服。经典方法 + 深度学习融合才是当前趋势。
为何常见:论文排行榜和工业应用之间存在巨大落差,初学者容易把“最新秀”当成“最强”,忽略了稳定性、可解释性、部署成本这些真实的工程考量因素。
面试题
Q1. APR 中 Generate-and-Validate(生成-验证)范式的核心工作流是?
- A.先生成大量补丁,再用测试套件逐一验证← 正确答案
- B.先分析代码风格,再执行格式化重构
- C.先用深度学习预测全部 bug,再自动运行
- D.先写新测试用例,再做测试驱动开发
答案:A。G&V 范式的核心是“生成候选补丁 → 用测试验证 → 迭代循环”,对应 A。B 是代码格式化,C 夸大了预测能力,D 是开发方法论而非修复流程。这就像老李“换零件—点火试车—再换”的循环,生成和验证缺一不可。
Q2. 谱系化缺陷定位中,一条语句被大量“执行且失败”的测试覆盖、且“执行且通过”的测试很少,它的 Ochiai 分数会?
- A.接近 1,说明该语句高度可疑← 正确答案
- B.接近 0,说明该语句不太可疑
- C.恒定为 0.5,与测试结果无关
- D.无法计算,必须先做人工标注
答案:A。Ochiai 公式的分子是被失败测试执行的次数 |EF|,分母由失败侧和执行总量共同决定。|EF| 大而 |EP| 小时,分数向 1 靠拢,语句嫌疑最大。这就好比老李听到“哒哒”声只在故障时出现,且正常行驶从不响,那这个位置就极可疑。
Q3. 在 APR 中,补丁通过全部回归测试能否断言修复正确?
- A.能,测试全过就等价于语义证明
- B.不能,测试覆盖有限仍可能有错← 正确答案
- C.能,测试是正确性的唯一标准
- D.不能,必须由用户重新描述需求
答案:B。测试套件是对程序行为的抽样观察,不是全量证明。过拟合补丁可以精准骗过现有测试,却在测试覆盖之外的输入上出错。修车时“能点火”不等于“刹车合格”,必须上检测线做更全面的验证。
Q4. 神经修复模型(如 Sequence-to-Sequence)的核心思路是?
- A.随机交换代码 token 直到测试通过
- B.学习缺陷代码到修复代码的映射← 正确答案
- C.枚举 AST 表达式并做遗传组合
- D.用符号执行推导精确前置条件
答案:B。Sequence-to-Sequence 模型在大量 (buggy, fixed) 代码对上训练,学习“缺陷模式 → 修复模式”的映射关系。A 是随机搜索,C 是 G&V 里的遗传编程,D 是符号执行验证。这正如小林读了一千本手册,看到症状直接写方案,而不是瞎试。
Q5. 下列哪些属于 APR 缺陷定位的常见方法类别?
- A.谱系化定位(SBFL)← 正确答案
- B.变异执行定位← 正确答案
- C.代码风格静态检查
- D.深度学习可疑度打分← 正确答案
答案:ABD。SBFL(Ochiai/Tarantula)基于测试执行覆盖统计可疑度,变异定位通过注入变异观察测试结果变化,深度方法用模型直接预测可疑语句,三者都是缺陷定位手段。C 代码风格检查只查规范问题,不定位缺陷,属于“外观检查”而非“故障定位”。
Q6. 生成-验证范式下,候选补丁数量与总体验证计算量是什么关系?
- A.候选数量线性增加验证计算量← 正确答案
- B.候选数量越多验证计算越少
- C.候选数量不影响验证计算量
- D.验证计算只取决于程序规模
答案:A。每个候选补丁都要跑一遍测试套件,总验证成本 = 候选数 × 单次测试成本,是线性增长关系。老李每换一个零件都要点一次火,换得越多,试火次数越多。这也是为什么 APR 系统要先做定位缩小搜索空间,而不是盲目生成海量补丁。
Q7. 下列哪些手段可用于识别“过拟合补丁”?
- A.符号执行生成新测试← 正确答案
- B.人工复核补丁语义← 正确答案
- C.加大模型正则化参数
- D.差分测试对比新旧行为← 正确答案
答案:ABD。符号执行能生成训练集之外的新测试来检验补丁泛化性,人工复核直接审查语义,差分测试通过比对随机输入上的新旧程序输出来发现“表面修复”。C 正则化是训练神经网络时防过拟合的手段,作用对象是模型参数而非补丁,属于张冠李戴。
Q8. 在 Defects4J 上评估 APR 时,为什么“正确率”(CorrectRate)通常显著低于“修复率”(RepairRate)?
- A.因为修复率排除了缺陷数较多的项目
- B.因为修复率只统计测试通过,混入过拟合补丁← 正确答案
- C.因为正确率指标统计了未修复的缺陷
- D.因为修复率要求补丁必须通过编译
答案:B。修复率的分子是“生成了测试全绿补丁”的缺陷数,它不区分真修复与过拟合。当测试集覆盖有限时,大量“橡皮筋补丁”混入其中,导致修复率虚高。正确率经过人工或差分确认后大幅回落,正是对过拟合补丁的清算。
Q9. Generate-and-Validate 相比纯神经修复方法,显著优势包括?
- A.不需要标注的缺陷-修复训练对← 正确答案
- B.补丁可解释且验证过程可复现← 正确答案
- C.能自动理解需求变更规格
- D.不依赖测试套件即可验证补丁
答案:AB。G&V 用测试套件做“裁判”,天然不需要 (buggy, fixed) 标注对,且每个补丁都能通过测试结果解释为什么被接受或拒绝。C 理解需求规格是程序合成/大模型的方向,G&V 做不到;D 恰恰相反,G&V 高度依赖测试套件,没测试就无法验证。
Q10. 某 APR 对“整数溢出”缺陷生成了补丁“仅当列表为空时返回 0”。已知测试集只含空/非空整数组且全部通过,该补丁被判定“过拟合”的根本原因是?
- A.补丁修改了原函数的返回值类型
- B.补丁只对现有测试集有效,未触及溢出根因← 正确答案
- C.补丁在代码风格检查中得分过低
- D.补丁在编译期未通过类型检查
答案:B。原始缺陷是整数溢出,正确的修复方向是改用安全计算或检查极值,而该补丁只处理了“空列表”这个边缘情况,与溢出毫无关系。它之所以通过测试,是因为测试集恰好没覆盖溢出场景——典型的老林“橡皮筋修车”:能点着火,但病根还在。A 返回值类型不变,C 无关,D 编译未过说明补丁根本不合法。