LLM Fallback 降级策略:模型挂了,你的应用还能活吗
生产级 LLM 应用必须有 Plan B——超时、限流、宕机时怎么优雅降级
LLM Fallback 降级策略:模型挂了,你的应用还能活吗
生产级 LLM 应用必须有 Plan B——超时、限流、宕机时怎么优雅降级
生产级 LLM 应用的 llm fallback 实战:重试、熔断、多提供商降级、缓存兜底四层防线。讲清指数退避加 jitter、超时预算分配、大模型降级小模型的质量权衡,以及级联超时、重试风暴等真实工程坑。
做过 LLM 应用上生产的都知道一个真相:API 一定会出问题。 超时、429 限流、偶发 500、甚至整个服务商宕机。如果你的应用死死绑在一个模型上,它一打喷嚏,你就全挂。
LLM fallback(降级)策略就是给应用上的保险。但光有“换模型”还不够——你需要一套分层、可观测、可配置的降级体系(也就是完整的 llm fallback routing),才能让应用在故障中依然体面地活着。
会遇到的故障
每一种,你都得想好「然后呢」。而且故障可能链式触发——主模型挂了,备用模型也可能被同样的限流策略挡住。
降级策略分层
从轻到重,一层层兜。关键是每层都要有明确的触发条件和退出条件。
第一层:重试(Retry)
偶发错误,等一下重试往往就好了。用指数退避加抖动(jitter),别傻等也别猛冲:
python
import time
import randomdef call_with_retry(fn, max_retries=3, base_delay=1.0, max_delay=10.0):
for i in range(max_retries):
try:
return fn()
except (TimeoutError, RateLimitError) as e:
if i == max_retries - 1:
raise # 最后一次重试失败,向上抛
delay = min(base_delay * (2 ** i), max_delay)
# 加 jitter 避免惊群效应
delay = delay * (0.5 + random.random() * 0.5)
time.sleep(delay)
注意:429 错误通常带 Retry-After 头,优先用它。指数退避只适用于无明确重试时间的场景。
补充一层:熔断器(Circuit Breaker)
重试、降级、熔断经常被混为一谈,其实三者管的是不同层面:
一个最小可用的熔断器(状态机:关闭 → 打开 → 半开):
python
import timeclass CircuitBreaker:
def __init__(self, failure_threshold=5, recovery_timeout=30):
self.failure_threshold = failure_threshold # 连续失败多少次后跳闸
self.recovery_timeout = recovery_timeout # 跳闸后多少秒尝试半开
self.failures = 0
self.state = "closed" # closed / open / half_open
self.opened_at = None
def call(self, fn):
if self.state == "open":
if time.time() - self.opened_at > self.recovery_timeout:
self.state = "half_open" # 放一条试探请求过去
else:
raise RuntimeError("熔断中:快速失败,走降级逻辑")
try:
result = fn()
except Exception:
self.failures += 1
if self.failures >= self.failure_threshold:
self.state = "open"
self.opened_at = time.time()
raise
else:
self.failures = 0
self.state = "closed"
return result
熔断器包在主模型调用之外,熔断期间的异常直接触发降级链,而不是让请求排队等待。常见坑有两个:阈值设得太敏感(偶发超时也跳闸),或恢复时间过长(服务已恢复却还在熔断)。生产环境可以先用现成库(如 Python 的 pybreaker),跑稳了再考虑自研。
第二层:换模型(Model Fallback)
主模型不行,自动切备用模型。但不是简单遍历列表——你需要考虑:
python
更健壮的 fallback 链:按优先级 + 故障隔离
FALLBACK_CHAIN = [
{"model": "gpt-4o", "provider": "openai", "priority": 1},
{"model": "claude-3-5-sonnet", "provider": "anthropic", "priority": 2},
{"model": "gpt-4o-mini", "provider": "openai", "priority": 3},
# 兜底:用本地小模型或缓存
{"model": "local-fallback", "provider": "local", "priority": 4},
]def chat_with_fallback(messages, max_retries_per_model=2):
last_error = None
for entry in FALLBACK_CHAIN:
for attempt in range(max_retries_per_model):
try:
return call_model(entry["model"], messages)
except RateLimitError as e:
# 限流:等一会再试,但别等太久
time.sleep(2 ** attempt)
last_error = e
except (TimeoutError, ServiceError) as e:
# 服务端错误:直接换模型
last_error = e
break # 跳出重试循环,换下一个模型
except ContentRefusalError:
# 拒答:可能换模型也拒,直接走兜底
return DEFAULT_REPLY
# 全挂了,记录错误并返回兜底
log_fallback_failure(last_error)
return DEFAULT_REPLY
这也是为什么生产应用最好用一个统一的网关层(如 LiteLLM)来抽象多家模型——切换只改配置,不动业务代码。LiteLLM 原生支持 fallbacks 参数,可以配置模型列表和重试策略。
第三层:缓存(Cache)
常见问题的答案缓存起来。模型全挂时,至少高频问题还能用缓存答。但缓存不是银弹:
python
语义缓存示例(简化)
from sentence_transformers import SentenceTransformer
import numpy as npclass SemanticCache:
def __init__(self, threshold=0.9):
self.model = SentenceTransformer('all-MiniLM-L6-v2')
self.cache = {} # key: embedding, value: (answer, timestamp)
self.threshold = threshold
def get(self, query):
query_emb = self.model.encode(query)
for cached_emb, (answer, ts) in self.cache.items():
similarity = np.dot(query_emb, cached_emb) / (np.linalg.norm(query_emb) * np.linalg.norm(cached_emb))
if similarity > self.threshold:
return answer
return None
def set(self, query, answer):
self.cache[self.model.encode(query)] = (answer, time.time())
第四层:兜底回复(Graceful Degradation)
全部都不行了,也不能给用户甩一个 500。返回一个体面的兜底。但兜底不是一句话——根据场景分级:
设计要点
超时一定要设,而且要短。 别用默认的几十秒超时——用户等 30 秒早跑了。根据场景设 5-15 秒,超了就走 fallback。注意:大模型通常明显慢于小模型,超时要按模型分别调整,别把同一个阈值套在所有节点上。
fallback 链要考虑质量落差。 从 GPT-4o 降到小模型,回答质量会掉。关键场景宁可返回「稍后再试」,也别用一个明显变差的答案糊弄,反而砸口碑。一个实用做法:对 fallback 模型的输出做质量检查——如果置信度低于阈值,继续降级。
别把 fallback 写死在业务逻辑里。 抽一个统一的调用层,把重试、切换、缓存、兜底都收口在一处。业务代码只管「我要个回答」,怎么容错是底层的事。推荐用装饰器模式或中间件模式封装。如果你同时接入了多家提供商,这个统一调用层也是做 API 集成 治理的天然位置——限流策略、密钥轮换、用量统计都可以在这里统一处理。
监控 fallback 触发率。 如果备用模型经常被触发,说明主模型有问题,这是个信号,要去查。可以接 LLM 可观测性工具(如 LangSmith、LangFuse)盯着。关键指标:
考虑故障隔离。 如果主模型因限流挂了,备用模型最好用不同服务商。否则两个模型可能被同一个限流策略挡住。例如:OpenAI 的 GPT-4o 和 GPT-4o-mini 共享 TPM 配额,一个被限流,另一个也危险。
一个完整的降级链
用户请求
→ 查缓存(命中直接返回,跳过所有模型调用)
→ 主模型(GPT-4o)+ 重试(3 次,指数退避)
→ 备用模型 1(Claude 3.5 Sonnet)+ 重试(2 次)
→ 备用模型 2(GPT-4o-mini)+ 重试(2 次)
→ 本地小模型(如 Llama 3.1 8B)+ 重试(1 次)
→ 兜底回复(根据场景分级)
注意:缓存要放在最前面,但缓存命中后要异步更新缓存(避免缓存击穿)。本地小模型作为最后一道防线,虽然质量差,但至少能给出一个回答——自建本地推理的方案见 模型部署专题。
小结
LLM 应用的健壮性,不看它顺利时多强,看它出问题时多稳。上生产前,先问自己一句:模型现在挂了,我的用户会看到什么? 答不上来,就该补 llm fallback 了。
但 fallback 不是万能药。它只能缓解故障,不能根治。真正健壮的系统,还需要:
FAQ
Q: fallback 链太长会不会导致响应时间过长? A: 会。建议设全局超时(如 30 秒),超时后直接走兜底。另外,fallback 链中的每个模型都要设独立超时,避免一个模型拖死整个链。
Q: 如何避免 fallback 模型被同一个限流策略挡住? A: 使用不同服务商(如 OpenAI + Anthropic + 本地模型)。如果只能用同一家,至少选不同模型(如 GPT-4o 和 GPT-4o-mini 共享配额,但 GPT-4o 和 GPT-3.5-turbo 可能独立配额)。
Q: 语义缓存会不会返回过时答案? A: 会。建议设 TTL(如 1 小时),并定期清理。对于时效性强的场景(如新闻、价格),不要用语义缓存。
Q: 本地小模型作为兜底,质量太差怎么办? A: 本地模型只用于低风险场景(如闲聊、简单问答)。高风险场景(如医疗、金融)直接返回「系统不可用,请联系人工」。质量差比错误答案好。
Q: 如何测试 fallback 策略是否有效? A: 用混沌工程:模拟 API 超时、限流、500 错误,观察 fallback 是否按预期触发。推荐工具:Chaos Mesh(Kubernetes 环境)或自定义 mock 服务。
*最后更新:2026 年 7 月。请以各工具官方文档为准。*
相关工具
相关教程
系统拆解 Harness 的概念、架构、与模型的关系,以及如何通过 Harness 实现 Agent 的自进化与可控执行
对比主流AI编程工具,剖析架构、Harness、循环工程与企业落地经验
从数据架构角度出发,结合 Skill、语义层和知识库,解决 Agent 落地中的指标口径、实时数据和权限等卡点。
从底层原理到前沿方案,系统降低大模型部署成本
掌握四种循环模式,设计可验证的自动化开发流水线
生产环境 LLM 成本优化全攻略,每个技巧都有实测数据