Claude 连续两天出故障以后,我重新看了一遍“多模型容灾”这件事
8 月 16 日,Claude 出现了一次服务中断。
Anthropic Status Page 记录的范围包括 claude.ai、platform.claude.com、Claude API、Claude Code 和 Claude Cowork。
8 月 17 日,又出现了 Claude Opus 5 和 Claude Sonnet 5 的 degraded performance。昨天这次事件从状态页第一次标记 investigating 到 resolved,大约经历了一个半小时;中间 Opus 先恢复,Sonnet 继续处于 degraded 状态。
今天状态页已经显示 All Systems Operational。
我把这段时间线重新看了一遍,最大的感受不是“Claude 不稳定”。任何大型云服务都会有故障。
真正值得检查的是:我们嘴里说的多模型容灾,到底是“换了一个模型名”,还是“真的换了故障域”。
很多代码长这样:
try {
return claudeOpus.call(request);
}
catch (Exception e) {
return claudeSonnet.call(request);
}
看起来有 Primary 和 Fallback 两个模型。
但如果两者共享同一家 Provider、同一鉴权系统、同一 API 入口、同一网络、同一额度和同一账户,那么它更接近模型级 Fallback,而不是 Provider 级容灾。
昨天的状态页恰好能说明这个区别。
我现在会把故障域拆成五层
Model
Provider
Account
Region / Endpoint
Dependency
举例:
routing:
primary:
provider: anthropic
model: sonnet-5
account: account-a
fallback_1:
provider: anthropic
model: opus-5
account: account-a
fallback_2:
provider: openai
model: gpt-5.6-terra
account: account-b
fallback_1 能解决单模型容量、特定模型错误和模型版本问题,但不太能解决 Provider API 整体故障、认证故障和账户问题。
fallback_2 才开始跨 Provider。
但跨 Provider 也不是加一行配置
最大的麻烦是模型并不完全等价。
同一个请求切过去之后:
- Tool Schema 支持可能不同;
- Structured Output 行为不同;
- System Prompt 权重不同;
- Context Window 不同;
- Reasoning 参数不同;
- 图片、PDF 支持不同;
- Tool Call ID 格式不同;
- 流式事件不同。
所以真正的容灾单位不是 model_name,而是 capability profile。
public record ModelCapabilityProfile(
String provider,
String model,
boolean toolCalling,
boolean structuredOutput,
boolean vision,
boolean pdf,
int contextWindow,
Set supportedToolTypes,
RiskTier riskTier) {
}
一个任务要求 Tool Calling、JSON Schema、PDF 和至少 200K Context,那么不是所有 Fallback 都能进入候选池。
第二个坑:故障时所有请求一起切,备用也会被打爆
典型事件:
Primary错误率上升
↓
100%请求立即切Fallback
↓
Fallback突然吃到2倍流量
↓
Fallback限流
↓
全挂
所以切换应该渐进。
例如:
Primary error rate > 5%
→10%切Fallback
>10%
→30%
>20%
→70%
明确不可用
→100%
同时观察 Fallback P95、429、5xx、Queue Depth 和 Budget。
第三个坑:把 Provider Status Page 当实时路由 API
状态页很有用,但它不应该是唯一信号。
原因很简单:你的请求已经失败了,状态页可能还没更新;反过来,状态页显示故障,你所在 Region 或模型也可能已经恢复。
生产路由应该以自身遥测为主。
public record ProviderHealth(
double successRate,
double timeoutRate,
double rateLimitRate,
Duration p95Latency,
int sampleCount,
Instant measuredAt) {
}
再把外部 Status 作为辅助信号。
我会算一个 Health Score
不需要复杂机器学习。
double score =
successRate * 0.60
+ latencyScore * 0.20
+ rateLimitScore * 0.10
+ externalStatusScore * 0.10;
然后粗分:
score >= 0.90 HEALTHY
0.70—0.90 DEGRADED
< 0.70 UNHEALTHY
阈值按真实历史校准。
第四个坑:失败重试把故障扩大
Provider 开始 5xx 后,应用每个请求重试 3 次,原来每秒 100 个请求,瞬间可能变成 300+。
所以要有 Retry Budget。
retry:
max_attempts: 2
max_retry_ratio: 0.10
backoff: exponential
jitter: true
全局最多只有 10% 的请求能进入额外重试。
第五个坑:流式请求已经输出一半,还能不能切模型
这是最麻烦的一类。
用户已经看到“根据你的合同……”,突然 Provider 连接断了。
如果直接把另一个模型输出接在后面,可能出现语气突变、内容重复、前后事实冲突和 Tool 状态不一致。
我的倾向是:
纯文本
明确提示生成中断,重新生成完整答案。
有 Tool 副作用
不能直接重跑。
先检查:
哪些Tool已经成功?
有没有UNKNOWN?
幂等Key是什么?
再恢复。
这就是为什么“模型容灾”和“Agent恢复”是两回事
聊天模型失败,重新请求通常还比较简单。
Agent失败时,可能已经查数据库、建工单、发邮件、更新CRM或提交审批。
换 Provider 只是换了大脑,外部世界并没有回滚。
所以需要:
Checkpoint
Tool Ledger
Idempotency Key
UNKNOWN Reconcile
我现在会做三个级别的演练
Level 1:单模型故障
人为让 Claude Sonnet 5 返回 503,检查能否切到 Claude Opus 5。
Level 2:Provider故障
Anthropic 全部拒绝,检查能否切到另一个 Provider,而且 Prompt、Tool、JSON 和成本都仍可接受。
Level 3:执行中故障
Agent 已经成功执行 Tool A,正在调用模型准备 Tool B 时断掉。
恢复后必须保证 Tool A 不会重复。
这一级才真正接近生产。
最后说一个我现在不太喜欢的配置
models:
- claude-sonnet
- claude-opus
- claude-fable
看起来很丰富,但它没告诉我是不是一个 Provider、一个账户、一个故障域、同一权限和同一 API 入口。
我更愿意写成:
routes:
standard:
primary:
provider: anthropic
model: sonnet-5
failure_domain: anthropic-prod
fallback:
provider: openai
model: gpt-5.6-terra
failure_domain: openai-prod
容灾真正要设计的是 failure domain,而不是模型列表。
昨天 Claude 的事件已经结束了。但这类故障一定还会发生。
如果一个 AI 应用只有在供应商 100% 健康时才能工作,那它不是生产系统,只是一个连接了 API 的 Demo。
更多企业级 AI 应用、Agent、RAG 与模型工程化内容,我会继续整理在 智元界:
https://www.zyentor.com/