AI 学习笔记(十七):LLM 事故响应(Incident Response)最小实践

上一篇我们把成本治理的几个核心杠杆收起来了。
这一篇继续生产运维实践第三部分:LLM 事故响应(Incident Response)

很多团队线上出问题时,并不是完全没有监控,而是缺下面这几样东西:

  1. 没有统一事故分级
  2. 没有固定止血顺序
  3. 没有对外同步模板
  4. 没有把事故样本回灌进后续评估与门禁

结果就是:大家都很忙,但系统恢复得并不快,复盘也很难真正沉淀成工程能力。

这篇仍然只讲最小可落地版本,目标只有三个:

  1. 先快速确认“是不是事故”
  2. 再用最小代价止血
  3. 最后把坏样本沉淀成可回归资产

1. 先统一口径:什么才算 LLM 事故

不是每次 429、一次超时或一条错误日志都算事故。
真正应该进入 incident response 的,通常是下面 4 类情况:

  1. 可用性事故
    核心路由大面积失败、超时飙升、供应商不可用,用户明显无法完成任务
  2. 质量事故
    新 prompt / 新模型 / 新检索策略上线后,结构化输出失败率、引用错误率、幻觉率明显升高
  3. 成本事故
    请求暴涨不是问题,但 cost_per_successful_request 短时间失控才是问题
  4. 安全与副作用事故
    工具执行越权、错误写回、错误发消息、敏感内容泄露、危险自动化动作未被拦住

一个很实用的判断标准是:

  • 用户是否明显受影响
  • 影响是否持续扩大
  • 是否需要跨人协同止血

如果三个问题里有两个答案是“是”,基本就该按事故处理,而不是把它当成普通 bug 慢慢排。

2. 事故分级先做简单,不要一开始搞得太细

最小分三级就够:

2.1 P1

满足任一条件即可:

  1. 核心路径不可用,且无可接受降级
  2. 输出存在明显安全风险或错误副作用
  3. 大面积用户受影响,且影响还在扩大

处理目标:

  • 先止血,再解释
  • 立即冻结相关发布与自动化写操作

2.2 P2

常见形态:

  1. 主模型异常,但 fallback 还能用
  2. 结构化输出错误率明显升高,但可以切回保守模式
  3. 检索异常导致质量下降,但还能通过缓存、规则兜底维持核心体验

处理目标:

  • 控制影响范围
  • 保住核心场景

2.3 P3

常见形态:

  1. 非核心路由失败
  2. 内部工具问题,对外影响有限
  3. 观测到异常趋势,但尚未突破用户体验阈值

处理目标:

  • 按标准故障处理
  • 不必拉满 incident 机制

不要把分级直接绑定到“报错类型”,要绑定到用户影响与业务风险
同样是 429,核心支付问答链路和内部草稿总结工具,优先级完全不一样。

3. 前 15 分钟只做 6 件事

事故刚发生时,最怕的是同时开 10 个方向,最后谁都不知道自己在做什么。

我更推荐前 15 分钟固定只做这 6 步:

  1. 确认影响面
    看受影响路由、租户、地区、模型、provider、版本,不要只盯一条报错
  2. 冻结变更
    暂停刚上线的 prompt、模型路由、检索配置或自动化写操作
  3. 启动止血方案
    优先切 fallback、关高风险工具、缩上下文、走缓存或人工兜底
  4. 指定一个指挥角色
    至少要有人统一做决策和更新时间线,避免多人同时乱切配置
  5. 建立单一事实源
    用一个文档、一个频道或一个工单同步状态,不要到处散落聊天记录
  6. 约定固定更新节奏
    例如每 15 分钟更新一次当前状态、影响范围、下一步动作

这一步的核心不是“分析出最终根因”,而是快速把系统拉回可控状态

4. 止血顺序很重要:先保守降级,再精细修复

很多团队事故扩大,不是因为没有技术手段,而是止血顺序错了。
更稳的顺序通常是下面这样:

4.1 第一层:切到更稳的 provider / model

适用场景:

  • 某个供应商 429/5xx/529 异常升高
  • 某个模型时延突然拉长
  • 某个新模型输出格式漂移

动作优先级:

  1. 切同 provider 的更稳模型
  2. 再切跨 provider fallback
  3. 同时降低并发或收紧超时

4.2 第二层:缩功能面

适用场景:

  • 工具链太长导致失败点太多
  • structured output 解析失败率升高
  • 检索链路或重排链路不稳定

常见动作:

  1. 关闭非关键工具调用
  2. 关闭长链推理步骤
  3. 把复杂结构输出降成文本或较小 schema
  4. 缩短检索上下文和输出长度

4.3 第三层:切到安全兜底

适用场景:

  • 高风险写操作可能造成错误副作用
  • 检索质量漂移严重,结果不可信
  • 自动化流程正在错误写回

常见动作:

  1. 切只读模式
  2. 切缓存答案或 FAQ 模板
  3. 切人工审核 / 人工接管
  4. 直接关闭高风险入口

要记住一个非常现实的原则:

事故期间的目标不是“保持所有功能完整”,而是“先把错误影响和副作用压住”。

5. LLM 事故和普通 Web 事故最大的不同

LLM 系统的事故,往往不只是一条 500。

它和传统 Web 故障相比,至少多了 4 个特殊维度:

  1. 输出质量会静默下降
    接口没挂,但答案已经不可靠
  2. 同一请求链路更长
    可能经过检索、重排、prompt 拼装、模型调用、工具执行、结构校验、回写
  3. 供应商问题不可控
    你只能路由、降级、限流,不能真正修复对方系统
  4. 错误可能带副作用
    模型不是只“回答错了”,还可能发错消息、改错状态、写错内容

所以 LLM incident response 必须额外保留这些证据:

  1. provider / model
  2. prompt_version / prompt_hash
  3. retrieval_doc_ids 或知识片段 hash
  4. tool_calls / fallback_used
  5. input_tokens / output_tokens / 成本变化
  6. request_id / trace_id

没有这些字段,后面几乎很难判断:

  • 是供应商问题
  • 是新 prompt 问题
  • 是检索召回问题
  • 还是工具链副作用问题

6. 一段可直接复用的最小止血策略代码(Node.js)

下面示例只演示一件事:
把常见事故信号收敛成明确的降级动作,避免线上完全靠人拍脑袋。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const INCIDENT_POLICIES = [
{
name: "provider-outage",
when: (signal) =>
signal.providerErrorRate >= 0.2 || signal.providerStatus === 529,
action: {
routeMode: "provider-fallback",
disableTools: true,
maxOutputTokens: 600,
},
},
{
name: "schema-drift",
when: (signal) => signal.schemaFailureRate >= 0.15,
action: {
routeMode: "safe-model",
structuredOutput: "strict-minimal",
disableNewPromptVersion: true,
},
},
{
name: "retrieval-bad",
when: (signal) => signal.emptyRetrievalRate >= 0.25,
action: {
routeMode: "cached-answer",
disableWriteActions: true,
requireHumanReview: true,
},
},
];

export function decideIncidentAction(signal) {
for (const policy of INCIDENT_POLICIES) {
if (policy.when(signal)) {
return {
incident: true,
policy: policy.name,
...policy.action,
};
}
}

return {
incident: false,
routeMode: "normal",
};
}

这段代码的价值不在“写法高级”,而在于把事故响应中的几个关键动作显式化:

  1. 事故信号可枚举
  2. 止血动作可回放
  3. 触发策略可审计

后续你可以继续把它接到 feature flag、路由器或配置中心上。

7. 对外同步别写散文,固定成一个模板

事故期间对内对外同步,重点不是“写得多详细”,而是让人一眼看懂当前状态。

建议固定成下面 4 行:

  1. 当前状态
    已确认/已止血/恢复中/已恢复
  2. 影响范围
    哪些路由、哪些用户、什么时间段
  3. 临时措施
    已切 fallback、已关写操作、已缩上下文、已人工接管
  4. 下一次更新时间
    明确一个时间点,不要写“稍后同步”

例如:

1
2
3
4
状态:已确认 P1,正在恢复
影响:2026-03-25 15:20 起,核心问答路由错误率升至 32%,主要影响结构化输出场景
措施:已冻结 chat-v4 prompt 发布,切换到 safe-model + 只读模式,关闭外部写工具
下次更新时间:16:00

模板化的好处是:

  • 降低沟通成本
  • 避免不同人说法不一致
  • 方便事后回放时间线

8. 事故复盘的终点,不是文档,而是回归闭环

很多团队复盘最大的问题是:
文档写了,但系统没有因此变强。

我建议最小复盘至少产出 5 个结果:

  1. 时间线
    从发现、确认、止血、恢复到验证完成
  2. 根因分类
    provider、prompt、检索、工具、副作用、容量、流程
  3. 防再发动作
    例如加门禁、加回退开关、改超时、补缓存、补灰度
  4. 坏样本沉淀
    把线上失败样本回灌到评测集和回归基线
  5. 责任到人
    每个 action item 要有 owner 和截止时间

对 AI 系统来说,第四点尤其关键。
如果事故里的坏样本没有沉淀进评测集,下次它很可能以另一种形式重新出现。

9. 一天内可落地的 Incident Response Checklist

如果你想把这篇直接变成行动项,可以按这个顺序落地:

  1. 定义 P1 / P2 / P3 分级标准
  2. 给核心路由准备 provider fallback 和 safe-mode 开关
  3. 明确哪些动作在事故期间必须切只读
  4. 固定一份状态同步模板
  5. 为事故保留 provider/model/prompt_version/request_id/trace_id
  6. 把线上坏样本写进评测集
  7. 复盘后把防再发动作接进发布门禁

做到这里,incident response 就不再是“靠经验救火”,而是一个可以重复执行、可以持续优化的工程流程。

总结

LLM 事故响应最重要的不是 heroic debugging,而是三件事:

  1. 快速确认影响范围
  2. 有顺序地做保守止血
  3. 把坏样本和修复动作回灌进系统

如果你现在只能先做一件事,我最推荐的是:

把 provider fallback、只读开关、状态同步模板和坏样本回灌这四件事先固定下来。

下一篇我会继续生产运维实践第四部分:LLM 故障演练(Game Day)最小实践,把演练脚本、注入场景、回滚验证和上线前演习串起来。

参考资料

本文永久链接: https://www.mulianju.com/learning-notes/ai-learning-notes-llm-incident-response-minimal-practice/