我把一个生产Bug的排查过程,交给AI处理——20分钟后我关掉了它

0 阅读9分钟

上周四下午四点半,距离下班还有半小时。

监控告警突然炸了。

[ERROR] 2026-03-03 16:32:07 OrderService - 订单创建失败
java.lang.NullPointerException: Cannot invoke "String.length()" because "str" is null
    at com.xxx.service.OrderService.createOrder(OrderService.java:87)
    at com.xxx.controller.OrderController.create(OrderController.java:43)

用户在投诉:下单页面一直转圈,提交不了。

我打开钉钉,看了一眼错误率:3分钟内,下单接口报错率从0.1%飙到了38%。

这不是小事。

以前遇到这种情况,我的第一反应是:打开IDEA,连日志,开始逐行看堆栈。

这次,我做了一个不一样的决定:

把整个排查过程,交给AI来主导。

我想看看,AI到底能做什么,不能做什么。

结果出乎我意料。


第一步:把现场信息喂给AI(3分钟)

我把能拿到的信息全部复制给Claude:

生产环境告警,请帮我分析:

错误日志:
[ERROR] OrderService - 订单创建失败
java.lang.NullPointerException: Cannot invoke "String.length()" 
because "str" is null
    at OrderService.createOrder(OrderService.java:87)

监控数据:
- 报错开始时间:16:32
- 报错率:38%(3分钟内从0.1%飙升)
- 影响接口:POST /api/order/create
- 其他接口正常

最近变更:
- 今天14:00,发布了一个版本,主要改了优惠券模块

请帮我分析:
1. 可能的原因是什么?
2. 排查思路是什么?
3. 需要我提供哪些额外信息?

AI的回答很快,而且超出了我的预期:

初步判断: NullPointerException发生在OrderService.java第87行,str为null。 结合变更信息(优惠券模块),推测最可能的原因:

高概率(70%): 订单创建时调用了优惠券相关逻辑,优惠券码为空时没有做null检查, 直接调用了str.length()。

中概率(20%): 优惠券模块的修改引入了新的数据库字段或配置,但生产环境未同步, 导致查询结果中某个字段为null。

低概率(10%): 并发问题,多线程场景下对象状态被意外清空。

需要你提供:

  1. OrderService.java第87行的代码片段
  2. 今天14:00发布的具体diff
  3. 报错的请求参数(用没有填优惠券的订单试一下,是否复现)

我愣了一下。

AI给出了概率排序,还知道要让我用不填优惠券的订单复现——这是个老手才会想到的排查动作。

我立刻试了:不带优惠券码下单,正常。带优惠券码下单,报错。

问题范围直接锁定。


第二步:AI读懂代码,指出真正的问题(5分钟)

我把第87行前后的代码片段给了AI:

// OrderService.java 第80-95行
public OrderDTO createOrder(CreateOrderRequest request) {
    // 计算优惠金额
    BigDecimal discountAmount = BigDecimal.ZERO;
    if (request.getCouponCode() != null) {
        CouponDTO coupon = couponService.getCouponByCode(request.getCouponCode());
        // 第87行:
        if (coupon.getDiscountType().equals("PERCENTAGE")) {
            discountAmount = request.getTotalAmount()
                .multiply(coupon.getDiscountValue())
                .divide(new BigDecimal("100"));
        } else {
            discountAmount = coupon.getDiscountValue();
        }
    }
    // ...
}

AI的分析:

找到了。

第87行问题:coupon.getDiscountType() 返回null,导致 .equals() 抛出NullPointerException。

根本原因: couponService.getCouponByCode() 查不到优惠券时,没有返回null, 而是返回了一个空的CouponDTO对象(字段全为null)。

这是今天14:00发布的那次修改引入的:之前这个方法在找不到优惠券时 直接抛异常,新版本改成了返回空对象,但调用方没有同步修改。

修复方案(两种):

方案A(快,适合紧急修复):

CouponDTO coupon = couponService.getCouponByCode(request.getCouponCode());
if (coupon == null || coupon.getDiscountType() == null) {
    throw new BusinessException("优惠券不存在或已失效");
}

方案B(正确,适合根本性修复): 在couponService.getCouponByCode()里,查不到时直接返回null而不是空对象, 调用方统一判断null即可。这样语义更清晰,避免以后再踩同类坑。

建议: 先用方案A紧急修复,发版止血。问题恢复后再做方案B的根本修复。

我看完这段分析,立刻去翻了14:00的发版diff。

找到了。一模一样。


第三步:AI做的事,和AI做不到的事

这时候,我停下来,认真想了一下这20分钟发生了什么。

AI做到的:

  • 根据日志和上下文,在3分钟内给出了有概率权重的排查方向
  • 读懂了代码,准确定位了真正的根因(不是第87行,而是getCouponByCode的返回值设计)
  • 给出了两种修复方案,区分了"救火"和"根本修复"的优先级
  • 全程逻辑清晰,没有废话

换句话说:AI把我过去要花40分钟做的"分析和推理"部分,压缩到了5分钟。

AI做不到的:

但整个过程,有几件事AI完全帮不上:

第一,它不知道下午14:00发布了什么。

是我主动把"今天14:00发版,改了优惠券模块"这条信息喂给它的。如果我不说,AI只能对着日志猜。

这条信息,在我们团队的钉钉群里,不在任何日志里。AI看不到。

第二,它不知道这个bug的业务影响程度。

报错率38%看起来很高,但我知道这38%里,大多数是同一批用优惠券的测试用户在反复重试。真实影响的用户可能只有几十个,不需要立刻回滚,发一个hotfix就够了。

这个判断,需要对业务的理解,AI没有。

第三,紧急修复之后,它不知道要通知谁。

hotfix发完,我要给客服发一条话术让他们安抚用户,要给运营说一声下午的优惠券活动暂停推送,要给老板发一条简报说明事故原因和处理结果。

这些"人的工作",AI都不在场。


一个真实的数据对比

我把这次排查过程,和3个月前一次类似的线上问题做了对比。

3个月前(纯手工排查):

16:32  告警触发
16:35  确认报警不是误报
16:40  登上服务器查完整日志
16:55  根据堆栈找到出问题的代码
17:10  翻git log,找到引入问题的commit
17:25  确认根因,讨论修复方案
17:40  hotfix发版
17:50  确认恢复

总耗时:78分钟
我的状态:肾上腺素爆表,下班时精疲力竭

这次(AI辅助排查):

16:32  告警触发
16:35  整理现场信息,喂给AI
16:38  AI给出排查方向,立刻验证复现路径
16:43  把代码片段给AI,AI定位根因
16:48  确认根因,AI给出修复方案
16:55  hotfix发版
17:02  确认恢复

总耗时:30分钟
我的状态:焦虑感明显低,因为排查过程有逻辑,不是乱撞

时间缩短了一半,更重要的是:排查过程有了结构。

以前我排查问题靠的是直觉和经验,走哪条路全凭感觉。AI做的事,是帮我把"可能的原因"显式地列出来,每条都有概率,每条都有验证方法。

这个思路,让我少走了很多弯路。


3个用AI排查生产问题的实战技巧

用了几次之后,我总结出了一套固定的喂料方式。

技巧1:现场信息要"四件套"

喂给AI的信息,要包含这四样:

1. 完整的错误日志(包含堆栈,不要只截图)
2. 监控数据(报错率、报错时间、影响范围)
3. 最近的变更记录(最近一次发版改了什么)
4. 复现路径(能不能复现,怎么触发)

缺了任何一样,AI的分析质量会大幅下降。

信息越完整,AI越像一个刚接手这个项目的高级工程师。

信息不完整,AI就只能对着日志猜,给你一大堆"可能是A也可能是B也可能是C",完全没用。

技巧2:让AI给出概率排序,而不是所有可能性

很多人拿到AI的分析,发现列了七八条"可能的原因",不知道先查哪个,最后还是一头雾水。

改一下Prompt:

"这个报错可能是什么原因?""这个报错最可能的原因是什么?
   按照可能性从高到低排序,
   每条说明为什么你认为概率高,
   以及怎么验证。"

这样AI给你的是一个"排查顺序",而不是一张所有可能性的清单。

技巧3:让AI区分"救火"和"根本修复"

线上出问题的时候,你同时有两个目标:

  • 立刻止血:让报错停下来,用户能正常使用
  • 根本修复:找到问题根源,避免下次再出

这两个目标,有时候解决方案不一样。

在这次案例里,方案A(加null判断)可以1分钟写完马上发版,方案B(修改getCouponByCode的返回值设计)才是真正解决根源,但影响面更大,需要更多测试。

让AI明确区分这两种方案:

"请给出两种修复方案:
一种是最快能止血的临时方案,
一种是从根本上解决问题的正确方案,
说明各自的优缺点。"

这样你可以先发临时方案止血,下班之后再做正确方案。


写在最后

用AI排查这次Bug之后,我想清楚了一件事。

AI在这个场景里,扮演的不是"解决问题的人",而是"帮你结构化思考的人"。

我以前排查问题,靠的是12年积累的直觉:看一眼日志,凭经验猜几个方向,然后一个个验证。

这套方法有效,但效率取决于"今天直觉准不准"。

AI做的事是:把我脑子里隐性的排查逻辑,变成了显性的步骤。

你喂给它的信息越完整,它给你的推理就越准确。它不替你做决定,但它让你的决定过程更有据可依。


但有一件事我想说清楚:

AI排查问题的能力上限,取决于你给它的信息质量。

这次我能快速定位问题,不是因为AI多厉害,而是因为我知道要把"14:00发版改了优惠券模块"这条信息告诉它。

这条信息,是我从钉钉群里看到的,从团队协作里知道的,是12年工作经验给我的习惯——出了问题,第一件事是看最近有没有发版。

AI不知道这条信息。是我喂给它的。

AI是放大镜,不是眼睛。

你先得看到,它才能帮你放大。


你们遇到生产问题,有没有试过用AI辅助排查?效果怎么样?

欢迎评论区分享你的经历。


后端AI实验室 不讲概念,只谈实战 代码开源,每周更新

扫码_搜索联合传播样式-标准色版.png