核心要点
能讲清闭环:生成代码 → 执行(编译/运行/单测/lint/类型检查)→ 采集报错与失败用例 → 把错误反馈喂回模型 → 定位并修复 → 再次验证,循环直到通过
能给验证信号:编译错误、运行时异常、失败的单测、lint/类型检查输出都是「可机读的客观判据」,比让模型自评更可靠
能给退出策略:全部测试通过即停、达到最大重试轮次、连续 N 轮无进展(同样错误)即停并求助人工、超时或超预算熔断
能防震荡:用回归测试守住已通过的部分、要求最小改动、必要时回滚到上一个可用版本,杜绝「改 A 坏 B」反复横跳
标准回答
先讲闭环结构
自动修复循环的本质是把「人类调试的试错过程」自动化成一个反馈回路:生成代码 → 执行验证 → 采集失败信号 → 反馈给模型 → 定位修复 → 再次验证,如此往复直到通过或触发退出。每一轮的核心是「拿到一个客观可机读的失败信号」,再把这个信号原样喂回模型,让它基于真实报错而非凭空想象去改。
验证信号要客观且分层
验证阶段应分层执行,而不是只跑一种检查:编译/构建(语法、依赖是否过得去)、类型检查与 lint(静态层面的错误与风格)、单元测试/集成测试(行为是否正确)、运行时执行(是否抛异常)。这些都会产出结构化、可定位的输出(报错堆栈、失败用例名、断言差异)。把这些原始输出(必要时截断)连同相关代码片段一起回灌给模型,定位准确率远高于让模型「自己想哪里错了」。
退出策略是设计的重点
循环必须有界,否则会无限烧 token。要叠加多重退出条件:一是成功退出——全部测试与检查通过即停;二是最大重试轮次——达到上限(如 5~10 轮)强制停止;三是无进展检测——连续 N 轮出现同样的错误或失败用例集合没有缩小,判定为「卡住」,停下并降级求助人工;四是熔断——单轮或累计超时、超 token/费用预算,立即中断。多条件取「先满足者」生效,保证最坏情况成本与延迟有界。
防止「改 A 坏 B」的震荡
最隐蔽的坑是修复一个测试却弄坏另一个,导致在两组失败间来回横跳。对策有三:回归测试——每轮都跑全量(或受影响)测试集,新失败必须暴露,绝不只看本轮目标用例;最小改动——约束模型只改必要范围,diff 越小越可控、越易回滚;版本快照与回滚——记录每个「比上一轮更好」的可用版本,一旦某轮整体变差就回滚到上一个最优态,再换思路,而不是在劣化路径上继续叠加。
常见误区
⚠️ 常见踩坑
最常见的误区是「无限循环、只靠模型自己判断改没改对」——既不设最大轮次也不做无进展检测,结果模型反复尝试把预算烧光仍无结果。其次是只跑本轮目标测试而不跑全量回归,于是「改 A 坏 B」反复震荡却没人发现。还有人把整堆冗长日志一股脑塞回上下文,挤爆窗口又淹没关键报错——应截断并只保留与失败强相关的片段。正确姿势是:客观分层的验证信号 + 多重退出条件 + 全量回归 + 最小改动与回滚兜底。
追问
追问 1:怎样判定「连续 N 轮无进展」并优雅地停下来?
给每一轮的结果做指纹:失败用例集合 + 关键报错信息归一化后取哈希。若连续 N 轮(如 3 轮)失败集合没有缩小、或指纹完全重复,就判定无进展。此时不要继续硬怼,而是停止循环并降级:把当前最优的部分修复、剩余未通过的用例清单、以及卡住的报错一并交还给人工,或转交更强的模型/换一种修复策略重试。本质是用「失败集合是否在收敛」作为进度判据,而非单纯计轮数。
追问 2:把报错反馈给模型时,如何组织上下文才高效?
不要把原始日志整段倒进去。先做提炼:保留失败用例名、断言的期望值与实际值差异、异常类型与最顶层的几帧堆栈;再附上报错直接指向的代码片段(带行号),必要时给出相关函数定义。对超长输出做截断并保留首尾关键部分。结构化地告诉模型「哪个测试失败了、期望什么、实际什么、相关代码在哪」,比塞一大坨噪声更省 token 也更准。每轮只聚焦当前最相关的失败,避免上下文随轮次膨胀。
追问 3:如果项目本身没有测试,自动修复循环还能成立吗?
能成立但信号会弱很多,要补「替代判据」。最低限度可依赖编译/构建是否通过、类型检查与 lint 是否干净、程序能否正常启动运行而不抛异常。更进一步,可以让模型在修复前先为目标行为补写一批测试用例(characterization/回归测试),把「主观正确」转化为「可机读的客观判据」,再进入循环。没有任何可验证信号时,自动修复退化为开环生成,质量无法保证——此时应至少加人工确认环节,而不是盲目自动合并。
🔗 相似问题
同一考点的不同问法,面试官可能换着问,一起刷更稳
没找到想看的面试题?把你想看的告诉我们 →
延伸学习
按主题分类的相关资源,便于系统复习