ChatGPT、Claude、Grok同一时段异常:生产级AI应用为什么必须做多模型容灾?

0 阅读10分钟

2026年9月3日,多家主流AI服务在相近时间段出现异常。

OpenAI状态页记录了ChatGPT与Codex错误升高;Anthropic状态页则确认Claude Fable、Mythos和Opus多个模型受到影响。海外媒体和用户监测数据还显示,Grok、Gemini等服务也在相近时段出现访问问题。

需要先说明:

多个平台在相近时间出现异常,不等于它们一定由同一个故障引起。

但这次事件仍然暴露了一个现实问题:当AI已经进入客服、编程、搜索和业务自动化流程后,只连接一个模型,可能已经不够可靠。

一、多家AI服务出现了什么问题?

根据官方状态记录:

  • OpenAI报告ChatGPT和Codex出现错误升高;
  • Anthropic报告Fable、Mythos、Opus多个模型出现请求错误;
  • Grok等服务也出现大量用户故障反馈;
  • 部分平台在实施修复后逐步恢复。

OpenAI和Anthropic均未将这次事件描述为永久性故障。

不过对于正在运行的应用来说,即使服务只中断几十分钟,也可能造成:

  • AI客服无法回复;
  • 编程Agent任务中断;
  • 工作流停在中间状态;
  • 自动化任务重复执行;
  • 用户请求大量积压;
  • 重试流量进一步放大故障;
  • 已经调用的外部工具无法回滚。

普通聊天失败一次,用户可以刷新页面。

但如果Agent已经修改文件、发送消息或者调用业务接口,简单地"再试一次"可能产生新的风险。

二、为什么只配置一个模型不够?

很多AI应用的调用结构非常简单:

User request
   ↓
Business service
   ↓
Fixed model
   ↓
Return result

这种结构开发成本低,但模型或上游接口出现故障时,整个应用都会停止工作。

更稳妥的结构应该是:

User request
   ↓
AI call layer
   ├── Primary model
   ├── Same-tier fallback model
   ├── Low-cost degraded model
   └── Final fallback strategy

这里的"备用模型"不能只是在名称后面换一个版本。

如果所有模型最终依赖相同的服务商、区域或者基础设施,那么它们仍然可能同时不可用。

真正的容灾需要考虑多个层级:

容灾层级作用
同模型重试处理短暂网络抖动
同厂商模型切换处理单个模型异常
跨厂商模型切换处理供应商级故障
跨区域部署处理区域网络或云服务异常
本地规则兜底在全部模型失败时维持基本服务
人工接管处理高风险和不可恢复任务

三、哪些错误适合重试?

并不是所有API错误都应该重试。

适合重试的错误

常见的临时性错误包括:

  • 连接超时
  • 读取超时
  • 429 Too Many Requests
  • 500 Internal Server Error
  • 502 Bad Gateway
  • 503 Service Unavailable
  • 504 Gateway Timeout

这些错误可能由网络抖动、限流或者上游服务异常引起。

可以采用:

  • 较短的首次等待;
  • 指数退避;
  • 随机抖动;
  • 最大重试次数;
  • 超过阈值后切换模型。

不适合盲目重试的错误

下面这些错误通常需要先修改配置或请求:

  • 400 请求参数错误
  • 401 API Key无效
  • 403 权限不足
  • 404 模型不存在
  • 额度或余额不足
  • 内容安全策略拒绝
  • 上下文长度超限

如果对这些错误持续重试,不仅无法恢复,还可能制造更多请求和费用。

尤其是安全拒绝,不能被误判为普通服务故障后,自动切换到另一个模型绕过限制。

四、Python实现模型自动切换

下面使用兼容OpenAI SDK的接口,实现一个基础的重试和模型回退方案。

模型名称只是配置项,请替换成控制台中实际可用的模型ID。

import os
import random
import time

from openai import (
    APIConnectionError,
    APIStatusError,
    APITimeoutError,
    OpenAI,
)

client = OpenAI(
    api_key=os.environ["AI_API_KEY"],
    base_url="https://genvis.xyz/v1",
    timeout=30,
    max_retries=0,
)

MODEL_CANDIDATES = os.getenv(
    "MODEL_CANDIDATES",
    "primary-model-id,fallback-model-id,degraded-model-id",
).split(",")

RETRYABLE_STATUS_CODES = {
    408,
    429,
    500,
    502,
    503,
    504,
}


def wait_before_retry(attempt: int) -> None:
    delay = min(2 ** attempt, 8)
    jitter = random.uniform(0, 0.5)
    time.sleep(delay + jitter)


def request_model(model: str, messages: list[dict]) -> str:
    response = client.chat.completions.create(
        model=model,
        messages=messages,
    )

    return response.choices[0].message.content or ""


def chat_with_fallback(messages: list[dict]) -> tuple[str, str]:
    last_error = None

    for model in MODEL_CANDIDATES:
        model = model.strip()

        if not model:
            continue

        for attempt in range(2):
            try:
                answer = request_model(model, messages)
                return model, answer

            except (APIConnectionError, APITimeoutError) as error:
                last_error = error
                wait_before_retry(attempt)

            except APIStatusError as error:
                last_error = error

                if error.status_code not in RETRYABLE_STATUS_CODES:
                    raise

                wait_before_retry(attempt)

        print(f"{model} temporarily unavailable, switching to fallback model")

    raise RuntimeError("All candidate models failed") from last_error


messages = [
    {
        "role": "system",
        "content": "You are a technical support agent. Answer accurately and concisely.",
    },
    {
        "role": "user",
        "content": "Why does an API request return 503?",
    },
]

used_model, answer = chat_with_fallback(messages)

print(f"Model actually used: {used_model}")
print(answer)

这段代码做了四件事:

  1. 关闭SDK内置重试,避免与业务重试叠加;
  2. 只对临时性故障进行重试;
  3. 为每个模型设置有限的重试次数;
  4. 当前模型持续失败后,自动尝试下一个模型。

五、为什么必须使用指数退避?

假设上游服务突然出现故障,同时有一万个客户端立即重试。

如果每个客户端都以固定间隔持续发送请求,上游服务即使开始恢复,也可能再次被重试流量压垮。

指数退避会逐渐增加等待时间:

First failure: wait about 1 second
Second failure: wait about 2 seconds
Third failure: wait about 4 seconds
Fourth failure: wait about 8 seconds

再加入少量随机时间,可以避免大量客户端在完全相同的时刻再次发送请求。

不过,指数退避不能无限进行。

生产环境通常还需要限制:

  • 单模型最大重试次数
  • 整个请求最大耗时
  • 全链路最大调用次数
  • 单个任务Token预算
  • 同一用户并发数量

六、只做模型切换还不够

如果服务已经持续故障,每个新请求都先等待主模型超时,再尝试备用模型,会让用户一直承受额外延迟。

因此还需要熔断器。

熔断器一般有三种状态:

状态行为
Closed正常请求主模型
Open暂时跳过故障模型
Half-Open发送少量请求测试是否恢复

例如,一个模型在60秒内连续失败5次,可以暂时熔断2分钟。

熔断期间,新请求直接使用备用模型,不再等待主模型反复超时。

两分钟后,可以放行少量探测请求:

  • 探测成功:恢复正常调用;
  • 探测失败:重新进入熔断状态。

这比"每个请求都重新试一遍"更加稳定。

七、Agent任务不能直接整段重跑

普通文本生成通常是幂等的:失败后重新生成一次,影响不大。

Agent任务却可能已经执行了一部分操作。

例如:

Step 1: Generate refund plan
Step 2: Call refund API
Step 3: Send notification
Step 4: Write processing record

如果第三步发生超时,系统无法立即判断通知到底有没有发送成功。

此时直接从第一步重新执行,可能导致重复退款或重复通知。

因此,Agent容灾还必须记录任务状态:

  • task_id
  • current_step
  • tool_call_id
  • operation_status
  • request_fingerprint
  • last_successful_step

对于付款、退款、发券、删除数据和发送消息等操作,应当增加:

  • 幂等键;
  • 操作前确认;
  • 操作结果查询;
  • 状态持久化;
  • 人工复核入口;
  • 不可逆操作白名单。

模型负责决定"做什么",业务系统必须决定"这项操作是否允许再次执行"。

八、降级模型应该怎样选择?

备用模型不是随便选择一个便宜模型。

至少需要比较以下能力:

指标说明
上下文长度能否容纳当前任务资料
工具调用是否支持稳定的函数调用
结构化输出能否返回要求的JSON结构
多模态能力是否需要识别图片或文件
延迟能否满足实时业务需求
价格是否适合大量兜底请求
安全边界是否允许当前任务类型
服务商依赖是否与主模型共享故障域

例如,代码审查任务切换模型后,备用模型仍然需要理解大型代码上下文。

如果备用模型上下文不足,系统应该缩减输入、生成摘要或者转人工处理,而不是直接截断关键代码。

九、所有模型都失败时怎么办?

多模型并不代表永远不会失败。

当全部模型均不可用时,应用仍然需要最低限度的服务能力。

AI客服

可以返回预设提示:

Smart service is temporarily busy. Your issue has been recorded.
For account, payment, or security issues, please wait for manual handling.

内容生成

可以把任务写入队列,等待服务恢复后继续执行。

编程Agent

应保存当前工作区、执行步骤和最后一次成功操作,避免恢复后从头运行。

高风险业务

付款、退款、账号操作和数据删除等请求,应该立即停止自动化流程并转人工确认。

一个好的兜底方案,不一定能继续完成任务,但必须避免把暂时故障扩大成业务事故。

十、生产级AI调用检查清单

上线前可以逐项确认:

  • 是否设置连接和读取超时;
  • 是否限制单模型重试次数;
  • 是否只重试临时性错误;
  • 是否使用指数退避和随机抖动;
  • 是否准备同厂商备用模型;
  • 是否准备跨厂商备用模型;
  • 是否设置熔断和恢复探测;
  • 是否记录实际使用的模型;
  • 是否记录状态码、延迟和Token用量;
  • 是否设置单任务成本上限;
  • 工具调用是否使用幂等键;
  • 不可逆操作是否需要人工确认;
  • 全部模型失败时是否有兜底方案;
  • 是否定期进行故障切换演练。

十一、几个常见问题

多模型切换一定能避免宕机吗?

不能。

如果多个模型共享云服务、网络、区域或者同一个上游通道,它们仍然可能同时故障。多模型只能降低风险,不能消除风险。

遇到429应该立即换模型吗?

不一定。

短时间限流可以先进行有限重试;如果持续收到429,或者预计等待时间过长,再切换备用模型。

内容安全拒绝可以切换模型重试吗?

不应该将安全拒绝当作普通故障自动绕过。系统需要识别拒绝原因,并按照业务合规规则处理。

为什么要记录实际使用的模型?

因为切换后,输出质量、延迟和费用可能发生变化。只有记录实际模型,才能分析故障期间的成功率和成本。

备用模型需要和主模型能力完全相同吗?

不需要,但必须满足业务的最低能力要求。无法完成原任务时,应明确降级或者转人工,而不是返回看似成功但实际不可用的结果。

总结

这次多家AI服务在相近时间出现异常,提醒开发者重新审视AI应用的可靠性设计。

真正的生产级AI系统,不应该只是:

调用模型 → 返回结果

而应该具备:

Timeout control
→ Limited retry
→ Exponential backoff
→ Circuit breaker
→ Model switch
→ State recovery
→ Final fallback

模型能力越强、Agent执行的步骤越多,故障产生的影响也越大。

选择更强的模型可以提高任务上限;设计可靠的调用架构,才能决定业务能不能持续运行。

参考资料

  • OpenAI状态记录:ChatGPT与Codex错误升高
  • Anthropic Claude服务状态
  • Ars Technica:多家AI服务出现重叠故障
  • Axios:多家AI服务发生异常