文章建议先要求AI复现失败并收集根因证据,再修改代码。搜索结果被旧请求覆盖的案例说明,防抖可能降低故障频率,却不能解决响应乱序。
你把一条报错粘贴给 AI 助手。
它修改了一个条件,加了一次空值检查,又把某段代码包进 try/catch。
报错消失了。
但你知道它为什么会发生吗?又能确定这次修改真的解决了问题吗?
这就是让症状消失与理解 bug 之间的区别。
更好的起手 prompt 是:
“先不要改代码。帮我复现故障,并找到能证明其原因的证据。”
下面,我们把这个思路变成一套实用的调试流程。
假设用户输入新的搜索词后,你的应用偶尔会显示旧的搜索结果。
你让 AI 修复它。
它建议加上 debounce。
这听起来很合理。搜索输入框经常会用 debounce。减少请求次数,甚至可能让问题看起来没那么容易出现。
但看看下面这个执行顺序:
User searches for "react"
Request A starts
User searches for "react testing"
Request B starts
Request B finishes → correct results appear
Request A finishes → old results overwrite them
问题在于,响应没有按请求发起的顺序返回。
debounce 减少的是请求发起的频率。它并不能保证最新发起的请求最后完成。
一个看似合理的修复,可能让真正的 bug 原封不动地留在那里。
“搜索坏了”给助手留下了太多猜测空间。
先说清楚你观察到的现象:
Expected:
Results should match the current search query.
Actual:
Sometimes results from an earlier query replace the latest results.
Trigger:
Type one query, then quickly change it.
Frequency:
Intermittent. Easier to reproduce with a slow connection.
然后提供相关代码,并提出要求:
Do not edit anything yet.
Using the observed behavior and this code:
1. List up to three possible causes.
2. Separate observed facts from assumptions.
3. Explain what evidence would support or reject each cause.
4. Suggest the smallest reproduction.
这样,你得到的是有待调查的假设,而不是一个需要你直接相信的补丁。
间歇性 bug 难处理,是因为你无法可靠地比较修改前后的表现。
对于搜索这个例子,可以强制让较早发起的请求更晚完成:
const delay = (ms) =>
new Promise((resolve) => setTimeout(resolve, ms));
async function fakeSearch(query) {
await delay(query === "react" ? 800 : 100);
return [`Result for ${query}`];
}
先搜索 "react",稍后再搜索 "react testing"。
如果你的 UI 在每个响应到达时都直接应用结果,旧结果就会覆盖新结果。
现在,你有了一个可控的复现案例。
Help me create a minimal reproduction.
Control timing or inputs where necessary.
Keep the suspected failure mechanism intact.
Explain what this reproduction demonstrates
and what it does not establish.
复现案例说明,某种机制能够导致这个故障。但要把它与你实际遇到的问题联系起来,你仍然需要真实应用中的证据。
随意添加日志只会制造噪声。
有用的日志应该回答一个具体问题。
对于这个 bug,在每次请求发起、完成以及更新 UI 时,记录搜索词和请求 ID:
START id=41 query="react"
START id=42 query="react testing"
FINISH id=42 query="react testing"
APPLY id=42 query="react testing"
FINISH id=41 query="react"
APPLY id=41 query="react"
这段记录支持一个具体解释:较旧的响应在较新的响应之后更新了 UI。
What is the smallest amount of instrumentation
needed to distinguish these hypotheses?
For each log or measurement, explain:
- What question it answers
- Which hypothesis it could reject
Avoid logging secrets or personal data.
目标是减少不确定性,而不是把控制台塞满。
接受补丁之前,让助手把证据与故障联系起来。
Explain the causal chain using the reproduction,
logs, and relevant code.
Identify:
1. The triggering event
2. The incorrect behavior
3. The missing safeguard
4. How that produces the visible failure
State anything that remains uncertain.
用户发起了两次搜索。
两个请求都还在执行。
较早发起的请求最后完成。
代码没有检查这个请求是否仍对应当前搜索,就直接应用了它的结果。
UI 显示了过时的结果。
这个解释为修复指明了目标。
“API 很慢”还不够。慢 API 让问题暴露出来;缺少响应顺序保护,才让问题得以发生。
在一个简化的搜索控制器中,请求计数器可以阻止过时的响应更新结果:
let latestRequestId = 0;
async function search(query) {
const requestId = ++latestRequestId;
const results = await fakeSearch(query);
if (requestId !== latestRequestId) {
return;
}
renderResults(results);
}
只有最新一次搜索才能应用自己的结果。
在真实应用中,应把这个计数器放在相关组件或控制器内部。同时检查加载状态、错误处理、清空输入框以及组件清理等情况。
现在,给 AI 换一个任务:
Try to find a counterexample to this fix.
Check:
- An older request finishing last
- The latest request failing
- The input being cleared during a request
- The component being destroyed during a request
Explain which cases the patch handles
and which still need work.
这正是 AI 特别有用的地方:帮助你挑战一个方案,而不只是生成一个方案。
修改后能够通过的测试是有用的。
一个修改前失败、修改后通过的测试,则能提供更有力的证据,说明你确实解决了已经复现的故障。
对于这个例子,测试应该:
测试中应使用可控的 Promise,而不是随意设置延迟。
并且,由你自己定义预期行为:
Write a regression test for this requirement:
Once a newer search starts, an older response
must not replace its results.
Control request completion order explicitly.
The test must fail against the original implementation
and pass against the proposed fix.
测试应该由需求驱动。什么才算“正确”,不应该由实现来定义。
下次某个 bug 让你陷入反复应用 AI 生成补丁的循环时,可以使用这个 prompt:
Help me investigate this bug. Do not modify code yet.
Expected behavior:
[describe]
Actual behavior:
[describe]
Reproduction steps:
[list]
Relevant code and evidence:
[paste]
Please:
1. Separate facts from assumptions.
2. Rank up to three hypotheses and explain why.
3. Propose the smallest experiment to distinguish them.
4. Identify any missing evidence.
5. Explain the causal chain once evidence supports it.
6. Then suggest the smallest fix and a regression test.
Do not claim the cause is confirmed without evidence.
If you cannot run an experiment, say so.
你不需要为每一个拼写错误或明显的语法错误都做一番漫长调查。
但当一个 bug 偶发、反复出现,或者影响重要功能时,再打一个快速补丁的成本,可能比做一个小实验更高。
接受下一个 AI 修复之前,先问自己:
让 AI 帮你建立对修复的信心,而这份信心要有依据。
你遇到过什么 bug,最初那个“显而易见的修复”最后却被证明是错的?欢迎在评论区分享它的症状,以及真正的原因。
部分评论可能仅对已登录的访客可见。登录后即可查看全部评论。
如果需要进一步采取措施,你可以考虑屏蔽此人和/或举报滥用行为。