线上接口变慢最怕的是现象很明显原因却很散。最近处理过一次类似问题一个订单列表接口在高峰期偶发超时监控上看 P95 从 300ms 涨到 2s 以上但错误率不高应用也没有直接报错。业务同学的反馈是“有时点进去很慢”运维侧看到 CPU 没有打满数据库慢查询也不是每次都有。这类问题如果只靠经验很容易陷入几个方向之间来回切是不是 SQL是不是缓存是不是下游接口是不是线程池是不是 GC我这次没有直接把生产日志丢给 AI也没有让它“帮我定位根因”。更稳的做法是先脱敏、裁剪再让模型帮忙做日志归类、假设生成、排查顺序整理最后所有结论都回到监控、压测和代码验证上。下面记录一下完整过程。它不依赖某个特定模型ChatGPT、Claude、Gemini、DeepSeek 这类文本模型都可以参与差别主要在总结风格、长上下文处理和代码解释能力上。问题背景接口不报错但 P95 抬高项目是一个常见的 Spring Boot 服务接口大概长这样javaGetMapping(/orders) public PageResultOrderVO listOrders(OrderQuery query) { return orderService.listOrders(query); }订单列表会做几件事查订单主表批量查用户信息查询每个订单的优惠状态调用库存服务补充部分商品状态组装返回给前端。老实说这种接口在业务系统里很常见看起来只是列表查询背后却拼了好几个数据源。平时访问量不大时没问题一到高峰就容易暴露边界。监控上的现象是text接口GET /orders 平均耗时260ms - 580ms P95320ms - 2100ms P99600ms - 4800ms 错误率基本不变 发生时间10:00 - 11:30 较明显单看这几行还不能判断是数据库、外部服务还是应用内部排队。这个阶段最容易犯的错是拿着一段日志问 AI“这个问题是什么原因”模型会给出很多可能性但大多只是经验枚举没法直接落地。所以我先做了第一件事把问题材料整理成固定格式。先准备可分析的输入而不是直接贴一坨日志原始日志里有用户 ID、订单号、手机号片段、内部服务名、TraceId、真实 IP 等信息不能直接拿去给模型分析。我做了几类处理用户 ID 改成USER_001这类占位符订单号改成ORDER_001内部域名和服务名改成service-a、service-bIP、Token、Cookie 全部删除只保留时间戳、耗时、调用阶段、状态码、线程名每类日志只保留 510 条样本不整段复制。脱敏后的样例类似这样text2025-xx-xx 10:12:03.421 INFO [http-nio-8080-exec-42] traceT001 api/orders stepquery_orders cost85ms 2025-xx-xx 10:12:03.538 INFO [http-nio-8080-exec-42] traceT001 api/orders stepquery_users cost32ms 2025-xx-xx 10:12:04.912 INFO [http-nio-8080-exec-42] traceT001 api/orders stepquery_coupon cost1310ms 2025-xx-xx 10:12:05.101 INFO [http-nio-8080-exec-42] traceT001 api/orders stepcall_inventory cost180ms 2025-xx-xx 10:12:05.120 INFO [http-nio-8080-exec-42] traceT001 api/orders stepassemble cost15ms 2025-xx-xx 10:12:05.122 INFO [http-nio-8080-exec-42] traceT001 api/orders total1701ms status200 2025-xx-xx 10:15:44.201 INFO [http-nio-8080-exec-17] traceT002 api/orders stepquery_orders cost91ms 2025-xx-xx 10:15:44.266 INFO [http-nio-8080-exec-17] traceT002 api/orders stepquery_users cost28ms 2025-xx-xx 10:15:44.301 INFO [http-nio-8080-exec-17] traceT002 api/orders stepquery_coupon cost30ms 2025-xx-xx 10:15:46.662 INFO [http-nio-8080-exec-17] traceT002 api/orders stepcall_inventory cost2310ms 2025-xx-xx 10:15:46.683 INFO [http-nio-8080-exec-17] traceT002 api/orders stepassemble cost13ms 2025-xx-xx 10:15:46.684 INFO [http-nio-8080-exec-17] traceT002 api/orders total2483ms status200这里故意保留了两类慢请求一个慢在优惠查询一个慢在库存调用。真实排查时问题往往不是单点而是多个不稳定因素叠加。第一轮 Prompt只做归类不下结论我给模型的第一段提示词是text你是 Java 服务端性能排查助手。 下面是脱敏后的接口调用日志。请只做现象归类不要直接判断根因。 要求 1. 按 trace 维度整理每次请求的总耗时和最慢阶段 2. 统计哪些 step 经常出现在慢请求中 3. 区分“证据充分”和“需要补充数据”的部分 4. 不要编造日志中没有的信息 5. 输出一个排查优先级列表但每一项都要说明依据。 日志 {脱敏日志}这段 Prompt 里我刻意加了“不要直接判断根因”。因为性能问题最忌讳模型上来就说“可能是数据库索引问题”“可能是网络抖动”。这些当然可能但没有证据时只是猜。模型输出的有用部分大概是text观察 - T001 总耗时 1701ms其中 query_coupon 1310ms占主要耗时。 - T002 总耗时 2483ms其中 call_inventory 2310ms占主要耗时。 - query_orders、query_users、assemble 在样本中相对稳定。 - 慢请求并非集中在同一个 step但 query_coupon 和 call_inventory 都有明显尖刺。 证据充分 - 慢请求主要由某个下游步骤的耗时尖刺拉高。 - 应用自身组装阶段不是当前样本中的主要耗时。 需要补充 - query_coupon 是否对应数据库查询、缓存访问或内部 RPC - call_inventory 的超时配置、重试次数、连接池情况 - 慢请求是否与线程池排队有关 - 同时间段数据库连接池、HTTP 连接池是否接近上限。这一步的价值不是“找到答案”而是把混乱日志压缩成几个可验证方向。第二轮让 AI 帮忙设计排查顺序接下来我把已有监控指标也整理进去text补充信息 - 应用 CPU高峰期 45%60%未打满 - JVM GC无明显 Full GC - DB 慢查询偶发出现 coupon 表查询 1s - HTTP 客户端连接池暂无监控 - 库存服务调用 P95 同时段升高 - 订单主表查询 P95 稳定在 100ms 内。 请基于日志和补充信息给出排查顺序。 要求 1. 先排查最容易验证且影响最大的项 2. 每一步写清楚需要看什么指标 3. 不要给“优化代码”这种泛泛建议 4. 输出格式排查项、验证方法、可能结论、下一步。模型给出的排查顺序比我预期实用排查项验证方法可能结论下一步库存服务调用耗时看调用方和被调用方 P95/P99 是否同涨下游服务慢或网络/连接池问题加调用超时、熔断、连接池监控优惠查询慢 SQL查看 coupon 查询执行计划和索引命中部分条件未命中索引优化索引或拆查询HTTP 连接池补充 leased/pending/available 指标连接池排队导致尖刺调整连接池和超时策略DB 连接池看 active、idle、wait_count连接等待放大耗时调整池配置或降低慢查询应用线程池看 Tomcat busy threads、队列请求堆积限流或隔离慢依赖这张表可以直接拿去排查不是因为 AI “知道答案”而是它把每个方向和验证指标绑到一起了。第三轮拿代码片段让模型找“放大器”日志只能告诉我们哪里慢代码能告诉我们为什么慢会被放大。脱敏后的关键代码类似这样javapublic PageResultOrderVO listOrders(OrderQuery query) { PageOrder page orderRepository.queryPage(query); ListLong userIds page.getRecords() .stream() .map(Order::getUserId) .distinct() .collect(Collectors.toList()); MapLong, UserDTO userMap userClient.batchGetUsers(userIds); ListOrderVO result new ArrayList(); for (Order order : page.getRecords()) { CouponDTO coupon couponService.queryCoupon(order.getId()); InventoryDTO inventory inventoryClient.queryInventory(order.getSkuId()); OrderVO vo OrderVO.from(order); vo.setUser(userMap.get(order.getUserId())); vo.setCoupon(coupon); vo.setInventory(inventory); result.add(vo); } return PageResult.of(page.getTotal(), result); }这段代码里有一个很典型的问题用户信息做了批量查询但优惠和库存仍然在循环里逐条查。单次调用慢 100ms 时列表 20 条就是灾难。Prompt 我会这样写请阅读下面的 Java 代码分析它在接口性能上的风险点。 限制 1. 不要重写完整代码 2. 只指出可能导致 P95/P99 抬高的结构性问题 3. 区分“确定存在的问题”和“需要结合实现确认的问题” 4. 给出可验证的改造方向 5. 不讨论日志中没有出现的业务规则。 代码 {脱敏代码}模型通常能指出几个点couponService.queryCoupon(order.getId())在循环内调用可能形成 N 次查询inventoryClient.queryInventory(order.getSkuId())在循环内调用可能形成 N 次 RPC如果没有超时控制单个下游慢请求会拖住整个接口如果有重试重试会进一步放大尾延迟用户信息批量查了但优惠和库存没有批量化说明接口内部优化不一致。这些结论不复杂资深开发一眼也能看出来。但 AI 的价值在于它能在一堆代码和日志之间帮你把风险点整理成清单尤其适合接手不熟悉的老代码。第四轮改造不追求一步到位先做可回滚的小改动最后我们没有直接大改接口而是拆了几步。1. 先补监控给库存调用和优惠查询补充更细的指标javaTimer.Sample sample Timer.start(meterRegistry); try { return inventoryClient.queryInventory(skuId); } finally { sample.stop(Timer.builder(order.inventory.query) .tag(method, queryInventory) .register(meterRegistry)); }类似指标至少要能看到调用次数平均耗时P95/P99异常数超时数连接池等待情况。没有指标时所有优化都像是在猜。2. 再处理循环 RPC库存查询支持批量接口后代码改成javaListLong skuIds page.getRecords() .stream() .map(Order::getSkuId) .distinct() .collect(Collectors.toList()); MapLong, InventoryDTO inventoryMap inventoryClient.batchQueryInventory(skuIds); for (Order order : page.getRecords()) { InventoryDTO inventory inventoryMap.get(order.getSkuId()); // 继续组装 VO }优惠查询也类似尽量把逐条查询改成批量查询。如果暂时不能改下游接口至少要考虑本地短缓存、并发控制、超时降级而不是让列表接口串行等待。3. 明确超时和降级策略列表页通常不是强一致接口。库存状态、优惠展示如果短时间不可用可以考虑展示默认状态或部分降级但这要和产品、业务确认不能开发自己拍脑袋。示例javatry { return inventoryClient.batchQueryInventory(skuIds); } catch (TimeoutException e) { log.warn(inventory query timeout, skuCount{}, skuIds.size()); return Collections.emptyMap(); }这段只是示意。真实项目里要看业务是否允许空库存信息、前端如何展示、是否需要告警、是否影响下单链路。多模型在这个场景里怎么分工我不太建议在性能排查里纠结“哪个模型最懂 Java”。更实用的方式是分角色让一个模型做日志归类让另一个模型做代码风险点扫描再让第三个模型根据排查结果生成复盘文档最后由人把结论和监控证据对齐。不同模型的差异大概是ChatGPT流程化输出比较稳定适合整理排查步骤Claude长文本阅读体验好适合看较长的事故复盘或需求背景Gemini摘要速度快适合压缩日志片段和会议纪要DeepSeek中文技术表达自然适合把排查记录整理成团队文档Grok适合发散假设但结论更要回到证据验证。多模型交叉检查不是为了“投票”而是避免单一视角漏掉明显问题。真正的判断依据仍然是监控、日志、代码、压测结果。这类 Prompt 我会固定保存性能排查场景里Prompt 不需要写得很玄。关键是约束模型别乱猜。日志归类 Prompttext你是后端性能排查助手。 请分析下面的脱敏日志只做现象归类不直接下根因结论。 输出 1. 慢请求列表 2. 每个 trace 的最慢 step 3. 重复出现的慢 step 4. 证据充分的观察 5. 需要补充的数据 6. 建议排查顺序。 限制 - 不编造日志中没有的信息 - 不输出泛泛优化建议 - 每个判断都要引用日志依据。代码风险扫描 Prompttext请阅读下面的 Java 代码找出可能导致接口 P95/P99 升高的结构性风险。 重点关注 - 循环内数据库查询 - 循环内 RPC - 缺少批量接口 - 超时和重试 - 缓存击穿 - 线程池或连接池等待 - 结果组装中的复杂计算。 要求 - 区分确定问题和待验证问题 - 给出验证方法 - 不重写完整业务代码。复盘文档 Prompttext请根据下面的排查记录整理一份技术复盘草稿。 结构 - 现象 - 影响范围 - 时间线 - 直接原因 - 放大因素 - 修复动作 - 后续预防项。 要求 - 不夸大结论 - 没有证据的部分标记为待确认 - 适合发给研发团队内部评审。AI 辅助排查时我比较在意的几个边界第一日志一定要脱敏。不要把真实用户信息、订单号、Token、内部域名、数据库连接串贴出去。即使只是测试也应该养成处理样本的习惯。第二不要让模型替你决定线上动作。比如是否降级、是否扩大连接池、是否加重试都要结合业务影响和系统容量。AI 可以列选项但不能替团队承担风险。第三性能优化必须可回滚。尤其是老系统批量接口、缓存、并发调用都可能改变压力分布。先灰度再观察指标。第四不要迷信“看起来很合理”的解释。一次慢接口可能同时包含慢 SQL、下游抖动、连接池不足、线程池排队。根因分析要能被数据支撑。常见问题1. 可以直接把生产日志交给 AI 分析吗不建议。至少要做脱敏、裁剪和字段替换。真实用户信息、访问令牌、内部服务地址、订单号、手机号、邮箱、客户名称都应该去掉。性能排查只需要保留时间、耗时、阶段、状态码、线程、Trace 关系等必要字段。2. AI 判断“可能是索引问题”能直接按它说的建索引吗不能。建索引前要看执行计划、数据分布、查询频率、写入影响和现有索引结构。模型可以提醒你检查索引但不能替代数据库验证。3. 多模型分析结果不一致怎么办把它们当作不同排查假设而不是最终答案。谁的说法能被监控、日志、代码或压测验证谁就更有参考价值。没有证据的结论先放到待确认列表。4. AI 更适合排查哪类 Bug更适合信息整理型、路径梳理型问题比如日志归类、调用链分析、代码风险扫描、复盘文档整理。涉及并发时序、底层网络、JVM 深层问题时它可以辅助列方向但仍需要专业工具验证。5. 性能优化后怎么确认真的有效至少对比优化前后的平均耗时、P95、P99、错误率、下游调用次数、数据库 QPS、连接池等待、CPU、GC 等指标。只看单次请求变快不够要看高峰期整体表现。最后把 AI 放在“排查助手”的位置上这次慢接口排查给我的感受是AI 最适合做三件事把杂乱日志整理成可讨论的现象把代码里的性能风险列成清单把排查过程沉淀成团队复盘文档。但真正的闭环还是工程手段脱敏样本、指标监控、代码 Review、压测验证、灰度发布、回滚预案。如果你也想把 AI 用进日常研发不妨从慢接口、异常日志、代码 Review 这类高频且可验证的场景开始。不要一上来就期待它“定位根因”先让它帮你把问题拆小、把排查顺序排清楚效率提升会更稳定也更安全。