AI Agent 线上排障实战:日志分析、根因定位、最小修复与回归验证

在这里插入图片描述

上一篇我们讨论了如何让多个 AI Agent 分别负责前端、后端、测试和代码审查。很多读者紧接着会问:开发任务能拆给 AI,那么线上突然报错时,能不能也让 AI 自动排查并修复?

答案是可以,但线上排障和普通功能开发有一个本质区别:开发追求完成需求,排障首先追求控制风险。

一个“很聪明”的 Agent,如果没有边界,很可能看到异常后直接重构整条调用链;它也可能只修复日志里最显眼的一行,却忽略真正触发问题的数据条件。线上问题最怕的不是 AI 不会写代码,而是它在证据不足时过早动手。

本文用一个常见故障贯穿完整流程:

用户列表在同时选择“禁用状态”和月份范围时返回 500;其他筛选条件正常。要求定位根因、完成最小修复、验证兼容性,同时不影响正在进行的其他开发。

文中的接口、字段和命令均为通用示例,实际操作必须以自己项目的源码、日志和运行环境为准。

一、不要把“报错信息”直接当作根因

假设监控中出现下面的异常:

BadSqlGrammarException: Unknown column 'status' in 'where clause'
Request: GET /api/users?accountStatus=DISABLED&month=2026-08

看到这里,AI 很容易得出结论:“SQL 中字段写错了,把 status 改成 account_status 即可。”

这个结论可能正确,也可能只对了一半。我们还需要回答:

  • 为什么普通查询没有报错?
  • 为什么只有月份和状态组合时触发?
  • status 指的是用户状态,还是关联表中的记录状态?
  • 同一段 SQL 是否服务于其他接口?
  • 改字段后是否会造成歧义或破坏旧查询?
  • 线上数据库结构是否与本地实体完全一致?

因此,日志只能告诉我们“在哪里观察到了失败”,不能自动证明“失败从哪里产生”。

二、线上排障应该拆成五个阶段

在这里插入图片描述

一个稳妥的 AI Agent 排障流程可以分成:止损、取证、定位、修复、验证。

1. 止损:先判断影响范围

主 Agent 首先整理已知事实:

  • 首次发生时间和最近一次发生时间;
  • 受影响接口、用户和数据范围;
  • 是否持续发生,还是偶发问题;
  • 是否与刚发布的版本有关;
  • 是否存在可逆的临时规避方式;
  • 当前是否已经影响核心交易或数据正确性。

如果问题仍在扩大,优先级可能是关闭某个筛选入口、回滚刚发布的版本或启用降级,而不是继续让 AI 慢慢阅读整个项目。

注意:回滚、改线上配置、修改数据和执行数据库脚本都属于外部高风险动作。AI 可以准备方案,但在没有明确授权时不应自行执行。

2. 取证:建立可复核的事实集合

Agent 应收集与单次失败请求相关的:

  • 请求参数与必要的请求标识;
  • 完整异常类型和关键堆栈;
  • 对应服务版本或发布时间;
  • 实际执行的 SQL 及参数;
  • 同一时间段上下游服务的异常;
  • 成功请求与失败请求之间的差异。

日志中可能包含手机号、令牌、Cookie、地址等敏感信息。交给 AI 前应脱敏,最终排障报告也不应复制这些内容。

3. 定位:沿调用链验证假设

不要全仓库漫无目的地搜索。应从异常入口沿真实调用链反向追踪:

请求参数
  → Controller 参数绑定
  → Service 条件组装
  → Mapper 动态参数
  → SQL 分支
  → 实体与数据库字段

每前进一步,都要明确上一条假设是否被源码或运行证据支持。

4. 修复:只改变造成故障的必要部分

线上热修复不是展示代码美学的机会。如果一个字段限定就能解决问题,就不要顺便重写整个查询构造器。

5. 验证:证明修复有效且没有扩大影响

至少验证原始失败场景、相邻边界场景和旧功能兼容性。仅仅“编译通过”不能证明线上 Bug 已修复。

三、用证据链代替 AI 的直觉

在这里插入图片描述

这次故障可以形成如下证据链:

  1. 失败请求都同时携带 accountStatusmonth
  2. 仅状态筛选和仅月份筛选均可成功;
  3. 组合条件会进入 Mapper 中一个专用关联查询分支;
  4. 该分支同时连接 sys_user uuser_month_record r
  5. 两张表均存在 status 含义相近的字段;
  6. 动态条件写成了未限定表别名的 status = #{accountStatus}
  7. 用户状态真实字段属于 u.account_status
  8. 使用明确表别名后,原失败参数可以返回预期数据。

注意第 8 条必须来自实际测试,而不是“看代码应该可以”。

为了防止 Agent 跳步,可以要求它使用固定格式记录结论:

假设:组合查询中的状态字段引用错误。
支持证据:失败请求均进入同一动态 SQL 分支。
反对证据:普通状态查询使用另一段 SQL,未复现。
验证方式:使用相同参数执行 Mapper 测试并查看生成 SQL。
当前结论:假设成立,根因位于组合查询的状态条件。

如果只有支持证据,没有主动寻找反对证据,AI 很容易陷入确认偏误。

四、怎样让 Agent 提交“最小修复”?

在这里插入图片描述

最小修复不是“改动行数越少越好”,而是满足四个条件:

  • 直接针对已经证实的根因;
  • 不改变无关功能的行为;
  • 能被明确测试覆盖;
  • 出现问题时容易识别和回退。

本案例中,合理修复可能只是把动态 SQL 从:

<if test="accountStatus != null">
    AND status = #{accountStatus}
</if>

改为:

<if test="accountStatus != null">
    AND u.account_status = #{accountStatus}
</if>

但在真正修改前仍需确认三件事:

  1. 用户表别名确实为 u
  2. 实际数据库字段确实为 account_status
  3. 参数中的枚举值与数据库存储值能够正确映射。

以下行为不应混进本次热修复:

  • 重命名整个项目中的状态字段;
  • 将所有 XML 查询迁移成新的查询框架;
  • 顺手调整分页、排序或权限逻辑;
  • 格式化整个 Mapper 文件;
  • 删除看起来“暂时没用”的兼容代码。

这些工作即使有价值,也应单独建立任务,独立评估和验证。

五、排障 Agent 与修复 Agent最好分开

一个 Agent 从头做到尾,容易爱上自己最初的判断。更稳妥的角色划分是:

角色 主要职责 是否允许改生产代码
主 Agent 确定范围、组织证据、审批修复边界 负责最终决策
调查 Agent 阅读日志与调用链,提出并验证根因假设
修复 Agent 根据已确认根因实施最小改动 是,仅限授权文件
测试 Agent 复现原问题并执行回归矩阵
审查 Agent 检查根因证据、兼容性和改动范围

调查 Agent 不应一看到可疑代码就直接修改,因为一旦代码变化,后面的证据可能被污染。测试 Agent 也不应为了让用例通过而调整业务实现。

六、可以直接复制的调查提示词

你是线上问题调查 Agent,只做只读诊断,不修改任何项目文件,也不执行线上写操作。

故障现象:用户列表同时选择禁用状态和月份范围时返回 500,其他筛选条件正常。

请完成:
1. 根据日志确定失败入口、异常类型和触发条件;
2. 沿 Controller、Service、Mapper、SQL 和数据库字段追踪调用链;
3. 至少提出两个可能原因,并分别寻找支持证据和反对证据;
4. 给出最可能根因、影响范围和最小修复建议;
5. 列出仍未确认的事实和所需验证方式。

输出中不要包含令牌、手机号、Cookie 等敏感内容。
没有证据时不得把猜测写成确认结论。

七、可以直接复制的修复提示词

你是线上问题修复 Agent。根因已经确认:组合查询的账号状态条件引用了错误字段,正确字段为用户表别名 u 下的 account_status。

你的文件所有权仅限本次故障对应的 Mapper 和直接相关测试。

要求:
1. 实施能够解决根因的最小改动;
2. 不重构无关代码,不格式化整个文件;
3. 保持未传状态、仅状态、仅月份等旧场景行为不变;
4. 补充能够复现原故障的测试;
5. 报告修改文件、改动理由、实际执行的验证和未验证风险。

仓库中可能有其他人正在工作,不要覆盖或回退他人的改动。

八、回归验证不能只测原始报错参数

修复后建议建立一张回归矩阵:

场景 状态 月份 预期结果
旧接口 不传 不传 与修复前正常行为一致
单条件 禁用 不传 只返回禁用用户
单条件 不传 指定月份 返回该月份范围数据
原故障 禁用 指定月份 成功返回禁用用户数据
相邻场景 正常 指定月份 成功返回正常用户数据
空结果 禁用 无数据月份 返回空列表而非 500
非法输入 非法枚举 指定月份 按既有参数校验规则处理
分页组合 禁用 指定月份 总数与分页内容一致

如果项目允许,还应该比较修复前后的生成 SQL,确认变化只发生在目标条件上。

九、测试报告必须包含真实执行证据

合格的测试 Agent 输出应该类似:

原始失败场景:已复现,修复前抛出 SQL 异常。
目标 Mapper 测试:已执行,修复后通过。
相关模块测试:已执行,28 个用例通过,0 个失败。
完整项目构建:未执行,原因是本次仅获授权验证目标模块。
浏览器人工回归:未执行,需要测试环境登录权限。

不合格的输出通常只有一句:

代码已经检查,理论上没有问题。

“理论上”不能成为线上修复的放行依据。

十、独立审查应该重点看什么?

审查 Agent 不需要重新写一遍代码,而应集中攻击最危险的假设:

  • 根因是否由证据证明,还是仅凭异常文本猜测;
  • 修改字段是否属于正确的表和业务含义;
  • 动态条件是否位于正确的 SQL 分支;
  • 未传新条件时是否保持原行为;
  • 是否存在另一个相似 SQL 分支仍有同样问题;
  • 测试是否真的进入故障分支;
  • 修改范围是否夹带重构或无关格式变化;
  • 是否记录了无法在当前环境完成的验证。

每个审查问题都要包含文件位置、触发条件、影响和建议。单纯的代码风格意见,不应阻塞紧急修复。

十一、六种危险的 AI 排障方式

1. 看到异常就开始改代码

后果是根因尚未确认,现场证据被修改后的行为覆盖。应先形成可复核的复现条件。

2. 一次搜索不到就扩大到整个仓库

大量无关上下文会降低判断质量。应从失败入口沿调用链逐层搜索。

3. 把本地配置当成线上事实

线上版本、数据库结构和配置可能不同。本地源码只能证明代码意图,不能自动证明线上实际状态。

4. 为了保险顺手修改所有相似代码

相似不等于同一根因。批量修改会扩大回归面,也让问题更难回退。

5. 把编译通过当成故障已经修复

编译只能证明语法和部分类型正确,无法证明目标 SQL 分支和真实参数已经工作。

6. 隐藏未验证项

如果无法连接测试数据库、无法登录页面或无法获得线上版本信息,应明确报告,而不是用“应该”填补空白。

十二、最终交付报告模板

【故障现象】
用户列表在 accountStatus=DISABLED 且指定 month 时返回 500。

【影响范围】
仅组合筛选分支受影响;普通列表和单条件查询未发现异常。

【根因证据】
组合查询进入关联 SQL;状态条件使用了错误字段;生成 SQL 与异常信息一致;修正字段后原参数测试通过。

【代码改动】
仅修改目标 Mapper 的状态条件,并增加原故障场景测试。

【验证结果】
列出实际执行的测试、结果和关键证据。

【未验证项】
列出当前权限或环境无法覆盖的验证。

【上线与回退建议】
说明观察指标、验证窗口和可执行的回退路径,实际操作需经负责人授权。

十三、写在最后

AI Agent 可以显著缩短日志检索、调用链追踪和测试用例整理的时间,但它不能取代线上变更需要的证据、授权和责任边界。

可靠的 AI 排障并不是:

报错丢给 AI,等待它自动修好。

而是:

先止损,再取证;先证明根因,再提交最小修复;最后用独立验证证明没有扩大风险。

当每一条结论都能回到日志、源码或测试结果,多 Agent 才是一支可用的排障小队;否则,它们只是同时提出更多听起来合理的猜测。

下一篇我们可以继续深入:如何给 AI Agent 建立项目级规则,让它每次进入陌生仓库都能自动识别技术栈、开发边界和验证方式。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐