AI 排障的真实边界:它能替你看指标,不能替你定责 原创
本文是 SRE 实战系列第 24 篇,第二循环第二组的第三篇,也是第二循环的收官篇。
前面二十三篇讲的全是"人怎么把系统管住":怎么定目标、怎么被叫醒、怎么安全地改、怎么证明它扛得住、怎么算余量、怎么组织一次事故、怎么把数据捞回来。这一篇讲一个新来的角色——它不睡觉、不抱怨、看数据比你快十倍,但它不承担任何后果。
全文约 1.3 万字。从一次 38 分钟的事故开头:值班同学在告警后 90 秒就拿到了一份结构清晰、事实全对的诊断结论,然后沿着它走了 15 分钟,走反了。然后回答五个问题:AI 到底压掉了排障的哪一段、哪一段能交给它哪一段绝对不能、接进 on-call 链路会踩哪六个坑、最小可行的接法长什么样、以及怎么用数字证明它不是个贵的玩具。
这一篇的立场:AI 的视野不是被模型能力限制的,是被工具清单限制的。它看得见的每一个事实都对,但它会用看得见的东西去解释看不见的原因,并且用同样的语气说出来。
一、21:14 到 21:52:一份事实全对的错误结论
周二的晚上,值班的人叫陈默,这是他的第三个 on-call 周。
21:11,告警进来:order-api 的 p99 超过 800ms,持续 3 分钟。这条规则是第 3 篇那套燃烧率告警的产物,误报率不高,他没犹豫。
21:14,他做了两件事,几乎同时:在大盘上打开订单服务的面板,把告警内容粘进了值班群里那个接好了工具的 AI 助手。
21:15:30,AI 回复了。90 秒,格式规整,五条事实、两个假设:
【事实】
1. order-api 集群 CPU 使用率 82%(5 分钟均值),24 个副本
2. JVM GC pause p99 = 210ms,较 1 小时前上升 4.2 倍
3. 请求量 3.1k QPS,较同时段基线上升 1.4 倍
4. payment-gateway 调用超时率 1.8%(阈值 1%)
5. 无线程池拒绝记录,但活跃线程数已达上限的 94%
【假设】
H1(置信度 高):内存压力导致 GC 频繁,进而抬升延迟。
建议:扩容至 40 副本,观察 5 分钟。
H2(置信度 低):下游 payment-gateway 超时有轻微影响,建议关注。每一条事实都是真的。这五条数据都是从监控系统里实打实查出来的,数字没有一处编造,时间窗口也对。
陈默看 H1 的理由站得住:CPU 82%、GC 涨了 4 倍、活跃线程到 94%,这是典型的资源压力形状。21:16 他扩到了 40 副本。
21:22,p99 到了 1.1 秒。更差了。
他回头看 H2。但那句话只有一行,置信度标的"低",而且它排在第二,前面那个已经说得那么像了。他又花了几分钟确认线程堆栈、看连接池,21:31,他忽然想起一件事——20:50 网关组做过一次配置调整。
去变更平台一查:payment-gateway 的 idle_timeout 从 60s 改成了 15s,目的是优化连接复用率。改动的人写了说明,评审通过了,21:00 生效范围扩到全量。
连接被提前关掉,客户端 SDK 按默认策略重试,请求量变成 2.3 倍,order-api 到 payment-gateway 的连接池被打满(占了 30 个配额里的 30 个),线程开始排队。线程排队导致 GC 压力上升,GC 压力导致 CPU 上升。
也就是说:CPU 82% 是结果,不是原因。 AI 的五条事实全是结果性证据,它给的 H1 把因果方向搞反了。
21:32 决定回滚配置,21:38 执行完,连接池要等既有连接自然老化,21:52 p99 回到 210ms。总时长 38 分钟。
事后复盘时有人问了一个很好的问题:AI 省了时间吗?
拆开看:
| 段 | 人工估算 | 实际(AI 参与) | 差值 |
|---|---|---|---|
| T_detect(到有人知道) | 3 分钟 | 3 分钟 | 0 |
| T_context(拼上下文) | 8~12 分钟 | 90 秒 | -8 分钟 |
| T_verify(验证假设) | 4~5 分钟 | 15 分钟 | +10 分钟 |
| T_decide(拍板回滚) | 1 分钟 | 1 分钟 | 0 |
| T_act(执行 + 恢复) | 20 分钟 | 20 分钟 | 0 |
省了 8 分钟,多花了 10 分钟,净亏 2 分钟。 而且是那种最难受的亏法——不是多做了无用功,是少看了该看的地方。
这次事故不复杂。它甚至不能算 AI 的失败,因为 AI 从来没被允许知道 20:50 那次变更:变更平台是另一套系统,没有接进它的工具列表。它的世界里根本没有那个东西。
但它也没有说"我不知道"。它用看得见的五条证据,拼出了一个看不见的原因的解释,语气和它对的时候一模一样。
这就是这一篇要谈的边界。
二、把事故时间拆开:AI 只压得动其中一段
2.1 一个比"MTTR"更细的分解
第 22 篇把 MTTR 拆成了 MTTD / MTTA / MTTK / MTTR-R 四段,那是给组织看的。要看清楚 AI 能碰哪一段,需要再细一层:
T_incident = T_detect + T_context + T_verify + T_decide + T_act- T_detect:从故障发生到有人知道。告警规则的地盘,跟 AI 关系不大(除非让 AI 做告警降噪,那是第 6 篇的话题)
- T_context:从有人知道到"手上有一份能用来判断的材料"。翻面板、查日志、找最近有没有人改过东西、把三个系统的时间戳对齐
- T_verify:从有假设到确认或排除。抓包、打点、复现、对比
- T_decide:从确认到有人拍板。要不要回滚、要不要扩容、要不要发公告
- T_act:从拍板到影响消除。执行、等待、验证
一次普通事故里,这五段的量级大概是 3 / 10 / 8 / 5 / 20,加起来 46 分钟,其中 T_act 常常是最大的一块,而它几乎完全不受诊断质量影响——回滚要时间,连接要老化,缓存要预热。
AI 真正能大幅压缩的只有 T_context。 这是它最扎实、也最不性感的价值:把"从十几个系统里捞数据、对齐时间轴、抄进同一个文档"这件事,从十分钟压到一分钟。
一个不好听的数字:多数团队里 T_context 占 MTTR 的比例在 20%~30%。这意味着哪怕 AI 把 T_context 压到零,MTTR 的天花板也只有 25% 的改善。任何宣称"AI 让 MTTR 降 70%"的说法,要么算错了账,要么改善其实来自别的地方。
2.2 它还能动 T_verify,但方向不一定对
T_verify 是 AI 唯一可能"帮倒忙"的一段。
- 命中时:AI 的 top-1 假设正确,人直接去验证那一条。T_verify 从 8 分钟掉到 3 分钟,这是真收益
- 未命中且高置信时:人沿着错误方向走。第一节那 15 分钟里,有 8 分钟花在扩容和等扩容上,剩下 7 分钟花在"为什么扩容没用"上——而这 7 分钟本来应该花在"还有别的原因吗"
第二种情况有个名字:锚定。它比"多做了一个无用动作"严重得多,因为它会占用的是本该用来重新提问的那段时间。而且它有个恶性特征:AI 越像人,锚定越强。 一份格式规整、编号清晰、带置信度的输出,比一段啰嗦的日志可疑得多,也更容易被当成结论。
第 22 篇讲 IC 有一条原则——IC 不碰键盘。同一个道理:值班的人把结论权交出去的那一刻,他就不再是在诊断,而是在执行。
2.3 期望值算一遍:命中率低于某个数就是净亏
把上面的东西写成一个估算模型。只算前四段(T_act 不变),单位是分钟:
E[ΔT] = -k·T_context + p·(-a·T_verify) + (1-p)·(b·T_verify + T_reset)k:AI 压掉 context 的比例,实测 0.7~0.9,取 0.8p:top-1 假设命中率a:命中时 verify 的缩短比例,取 0.6b:未命中时 verify 的放大倍数,实际观测在 1.5~3 之间,取 1.5T_reset:从错误方向撤退、重建共同认知的时间,3~5 分钟,取 4
代入 T_context = 10、T_verify = 5:
| 命中率 p | ΔT(分钟) | 结论 |
|---|---|---|
| 0.8 | -8 - 2.4 + 1.5 + 0.8 = -8.1 | 明显收益 |
| 0.5 | -8 - 1.5 + 3.75 + 2 = -3.75 | 有收益 |
| 0.3 | -8 - 0.9 + 5.25 + 2.8 = -0.85 | 基本为零 |
| 0.2 | -8 - 0.6 + 6 + 3.2 = +0.6 | 净亏 |
| 0.1 | -8 - 0.3 + 6.75 + 3.6 = +2.05 | 明显净亏 |
盈亏平衡点大概在命中率 25% 左右。
这个数不是为了精确,是为了把讨论从"AI 好不好用"拉到"这个团队的命中率是多少,为什么是这个数"。后者可以改,前者不能。
2.4 命中率取决于事故类型,而事故类型取决于有没有接变更
继续追一层。命中率不是一个常数,它跟原因在哪有关:
| 事故类型 | 原因在哪 | 没接变更记录 | 接了变更记录 |
|---|---|---|---|
| 资源型(CPU / 内存 / 磁盘 / 连接) | 指标里看得见 | 0.7 | 0.7 |
| 依赖型(下游超时、三方异常) | 指标 + 拓扑里看得见 | 0.4 | 0.5 |
| 变更型(配置 / 发布 / DDL / 扩缩容) | 在变更平台里,不在监控里 | 0.1 | 0.7 |
| 数据型(脏数据、错误脚本) | 在审计日志和 binlog 里 | 0.05 | 0.15 |
再看一眼事故的实际分布。第 19 篇引过的行业口径是"70% 的故障来自变更",即便按最保守的 40% 算,用上表加权:
- 不接变更记录:
0.3×0.7 + 0.2×0.4 + 0.4×0.1 + 0.1×0.05 ≈ 0.34。看着还行? - 但如果不接变更记录,那 40% 的变更型事故的 top-1 假设全部错误且全部有证据支撑(因为资源指标一定会在变更事故里变差——任何变更事故都会推高 CPU 或延迟)。这些恰好是最容易锚定的情况。
所以第一节那次不是运气差,是结构性必然。在没接变更记录的 AI 排障系统面前,所有变更型事故都会长成"资源压力"的样子。
这就得出这篇最实用的一句判断:
AI 排障的第一优先级不是换更好的模型,是给它接上变更记录。命中率从 0.1 到 0.7 的跨度,比任何一次模型升级都大。
第一节那 38 分钟里,如果 AI 有一个 list_changes 工具,它在 90 秒后给出的第一行会是"20:50 payment-gateway 修改 idle_timeout 60s → 15s(配置变更,已全量)"。后面所有事都不是现在这个形状。
三、一条判据:哪一段能交给 AI
工具列表能改,模型能力在涨,边界会移动。所以需要的不是一张"能/不能"的静态清单,而一条能反复用的判据。
三个问题,按顺序问:
Q1 可见性:这个动作需要的输入,是否全部在我的工具清单里?
不是"理论上能不能拿到",是"现在这个 Agent 的 tool schema 里有没有"。看不到变更记录,就等于变更事件不存在——不管它在另一套系统里的数据有多完整。这一条的残酷之处在于:模型不会因为缺少输入而降低置信度,它只会因为缺少输入而改变解释。 第一节那五条事实就是证据。
Q2 可逆性:这个动作做错了,能否在 5 分钟内撤销?
5 分钟这个数取自第 8 篇的止血标准。可逆的动作,错了就撤,试错成本接近零,可以放手;不可逆的动作(写数据、发公告、删备份、对外定责),错了没有撤销键(第 19、23 篇反复讲的那件事),就必须有人签字。
Q3 可算性:判断"做对了没有",是否需要系统之外的损失函数?
这是最容易被忽略的一条,也是"不能替你定责"的技术解释。恢复哪个时间点、要不要对外承认事故、要不要为了止血牺牲一批用户、这次损失算谁的——这些判断的目标函数在财务、法务、商务口径里,不在任何监控系统里。第 23 篇第七节那句话是同一个意思:能不能在 30 分钟内把反向 SQL 全量审阅一遍,这个阈值不是技术参数,是风险偏好。
三问落成表:
| 环节 | Q1 可见 | Q2 可逆 | Q3 可算 | 交付形态 |
|---|---|---|---|---|
| 拉数据、对齐时间线 | ✅ | ✅(只读) | ✅ | 自动做,不需要人看过程 |
| 生成候选假设 | ✅ | ✅(不产生副作用) | ✅ | 自动做,但必须带证据与反证 |
| 验证假设(查一条查询) | ✅ | ✅ | ✅ | 自动做,可以自动下钻 2~3 层 |
| 执行止血(扩容 / 重启 / 摘流量) | ✅ | ⚠️ 多数可逆 | ✅ | 建议 + 人确认,一键执行 |
| 回滚到某个版本 / 时间点 | ⚠️ 变更链常常不全 | ❌ | ⚠️ | 人拍板,AI 只提供决策材料(第 19、22 篇) |
| 恢复哪个时间点(数据) | ❌ | ❌ | ❌ | 人拍板,AI 只做影响面估算(第 23 篇) |
| 对外沟通口径 | ❌(外部还没发生) | ❌ | ❌ | 人拍板,AI 可以起草(第 22 篇) |
| 定责、复盘结论 | ❌ | ❌ | ❌ | 人拍板,AI 只做时间线整理 |
看这张表会发现,"能不能交给 AI"跟"这件事难不难"几乎无关,只跟这三问有关。生成一整套根因假设是难的,但它三问全过,所以可以放手;决定要不要发那条状态页是容易的,但三问全不过,所以必须人按。
这也解释了为什么很多团队接入 AI 后感觉"没什么用":他们把 AI 放在了最后一格(让它给结论),而不是第二格(让它给证据和候选)。
四、AI 已经比人快的三件事
这三件事不性感,但每件都能算出时间差。
4.1 拉数据:从十几个库到一次调用
人工拼一次上下文,典型动作是这样的:打开监控看板选服务、选时间窗、切三个指标面板、从一个面板截图、打开日志系统换一套查询语法、打开链路追踪找 trace、打开变更平台按时间筛、打开 K8s 看 Pod 事件、把八条东西贴进文档、手动把时间戳对齐。
八到十二个动作,八到十二分钟。中间最耗时的不是查询本身,是切换上下文——每换一个系统就要重新交代一次"我在看什么"。
AI 做这件事没有优势在"快"上,优势在它不需要重新进入状态。六个工具一次并行调用,40 秒到 90 秒,产出的东西甚至比人工更整齐。
这里有个反直觉的地方:这一步的质量不取决于模型,取决于工具设计。 一个 query_metrics(expr, start, end, step) 的好用程度,比模型是哪个版本重要得多。看板系统给人用的 API("返回一个图表的 JSON")和给 Agent 用的 API("返回带单位、带时间语义的样本点")不是同一个东西,这层如果照抄,后面全白搭。
4.2 串时间线:真正难的不是排序
把信号排成一条时间线,技术上有四个坑,每一个都会让 AI 给出的时间线看起来合理但是错的:
时钟漂移。 应用容器、节点、数据库、网关、日志采集器,五处时钟误差各几十毫秒到几秒。一次重试风暴里,"A 在 B 之前的 200ms 发生"这件事可能就是结论的全部,而这 200ms 恰好落在漂移范围内。第 23 篇那个"毫秒级 RENAME 导致全表不可用 8 秒",靠的就是这种精度。对策很朴素:给每个时间戳带上它的采集来源和精度,别让模型在 drift 里做因果推断。
时区。 一条来自业务系统的日志写了本地时间,一条来自基础设施的写了 UTC,一条来自海外的写了带偏移量。三个都是"21:14",差 8 小时。这是 AI 最容易出错、人类也最不容易发现的一类错误——因为它不产生矛盾,只产生一条看起来通顺的错误时间线。
单位与口径。 p99 和 avg、5 分钟均值与 1 分钟峰值、QPS 与 RPM、字节和 bits。第一节那个例子就是口径问题:82% 是 5 分钟均值,而那一刻的峰值是 96%。均值看起来"还有余量",峰值才是真相。第 21 篇那句"任何只报平均值的容量结论,都等于没报",在 AI 这里变成了"任何不带聚合口径的指标,都不要喂给模型"。
采样间隔。 15 秒采样和 1 分钟采样的两套数据放在一条轴上,前者看起来"更早发现",其实只是分辨率不同。AI 会把这个差异解释成"先兆"。
这四条落成一条工程纪律:上下文包里每一条数据都必须自带 (时间戳, 时区, 采集源, 聚合方式, 采样间隔) 五元组。 缺一项就会在某个夜里变成一次错误的因果推断。这条纪律写起来无聊,但它是"AI 能串时间线"这个能力的地基。人工串时间线之所以慢,正是因为人懒得记这五元组,来回切面板确认。
4.3 找相似案例:RAG 最实用的落点
第三件事是在历史里找"这条告警以前出现过吗、当时是什么原因"。
这件事人的效率极低:翻 Wiki、翻群聊记录、问老人。而这件事恰好是检索最擅长的形状——一批结构松散的文本、一个具体的查询、答案要求"带出处"。
第 18 篇那套 Runbook 体系在这里第一次产生复利:Runbook、事故记录、复盘文档三样东西如果都有统一的结构(第 22 篇的事故记录 schema 就是干这个的),检索质量会立刻上一个台阶。没有结构的历史文档,检索出来的是相似的字,不是相似的事。
一个可验收的指标:相似案例检索的"首条命中率",用过去 50 次真实事故回测,看第一条返回的案例是不是同一个根因。这个数在结构良好的知识库里能到 50%~60%,在只有群聊记录的环境里通常低于 15%。这个差距不是模型造成的。
五、AI 给不出结论的三件事
这一节不是"模型还不够强",是"输入不在系统里"。区别很大:前者等两年就能解决,后者等十年也不会自动消失。
5.1 定责:损失函数不在任何库里
一次事故里有一类问题,答案取决于"谁承担后果":
- 为了止血,牺牲哪部分用户?—— 取决于哪个客户在合同里写了 SLA 赔付条款
- 数据恢复到哪个时间点?—— 取决于丢掉的这批订单值多少钱,以及能不能事后补
- 要不要对外承认?—— 取决于法务意见和公关节奏
- 这个责任算变更方还是算容量方?—— 取决于组织内的分工约定
第 23 篇那个案子里,"12 万行数据恢复 vs binlog 反解"的选择,取决于"能不能在 30 分钟内审完反向 SQL"——而这个阈值本身是风险偏好,不是技术参数。AI 可以把反向 SQL 全量生成出来、把影响面算到行,但它不能决定"容忍这 3% 的错误率还是多花 3 小时"。
一个能落地的处理方式:把这类判断显式地变成事故记录里的一个字段,而不是让它藏在"大家都懂"里。
# incident 记录里必须有的一段(承接第 22 篇的 schema)
decisions:
- id: D3
question: "恢复到 15:00 还是 14:00 的快照"
options:
- desc: "15:00 快照,丢失 15:00~15:20 共 20 分钟的订单"
cost: "预计 1,200 单需人工补录,客诉约 40 起"
- desc: "14:00 快照 + binlog 重放到 15:20"
cost: "RTO 增加 70 分钟,重放风险中等"
ai_input: "影响面估算、两种方案的时间成本、历史同类案例 2 起"
decided_by: "IC + 业务负责人"
decided_at: "2026-11-07T15:50:00+08:00"
rationale: "客诉成本低于 70 分钟的业务中断成本"关键字段是 ai_input 和 decided_by 分开放。AI 提供材料,人做决定,两者都留痕。 这不是形式主义——它同时解决了两个问题:事后没人说得清"当时为什么这么选",以及"AI 说的"变成推卸责任的说法(见 6.6)。
5.2 拍板回滚:回滚的代价没人写进任何系统
第 19 篇讲"回滚不是撤销键",第 22 篇讲"回滚的决策权在谁"。这两件事叠起来,就是 AI 在回滚这件事上越不过去的墙。
要判断"该不该回滚",需要知道:
- 这次变更涉及哪些服务、哪些配置、哪些 flag(可见性,勉强能满足)
- 回滚会把哪些已经发生的写入留在原地(不可逆,AI 只能列出不能计算后果)
- 回滚本身会不会引发二次雪崩(第 19 篇那个案例里,回滚成功而故障没停)
- 谁有权按这个按钮,按错了怎么免责(第 22 篇的授权红线)
第三条最要命。AI 完全有能力生成一份"回滚风险评估",但它没法为这份评估负责——而不负责的评估会系统性偏乐观,因为悲观需要具体的损失量级,乐观不需要。
第一条也常被高估。第一节的教训是:可见性是个二元量,不是程度量。 变更链断了 20%(某个服务的配置在另一套系统里),AI 就看不见那 20%,但它不会说"我的变更视图有 20% 缺口,所以别信我的因果链"。它会把剩下的 80% 讲成一个完整的故事。
能给的合理交付形态是:AI 出一份"回滚前的检查表补全"——把四项(镜像、配置、flag、迁移版本)挨个查一遍,缺哪个标红。这是第 19 篇 rollback-point.sh 的自然延伸,人照着表按按钮。这件事 AI 做得比人好,因为它不会漏项、不会因为赶时间跳过。
5.3 跨团队权衡:谁在事故里被叫醒,是政治不是技术
第 22 篇讲过,一次事故要做的决定数是 n 个,每个决定的成本是 t 分钟。AI 能把 t 压下来(把材料准备好),但压不动 n——因为 n 由"这件事需要谁同意"决定。
有一个很具体的例子:要不要把 DBA 从床上叫起来。
技术上这是个简单判断(主从延迟 40 秒,正在恶化,写入已经开始排队)。但真实的决策依据是:这位 DBA 明天早上有一个上线窗口、他这个月已经被叫了三次、这次如果不叫他而出了问题算谁的。
这些信息一条都不在系统里。更准确地说:它们的存在形式是"大家都隐约知道",而不是"可以查询的记录"。 而 AI 的世界里只有后者。
所以这类判断的落点不是"让 AI 更懂人",而是"把组织约定显式化"。第 22 篇的通知矩阵、升级四段结构、决策权清单,本质都是在做这件事——把"该问谁"从人的记忆里搬到系统里。一旦搬进去,AI 就能用;没搬进去之前,AI 用不了,而且不会告诉你它用不了。
六、接进 on-call 链路的六个坑
6.1 幻觉的三种形状,只有第一种好抓
把幻觉当成"模型瞎编"是不够的,它至少三种形状,危险程度递增:
形状一:编造不存在的东西。 说"我看到 pg_stat_activity 里有 200 个 idle in transaction",而那个库根本不是 PG。这种最容易发现,因为老手一眼能看出指标名不对。防御成本低。
形状二:数字对,口径错。 第一节的 82%(5 分钟均值)就是这一类。数字真实,查询真实,就是聚合方式选错了。这种最难发现——因为它长得跟正确答案一模一样,且你无法从输出本身看出它是均值还是峰值。
防御写进工具设计里,而不是提示词里:
# 反面写法:让模型自己拼 PromQL
def query_metrics(expr: str): ... # 模型写 "cpu_usage{svc='order-api'}"
# 它不知道这个指标是 5m 均值还是 gauge 瞬时值
# 正面写法:把口径变成必填参数,返回体里也带出来
def query_metrics(
metric: str, # 只能从白名单里选(指标字典)
service: str,
window: str, # 例 "5m" / "1m"
agg: Literal["avg", "max", "p50", "p99"], # 聚合方式必填,不许默认
lookback: str = "1h",
) -> list[Sample]:
"""
返回的每个 Sample 都带 meta:
{"value": 82.1, "unit": "%", "agg": "avg", "window": "5m", "at": "2026-11-07T21:11:00+08:00"}
没有 meta 的样本一律不返回。这样模型没法"忘记"口径,因为它必须是输出的一部分。
"""形状三:因果倒置。 把结果当原因。CPU 高 → 说是 CPU 导致延迟高,而实际是重试堆积导致 CPU 高。这种最危险,因为它在逻辑上永远成立:CPU 高确实会推高延迟,相关性和因果性在这一步无法区分。
唯一的防御是强制反证。见 7.3 的 prompt 骨架。
6.2 上下文截断:关键那一行在第 3471 行
日志有 12000 行,模型的 context 装不下,于是取前 200 行 + 后 200 行。看起来合理,实际上:
- 前 200 行是故障刚开始时的正常日志
- 后 200 行是恢复期的日志
- 中间那 11600 行里有真正的线索
这是"沉默的错误"——AI 基于残缺输入给出的结论,看起来和对的结论没有任何区别。
三条对策,按成本排:
- 检索代替倾倒。 不要
tail -n 5000,而是用结构化查询先聚合成"错误指纹"(异常类型 × 消息模板 × 次数 × 首末时间),把 12000 行压成 15 行。这一步用 Drain3 之类的模板挖掘算法,或者最土的正则归一。压缩比常常是 500:1,且信息密度更高。 - 显式标注残缺。 上下文包里必须有一句机器可读的话:
log_coverage: "12,000 行中的 4,000 行(错误级别全量 + INFO 采样 10%)"。让模型知道它拿到的不是全集,它才有可能说"这里我看不到"。 - 两次下钻。 第一次只给聚合视图,模型要求下钻时再给原始行。这比一次喂全量便宜十倍,且更准。
第 2 条最容易被跳过,因为它需要改的是采集侧而不是提示词侧。但没有它,第 1 条和第 3 条就没有意义——模型不知道自己在哪。
6.3 权限:只读和写必须在物理上分开
这条没什么好商量的,但经常被"为了方便"破坏。
一个具体的设计:
# 工具分三个授权层,靠凭据隔离,不靠提示词约束
tools:
layer_read: # 默认授予,无副作用
- query_metrics
- search_logs
- get_trace
- list_changes
- get_topology
- get_runbook
- get_slo_budget
layer_write: # 需要人点击确认,Agent 只能"提议"
- scale_workload # 扩缩容
- restart_workload # 重启
- toggle_feature_flag # 开关
layer_forbidden: # 任何情况下不授予
- exec_in_pod # 第 20 篇那次 Game Day 就卡在这
- mutate_database
- delete_resource
- update_status_page # 对外,见 5.1关键不是分层本身,是用凭据分层,不用提示词分层。用提示词写"你只能读不能写",等于把保险柜的密码贴在保险柜上——一次 prompt injection 或者一次模型幻觉就穿过去了,而且穿过去之后没人知道。
另一个容易漏的点:layer_read 也有副作用。一次全集群的 search_logs 打满日志系统的查询并发,或者一次超大范围的 PromQL 让 Prometheus OOM,这是真实发生过的。所以只读层也要有配额:单次查询时间范围上限、返回行数上限、并发上限。
6.4 延迟与耐心:值班的人只等 90 秒
事故里的人没有耐心。这是物理事实,不是态度问题——凌晨三点半,一个人在手机上,光线不好,压力很大。
一个 Agent 排障的延迟构成:
| 环节 | 典型耗时 |
|---|---|
| LLM 首轮推理 | 3~8 秒 |
| 并行调 6 个工具 | 5~20 秒 |
| 第二轮推理 + 下一层下钻 | 15~40 秒 |
| 三轮循环(有些框架默认跑三轮) | 60~150 秒 |
| 长上下文推理(30k+ token) | 额外 20~40 秒 |
超过 90 秒,人的反应不是等,是"先自己看一眼"。 而"自己看一眼"会把 AI 的输出降级成一个事后的对照材料,它最有价值的那个功能(省掉 T_context)当场作废。
所以接入设计有一条硬要求:首个有用的输出必须在 30 秒内出来,哪怕它只是一份事实清单。 做法是拆成两段:
- 第一段(< 30 秒):并行拉六类数据,只出事实表,不下结论。这段是可以提前预热的——告警触发的那一刻就把数据开始拉
- 第二段(30~120 秒):出候选假设,每条带验证查询
- 第三段(按需):自动下钻验证,每验证一条就推一条增量
第一节那 90 秒其实已经不算慢,问题出在它只给了一次性的完整输出,人拿了就没再互动。分段推送的话,21:15 拿到事实表,21:15:40 拿到假设,21:16:30 拿到"我查了 H1,扩容后 p99 未改善,H1 排除"——这次事故可能就是 21:30 结束。
6.5 成本:一次排障 30 万 token 的账
算一遍,免得后面被财务问倒。
一次中等复杂度的排障,三轮循环:
- 系统提示 + 工具定义:4k token
- 第一轮上下文包(事实表 + 日志摘要 + 拓扑 + 变更列表):25k
- 第二轮下钻(原始日志片段 + 查询结果):40k
- 第三轮(另一条假设的下钻):30k
- 累积的对话历史每一轮都重发:大致上总量是单次的 2.5 倍
一轮下来 25 万 ~ 35 万 token。按当前主流模型的价格量级,单次排障的直接成本在几块到几十块人民币之间。看似不多,但要乘上:
- 每条告警都可能触发(第 6 篇那篇把告警从 500 降到 50,一年仍有 1.8 万条)
- 值班的人会反复追问(平均 3~5 轮)
- 复盘时还会再跑一遍(这是好事,但也要算钱)
一个 50 人研发团队的量级:年成本几千到几万元,跟一个工程师的月薪同量级。这个数字通常划得来,但前提是命中率真的在 0.5 以上。 命中率 0.1 的时候,你花的是同样的钱,买到的是 2 分钟的净亏损。
省钱的三条工程手段,都值得做:
- 缓存事实层。 同一服务的拓扑、Runbook、指标字典一小时变不了一次,缓存命中率能到 80% 以上
- 小模型做路由。 用便宜模型判断"这条告警要不要深挖",只有需要深挖的才进大模型。一次分类成本是大模型的 1/20
- 设预算上限。 单次排障 token 上限,超了就强制输出当前结论 + 标注"未完成下钻"。这个上限同时保护成本和延迟
6.6 最深的坑:AI 的结论变成责任的出口
前面五个都是技术坑,这个不是。
复盘会上出现这种句子:"当时是 AI 建议扩容的"。
这句话的问题不在于它是否属实(通常是属实的),而在于它结束了一次本该发生的讨论。原本要问的是"为什么第一反应是扩容",现在这个问题被替换成了"AI 为什么说扩容"。前者会指向一个可改的东西(缺变更视图、缺依赖拓扑),后者只会指向"下次别信 AI"。
三个具体的防御:
第一,把 AI 定位写进值班规范,用一句话:AI 的输出是证据,不是结论。 谁签字谁负责,这是第 22 篇"追责只针对没记录、不针对决定的正确性"的直接延续。如果 AI 的输出没有被记录在 ai_input 字段里,那这次事故的复盘就是不合格的——因为你没法判断人到底是被锚定了还是独立判断了。
第二,AI 的输出必须可被否决,且否决要被记录。 就像第 22 篇记录 decisions.rejected 一样:AI 给了 H1 扩容,人选择了不扩容去查变更——这个否决动作本身就是最有价值的训练数据。它告诉你哪类事故里 AI 的判断不值得信。
第三,永远不要把 AI 的置信度当作概率。 那个"置信度:高"是模型对文本自然度的判断,不是对正确的判断。第一节里 H1 标"高"、H2 标"低",而正确答案恰恰是 H2 那一行。实践中最可靠的做法是干脆不显示置信度——它会制造一种不存在的严谨感,而人天生会抓住一个数字当锚。
七、最小可行的接法:从"只给事实"开始
7.1 四个阶段,倒着做会踩雷
| 阶段 | 做什么 | 关键约束 | 预期收益 | 工作量 |
|---|---|---|---|---|
| 0 | 只做上下文聚合,不出结论 | 只读、只列事实、不下判断 | T_context -80% | 1~2 周 |
| 1 | 补工具:变更记录、拓扑、Runbook 检索 | 变更记录是重中之重 | 命中率 0.1 → 0.6 | 2~4 周 |
| 2 | 出候选假设 + 自动下钻验证 | 每条假设必须带反证 | T_verify -40% | 3~4 周 |
| 3 | 复盘辅助(时间线、事故记录生成) | 输出必须能被人改 | 复盘耗时 -60% | 2~3 周 |
顺序很重要,因为阶段 0 就能产生可观测的收益,而且它没有任何失败模式——它不会给出错误结论,因为不给结论。
阶段 3 的 ROI 常常高于阶段 2,这点被严重低估。事中排障的所有约束(时间紧、信息缺、压力大)在事后全都消失了,而事后整理时间线又恰恰是 AI 最擅长的事:把散落在六个系统里的信号对齐、按模板填进事故记录、找出"决策间隔超过 10 分钟"的位置。第 22 篇那套事故记录 schema,人工填一次要 40 分钟,AI 起草 + 人改要 10 分钟。
7.2 六个工具的最小集
不需要一次接二十个系统。下面六个,覆盖了 80% 的上下文需求:
tools:
- name: query_metrics # 指标(带口径元数据,见 6.1)
- name: search_logs # 日志(结构化 + 错误指纹聚合,见 6.2)
- name: list_changes # 变更记录:发布、配置、DDL、扩缩容、开关
- name: get_topology # 依赖拓扑 + 所属团队 + 各自的 SLO
- name: get_runbook # 该服务的 Runbook(第 18 篇)+ 历史事故(第 22 篇 schema)
- name: get_slo_budget # 当前错误预算(第 10 篇),决定"能不能更激进"list_changes 是里面最不起眼、也最关键的一个。它的设计有两个要点:
def list_changes(lookback: str = "4h", scope: str = "all") -> list[Change]:
"""
必须返回四类变更,缺一类就会造成"变更视图缺口":
1. 应用发布(镜像 tag、commit、发布人)
2. 配置变更(网关、Nginx、feature flag、DB 参数)
3. 数据变更(DDL、批量脚本、数据修复)
4. 基础设施变更(扩缩容、节点替换、网络策略、证书)
每条必须带:
- started_at / ended_at(带时区)
- blast_radius(影响的 service 列表,允许为空但要显式给空)
- change_level(C1-C4,第 19 篇的分级)
- reversible(bool + 预计回滚耗时)
找不到任何变更时,返回空数组,不要返回"无相关变更"这种自然语言——
模型对"空数组"和"查不到"的处理方式不同。
"""第一,四类变更必须都覆盖。只接 CI/CD 的发布记录,等于只看见 40% 的变更。第一节那次是配置变更,在网关系统里。
第二,空数组和查询失败必须区分。"最近 4 小时没有变更"和"变更平台 API 超时了",对模型来说是两件完全不同的事,但对糊在一起的实现来说是同一件事。这是"AI 说没有变更"这种事故的唯一成因。
7.3 一个强制反证的 prompt 骨架
不用写很长,关键是三条硬约束:事实必须可回溯、假设必须带反证、允许说不知道。
你是值班助手的上下文分析模块。你的输出会被一个正在处理事故的工程师阅读,
他会在 90 秒内决定下一步动作。
【硬约束】
1. 任何事实性陈述必须附上产生它的工具调用参数(query / 时间窗 / 聚合方式)。
没有工具调用支撑的陈述,一律不要写。
2. 每条假设必须写三样东西:
- 支持证据(事实编号)
- 反证条件:如果观察到什么,这条假设就不成立
- 验证动作:一条具体的、能在 2 分钟内跑完的查询
3. 如果现有数据不足以区分两条假设,明确写"当前数据无法区分 H1 与 H2,
需要 X"。
4. 不要给置信度分数。不要用"极可能""基本确定"这类词。
5. 你不知道的东西比你知道的更重要。在输出末尾固定列出一节
【我看不到的】:本次分析中缺少的数据源、断链的变更记录、被截断的日志。
【输出格式】
## 事实(每条带 tool_call_id)
## 假设(H1/H2/...,每条带:支持证据 / 反证条件 / 验证动作)
## 我看不到的第 2 条是整段最重要的。要求模型给出"反证条件",会把因果倒置这类错误逼出来。 在第一节那个案例里,如果被要求写反证条件,H1 会写成:
H1: 内存压力导致 GC 频繁
反证条件: 扩容后 p99 未改善,或活跃线程数上升但连接池等待时间同步上升
验证动作: 扩容 5 分钟后对比 p99;同时查 order-api → payment-gateway 的连接池等待时长第二句反证条件就能把方向扭过来——因为"连接池等待时间同步上升"这个观察一旦做出来,内存假设就塌了。而写不出来的假设,本身就是一个信号。
第 4 条(不要置信度)在实践里阻力最大,因为产品经理喜欢那个小徽章。但第一节那个案例里,徽章正好标反了。
7.4 一个上下文打包脚本
把上面所有约束落成一个能跑的东西。核心不是"调模型",而是"打包"——模型好不好,八成看这包打得干不干净。
#!/usr/bin/env bash
# evidence-pack.sh —— 把一次告警的上下文打包成一个结构化文件
# 用法:./evidence-pack.sh <alert_id>
# 输出:evidence/<alert_id>.yaml(人可读,也是喂给模型的唯一输入)
set -euo pipefail
ALERT_ID="$1"
OUT="evidence/${ALERT_ID}.yaml"
SVC="$(alert_field "$ALERT_ID" service)" # 从告警里取服务名,取不到直接失败
WINDOW_START="$(alert_field "$ALERT_ID" starts_at)" # 必须是带时区的 ISO8601
mkdir -p evidence
{
echo "alert_id: ${ALERT_ID}"
echo "service: ${SVC}"
echo "window:"
echo " start: ${WINDOW_START}"
echo " tz: Asia/Shanghai" # 强制显式时区,见 4.2
echo "coverage:" # 显式声明每个数据源的完整度,见 6.2
echo " metrics: full" # 指标全量
echo " logs: 'errors_all, info_sampled_10pct'" # 日志只采了错误级 + 10% 的 info
echo " changes: '4h'" # 变更只回溯 4 小时
echo " traces: 'sampled_1pct'"
echo
# 1) 事实层:六个工具并行拉,各自失败不影响其他(缺了要在 coverage 里标出来)
for t in metrics logs changes topology runbook slo_budget; do
if ! fetch_${t} "${SVC}" "${WINDOW_START}" > "/tmp/${ALERT_ID}.${t}" 2>/dev/null; then
# 关键:失败要写进文件,不能静默跳过——否则模型会以为自己看到了全集
echo " ${t}: 'FETCH_FAILED'" >> "${OUT}.coverage.tmp"
continue
fi
echo "## ${t}" >> "$OUT"
cat "/tmp/${ALERT_ID}.${t}" >> "$OUT"
echo >> "$OUT"
done
# 2) 日志不能直接倒:先聚合错误指纹,压缩比通常 200:1 以上
aggregate_error_fingerprints "/tmp/${ALERT_ID}.logs" >> "$OUT"
# 3) 变更必须四类齐全(发布 / 配置 / 数据 / 基础设施),缺哪类显式标注
check_change_coverage "/tmp/${ALERT_ID}.changes" >> "$OUT"
} >> "$OUT"
# 4) 体积护栏:超过 60k 字符就砍最不重要的部分,并记录砍了什么
guard_size "$OUT" 60000 || echo "truncated: logs(kept_fingerprints)" >> "$OUT"
echo "packed: ${OUT} ($(wc -c < "$OUT") bytes)"三处细节值得单独说:
coverage 段。 它是整个包里最有价值的十行。它让模型知道"哪些数据是完整的、哪些是抽样、哪些拉失败了"。有了它,模型才有能力说"我看不到 xx";没有它,模型一定会用一个完整的故事覆盖掉缺口。
失败必须留痕。 fetch_changes 超时了,就要写 changes: FETCH_FAILED。糊成"无变更",就会变成一次错误的排除法。
体积护栏要记录砍了什么。 截断本身不可怕,可怕的是截断后模型不知道被截了。
7.5 什么永远不要接
- 写类工具(
exec_in_pod、restart、scale、delete):可以给人一个按钮,但按钮的权限是人的,不是 Agent 的 - 对外发布(状态页、客户通知、公告):第 22 篇 CL 的活儿,AI 可以起草
- 定责结论:任何形式的"根因是 X 团队的操作失误"都不该由 AI 输出,哪怕是正确的
- 跨系统的数据修改:第 23 篇那 12 万行回写,AI 可以生成脚本、可以算影响面、可以校验,但执行必须人按
八、五个度量:证明它不是个贵的玩具
AI 排障最容易死在"感觉有用"上。五个数,都能量。
| 指标 | 定义 | 参考值 | 为什么是它 |
|---|---|---|---|
| T_context 中位数 | 告警触发到上下文包就绪的时间 | 接入前 8~12 min,接入后 < 2 min | 唯一必然改善的数,也是最容易被忽略的收益 |
| top-1 假设命中率 | AI 首条假设与最终根因一致的比例 | 只读工具 0.2~0.35;接全变更 0.5~0.65 | 决定这件事是赚钱还是赔钱的分水岭 |
| 误锚率 | top-1 错误 且团队前 10 分钟沿其行动的比例 | < 15% | 唯一能反映"AI 拖慢事故"的数,比命中率更能说明风险 |
| 分级别 MTTK 对比 | AI 参与 vs 未参与,按事故级别分组 | 小事故 -20%~-30%;大事故 ±5% | 预期结论反直觉,且它决定你该在什么场景用它 |
| AI 输出被否决率 | 人明确不采纳 AI 建议的比例 | 15%~30% 较健康 | 太低说明人在照抄,太高说明工具不对 |
三个提醒:
第一,不要报均值,报 P50 和 P90。 第 22 篇讲 MTTR 时已经说过一次,这里同样成立,而且更严重——AI 的收益极度偏向简单事故,均值会把它抹平。
第二,分级别看。 一条经验:小事故(P3/P4)AI 的收益明显,因为原因简单、工具清单基本够用;大事故(P1/P2)收益很小,因为原因复杂、跨系统、涉及组织判断。如果把它们混在一起算,会得到一个"好像有点用但不明显"的数字,然后这个项目就被砍了。
第三,误锚率要靠记录才能算。 它需要知道"人前 10 分钟在干什么",而这件事只有事故记录里有。所以第 22 篇的事故记录 schema 是这一篇的前置条件——没有事故记录,就没有 AI 排障的度量;没有度量,就只能靠感觉。
一个可以直接跑的统计脚本:
#!/usr/bin/env python3
# ai-triage-metrics.py —— 从事故记录算 AI 排障的五个数
# 数据源:incidents/*.yaml(第 22 篇 schema + 一个 ai_triage 段)
import glob, math, yaml
incs = [yaml.safe_load(open(f)) for f in glob.glob("incidents/*.yaml")]
def pctl(xs, q):
xs = sorted(xs)
return xs[max(0, math.ceil(len(xs) * q) - 1)] if xs else 0
reviewed = [i for i in incs if i.get("ai_triage")]
if not reviewed:
raise SystemExit("没有带 ai_triage 段的事故记录,先改记录模板")
ctx = [i["ai_triage"]["t_context_min"] for i in reviewed]
hit = [i for i in reviewed if i["ai_triage"]["top1_hit"]]
anch = [i for i in reviewed
if not i["ai_triage"]["top1_hit"] and i["ai_triage"]["acted_on_top1_within_10m"]]
print(f"样本 {len(reviewed)} 起(占全部 {len(reviewed)/len(incs):.0%},样本少时只看趋势)")
print(f"T_context P50={pctl(ctx,.5)}min P90={pctl(ctx,.9)}min")
print(f"top-1 命中率 {len(hit)/len(reviewed):.0%}")
print(f"误锚率 {len(anch)/len(reviewed):.0%} ← 超过 20% 先修工具再谈推广")
# 按级别看 MTTK,这是最容易被均值抹掉的一段
for lvl in ("P1", "P2", "P3", "P4"):
a = [i["mttk_min"] for i in reviewed if i["severity"] == lvl and i["ai_triage"]["used"]]
b = [i["mttk_min"] for i in reviewed if i["severity"] == lvl and not i["ai_triage"]["used"]]
if len(a) >= 3 and len(b) >= 3:
print(f"{lvl} MTTK P50 用={pctl(a,.5):.0f}min 不用={pctl(b,.5):.0f}min "
f"({(pctl(a,.5)-pctl(b,.5))/pctl(b,.5):+.0%})")mttk_min 字段来自第 22 篇的 MTTK 拆解,ai_triage 段是这一篇新加的。两个 schema 拼起来,才能回答"AI 到底有没有让事故变短"——单独任何一个都答不了。
九、二十项 AI 排障接入自检清单
按"数据 / 工具 / 输出 / 边界 / 组织"五组。每项写到可验收。
数据
- 上下文包里每条指标都带 (时间戳, 时区, 采集源, 聚合方式, 采样间隔) 五元组
list_changes覆盖四类变更:发布、配置、数据、基础设施- 空数组与查询失败在返回体里可区分(
[]vsFETCH_FAILED) - 日志先聚合错误指纹再喂模型,压缩比有实测记录
- 上下文包里有显式的
coverage段,声明每个数据源的完整度
工具
- 工具分三个授权层,靠凭据隔离,不靠提示词
layer_forbidden里包含exec_in_pod/mutate_database/update_status_page- 只读工具也有配额:单次时间窗上限、返回行数上限、并发上限
- 指标查询的
agg参数必填,无默认值 - 工具定义是给 Agent 用的(带单位、带语义),不是照抄给人看的 API
输出
- 每条事实性陈述都能回溯到一次工具调用(
tool_call_id) - 每条假设都强制包含"反证条件"与"验证动作"
- 输出里固定有【我看不到的】一节
- 不显示置信度分数,不使用"极可能"这类修辞
- 首个有用输出(事实表)在 30 秒内产出
边界
- 值班规范里有一句明确表述:AI 的输出是证据,不是结论
- 事故记录里有
ai_input字段,与decided_by分开 - AI 建议被否决的动作被记录(对应第 22 篇的
decisions.rejected) - 数据恢复时间点、对外口径、定责结论三类判断,AI 只出材料
组织
- 误锚率纳入月度复盘,超过 20% 时暂停推广、先修工具
- MTTK 对比按事故级别分组统计,不报均值
- 单次排障 token 成本有预算上限,超限强制降级输出
- 有一次真实事故的完整复盘包含"AI 说了什么、人做了什么决定"的对照
十、四阶段路线
阶段一(第 1~2 周):先让它只说话
- 接
query_metrics+search_logs+list_changes三个工具,只做上下文聚合 - 输出只有事实表,加上【我看不到的】。明确禁止输出结论和建议
- 把
list_changes的四类变更打通——这一步通常是全篇最费劲的,因为变更散在四五个系统里 - 量化起点:手动跑 20 次,记下 T_context 的中位数
这一阶段不需要任何模型调优。工具接对了,收益就已经在。
阶段二(第 3~6 周):给它假设,但要它自证
- 加上"假设 + 反证条件 + 验证动作"的输出格式
- 实现自动下钻:模型可以主动发起 2~3 层查询,每层都记录证据
- 用过去 30 次真实事故回测命中率。这一步不能跳过——它决定后面值不值得做
- 如果命中率低于 0.4,回头查工具,别查模型
阶段二最容易犯的错是:为了让 demo 好看,把"反证条件"这一节省掉。省掉之后,输出立刻从"可讨论的材料"变成"权威的结论",而这正是 6.6 那个坑的入口。
阶段三(第 2~3 月):进 on-call 链路,但不进决策链
- 告警触发时自动预热上下文包(30 秒内出事实表)
- 分段推送:事实 → 假设 → 增量验证
- 止血类动作做成"AI 提议 + 一键执行",权限归人
- 开始记录
ai_triage段,跑五个度量,尤其是误锚率
阶段四(第 4~6 月):把重心挪到事后
- 复盘辅助:AI 起草事故时间线与记录,人改
- 相似案例检索接进 Runbook 体系(第 18 篇),用首条命中率验收
- 把"AI 建议被否决"的记录反哺成 Runbook 的新条目——人否决 AI 的理由,往往就是 Runbook 里缺的那一句
- 能力成熟后仍然保留一条硬边界:不接管任何不可逆的动作,不输出任何定责结论
十一、和前面各篇的关系
- 第 6 篇(告警治理):告警量决定了 AI 的调用量。500 条/天降到 50 条/天,不是一个运维体验的改善,它是 AI 排障成本能不能成立的前提
- 第 10 篇(错误预算):
get_slo_budget这个工具把这个数交给模型。它决定"能不能更激进地止血"——预算还剩 60% 和只剩 5%,同一个动作的意义完全不同 - 第 14 篇(eBPF):AI 看不见内核,除非有人把 eBPF 的观测结果做成工具。本文 6.3 里那个"打满还是泄漏"的判断,正是第 23 篇 9.3 节那套 eBPF 查询的产物——没有那一层数据,AI 给出的连接池结论必然是猜的
- 第 18 篇(Runbook):
get_runbook的数据源。Runbook 的结构化程度直接决定相似案例检索的质量;没有结构的历史文档,检索出的是相似的字,不是相似的事 - 第 19 篇(变更安全):
list_changes的字段设计直接沿用 C1-C4 分级。本文最核心的结论——AI 的第一优先级是接上变更记录——本质是那篇"70% 故障来自变更"的推论 - 第 20 篇(混沌演练):演练是最好的 AI 训练场和评测场。一次演练里你知道真实故障是什么,可以让 AI 在没有压力的条件下跑一遍,算出它的命中率。用演练数据评测 AI,比用生产事故便宜十倍
- 第 21 篇(容量):AI 给"扩容"这种建议的时候,必须知道容量水位,否则和建议"多喝热水"没有区别。第一节那次扩容到 40 副本,如果它先查了连接池配额,就不会给出这个建议
- 第 22 篇(事故指挥 IC):这一篇和它是镜像关系。22 讲"人怎么组织一次事故",24 讲"机器在事故里能站哪个位置"。两者的接口是事故记录里的
ai_input与decided_by——分开记录,就是这条边界的物理形态 - 第 23 篇(数据库 SRE):AI 在数据层最靠谱的落点是"从 binlog 和慢日志生成时间线与候选变更清单",最不靠谱的是"替你决定恢复哪个时间点"。5.1 节那个
decisions例子就是这句话的具体写法 - AIOps 专栏:
03.AIOps那七篇(K8s GPT、K8s Chat CLI、Agent 实战)是工具怎么造;这一篇是工具造完之后该放在哪、不该放在哪。造和用是两件事 - 周刊第 1 期:那一期讲的 Nightingale 上 MCP Server、HolmesGPT、opensre,都是"给 Agent 开放查询接口"这条线在生态上的落地。趋势很清楚:MCP 正在从加分项变成及格线。而本文想说的是——接口开得多不等于开得对,缺一个
list_changes,其余六个白接
写在最后
如果这篇只带走一句:
AI 的视野不是被模型能力限制的,是被工具清单限制的。
第一节那五条事实一条都没错。它错在把结果当原因,而这个错不是逻辑能力不足,是它的世界里没有 20:50 那次配置变更。它用看得见的五条证据,解释了一个看不见的原因,语气和它对的时候一模一样。
所以接入 AI 排障的第一件事,不是选模型,不是写提示词,是把变更记录接进去。命中率从 0.1 到 0.7 的跨度,比任何一次模型升级都大。而命中率低于 25% 的时候,接 AI 是一次净亏损。
如果只带走一个动作:
把上周所有事故翻出来,统计一下:AI 的 top-1 假设,有几次是对的?错的那几次,人有没有沿着它走?
这两个数——命中率和误锚率——决定了这件事在你这里是不是个玩具。它们不需要接入 AI 才能算,先把人工诊断的"首次假设"和"是否被锚定"记下来就行。先有度量,再谈工具。
最后说一句边界之外的话。
"不能替你定责"不是在贬低 AI,恰恰是在保护它的价值。责任这个东西的本质是"有人承担后果",而承担后果需要两件模型没有的东西:一个可以在事后被追讨的身份,和一个不在系统里的损失函数。事故里最贵的从来不是"不知道原因"(原因总能查到),而是"没有人有权决定现在该牺牲什么"。
第 22 篇讲 IC 时有一句:IC 不碰键盘。这句话对 AI 同样成立——它能看、能算、能把三天的日志压成三十行,但它不该按任何一个不可逆的按钮。 它最好的位置不是指挥官,是那个永远清醒、永远记得问"还有别的原因吗"的参谋。
用对了,它把 T_context 从十分钟压到一分钟,让值班的人把力气花在问对问题上。
用错了,它给你一个漂亮的、自信的、事实全对的错误方向,然后整个团队一起走了十五分钟。