我告诉了AI入口,为什么它还是改错了?——AI编程工具的真实使用心得

一个真实的故事

前几天,我在改一个绑卡功能的异常处理问题。

用户反馈说:绑卡失败时永远只提示“绑卡签约申请失败”,没有任何具体原因。我很快定位到问题在调用链的第四层——一个底层Client的catch块把原始异常信息吞掉了,抛出了一个硬编码字符串。

我想,这不正好用AI来改吗?于是打开了Cursor,输入:

“绑卡失败时抛出具体失败原因,入口是 /api/userBank/bindApply”

结果让我很失望。AI直接把全局异常处理器改了,加了一段统一返回“绑卡失败”的逻辑。我想要的底层修改,它一点没动。

我不信邪,又试了Kiro、Copilot Chat,结果惊人地一致——所有AI都选择了改全局异常处理器

为什么?我已经告诉它入口了啊,它顺着调用链往下找,不就发现问题在第4层了吗?

问题出在哪?

我花了一整天反复试验,终于想明白了。

误区1:“入口”这个词的含义不一样

对我来说,“入口”意味着:从这个API开始,深度优先遍历整个调用链,直到第三方接口。

但对AI来说,“入口”只是:找到了Controller里的那个方法,然后——停下来了

AI面临一个它无法解决的困境:追多深才算够?

  • 追到Service层?够不够?
  • Service调了另一个Service,要不要继续?
  • 追到Client层?这是不是底了?
  • Client里发HTTP请求,要不要追到网络层?

AI不知道答案。它的设计哲学是:追一层,停下来等用户反馈。用户不说“继续”,它就不动。

误区2:我以为AI会“主动探索”

我以为AI会像人一样,遇到问题就顺着调用链往下挖,直到找到可疑的地方。

但AI不是这样的。AI是懒惰的——不是态度上的懒,而是设计上的保守。在没有明确指令的情况下,它会选择改动最小、风险最低的方案。

改全局异常处理器,只改一个文件,影响面可控,逻辑简单。这是AI眼中最“安全”的答案。

改底层Client的catch块,需要:

  1. 找到那个文件
  2. 理解异常处理逻辑
  3. 修改后确认不影响上层
  4. 可能还要改多层调用

风险大、改动多,AI天然排斥这种方案。

误区3:我高估了AI的“调用链追踪”能力

这是最核心的问题。AI根本不会主动追踪调用链

它的工作方式是:你给它5个文件,它就分析这5个文件。你给它1个入口,它只看那个入口所在文件的直接调用,不会递归地去看每个被调用方法的实现。

为什么?因为成本。

假设每个文件有500行代码,追一层需要读1个文件,追两层需要读3-5个文件,追三层需要读10+个文件。AI的上下文窗口有限,它不可能无限制地往下追。

更重要的是,大部分用户的真实需求并不需要追到底。AI选择了性价比最高的策略:先看第一层,用户不满意再说。

那我以后怎么用AI修bug?

经过这次折腾,我总结出了一套可行的协作模式。

核心原则:分析和修改分离

绝对不要让AI一次性完成“分析+修改”。一定要分成两步:

第一步:让AI分析,不改代码

不要改代码,只分析:
从入口 /api/userBank/bindApply 开始,帮我追踪完整调用链。
每一层列出:
1. 调用了什么方法
2. 异常是怎么处理的
3. 找出哪一层把具体异常信息丢掉了

AI会输出类似这样的分析:

第1层: UserBankController.bindApply() - 无异常处理
第2层: BankCardServiceImpl.deductPreBoundCard() - 捕获后重新抛出
第3层: BankPayService.sendSignRequest() - 捕获后抛IllegalStateException
第4层: BankPayClient.bindBankCardSms() - 捕获后抛"绑卡签约申请失败" ← 问题在这里

第二步:确认后,指导AI修改

确认问题在第4层。修改 BankPayClient.bindBankCardSms() 第95行:
把 throw new BusinessException("绑卡签约申请失败");
改成 throw new BusinessException("绑卡失败:" + e.getMessage(), e);

实战模板

我总结了三个实用模板,覆盖不同场景:

模板1:分析调用链

不要改代码,只分析。
入口:[API路径]
请列出完整调用链(至少5层),标注每层的异常处理方式。
找出具体异常信息在哪一层丢失的。
分析完停下来,等我确认。

模板2:搜索定位

搜索“[具体错误信息字符串]”,
找到抛出这个异常的位置,
告诉我文件名和行号。
不要改代码。

模板3:精准修改

修改 [文件名] 第[行号]行,
把 [原代码]
改成 [新代码]
不要改其他文件。

善用“追问”

AI分析不到位时,不要重新提问,直接追问:

你:追到第3层停了,继续往下追
AI:第4层是BankPayClient.bindBankCardSms()
你:再追,看这个方法里调用了什么
AI:调用了sendRequest(),里面catch了异常
你:好,就改这个catch块

你不需要自己读代码,但需要会追问。 AI帮你读,你来判断方向。

不同AI工具的对比

我测试了三个主流工具,感受如下:

工具 优点 缺点 适合场景
Cursor 代码理解能力强,支持多文件编辑 Agent模式容易过度修改 复杂重构(需严格review)
GitHub Copilot 保守、可控,不会擅自改代码 多文件能力弱 日常编码、小范围修改
Kiro 界面友好,免费 调用链追踪能力一般 学习和探索

我的最终选择是双持

  • 日常用 Copilot(补全、问答、小修改)
  • 复杂重构用 Cursor,但关掉自动执行,每次都人工review diff

写在最后

这次经历让我明白了一个道理:

AI编程工具不是“自动驾驶”,而是“导航仪”。

  • 导航仪会告诉你路怎么走,但方向盘还在你手里
  • 导航仪可能选错路,你需要判断要不要听它的
  • 导航仪不知道你的目的地是哪个门,你需要明确告诉它

不要指望AI一次性搞定所有问题。把它当成一个24小时在线的、会写代码的、但需要你不断引导的搭档。

用对了方法,它能让你的效率提升10倍。用错了方法,你会花更多时间在“纠正AI的错误”上。

最后送你一句话:

不要让AI当侦探,让它当工匠。你告诉它钉子在哪,它帮你敲。你让它自己找钉子,它就会敲错地方。


希望这篇博客能帮你少踩一些坑。如果你也有类似的经历或更好的方法,欢迎交流。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐