同一个 Bug,AI 已经改了三轮。
原来的问题还在,旁边两个功能又坏了。
这个时候继续说“接着修”,往往就是项目真正失控的开始。
因为连续几轮都没解决,说明前面的原因判断、修改位置或者验证方法,至少有一项出了问题。
它可能还没找到最先出错的位置,也可能找到了现象,却把代码改在了不真正负责这件事的地方。
你再催,它就会继续加判断、加兼容、加绕路。
Bug 还在,代码先被补丁糊满了。
一天一个 vibe coding 小技巧。
今天就讲清楚,同一个问题反复修不好时,怎么让 AI 真正停下来查原因。

一共四步,每一步该说的原话,我都直接给你。想要整理好的完整版,看到最后我告诉你怎么拿。
一、先说清楚,什么时候该踩这脚刹车
先说清楚这个“三”。
它不是什么强制标准,但也不是我一个人的习惯。
国外做 AI 编程的人给这种状态起了个名字,叫死亡循环。普遍的建议就是:同一个问题让 AI 改到第三次还没好,就别再让它试了。
道理很朴素。连续三轮都没解决,说明它对原因的判断从一开始就错了,再来第四次,只是换个写法继续碰运气。
那什么才算一轮?
一轮完整的处理,至少包含三件事。
AI 提出一个明确原因,针对这个原因完成一次修改,再重新走一遍原来会出错的过程。
如果问题仍然存在,这才算一轮失败。
同一个问题连续三轮还是没解决,我就不再允许它继续试。
有时还没到三轮,也该提前停。
比如每改一次,都会让新的功能跟着坏掉。
或者 AI 已经说不清前几次为什么失败,只是在换一种写法继续碰运气。
这些现象都说明,局部修改已经失去方向。
这时候最不能说的,就是“不管用什么办法,先给我修好”。
目标压得越死,AI 越容易为了交差,先把报错藏起来。
藏起来长什么样?它可能在出错的那一段外面裹一层,让程序即使失败也不吭声;也可能干脆把那个报错提示删掉,页面上换成一句“加载中”。
你一看,红字没了,以为修好了。
实际上那一步根本没跑成功,只是从“报错”变成了“悄悄失败”。
等你发现的时候,往往是用户来问,我的订单怎么一直没提交上去。
页面暂时不报错,不等于真正的问题已经解决。
所以踩下刹车的第一句话,不是“接着修”,而是让它先停手:
「停止一切代码修改,本轮不再以“先把功能做出来”为目标追加补丁、兼容分支和绕行逻辑。」
二、第一步:换个新对话,再补一份真源
停手之后,还有个动作很多人不知道要做:把当前这个对话关掉,重开一个。
因为聊到这会儿,这个对话里已经堆满了三轮失败的尝试、被推翻的判断,还有你们互相矛盾的指令。
AI 每次回答都会把前面这些一并读进去。
它于是被自己错过三次的判断带着走,你越催,它越是在那条错路上打转。
换个新对话,等于把这些干扰全部清掉。
代价只是你要把必要的信息重新交代一遍——而下面这几步,正好就是在交代这些。
新对话开好,第一件事不是让它查。
它得先知道这个功能原本应该做成什么样。
当前阶段要完成什么,哪些行为不能改变,页面、接口和数据之间怎么配合,什么结果才算通过。
这些东西写下来,就是当前阶段的真源。
它不是拿来限制排错的死答案。
而是让 AI 在检查现有代码时,知道哪些地方已经偏离了原来的设计。
如果你只说了两句话就让 AI 开始干,需求和边界一直靠它猜,那项目越改越乱并不意外。
但也不用因为过去没写文档,就把整个项目扔掉。
让它根据已经确认的需求、现有代码、真实运行结果和 Git 记录,把当前阶段重新整理出来:
「依据现有需求文档、阶段记录、当前代码、真实运行结果和 Git 历史,重建该功能当前阶段的真源。内容包含:本阶段要解决的问题、正常流程的预期运行路径、不得变更的现有行为、判定完成的验收标准。」
这里还要追一句,不然它会把猜的和真的混在一起写给你:
「逐项区分三类内容:已由文档与代码互相印证的事实、文档与代码存在冲突之处、需要我确认的开放问题。本轮只交付阶段真源,不进入缺陷修复。」
哪些是你明确要求过的,哪些是代码现在真的在做的,哪些只是它的推测,必须分开。
你确认这份真源,才进入下一步。
三、第二步:把现象钉死,再翻出前三轮
真源确认以后,才开始查。
这一步只干两件事:把问题钉死,把老账翻出来。
先说钉死。
最好能找到一套固定操作,让问题每次都出现。正常结果该是什么,实际又发生了什么,一并写清楚。
「先固定复现路径:写明操作步骤、预期结果和实际结果。本轮不修改任何代码。」
但有些问题不是每次都犯。
它可能挑时间、挑数据,也可能网络一抖或者第三方服务一故障才出来。
这时候最怕 AI 为了凑“稳定复现”,给你编一条根本没发生过的路径。
所以要补一句:
「无法稳定复现时,记录发生时间、操作步骤、输入数据、运行环境、发生频率和相关日志,另外定义一套修改前后都能重复执行的观察标准,不得以虚构的复现路径充当稳定复现。」
观察标准就是:连续运行多少次,出现什么日志、什么返回结果或者什么页面现象,就算问题又犯了。
这样即便它不是每次都出现,修改前后仍然有同一把尺子可以比。
接着是翻老账。
前三轮改了什么,必须全部摆出来:
「列出前三轮各自的原因判断、修改内容、验证结果,以及未能解决的原因。」
这一步很重要。
它能阻止 AI 把已经失败过的办法,换个说法再做一次。
老账翻完,再让它顺着整条链路找第一个出问题的地方:
「围绕当前问题审计完整调用链,定位第一个可观测到异常的边界,用它收敛排查范围。该边界不等同于根因,异常在何处产生仍需由证据判定。」
举个例子。页面提交的数据本来是对的,到了接口以后才变错,那就继续查接口。
如果接口返回已经正确,页面显示时才出问题,就不该转头去改数据库。
注意最后那半句:找到这个位置,只是把范围缩小了。
它告诉你问题最早在哪里露出来,还不能证明这一层就是根因,更不能马上把责任推给这一层。
四、第三步:逼它拿出根因,别信“听起来很合理”
查到可疑位置以后,AI 往往很快就说“已经找到根因了”。
先别急着信。
有些问题只有一个原因。
还有些问题,是特定数据、程序状态、网络或者第三方服务碰到一起才会出现。
所以它找出来的,可能是一个原因,也可能是一组缺一不可的原因。
不管哪一种,你都用同一把尺子卡它——同时解释三件事:
「根因必须同时解释三点:为什么出现当前症状、为什么最早在这个位置观测到异常、为什么前三轮修改都没有解决。三点不能同时解释的,不得宣布根因成立。」
只解释其中一个,它仍然只是猜测。
光有这一句还不够,得让它把所有可能摆到台面上:
「建立原因假设表,每条假设列出支持证据、反证、下一步排除方法和当前状态。判定为多条件共同触发的,列出该组条件,并设计逐个移除条件的验证方法。」
逐个拿掉一个条件看问题消不消失,才能判断这些条件是不是真的缺一不可,而不是碰巧一起出现。
如果问题涉及框架、依赖或者第三方服务,还要让它去核对官方说法:
「核对当前版本的官方文档、变更日志,以及 GitHub 上已确认的问题和修复讨论。」
接下来是这一步里最容易被跳过的一件事,也是最省钱的一件事。
支付、短信、AI、地图、文件存储这些能力,并不完全跑在你的项目里。
你的程序只是把请求发到服务商那边。
所以功能突然失败,问题不一定出在你的代码。
服务商可能正在故障。也可能是账号被停用、余额或额度用完、密钥失效、允许访问的域名或 IP 变了,又或者请求次数已经到上限。
可 AI 眼前看见的,往往只是自己程序里的一次调用失败。
它要是默认问题一定在代码里,就会反复改参数、换接入工具、加重试。
外面的故障没消失,自己本来跑通的接入代码反而被改乱了。
所以在它动第三方接入代码之前,先让它给你一张你自己去点的清单:
「将服务商侧故障单独列为一条原因假设,并输出一份由我手动执行的检查清单,覆盖管理后台中的服务状态、账号状态、余额或额度、密钥权限、域名与 IP 访问限制、请求频率限制、准确错误码、故障时间和可见的服务商日志;服务商提供官方状态页面的,一并给出查看位置。我只回传检查结论和已脱敏的错误信息,不提供密钥原文。上述核对完成之前,不修改第三方接入代码。」
这张清单你自己打开后台,一条条看过去就行,不需要懂代码。
这一步的最后,才轮到方案:
「只输出一份针对已证实原因、可验证的最小修复方案,写明变更位置、判定这些位置应当负责的依据、必须保持不变的功能,以及问题已解决的证明方式。同一原因确需跨文件调整的,可归入同一修复单元;本单元范围以外的问题不处理。本轮不修改代码,经我确认后再实施。」
方案看不懂,就让它用大白话重讲一遍。
如果它连“为什么前三轮都失败”都说不清楚,这份方案还不够让你点头。
五、第四步:只改证实过的那一处,改完自己验
方案确认了,也不是放开让它随便改。
动手之前先存个退路。
让它列出准备保存的文件、还没提交的修改,以及没被 Git 记录的文件,把存着真实密钥和配置的文件、生产数据、用户信息和不该进仓库的日志排除掉,再存一个能退回来的检查点。
当前这版本来就有毛病,就明确标成“问题修复前”,别假装它是个稳定版本。
改之前,还要先把“坏的样子”留下来。
跑一遍原来的复现过程,或者按前面定好的观察标准跑一轮,把失败结果存下来。
不然改完你没有对照物,只能听它说“好了”。
这两件事加上后面的验证,可以一次说完:
「执行已确认的最小修复方案,不扩大变更范围。先核对 Git 状态,列出待提交与待修改的文件,排除存放真实密钥和配置的文件(具体文件名按本项目所用框架的约定判定)、生产数据、用户信息和日志,随后创建一个标注为“问题修复前”的检查点。
修改前先执行已确认的复现流程;无法稳定复现时,按观察标准留存修改前证据。
变更范围限于已证实原因确需调整的位置,不顺手整理无关代码,不顺手重做周围功能。
修改完成后重新执行完全相同的复现流程或观察标准,再验证本次改动可能波及的正常功能。
将修改前后的证据、受影响功能的验证结果和实际变更内容写回审计文档。
任一项未通过即停止追加补丁,携新证据返回原因假设表重新判定。」
最后那句是这一步的关键。
原来的错误消失了还不算完,还要看这次改动有没有把别的地方带坏。
只有原问题通过、受影响的功能也正常,这次修复才算成立。
如果结果还是不对,就把新证据补回文档,回到假设表重新判断。
不能假装前面那个根因判断没发生过,让它接着往代码上堆东西。
六、最后
一个 Bug 难修,不代表整个项目都不行。
真正危险的,是你和 AI 一起进入“再试一次”的循环。
改一次,猜一次。
再坏一个地方,就再补一层。
最后谁都说不清,项目为什么还能运行,又为什么随时可能出问题。
三轮以后停下来,不是认输。
是把“碰运气改代码”,重新变成“拿证据解决问题”。
那四步你记住顺序就行:
第一步,让它停手,换个新对话,先补一份真源。
第二步,把现象钉死,翻出前三轮失败记录。
第三步,逼它拿出能同时解释三件事的根因,还要先排除服务商那边的问题。
第四步,只改证实过的那一处,改完自己验一遍。
当你学会在 AI 乱试以前踩下刹车,难缠的 Bug 就不再只能靠运气解决。