线上出问题怎么查?一套可复现的排障 SOP(O04)
系列《AI 应用生产化手册》第 9 篇(共 30 篇)|配套开源项目:github.com/ChenYingbo/... 本篇是模块二(可观测性)收尾:日志 → 追踪 → 指标 → 排障,四件套齐了
一、先看问题:工具是散的,人是慌的
前三篇备齐了观测工具(日志/trace/指标),但还差最后一块拼图:
- 工具是散的------出问题时手忙脚乱:先看哪个?指标、trace、日志怎么串起来?
- 靠经验不靠流程------老手凭直觉定位,新手抓瞎;同样的故障每次排查路径都不一样。
- 修完就完事------没有复盘,同类故障下周再来一遍。
解法:把排查过程固化成 SOP + 工具化(一键收集现场)+ 复盘模板。
核心认知:可观测的终点不是工具,是"流程"------让任何人(包括三个月后的你)拿到 SOP 都能按步骤定位问题,并且每次排查都在积累案例库。
二、原理:五步排查路径
arduino
① 指标发现(O03) "整体不对劲" → 定级、定影响面
↓
② trace 定位(O02) "找到具体请求" → 看哪一步异常
↓
③ 日志看细节(O01) "补证据" → 错误详情、上下文
↓
④ 复现 + 修复 + 回归(E04 门禁)→ "修好 = 评测通过"
↓
⑤ 复盘归档 → 防复发行动项
为什么是这个顺序? 指标最快但最粗(只知道"坏了");trace 精确但要知道看哪条;日志最细但要先有 request_id。从粗到细,每步都在缩小范围。
常见故障分类(先分类再排查)
| 故障 | 第一嫌疑 | 定位入口 |
|---|---|---|
| 幻觉/答错 | 上下文问题 | trace 的 input + 评测 |
| 超时 | 模型/网关慢 | metrics 分位 + trace span 耗时 |
| 错误率上升 | 网关/Key/429 | 现场快照的错误列表 + trace |
| 上下文溢出 | 长对话管理 | trace 的 input tokens |
| 成本爆炸 | 重试风暴/死循环 | metrics 成本 + token 峰值 |
| 工具错配 | 工具 Schema/路由 | trace 的 tool span(RAG/Agent 后) |
分类的价值:第一眼决定去哪一层看,而不是漫无目的地翻。
关键纪律:先止血,再根治
S1 故障(全挂/数据泄露):
① 先降级/回滚 → 恢复服务
② 稳定后再慢慢查根因
③ 严禁边排查边让用户继续踩雷
排障的第一优先级永远是"恢复服务",不是"找到原因"。
复盘三问(没有行动项 = 没复盘)
- 根因是什么?(一句话,不是"网络波动"这种废话)
- 防复发措施是什么?(代码/告警/评测集三选一,必须落地)
- 案例库是否补了一页?(下次同类问题 10 分钟解决而不是 2 小时)
三、动手:一键收集现场快照
bash
git clone https://github.com/ChenYingbo/ai-prod-demo.git && cd ai-prod-demo
source .venv/bin/activate
# 收集现场(用样例日志演示,免 Key)
python scripts/diagnose.py --log tests/fixtures/sample_structured.log --slow-ms 2500
真实输出:
ini
===== 现场快照 =====
[WARN] app /health: 连接被拒
[WARN] LiteLLM 网关: 连接被拒
[OK ] Langfuse: HTTP 200
[INFO] 日志行数: 33
[INFO] 近期事件: chat_request(r10), llm_call(r10), chat_error(r10)
[INFO] 错误数: 1(最近: 1 条可见)
ERROR r10: LLM 调用失败: Error code: 502
[INFO] 慢请求(>阈值ms): 1 条
SLOW r05: latency=3000ms
[INFO] token 峰值: in=180 (request r09)
一条命令同时回答四件事:服务健康吗?最近有哪些错误?哪些请求慢?谁在烧 token?
三个故障演练(建议有 API Key 后做)
| 故障 | 制造方法 | 定位路径 |
|---|---|---|
| 改坏提示词 | 把 prompts/chat-system/ 模板改成"只会说不知道" |
评测通过率暴跌 → trace 看 input → 定位提示词 |
| 网关故障 | docker stop ai-prod-litellm |
现场快照网关 WARN → 错误率飙升 → 修复 = 重启 + 补 fallback |
| 模拟超时 | .env 设 LLM_CONNECT_TIMEOUT=0.5 |
metrics P95 暴涨 → trace 看 llm_call 超时 → 修复 = 合理超时 + 重试 |
每个故障走完整 SOP:收集现场 → 指标定级 → trace 定位 → 修复 → 回归门禁 → 归档案例。
案例库归档
bash
docs/cases/CASE-2026-001-提示词退化.md
docs/cases/CASE-2026-002-网关宕机.md
docs/cases/CASE-2026-003-超时风暴.md
四、真实踩坑
- 跳过收集现场直接猜:现场没了(日志轮转)就只能猜------先跑诊断脚本
- 先找根因再止血:S1 必须先降级/回滚,让用户继续踩雷不可接受
- 只修表面:502 重启网关就好了,但根因(无 fallback)没解决------下月再来
- 修好不回归:改完直接上线,没跑门禁------"修 A 坏 B"就是这么来的
- 复盘没有行动项:写"加强监控" = 没有复盘
- (实测)故障期的错误会被缓存 :我们真实踩过------兜底答案被 SQLite 缓存,故障恢复后重复提问仍命中"服务不可用"。排障时记得清缓存,否则你会以为故障没好
- 三样工具数据脱节:request_id 没贯穿 → 指标、trace、日志对不上------request_id 是这一切的前提
五、模块二小结(可观测性 4 篇收官)
| 篇 | 解决的问题 | 核心交付 |
|---|---|---|
| O01 | 出事了不知道发生了什么 | 结构化日志 + request_id |
| O02 | 看日志像脑内拼图 | Langfuse 可视化 trace |
| O03 | 不知道整体表现 | 指标分位 + 告警 |
| O04 | 排查靠经验 | 排障 SOP + 现场快照工具 + 复盘模板 |
一条主线:从"出事了才知道"到"随时知道在发生什么、按流程定位到根因"。