LLM 多供应商故障切换与结果一致性系统设计
“主模型超时就换备用模型”听起来简单,实际可能造成重复扣费、工具参数格式变化、结构化输出失效、数据跨区域、流式响应半截和质量突然下降。可靠的 failover 是一套能力约束下的路由与恢复系统。
一、30 秒面试回答
我不会把 fallback 写成一个 provider 列表。网关先把业务请求规范成内部契约,并根据模型能力矩阵、数据驻留、场景风险、上下文窗口和输出格式计算可用候选。故障时区分连接失败、限流、超时、模型错误和内容策略拒绝:只有可安全重试的错误才切换;带副作用的工具任务必须依靠 idempotency key 和运行状态防止重复执行。流式请求一旦已向用户输出内容,通常不做“无缝换模型”,而是结束当前 run、保留部分结果并明确重试策略。所有路由、fallback、成本、质量和 provider 错误写入 trace;备用路径也要离线评测、灰度和定期演练,不能等主服务挂了才发现不兼容。
二、先定义:什么可以切、什么不能切
| 请求类型 | 是否可自动切换 | 原因 |
|---|---|---|
| 幂等的短文本分类 | 通常可以 | 结果可校验,副作用小 |
| RAG 问答 | 可以但需固定索引与 Prompt | 需保持证据与引用口径 |
| JSON 结构化输出 | 仅切到兼容 schema 的模型 | JSON mode/tool calling 支持不同 |
| 流式聊天已输出 token | 不宜静默切换 | 两个模型的措辞和事实可能拼接 |
| Agent 工具写操作 | 需谨慎,通常暂停恢复 | 可能重复下单、发信、改库 |
| 推理/视觉/长上下文 | 取决于能力矩阵 | 备用模型可能不支持能力或窗口 |
核心原则:provider 可用不等于对当前请求可用。 路由必须先验证能力和安全约束,才谈延迟与价格。
三、内部请求契约与能力矩阵
应用不应直接向各厂商拼不同字段。先定义内部请求:
{
"run_id": "r_123",
"tenant_id": "acme",
"task_class": "rag_answer",
"messages": ["..."],
"required": ["streaming", "json_schema"],
"context_tokens": 48000,
"data_residency": "cn",
"risk_tier": "high",
"idempotency_key": "msg_987"
}能力注册表维护而不是硬编码:
| 能力 | 示例 |
|---|---|
| 输入/输出窗口 | 最大上下文、最大生成长度 |
| 交互协议 | streaming、tool calling、JSON schema、vision |
| 质量约束 | 评测分数、支持语言、领域适配 |
| 运行约束 | 区域、延迟、配额、价格、健康状态 |
| 安全约束 | 数据保留、内容策略、审计能力 |
能力变化要版本化。供应商升级模型或废弃参数时,先更新契约测试与回归集,再允许进入路由池。
四、路由决策顺序
request -> tenant/data policy -> required capability filter
-> context/window filter -> provider health filter
-> quality tier filter -> cost/latency ranking
-> selected route + fallback chain snapshot先做不可协商过滤,再做排序。不要因为某个备用模型便宜就让它接高风险结构化任务;也不要在模型已经输出半个 JSON 后随意切换到不兼容的工具协议。
路由结果要成为运行快照的一部分:模型、provider、adapter、Prompt、工具 schema、索引和策略版本都要记录。否则事后无法解释“为什么这次从 A 切到 B”。
五、错误分类与重试矩阵
| 现象 | 处理 | 是否切换 provider |
|---|---|---|
| DNS/连接失败 | 短暂重试后熔断 | 可以 |
| 429/配额不足 | 尊重 Retry-After、排队或切换 | 可以,受租户预算约束 |
| 上游 5xx | 有界重试、熔断 | 可以 |
| 请求超时且未收到字节 | 重试或切换 | 通常可以 |
| 已收到部分流 | 停止并报告中断,建议用户重试 | 不做静默切换 |
| 400/schema 不兼容 | 修复适配器或降级能力 | 不应盲目重试 |
| 内容审核拒绝 | 保留拒绝语义 | 不能用备用模型绕过 |
重试必须有上限、退避和全局预算。盲目“重试 + fallback”会放大流量并制造多次计费。每一次尝试都要记录 attempt 序号和原因。
六、幂等与副作用:切换时最容易出事故的地方
生成文本的重复通常只是体验问题;工具写操作重复可能是真实事故。应将 Agent 的运行拆成可恢复状态:
planned -> authorized -> tool_started -> tool_committed -> observed -> completed- 执行器用业务幂等键去重,不依赖模型“记得自己调过”。
- provider 切换前先读取工具状态;
tool_started不代表可安全再次执行。 - 对不可逆动作要求事务、补偿或人工确认;自动 fallback 只恢复未提交的推理步骤。
- 所有批准与授权绑定到具体任务、参数摘要和过期时间,不能被备用模型复用为泛化权限。
七、流式响应与会话连续性
流式请求的正确终态不是“连接断了”。当 provider 在已输出 delta 后失败:
- 保存已发送事件、引用和 usage,标记
provider_interrupted。 - 不把备用模型的开头拼到旧文本末尾,避免语义/事实混杂。
- UI 显示可解释状态:保留草稿、重新生成或从检查点恢复。
- 对可重放的任务,基于同一输入创建新的
run_id,并明确新模型/版本。 - 对 Agent,将工具完成状态与文本生成状态分离,避免用户误以为动作未执行。
详见:LLM 流式输出与会话恢复设计。
八、熔断、健康检查与避免雪崩
健康不能只看 HTTP 200。每个 route 至少观测:成功率、429/5xx、TTFT、TPOT、结构化输出有效率、内容策略拒绝率和单位成功成本。熔断器常见状态为 closed、open、half-open:
closed:正常发送并积累窗口指标。open:短时间不再发新请求,保护上游和本地队列。half-open:少量探针验证恢复,避免全量回流造成二次故障。
熔断范围要合理:可按 provider、region、model deployment 或租户配额拆分。把一个模型的 429 当作“整个供应商全挂”会造成不必要的级联切换。
九、质量一致性:备用路径也要有门禁
不能只以“返回了文本”判定 fallback 成功。为每个任务等级定义最低质量契约:
| 任务 | 最低门槛示例 |
|---|---|
| 客服问答 | 引用完整率、拒答策略、解决率 |
| JSON 抽取 | schema valid rate、字段准确率 |
| RAG | 授权集合内召回、groundedness、引用页正确率 |
| Agent | 工具选择/参数、越权拦截、任务完成率 |
| 代码生成 | 构建/测试通过率、安全扫描 |
备用模型只在通过对应离线评测、成本边界和安全策略后才进入候选池。灰度时单独看 fallback traffic,不能把它混在主模型平均指标里掩盖退化。
十、数据驻留、隐私与账单
路由时的数据政策优先级高于价格和延迟:某些租户只能使用指定区域、私有部署或零保留 endpoint。trace 中记录的 prompt、工具结果和错误体必须脱敏;不要为了排障把完整敏感上下文转发到备用厂商。
计量事件应记录:
run_id, attempt, provider, model, route_reason, fallback_reason,
input/output/cached tokens, price version, latency, outcome这样才能区分主路由成本、重试成本、失败成本和降级带来的业务影响,并支持按租户的预算与争议核对。
十一、演练与发布
每条 fallback 链都需要定期演练,而不是只写在配置里:
- 注入 429、连接超时、区域不可达、模型输出畸形和流中断。
- 验证熔断、队列、重试上限和恢复探针是否按预期工作。
- 回放结构化输出、RAG、工具调用和长上下文的兼容性测试。
- 检查数据驻留、密钥权限、审计事件和账单是否完整。
- 发布新 provider adapter 或模型版本时先 shadow,再小流量灰度。
演练结果应形成能力矩阵的证据,而不是一份一次性的故障报告。
十二、高频面试问答
Q:429 发生时一定要切换模型吗?
不一定。先看是否是单租户配额、临时全局限流还是模型部署异常;可能更适合排队、尊重 Retry-After 或限流。只有备用模型满足能力、数据、质量和预算要求时才切换,且要防止所有请求同时涌向备路由。
Q:流式输出中断后,为什么不直接接备用模型继续?
不同模型的语气、事实、引用和内部状态不一致,拼接会产生不可解释的答案;若已执行工具还可能重复动作。应结束旧 run、保留已输出草稿和审计,按产品策略让用户重试或从显式 checkpoint 恢复。
Q:如何防止 fallback 降低安全性?
安全策略、授权校验、工具网关和输出控制必须在 provider 之外一致执行;能力矩阵包含内容安全、结构化输出和数据驻留;审核拒绝不能通过换模型绕过;备用路线同样跑对抗评测和灰度。
Q:多供应商如何避免重复扣费?
为每次业务请求建立 run 和 attempt,使用幂等键;仅在尚未收到可确认结果且错误可重试时发起下一 attempt;记录每个 provider 的 usage 与价格。工具副作用由业务幂等键和状态机去重,不能只靠 API 重试语义。
十三、项目讲法模板
我们将多供应商接入统一到模型网关,业务只提交内部请求契约。网关先按数据驻留、上下文窗口、工具/JSON/视觉能力和质量门槛过滤候选,再按实时健康、延迟与成本排序。每个 run 固定路由与 fallback 链;错误按 429、网络、超时、协议不兼容和内容拒绝分别处理,熔断和重试都有预算。流式中断不静默拼接备用模型,工具写操作通过幂等键与执行状态机保护。我们用备用路径的结构化有效率、RAG 引用质量、Agent 安全和失败成本做独立门禁,并定期故障演练。
继续学习:大模型网关、Agent 模型路由与能力治理、MaaS 平台生产实践、LLM 推理容量与弹性伸缩设计、LLM 流式输出与会话恢复设计。