AI Agent 线上排障实战:日志分析、根因定位、最小修复与回归验证
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 的直觉

这次故障可以形成如下证据链:
- 失败请求都同时携带
accountStatus和month; - 仅状态筛选和仅月份筛选均可成功;
- 组合条件会进入 Mapper 中一个专用关联查询分支;
- 该分支同时连接
sys_user u和user_month_record r; - 两张表均存在
status含义相近的字段; - 动态条件写成了未限定表别名的
status = #{accountStatus}; - 用户状态真实字段属于
u.account_status; - 使用明确表别名后,原失败参数可以返回预期数据。
注意第 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>
但在真正修改前仍需确认三件事:
- 用户表别名确实为
u; - 实际数据库字段确实为
account_status; - 参数中的枚举值与数据库存储值能够正确映射。
以下行为不应混进本次热修复:
- 重命名整个项目中的状态字段;
- 将所有 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 建立项目级规则,让它每次进入陌生仓库都能自动识别技术栈、开发边界和验证方式。
更多推荐


所有评论(0)