---
title: "事故复盘模板：API 故障复盘怎么写，时间线怎么用数据还原"
description: "一份可直接复制的中文事故复盘模板，含摘要、影响、时间线、根因、促成因素和行动项；讲清怎么用外部探测与状态页记录核对时间线，以及上游 AI API 出故障时自己团队的复盘该写什么。"
url: https://cdnping.org/blog/incident-postmortem-template-for-api-outage
language: zh-CN
published: 2026-10-25
category: "排障指南"
tags: ["事故复盘","故障排查","可用性","AI API","监控"]
source: cdnping.org
license: Free to quote and summarize with a link to the url above.
---
# 事故复盘模板：API 故障复盘怎么写，时间线怎么用数据还原

一份能用的事故复盘模板，核心是六个部分：摘要、影响、时间线、根因、促成因素、行动项（下面的模板另加了一节“做得好的地方”）。容易写虚的是其中两块：时间线要用监控数据核对，不能靠回忆拼；上游服务（比如某家 AI 模型 API）出故障时，复盘对象要换成“我们自己的应对”。下面先给可复制的模板，再逐段讲怎么写实。

## 为什么很多复盘写完没人看？

常见的问题有三个：

- 时间线是事后凭记忆补的，“大约 3 点左右发现异常”，没人能复查。
- 根因写成“上游服务不稳定”，然后就没有下文，行动项是“加强监控”。
- 影响只写“部分用户受影响”，没有请求数、失败率或时长。

复盘的价值在于下一次少花时间。所以每一句都应该能回答：证据在哪？下次能不能更早发现、更快恢复？

## 中文事故复盘模板（可直接复制）

```markdown
# 事故复盘：<一句话描述现象>，<日期>

状态：草稿 / 评审中 / 已定稿
负责人：<角色，例如当周值班>
评审时间：<日期>

## 1. 摘要
- 发生了什么（一句话）：
- 持续多久（开始 - 恢复，注明时区）：
- 影响多大（失败请求数 / 失败率 / 受影响功能）：
- 根因类别：自身代码 / 配置 / 基础设施 / 上游依赖 / 网络
- 当前状态：已恢复 / 已缓解待根治

## 2. 影响
| 指标 | 数值 | 数据来源 | 统计窗口 |
|---|---|---|---|
| 失败请求数 | | | |
| 失败率（失败 / 总请求） | | | |
| 受影响功能或接口 | | | |
| 用户可感知时长 | | | |

## 3. 时间线（统一用 UTC，括号内附北京时间）
| 时间 | 事件 | 证据（链接 / 截图 / 日志查询） |
|---|---|---|
| T0 | 第一个异常信号（探测失败、错误率上升） | |
| T1 | 告警触发 | |
| T2 | 有人确认并开始处理 | |
| T3 | 上游状态页首次更新（如适用） | |
| T4 | 采取缓解措施（切换、降级、回滚） | |
| T5 | 指标恢复 | |
| T6 | 官方宣布恢复 / 事件关闭（如适用） | |

关键间隔：发现耗时 T1-T0 = ；响应耗时 T2-T1 = ；缓解耗时 T5-T2 = 

## 4. 根因
<直接原因是什么，用证据说话；不确定就写“待确认”和确认方式>

## 5. 促成因素
<哪些条件让影响变大或持续更久：缺少超时、重试放大、单一供应商、告警阈值等>

## 6. 做得好的地方 / 运气成分
-

## 7. 行动项
| 编号 | 行动 | 类型（预防 / 发现 / 缓解） | 负责人 | 截止日期 | 验收标准 |
|---|---|---|---|---|---|
| A1 | | | | | |
```

几点约定：

- 无责复盘：写“告警阈值设成 30 分钟导致发现晚”（示例），不写“某某没看告警”。复盘对事不对人，否则下一次大家会倾向少写细节。
- 时区统一：状态页、日志、监控平台的时区经常不一样，混写很容易让时间线错位几个小时。
- 每个行动项都要有验收标准：“加强监控”不是行动项，“对上游 API 增加每 5 分钟一次的外部探测，连续 2 次失败告警”（数值按自己的业务定）才是。

## 时间线怎么用数据还原，而不是靠回忆？

时间线里最有价值的是几个时间差：异常何时开始、你何时知道、官方何时承认、何时真正恢复。这几个点分别来自不同的数据源，需要逐一对上。

### 第一步：确定 T0，第一个异常信号

T0 优先取外部探测或请求日志里的第一次失败，而不是告警时间。告警通常有聚合窗口和阈值，会比真实开始晚。

如果你有自己的请求日志，可以按分钟统计 5xx 和超时：

```bash
# 假设日志是 JSON 行格式，含 ts（ISO 时间）和 status 字段
jq -r 'select(.status >= 500) | .ts[0:16]' app.log | sort | uniq -c | head -20
```

第一个明显高于基线的分钟就是候选 T0。再往前看 10 分钟，确认之前确实是正常的。

没有自己的探测时，可以参考第三方的外部探测。cdnping 的 [API 状态页](/status) 从 Cloudflare 边缘每 5 分钟探测一次各官方 API 入口，保留 30 天历史；探测方法写在 [数据方法](/methodology) 里。注意 cdnping 从 2026-10-17 才开始采集，更早的事故没有它的探测数据。外部探测的分辨率是 5 分钟，用来核对“那段时间入口是否可达”足够，精确到分钟还得靠你自己的日志。想自己搭探测，可以参考 [自己测 AI API 的可用率](/blog/measure-ai-api-uptime-yourself)。

### 第二步：对上官方状态页的时间

上游状态页给出的“事件创建时间”是 T3，它往往晚于 T0。状态页的事件等级、组件怎么读，可以看 [怎么看 OpenAI 状态页和 Claude 状态页](/blog/how-to-read-ai-status-pages)。

下面用 cdnping 同步的官方状态页记录做一个整理示例（来源：cdnping 每 15 分钟同步的官方状态页事件，取 2026-10-15 前后几条；分钟数为 cdnping 记录的事件持续时长）：

| 服务商 | 事件标题（原文） | 影响级别 | 创建时间（UTC） | 北京时间 | 记录时长 |
|---|---|---|---|---|---|
| Cloudflare | Increased HTTP 502 Errors | minor | 2026-10-15 10:47:18 | 10-15 18:47 | 591 分钟 |
| OpenAI | Widespread feature degradation | major | 2026-10-15 16:29:26 | 10-16 00:29 | 146 分钟 |
| Cloudflare | Network Performance Issues in Eastern North America | major | 2026-10-15 20:48:17 | 10-16 04:48 | 49 分钟 |
| Cloudflare | Increased HTTP 5xx Errors Ashburn | minor | 2026-10-16 13:46:51 | 10-16 21:46 | -43 分钟 |

假设你的服务依赖 OpenAI API，在 10 月 15 日那次事件里受了影响，时间线可以这样写：

```text
T0  2026-10-15 16:2x UTC  自己日志中 5xx 开始上升（填实际分钟）
T3  2026-10-15 16:29 UTC  OpenAI 状态页创建事件 "Widespread feature degradation"（major）
T6  约 18:55 UTC          按记录时长 146 分钟推算的事件关闭时间
T5  ?                     自己的错误率回到基线（以日志为准，可能早于或晚于 T6）
```

T5 和 T6 要分开写。官方关闭事件的时间和你的服务恢复的时间不一定一致：可能你的重试队列还在消化积压，也可能你早就切到了备用路径。

### 第三步：检查数据本身是否可信

上表最后一行的时长是 -43 分钟。在 cdnping 这段记录里还有几条类似的负数（例如 -57、-17、-183 分钟）。可能的原因是状态页事后改写了开始时间，或者事件属于补录。不管哪种原因，负数时长都不能直接写进复盘。遇到这种情况，回到官方状态页的事件详情，逐条看 “Investigating / Identified / Resolved” 的更新时间，自己算。

这一步也适用于你自己的监控：探测节点本身挂了、时钟漂移、日志延迟入库，都会让时间线错位。复盘里写清每个时间点的来源，评审时别人才能复查。

### 第四步：用请求计数量化影响

“影响”一节最好有分母。以 AGI Plan 公开的逐小时请求统计为例（AGI Plan 是 cdnping 的商业合作方；数据来自 `https://agiplan.dev/api/status/requests`，不需要登录，口径是只有 5xx 算平台失败）。下面是 2026-10-16 连续三个小时的计数，每个小时桶从整点后第 5 分钟起算：

| 小时桶起点（UTC） | 成功 | 失败 | 失败率 |
|---|---|---|---|
| 06:05 | 664 | 722 | 52.1% |
| 07:05 | 455 | 877 | 65.8% |
| 08:05 | 921 | 107 | 10.4% |

这类数据能回答“影响有多大、什么时候开始回落”，但回答不了“为什么”。同一时间段上游有没有事件，要对照状态页记录；单看这三行，不能下根因结论。这正是复盘里“根因”和“影响”要分开写的原因。

失败率、可用率和错误预算怎么换算，可以参考 [SLI、SLO、SLA 到底差在哪](/blog/sli-slo-sla-error-budget-explained)。

## 上游 AI 服务出故障，自己的复盘写什么？

当根因是“OpenAI / Claude / 某家云服务出了问题”时，不少团队就不写复盘了。这种情况其实更该写，因为上游故障并不少见。按 cdnping 同步的官方状态页记录（2026-09-17 至 2026-10-17），Claude 有 6 条 major 级别事件，OpenAI 有 4 条 major、19 条 minor，Cloudflare 有 3 条 major、19 条 minor。更完整的统计见 [AI 服务故障盘点：2026 年 9–10 月](/blog/ai-service-incidents-sep-oct-2026)。

上游的根因你改不了，复盘的焦点放在下面这些问题上：

### 我们比官方早还是晚知道？

对比 T0、T1 和 T3。如果你的告警比官方状态页还晚，说明你在依赖用户反馈或官方公告来发现问题。改进方向是加外部探测，具体做法见 [AI 应用可用性监控怎么做](/blog/ai-app-availability-monitoring-guide)。遇到问题时也可以先看 [/down](/down)，那里汇总了官方状态页、每 5 分钟的 API 探测和用户报告，能较快判断是不是普遍现象。

### 错误码处理对不对？

看日志里失败请求的状态码分布：

```bash
jq -r 'select(.upstream=="openai") | .status' app.log | sort | uniq -c | sort -rn
```

502、503、529 这类通常值得带退避重试；400、401 重试没用，只会放大流量。如果事故期间重试把请求量放大了几倍，这就是一条促成因素。各状态码的含义和是否该重试，见 [大模型 API 错误码速查](/blog/ai-api-error-codes-400-to-529-cheatsheet)。

### 有没有降级或切换路径，用了吗？

逐项检查：

- [ ] 是否有备用模型或备用供应商？切换要改代码还是改配置？
- [ ] 切换花了多久？是谁决定的？有没有预先写好的判断条件？
- [ ] 降级后用户看到了什么：报错、排队提示，还是功能悄悄变差？
- [ ] 超时设置是否合理？有没有请求挂满连接池拖垮其他功能？
- [ ] 恢复后是否切回？切回时有没有引起第二次波动？

### 我们对用户说了什么？

记录第一次对外通告的时间、渠道和措辞。如果用户比你的公告更早发现问题，可以考虑给自己的服务做一个状态页，参考 [给 AI 服务搭一个状态页](/blog/build-status-page-for-ai-service)。

### 上游故障类复盘的行动项示例

| 行动 | 类型 | 验收标准 |
|---|---|---|
| 对每个上游 API 增加外部探测，连续 2 次失败告警 | 发现 | 演练中 10 分钟内收到告警 |
| 5xx 重试改为指数退避并设上限 | 缓解 | 压测中重试请求不超过原请求量的设定倍数 |
| 写好切换备用供应商的操作手册和触发条件 | 缓解 | 值班人员按手册独立完成一次切换演练 |
| 订阅上游状态页事件通知 | 发现 | 测试事件能推送到值班群 |

表里的“设定倍数”“10 分钟”请按自己的业务定，这里只是示例。

## 写完之后的自查清单

提交评审前过一遍：

1. 时间线每一行都有证据链接或查询语句吗？
2. 时区统一了吗？
3. 影响一节有分母（总请求数）和统计窗口吗？
4. 根因有证据，还是推测？推测是否标了“待确认”？
5. 有没有出现人名指责？改成对流程和系统的描述。
6. 每个行动项都有负责人、截止日期和验收标准吗？
7. 是否单独写了“如果再发生一次，我们能更早发现吗”？
8. 引用的外部数据（状态页、第三方探测）是否注明来源、窗口，是否检查过异常值（例如负数时长）？

复盘定稿后，过一到两周回头看行动项完成了多少，没完成的在周会上单独过一下。
