环境检查
- 已有至少 2 个可调用 channel(官方 + 中转 / 多家中转 / 多 provider)
- Python / Node.js 项目,能改后端代码
- 决定监控存储方案(Postgres / TimescaleDB / Datadog 任选)
失败判定规则(共用)
TRIGGER_FALLBACK = {
"http_429": True, # 限速,等 Retry-After 再 fallback
"http_5xx": True, # 服务端错误立即 fallback
"timeout_connect": True, # 连不上立即 fallback
"timeout_read": True, # 30s 没首字节 fallback
"moderation_block": True,# 内容被审核拒绝可考虑 fallback
"json_parse_fail": True, # 返回格式错误
"stream_stall_secs": 60, # streaming 中 60s 没新数据
}
方案 A:应用层 try/catch(最简单)
import anthropic, openai
from anthropic import RateLimitError, APITimeoutError, APIStatusError
def chat_with_fallback(messages):
try:
return anthropic.Anthropic().messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024, messages=messages,
)
except (RateLimitError, APITimeoutError, APIStatusError) as e:
log_fallback("anthropic", str(e))
return openai.OpenAI().chat.completions.create(
model="gpt-4o", messages=messages,
)
50 行代码。适合 1-2 个 channel + PoC 阶段。
方案 B:LiteLLM Router(推荐)
from litellm import Router
router = Router(
model_list=[
{
"model_name": "chat-main",
"litellm_params": {
"model": "anthropic/claude-3-5-sonnet-20241022",
"api_key": "sk-ant-...",
},
},
{
"model_name": "chat-main",
"litellm_params": {
"model": "openai/gpt-4o",
"api_key": "sk-...",
},
},
{
"model_name": "chat-main",
"litellm_params": {
"model": "openrouter/anthropic/claude-3-5-sonnet",
"api_key": "sk-or-v1-...",
},
},
],
fallbacks=[{"chat-main": ["chat-main"]}], # 同名 group 内 fallback
cooldown_time=30, # 失败 channel cool 30s
num_retries=2, # 每个 channel 重试 2 次
)
resp = router.completion(model="chat-main", messages=[...])
20 行配置 + 多 channel 自动权重 + cool-down + retry。生产推荐。
方案 C:OpenRouter models 参数(最快上手)
client.chat.completions.create(
model="anthropic/claude-3-5-sonnet",
extra_body={
"models": [
"anthropic/claude-3-5-sonnet",
"openai/gpt-4o",
"google/gemini-2.5-flash",
],
},
messages=[...],
)
零代码改动,OpenRouter 服务端做 fallback。缺点:所有 channel 都在 OpenRouter 内,OpenRouter 自身挂了全挂。
方案 D:OneAPI 渠道权重(团队场景)
OneAPI 控制台 → 渠道 → 添加多个 channel → 设置权重与优先级。OneAPI 自动按权重轮询 + 失败时跳过。
主路 channel A:anthropic 官方,权重 5,优先级 high
备路 channel B:openrouter,权重 3,优先级 mid
兜底 channel C:中转 X,权重 2,优先级 low
适合 5+ 人团队 + 集中管理需求。
监控埋点
def log_fallback(channel_failed, reason):
db.execute(
"INSERT INTO llm_fallback_log (ts, channel, reason) VALUES (NOW(), %s, %s)",
(channel_failed, reason),
)
def log_call(channel, model, latency_ms, status):
db.execute(
"INSERT INTO llm_call_log (ts, channel, model, latency_ms, status) VALUES (NOW(), %s, %s, %s, %s)",
(channel, model, latency_ms, status),
)
每 5 分钟跑一次:
SELECT channel,
COUNT(*) FILTER (WHERE status='success') * 1.0 / COUNT(*) AS success_rate
FROM llm_call_log
WHERE ts > NOW() - INTERVAL '5 min'
GROUP BY channel;
成功率 < 95% 的 channel 触发告警。
常见失败原因
- 没设 cooldown:主线 429 后立刻又被打挂
- fallback 链太长:5 级 fallback 用户等 30 秒,体验更糟
- 不同 provider prompt 格式差异:fallback 后输出质量差
- 监控不埋:fallback 经常触发但没人知道
安全设置
- 每个 channel 的 key 单独存
- fallback 链路加 request_id 透传方便排查
- 设置月级 fallback 触发上限(超过表示主路有大问题,告警)
跨地区访问
国内访问境外多个 provider 都需要稳定网络。考虑把免外卡的 LLM API 中转线路配进 LiteLLM Router 作为最后一级 fallback,主线官方 + 备线官方都被墙时仍能服务用户。
运维备忘
Fallback 链路稳定运行后,建议记下三样东西:当前主备 channel 的配置、最近一次 fallback 触发的原因和次数、下个月要轮换的 key。多人协作时把负责人和后台入口写进一张共享表格,换人或换中转方时不会断掉保护链路。
LLM fallback 路由的落地条件
LLM fallback 路由最怕把法律主体、收款工具和产品代码混成一个问题。动手前看清现金流、工具栈和入口位置,金额较大或涉及税务时应交给专业顾问处理。
一个人运营时可以用表格压住复杂度:负责人、后台入口、到期日、费用来源和回滚动作各占一列,避免换服务商时才发现资料缺口。
涉及 Stripe、公司注册、税表或签证的内容,只能作为操作参考。当前页面没有覆盖你所在司法辖区的特殊规定时,不应把它当成法律或税务意见。
| 项目 | 看什么 | 不宜继续的信号 |
|---|---|---|
| 现金流 | 当前后台、日志或设置页里能直接看到的字段 | 页面提示和手头资料对不上 |
| 工具栈 | 费用、权限、地区或设备造成的实际影响 | 已经影响付款、审核、生产环境或家庭使用 |
| 入口位置 | 回退入口、旧配置、官方支持材料 | 找不到回滚方式,或责任人无法确认 |