确认告警是不是 API 事故
我会先把 429、529、timeout 分开看。混在一个「AI failed」指标里,基本等于没监控。
| 信号 | 大概率含义 | 第一动作 |
|---|---|---|
| 429 | 请求或 token 触发限制 | 降并发,按 retry-after 等待 |
| 529 | 上游过载 | 短退避重试,查状态页 |
| timeout | 响应慢或网络慢 | 开 streaming,拆短任务 |
| 5xx | 临时服务错误 | 记录 request_id,有限重试 |
告警阈值别太玄学。早期 SaaS 可以先设:5 分钟内错误率超过 5%,或付费用户连续失败 3 次,就进入人工关注。
事故当下怎么处理
先冻结并发增长。把队列 worker 从 10 降到 3,把实时接口的 max tokens 降一点。429 最怕你越失败越重试。
然后是读响应头和错误体。能拿到 retry-after 就尊重它;拿不到就用指数退避:2 秒、4 秒、8 秒,最多 2-3 次。每次重试都要带同一个业务 request id。
接下来把非实时任务进队列。总结长文、批量生成、导出报告都不该卡住主请求。用户看到「处理中」,比前端转 60 秒后报错好得多。
最后触发降级。主模型不可用时,短回复、分类、标题生成可以转小模型;高价值任务排队等恢复。别让低价值批量任务吃掉付费用户的实时额度。
生产代码要有哪些护栏?
const policy = {
maxRetries: 2,
baseDelayMs: 2000,
timeoutMs: 60000,
queueWhenOverloaded: true,
fallbackModel: "claude-smaller-or-fast-model"
};
这段只是骨架。真正关键的是状态机:created -> running -> retrying -> degraded -> succeeded/failed。没有状态机,用户刷新一次就可能重复扣额度,客服也查不到任务到底有没有跑完。
日志和看板怎么记?
| 字段 | 为什么要记 |
|---|---|
| request_id | 串起前端和后端 |
| user_id / plan | 判断是否影响付费用户 |
| model | 看是不是单模型问题 |
| input/output tokens | 算成本和限流压力 |
| status_code | 区分 429、529、timeout |
| retry_count | 防止重试雪崩 |
| final_state | 复盘用户是否拿到结果 |
不要默认存完整 prompt。调试期可以采样,但要脱敏、限期保存。很多 indie 产品早期没问题,等做 B2B 后才发现日志里都是客户资料。
超过 10 分钟还没恢复
暂停批量任务,给前端加提示,付费用户请求优先,后台每 5 分钟看一次 Anthropic status 和自身错误率。需要备用通道时,可以接入独立开发者可用的 Claude / OpenAI API 中转作为降级路径,但业务层仍要保留限流和日志。
复盘 checklist
- 事故开始和结束时间是否明确
- 429 是 RPM、TPM 还是账户额度导致
- 529 是否和上游状态页一致
- 哪些接口没有幂等 id
- 哪些任务应该从同步改异步
- 用户提示是否清楚
- 成本是否因为重试放大
复盘时我会把用户影响写成数字:多少请求失败,多少付费用户受影响,多少任务自动恢复,多少任务需要人工补跑。只写「上游波动」没有意义,下一次还是会乱。Runbook 要沉淀成配置改动、代码改动和客服话术,而不是一份没人看的事故记录。
还要检查成本。429 事故里最容易出现重试放大,原本 100 次请求,因为三层重试变成 280 次。即使最后用户拿到了结果,你的毛利也会被吃掉。每次事故后看一次 token 曲线,能帮你决定该限并发、缩短上下文,还是把某类任务改成异步。