当你的生产系统同时接入 Claude 和 OpenAI,真正难的不是“接上 API”,而是在故障发生时还能稳态服务。一个供应商偶发 429/5xx、区域波动或模型超时,都会把下游体验打穿。
这篇给你一套可直接落地的双供应商网关方案:健康探测、熔断切换、SLA 分级回退、以及可观测性闭环。目标不是追求“永不失败”,而是失败可控、成本可控、体验可控。
先给结论:三层防线
- 第一层:主动健康探测(分钟级)
- 按模型维度探测
p95 latency、error rate、429 rate
- 按模型维度探测
- 第二层:熔断 + 半开试探(秒级)
- 连续错误触发熔断,短窗口后半开试探恢复
- 第三层:SLA 回退策略(请求级)
- 按请求等级自动降级:质量优先 / 成本优先 / 延迟优先
没有这三层,你的“多供应商”通常只是多了两份账单。
架构图(文字版)
- Client 带上
x-sla-tier(gold/silver/bronze)和x-intent(chat/code/summarize) - Gateway 根据路由策略选主模型(例如
claude-sonnet或gpt-4.1) - 发送前先查熔断状态 + 近 1 分钟健康分
- 失败时按策略回退:同供应商降级模型 → 异供应商切换
- 所有决策写入 metrics/log,支持回放与审计
1) 健康探测:别只看“活着没”
只做 /healthz=200 基本没意义。你需要“可服务健康度”评分。
推荐指标
provider_request_success_ratio_1mprovider_p95_latency_ms_1mprovider_429_ratio_1mprovider_5xx_ratio_1mprovider_timeout_ratio_1m
评分公式(示例)
health_score = 100
- (p95_latency_ms / 1000) * 8
- timeout_ratio * 60
- ratio_5xx * 80
- ratio_429 * 40
if health_score < 65 => unhealthy
2) 熔断与切换:宁可短时降级,不要雪崩
熔断参数(可直接起步)
- 连续失败阈值:
5 - 打开时长:
30s - 半开试探请求数:
3 - 半开成功阈值:
2/3
Go 伪代码
type CircuitState string
const (
Closed CircuitState = "closed"
Open CircuitState = "open"
HalfOpen CircuitState = "half_open"
)
func Route(req Request) Target {
candidates := rankedTargets(req) // 按 intent + 成本 + 质量排序
for _, t := range candidates {
if breaker[t].Allow() && health[t] >= 65 {
return t
}
}
return emergencyFallback(req) // 最后兜底
}
3) SLA 回退:把“失败策略”写成规则,而不是临时拍脑袋
三级 SLA 建议
- gold(关键请求)
- 允许跨供应商切换 + 重试 1 次 + 高质量模型优先
- silver(默认请求)
- 允许同供应商降级模型,再跨供应商一次
- bronze(成本敏感)
- 禁止高价回退,超预算直接返回降级结果
YAML 策略样例
sla:
gold:
max_retries: 1
allow_cross_provider_failover: true
quality_floor: high
silver:
max_retries: 1
allow_cross_provider_failover: true
quality_floor: medium
bronze:
max_retries: 0
allow_cross_provider_failover: false
quality_floor: basic
token_budget_per_req: 4000
4) 最小可行网关(MVP)命令清单
启动本地策略热更新(示例)
export ROUTER_CONFIG=/etc/llm-router/policy.yaml
export ROUTER_REFRESH_SEC=15
./llm-gateway --listen :8080
压测主路由与回退
hey -z 30s -c 20 -m POST \
-H 'x-sla-tier: silver' \
-H 'content-type: application/json' \
-d '{"intent":"chat","prompt":"explain circuit breaker"}' \
http://127.0.0.1:8080/v1/respond
人工触发熔断演练
curl -X POST http://127.0.0.1:8080/admin/breakers/open \
-d '{"provider":"claude","model":"sonnet"}'
常见错误与排障
错误 1:频繁来回切换(抖动)
现象: 路由在两家供应商之间疯狂跳,延迟反而更高。
根因: 没有最小停留时间(min dwell time)。
修复: 给每条路由加 hold_for: 20s,在窗口内只允许更高优先级故障打断。
错误 2:熔断恢复后立刻再炸
现象: Half-open 一放量就再次超时。
根因: 半开探测流量过大。
修复: 半开阶段限制并发 + 单独超时预算(例如 2s),先小流量恢复。
错误 3:成本失控
现象: 故障时大量请求被切到更贵模型,账单暴涨。
根因: 缺少“故障态预算闸门”。
修复: 增加 degraded_mode_cost_cap,超上限后强制走 silver/bronze 策略。
观测与告警(必须做)
至少拉齐这三类面板:
- 可用性:按 provider/model 的成功率与错误率
- 体验:按 SLA 分组的 p50/p95 延迟
- 成本:token 消耗与每 1k 请求成本
告警不要设太多,先把这两条做稳:
gold tier success_ratio_5m < 99%failover_rate_5m > 15%
总结
双供应商不是“两个 API key”,而是一套容灾操作系统。先把健康探测、熔断、SLA 回退三件事落地,再谈高级优化(A/B 路由、语义缓存、智能预算)。
如果你现在要上生产,先做 MVP:
- 每分钟健康评分
- 固定阈值熔断
- gold/silver/bronze 三档回退
这三步做完,90% 的线上惊魂夜会少很多。