一次接口 500 的排查里,把错误堆栈贴给助手,它给出三条可能原因,第一条是"数据库连接池耗尽"。工程师照着查了半小时,连接数一切正常。真实原因在第三条——一个 @Transactional 加在私有方法上导致事务没生效。教训不是"助手不可靠",而是它给的三条都是假设,而人把第一条当成了结论。
助手在排障上的价值与风险是同一个性质:它极擅长在几秒内列出候选假设,而这些假设的排序与真实系统的状态无关。它不知道你的流量形态、最近的发布、刚才改的配置。
1. 助手在排障各阶段的作用
| 阶段 | 助手的价值 | 风险 |
|---|---|---|
| 误读错误信息 | 高(翻译、定位关键字) | 低 |
| 列候选假设 | 高(广度) | 中(排序不可靠) |
| 判断根因 | 低 | 高(无系统状态) |
| 写验证脚本 | 中高 | 中(可能测错东西) |
第二项与第三项的落差是核心:它擅长"可能是什么",不擅长"这次是什么"。而排障的时间恰恰花在"这次"上。
这个定位也解释了为什么"提示越完整,助手越有用":它无法主动索取信息,你不给的东西它只能猜,而猜出来的内容与你的真实系统无关,却会被读成"它知道"。
所以正确的用法是把它的输出当成待验证清单,而不是答案。
2. 假设的排序该由什么决定
| 依据 | 例子 |
|---|---|
| 变更时间线 | 最近发布/配置变更优先 |
| 影响范围 | 全量 vs 单实例 |
| 历史相似度 | 上次同类现象的原因 |
| 可验证成本 | 十分钟能查的优先 |
第一项最有效:大多数突发问题的答案在"最近改了什么"里。助手不知道这条,所以你必须在提示里给它,或者自己先排一遍。
第四项是实践上的排序原则:先查成本低的假设,即使它概率略低——因为排障是串行的,错一条就浪费一轮。
// 给助手的上下文:这四项缺一项,它的排序就会跑偏
1. 变更时间线(最近 24h 的发布、配置、数据变更)
2. 影响范围(全部/部分实例、单用户/全体、特定地域)
3. 错误形态(报错文本、状态码、日志样例)
4. 已排除项(已经查过什么,结论如何)
// 缺第 4 项最常见:它会把已排除的假设重新列一遍
3. 它最容易错在哪
| 错误类型 | 表现 |
|---|---|
| 时代错位 | 按旧版本行为解释(框架升级后已变) |
| 配置无关 | 忽略你的实际配置,按默认值推理 |
| 因果倒置 | 把伴随现象当原因 |
| 过度自信 | 给出确定语气,实际是猜测 |
第一项在快速迭代的框架上很常见:它的知识停在某个版本,而你的行为已经变了。所以"这条在新版还成立吗"要单独确认。
第四项最难防:语气与可信度无关。同样一句"可能是连接池耗尽",加上"最可能"三个字就会让人先查它。
// 让助手显式标注可信度,比让它给结论有用
要求输出格式:
- 假设(一句)
- 支持证据(来自我给的日志的哪一行)
- 反证(什么现象会推翻它)
- 验证方法(一条命令或一个查询)
// 缺"反证"的假设不值得先查
4. 验证脚本的用法与陷阱
| 用法 | 说明 |
|---|---|
| 生成查询/命令 | 省时间,需确认语义 |
| 生成日志过滤正则 | 好用 |
| 生成复现脚本 | 需在小范围验证 |
| 直接在生产执行 | 绝对不要 |
第一项(生成查询)的用法要配一条纪律:让助手同时给出"预期结果"。有了预期,你才能判断"结果为空"是"确实没有"还是"查询条件写错了"。
-- 让助手给出查询 + 预期 + 反证
-- 假设:连接池耗尽
SELECT COUNT(*) FROM information_schema.processlist WHERE command='Sleep';
-- 预期:若接近 max_connections(如 190/200)→ 支持假设
-- 反证:若只有 20 条连接 → 该假设可排除
第四项不是谨慎问题而是顺序问题:助手写的命令往往"看起来对",而排障时人手快、心躁,容易直接粘贴。稳妥做法是先 --dry-run 或在只读副本上跑。
第二项有一个具体陷阱:正则里的转义、grep -E 与 grep -P 的差异,会让过滤结果"少了几条",从而误导判断。
// 助手给的正则先在样本上验证命中数,再用于生产
// 反例:直接用于 grep,命中偏少却以为日志里没有
grep -cE 'ERROR.*timeout' app.log
// 正例:先用已知存在的一行验证模式
echo '2026-11-10 ERROR upstream timeout' | grep -E 'ERROR.*timeout' && echo pattern-ok
5. 与人的分工
| 环节 | 谁做 |
|---|---|
| 收集现象 | 人(决定看什么) |
| 列假设 | 助手(广度) |
| 排序 | 人(结合变更与范围) |
| 验证 | 人(执行与判断) |
| 收敛根因 | 人 |
助手无法替代的是"判断哪些现象值得看":它的输入完全由你决定,你给什么它分析什么。所以输入的选择本身就是最关键的一步。
这个习惯还有一个副作用:写五行时你自己往往会想到答案。因为把"现象"与"解释"分开这个动作,本身就是在做归因排序。
一个实用习惯:先把现象写成五行,再贴给助手。这五行强迫你把"现象"与"解释"分开,而多数误判源于把解释当现象。
// 现象五行的写法(现象,不含解释)
1. 时间:11-10 14:02 起持续
2. 范围:order 服务全部 3 个实例
3. 表现:接口 5xx 比例 12%,日志出现 "upstream timeout"
4. 变更:13:50 发布过 order 服务(版本 v2.31)
5. 已排除:数据库连接数正常、下游健康检查通过
// 写成"连接池可能耗尽"就是解释,不是现象
6. 排错:五种"听了助手的话查错方向"
| 现象 | 成因 | 处理方向 |
|---|---|---|
| 查了半天不是那个原因 | 假设未排序 | 按变更时间线重排 |
| 它说的现象我这没有 | 版本/配置不同 | 补上下文再问 |
| 反复回到同一假设 | 没给已排除项 | 显式列出排除项 |
| 按它的命令操作出问题 | 直接在生产执行 | 先 dry-run |
| 结论对了但过程没法复用 | 只记了结论 | 记假设与验证 |
排障结束后还有一步值得做:把"验证有效的假设"写成可复用的检查项。例如"私有方法上的 @Transactional 不生效"应当变成一条代码评审检查项,而不是留在某个人的记忆里。
第五项是复盘层面的损失:如果只记"是事务没生效",下次遇到类似现象仍然要重来一遍。记下"我们查了什么、怎么排除的",才是可复用的资产。
7. 边界:什么情况不必用它
| 场景 | 为什么 | 做法 |
|---|---|---|
| 已明确根因 | 无需假设 | 直接修 |
| 现象明确且唯一 | 无需广度 | 直接查 |
| 涉密日志 | 不能外发 | 脱敏或不用 |
| 时间极紧的故障 | 排序成本高 | 按流程执行 |
还有一条与保密有关的边界:贴日志前先想一遍里面有什么。堆栈常带参数值、SQL、内网地址与用户标识;把它整段外发,等于把一份生产数据副本交出去。脱敏的成本远低于事后追责。
判断口径一句话:我需要的是"可能的原因列表"还是"这次的原因"。前者交给助手,后者只能靠你手上的系统状态。
8. 自测
- 助手在排障四个阶段中的作用与风险,哪一处的落差最大?为什么?
- 假设排序的四项依据里,哪一项最有效?为什么助手不知道它?
- 给助手的上下文若缺"已排除项",会发生什么?
- 为什么"语气自信"与"结论正确"无关?要求它输出"反证"有什么作用?
- "现象五行"为什么要排除解释?把解释当现象会造成什么后果?
- 判断"该不该用助手排障"的那个问题是什么?