← 返回资讯

海外模型不可用时的国产兜底方案

2026-08-07

海外大模型受制于跨境链路质量,出现超时、限流或服务中断时,如果没有兜底方案,整个依赖该模型的功能会直接不可用。国产模型兜底是生产级接入海外模型必须考虑的高可用设计。

为什么需要兜底方案

海外模型在国内使用时面临两类可用性风险:

  1. 网络层故障:跨境链路抖动、丢包,导致请求超时或连接失败
  2. 服务层故障:海外模型服务商自身的故障、计划维护、区域性中断

这两类问题的发生概率远高于国内 API 服务,且难以通过重试完全规避。对于 ToC 产品或关键业务流程,设计兜底逻辑是负责任的工程实践。

我见过最典型的一次事故是这样的:某天凌晨海外某模型服务商所在区域的骨干网出问题,国内到海外的请求成功率掉到不到一半,但没掉到 0——这是最麻烦的情况。如果服务全挂了,监控一眼能看出来;可它只是”偶尔超时、偶尔正常”,重试几次总能碰上一次成功,于是表面看起来”还活着”,实际上用户那边的平均响应时间已经从 2 秒涨到了 25 秒,客服工单量翻了三倍才被人发现。这种”半死不活”的状态,比彻底宕机更容易被漏掉,也正是兜底方案要重点覆盖的场景——你不能靠”服务是否完全不可用”来判断要不要切换,得靠超时率和错误率的滑动窗口统计。

再举一个真实会遇到的报错:Python 的 anthropic SDK 在跨境网络抖动时,抛出的往往不是超时异常,而是 anthropic.APIConnectionError: Connection error.,根因是 TCP 握手或 TLS 握手阶段就失败了,连请求都没发出去;而如果是海外那边限流,你会看到 anthropic.RateLimitError: Error code: 429,这种情况恰恰不该马上切兜底,应该先按官方建议的退避策略重试。搞混这两类错误,是很多团队兜底逻辑上线后依然”偶发卡死”的根源——把该重试的当成该切换的,或者反过来,都会让系统行为跟预期不符。

兜底架构选择

方案一:客户端熔断 + 自动切换

在业务代码层实现:主路调用海外模型,超时或错误达到阈值后触发熔断,自动切换至国产模型。

import anthropic
from openai import OpenAI  # 以 OpenAI 兼容格式的国产模型为例

OVERSEAS_TIMEOUT = 30  # 秒
FALLBACK_MODEL = "deepseek-chat"  # 国产兜底模型

def call_with_fallback(prompt: str) -> str:
    # 主路:Claude
    try:
        client = anthropic.Anthropic()
        resp = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=1024,
            messages=[{"role": "user", "content": prompt}],
            timeout=OVERSEAS_TIMEOUT,
        )
        return resp.content[0].text
    except Exception as e:
        print(f"海外模型失败,切换国产兜底: {e}")

    # 兜底:国产模型(OpenAI 兼容格式)
    fallback_client = OpenAI(
        api_key="your-domestic-key",
        base_url="https://api.deepseek.com/v1",
    )
    resp = fallback_client.chat.completions.create(
        model=FALLBACK_MODEL,
        messages=[{"role": "user", "content": prompt}],
    )
    return resp.choices[0].message.content

上面这段代码看着简单,但有三个容易踩的坑,值得展开说说。

第一,timeout=OVERSEAS_TIMEOUT 这个参数一定要显式传,不要用 SDK 默认值。anthropic SDK 的默认超时通常是几分钟级别,如果你不设置,遇到网络抖动时请求会一直挂着不返回,用户前端转圈转到天荒地老,比直接报错体验还差。30 秒是一个折中值:太短(比如 5 秒)会把海外模型正常的长回复也误判为超时;太长(比如 60 秒)又会让用户等太久才切到兜底。具体数值要结合你自己接口的 P95 响应时间来定,一般设成正常响应时间的 3~5 倍比较稳妥。

第二,except Exception as e 这种写法在生产代码里其实偷了懒——它会把所有异常都当成”该切兜底”,包括你自己代码里的 bug(比如 prompt 拼接时的 TypeError)。更严谨的做法是只捕获网络类和服务端类异常,比如 anthropic.APIConnectionErroranthropic.APITimeoutErroranthropic.InternalServerError,让业务逻辑错误正常抛出并被日志系统捕获,而不是被兜底逻辑悄悄吞掉。吞掉自己的 bug 是最难排查的一类线上问题,因为表面上”服务正常”(用户拿到了兜底模型的回复),实际上主路模型可能一直在因为你的代码问题而失败。

第三,这个函数里的 fallback 客户端每次调用都新建了一个 OpenAI(...) 实例,高并发场景下建议把它做成模块级单例(放在函数外初始化一次),避免重复创建连接池带来的额外开销。

优点:逻辑简单,不依赖外部组件,适合团队规模小、接入模型数量少(1~2 个)的早期阶段。
缺点:每个服务都需要重复实现这套 try/except 逻辑,熔断状态不跨实例共享——如果你有 10 个 Pod 在跑,每个 Pod 都要自己摸索一遍”海外模型是不是又挂了”,没法共享判断结果,也容易出现有的 Pod 已经切换、有的还在傻等的不一致状态。

方案二:API 网关层故障切换(推荐生产环境)

在 API 网关(如 LiteLLM、One API、合规聚合平台)层配置主备路由,业务代码无感知。

# LiteLLM 配置示例
model_list:
  - model_name: chat  # 统一对外暴露的模型名
    litellm_params:
      model: anthropic/claude-sonnet-4-5
      timeout: 30
  - model_name: chat  # 同名第二条,自动作为 fallback
    litellm_params:
      model: openai/deepseek-chat
      api_base: https://api.deepseek.com/v1
      api_key: your-domestic-key

router_settings:
  routing_strategy: latency-based-routing
  enable_pre_call_checks: true

这段 YAML 里有两个配置项经常被人直接抄走却不理解含义,简单拆一下。routing_strategy: latency-based-routing 的意思是:当同名的 chat 有多条路由时,网关会按最近一段时间各路由的实际响应延迟动态调整流量分配,而不是固定顺序”先试第一条,挂了再试第二条”。这对兜底场景其实是把双刃剑——如果海外模型只是”变慢了”但没有完全挂,网关可能会自动把一部分流量导向国产模型,你不需要等它彻底超时;但如果你的诉求是”只有主路完全失败才切换,绝不主动分流”,就得改成 simple-shuffle 或显式设置 fallbacks 字段,而不是用延迟路由。enable_pre_call_checks: true 则是让网关在真正发起请求前先做一次轻量校验(比如上下文长度是否超限、模型是否处于已知不可用状态),提前失败比等请求打过去再超时要省时间,尤其是海外模型这种单程网络延迟就有一两百毫秒的场景。

优点:业务代码不感知切换逻辑,熔断状态集中管理在网关里,支持更复杂的路由策略(延迟路由、权重路由、按错误码分类处理),新增模型或调整兜底顺序只改配置不改代码。
缺点:引入网关组件,需要你自己维护网关本身的高可用(网关挂了,主备模型再稳也没用),团队里得有人熟悉网关的运维和排障。

两种方案怎么选,我一般按团队和接入规模给建议:

维度客户端熔断(方案一)API 网关(方案二)
接入模型数量1~2 个,逻辑简单3 个以上,或未来会持续增加
团队规模1~3 人小团队,快速验证阶段有专职后端/运维,能维护网关
多实例部署熔断状态不共享,各实例各判断状态集中,行为一致
改动成本改代码、发版改配置、热更新
适合阶段MVP、早期验证生产环境、多模型矩阵

简单说:如果你现在只接了 Claude 一个海外模型加一个国产兜底,方案一半天就能上线,没必要为了”架构好看”上网关组件;但只要你的模型矩阵超过 3 个,或者预期未来会持续扩展,网关层的配置化管理会在半年后帮你省下大量重复劳动。

详见 API 网关故障切换配置

国产兜底模型选型(截至 2026-06,以官方为准)

模型适合兜底的场景OpenAI 兼容格式
DeepSeek(deepseek-chat)代码生成、通用问答、长文档
Qwen(通义千问)中文内容、多轮对话
文心一言(ERNIE)中文业务场景、百度生态内是(部分版本)
月之暗面(Kimi)长上下文场景兜底

具体模型能力对比见 国产模型横向对比

关键设计原则

  1. 超时要短,不要无限等待:海外模型超时建议设 15–30 秒,不要等到连接自然超时(可能 120 秒+)。判断标准很直接:拿你线上最近一周的正常响应时间做个 P95 统计,超时阈值设成这个数字的 3 倍左右,既不会误伤慢响应的正常请求,也不会让用户干等太久。
  2. 区分错误类型429 Rate Limit 应重试(配合指数退避,比如首次等 1 秒,失败再等 2 秒、4 秒,最多重试 3 次),5xx 或网络超时才触发兜底切换。把这两类混在一起处理,最常见的后果是:明明只是短暂限流,稍等一下就能正常调用,却被直接切到了国产模型,白白浪费了海外模型这次调用的额度和你为它付的费用。
  3. 熔断要有恢复探测:切换到国产模型后,定期(如 60 秒)发一个探测请求测试海外模型是否恢复,而非永久切换。这里有个实践细节:探测请求最好用一个极短的 prompt(比如”你好”),而不是真实业务请求,一是省成本,二是避免探测请求本身因为超长上下文又触发一次误判。
  4. 记录切换日志:每次切换都应记录原因(超时/限流/连接失败/5xx)、时间、切换前后的模型名,便于监控海外模型的可用率,也便于月底核算”这个月因为兜底多花了多少国产模型的调用费”。
  5. 国产模型也要有备份:国产模型的账期、配额管理同样重要,不能成为单点。见过团队把国产模型当”永远不会挂”的兜底,结果国产模型自己也遇到限流,两条腿一起瘸——建议至少准备两家国产模型互为备份,或者在网关里配成一个 fallback 链而不是单一目标。

进阶:异步/并发场景下怎么做兜底

如果你的服务是用 asyncio 或者要处理高并发请求,同步版本的 try/except 会阻塞事件循环,这时候该用 asyncio.wait_for 包一层超时控制,逻辑和同步版本一致,但不会卡住其他协程:

import asyncio
import anthropic

async def call_with_fallback_async(prompt: str) -> str:
    client = anthropic.AsyncAnthropic()
    try:
        resp = await asyncio.wait_for(
            client.messages.create(
                model="claude-sonnet-4-5",
                max_tokens=1024,
                messages=[{"role": "user", "content": prompt}],
            ),
            timeout=15,  # 异步场景可以设更短,因为不阻塞其他请求
        )
        return resp.content[0].text
    except (asyncio.TimeoutError, anthropic.APIConnectionError, anthropic.InternalServerError) as e:
        print(f"海外模型失败,切换国产兜底: {e}")
        # 兜底逻辑同上,此处省略
        return await call_domestic_fallback(prompt)

这里故意只捕获 asyncio.TimeoutErrorAPIConnectionErrorInternalServerError 三类,而不是笼统的 Exception——原因前面讲过,笼统捕获会把你自己代码的 bug 也吞掉。异步场景下超时可以设得比同步版本更短(比如 15 秒而不是 30 秒),因为异步不阻塞其他请求处理,切换更激进一点对整体吞吐反而有利,代价是极少数本来能在 20 秒内正常返回的海外请求会被提前切到兜底,这个取舍要结合你业务对”准确率 vs 速度”的偏好来定。

如果单个请求需要极高的可用性(比如金融场景的关键判断),还可以做”双发”——同时向海外和国产模型发请求,谁先成功用谁的结果,牺牲一部分成本换取延迟和可用性,但要注意这样两边的调用费都会产生,只适合小流量、高价值的关键路径,不建议全量请求都这么干。

常见问题

兜底模型的输出和主路模型一样吗?
不完全一样。不同模型的风格、格式遵循程度有差异。建议在设计 prompt 时尽量使用通用格式约束(如 JSON 输出),减少对特定模型风格的依赖,提高兜底时的输出一致性。

兜底切换会让用户感知到吗?
如果切换时机是在请求失败后(已有等待时间),用户会感到延迟增加。更好的体验是设置较短的超时(如 10 秒),超时后立即切兜底,总响应时间反而可能比等海外模型重试更短。

用聚合平台做兜底,需要自己写代码吗?
使用支持故障切换的聚合接入层(如力达云等候名单中的方案),通常只需在控制台配置主备模型,业务代码无需改动。具体能力以平台文档为准。

国产模型兜底时,之前的对话历史能带过去吗?
可以,只要在切换时将完整的 messages 数组传给国产模型 API 即可(多数支持 OpenAI 格式的国产模型兼容相同的消息格式)。注意:不同模型对超长历史的处理方式不同,需做截断保护。


本文仅作技术科普,不构成法律意见。企业接入海外模型须通过合规渠道,遵守数据出境相关规定。具体产品能力以各服务商官方文档为准。

相关阅读海外模型合规接入指南(Pillar) · 海外模型合规接入专题 · API 网关故障切换 · 国产模型横向对比

如需了解企业合规聚合接入方案(含多模型自动兜底),欢迎访问 力达云等候名单