跳转到主要内容

Gemini API 429、503 怎么解决:查配额、读错误与正确重试

遇到 Gemini API 429 或 503,先暂停批量发送,再检查错误正文和项目额度。本文给出从 QuotaFailure、RetryInfo 到有限重试的完整例子,说明何时降速、何时等额度恢复,以及怎样避免重试放大故障。

LaoZhang AI Team发布于更新于 11 分钟阅读
文章目录
Gemini API 429与503的额度排查和有序恢复

Gemini API 提示“服务器容量已达上限”时,先暂停批量请求,保留一条请求的 HTTP 状态码与完整错误正文。 如果确认每日额度已经耗尽,就停止秒级重试;如果是短时限流,降低发送速率并退避;如果返回 503,先做有限重试,再结合服务状态决定是否切换已经验证过的备用方案。

最快的排查顺序是:看错误详情,查对应项目的有效额度,单并发验证,再逐步恢复流量。 本文针对 Google AI Studio 项目使用的 Gemini Developer API,官方规则核验于 2026 年 9 月 8 日。Vertex AI、Gemini 网页版以及网盘存储容量应查看各自的设置。

先完成这四步,避免越重试越严重

  1. 暂停队列自动重发。 保留一个人工控制的测试请求,暂时把并发降到 1。先弄清楚失败原因,再恢复积压任务。
  2. 记录实际调用条件。 包括时间与时区、项目、模型 ID、接口地址、HTTP 状态、错误正文,以及响应提供的请求标识和等待提示。
  3. 打开 AI Studio 的有效速率限制。 选择真正处理请求的项目和型号,对照错误里的额度名称。入口可从官方速率限制页进入,避免拿旧文章中的固定 RPM 表代替自己的当前额度。
  4. 根据下表处理。 每次只改变一个因素,记录是否恢复。不要同时换网络、模型和密钥,导致结果无法解释。
你看到的证据现在采取的动作恢复条件
429,明确为每日请求或每日 token 额度停止短周期重试,核对额度重置或调整安排相应额度恢复后再发
429,明确为每分钟请求或输入 token 限制降低队列发送速率,必要时缩短输入,有限退避降载后最小请求能完成
429,命中滚动支出窗口减少短时间内的高成本请求,等待窗口腾出空间当前用量回到有效限制内
429,原因不明确保留日志,对照项目额度和服务情况原因查明后选择恢复方法
503,服务暂时不可用有限退避,查看官方状态,保留备用方案探测完成后逐步放量
400、401、403、404检查参数、密钥、权限或模型名称修正具体配置后再试

Google 排障指南建议对暂时性错误使用指数退避、随机抖动和次数上限。一条 503 响应说明这次请求无法完成,不能单独证明整个模型对所有用户都不可用。

从错误正文中找到额度和等待时间

直接使用 generateContent 时,应保留 error.code、error.status 和 error.details。下面是合成教学示例,展示字段位置;额度名称、数量和等待时间都要以你的实际响应为准。

json
{
  "error": {
    "code": 429,
    "status": "RESOURCE_EXHAUSTED",
    "message": "Quota exceeded",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.QuotaFailure",
        "violations": [
          {
            "quotaId": "ExampleRequestsPerMinute",
            "quotaValue": "20"
          }
        ]
      },
      {
        "@type": "type.googleapis.com/google.rpc.RetryInfo",
        "retryDelay": "12s"
      }
    ]
  }
}

这里的 quotaId 帮你定位触发的限制,quotaValue 是响应列出的额度,retryDelay 表示再次尝试前至少等待多久。字段定义可见 Google 的 QuotaFailure 与 RetryInfo。某次响应可能没有这些详情,不能因此自行补出一个“每日额度已满”的结论。

如果详情同时指向每日限制和短时间等待提示,先处理每日限制。等待十几秒不会增加已经耗尽的每日额度。也不要仅凭 message 里出现单词 quota 就把它归类为每日额度。

Interactions 使用另一套错误对象。 它的 error.code 是 rate_limit_exceeded、quota_exceeded 等字符串;官方错误页分别将它们解释为短时限流和每日额度超限。不要把该字符串字段直接套到上面的 generateContent JSON。

从 Gemini API 错误详情识别额度与重试等待提示

请求很少,为什么仍会遇到 429?

Gemini API 会分别检查多个限制,最先触发的那一项就能拦住请求。最常见的误判是只数调用次数,忽略每次输入大小。

假设某项目的有效限制是 60 RPM、120,000 输入 TPM,每次请求平均输入 8,000 token。仅按 token 维度计算,理论上每分钟最多容纳 120,000 ÷ 8,000 = 15 次请求,已经低于 60 RPM。按 60 次发送仍会超限。这里是便于理解的假设额度,不能复制成某个模型的官方配额。

实际队列还要给输入波动和其他程序留余量。固定间隔发送、限制积压任务释放速度,比只设置“最多 10 个并发”更直接地控制每分钟请求数。并发限制控制同时在途的数量,无法独自约束一批很快完成的小请求。

另外还要检查:

  • 同项目的其他应用。 官方限制按项目应用,不按 API 密钥应用。另建同项目密钥,不能增加总额度。
  • 长对话与附件。 后续请求携带的历史、文件和工具结果都会影响输入用量,最后一句话很短也可能是一个大请求。
  • 滚动支出限制。 当前部分账号存在按 10 分钟窗口计算的支出限制,是否适用取决于结算记录和账号状态。
  • 每日请求数。 RPD 在太平洋时间午夜重置,不是从报错时刻开始再等 24 小时,也不固定在北京时间零点。

以上规则来自官方速率限制文档。模型、层级和账号状态会改变有效额度;详细的层级与额度检查可继续看Gemini API 速率限制指南。

一个能直接连接请求的 Python 有限重试示例

下面使用 Python 3 标准库,直接调用非流式 generateContent,最多实际发送 4 次,累计主动等待不超过 30 秒。它读取 RetryInfo 和 Retry-After,对已识别的每日限制立即停止,未知 429 留给人工核对。没有再叠加 SDK 的自动重试。

把以下代码保存为 gemini_retry.py,在自己的环境配置 GEMINI_API_KEY 后运行。每次实际生成请求都可能产生用量。额度名称匹配只覆盖含 PerDay、PerMinute 的明确标识;其他命名会停在待查分支,需要按实际额度补充,而不是猜测。

python
import json
import math
import os
import random
import re
import time
import urllib.error
import urllib.request
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime


def error_policy(status, body):
    error = body.get("error", {}) if isinstance(body, dict) else {}
    details = error.get("details", []) if isinstance(error, dict) else []
    quota_ids, delays = [], []
    details = details if isinstance(details, list) else []
    for item in details:
        if not isinstance(item, dict):
            continue
        if item.get("@type") == "type.googleapis.com/google.rpc.QuotaFailure":
            violations = item.get("violations", [])
            if not isinstance(violations, list):
                violations = []
            for violation in violations:
                quota_ids.append(str(violation.get("quotaId", ""))
                                 if isinstance(violation, dict) else "")
        if item.get("@type") == "type.googleapis.com/google.rpc.RetryInfo":
            value = str(item.get("retryDelay", ""))
            if re.fullmatch(r"\d+(?:\.\d{1,9})?s", value):
                delays.append(float(value[:-1]))
    if status == 429:
        if any("perday" in q.lower() for q in quota_ids):
            return "quota_reset", 0
        if not quota_ids or not all("perminute" in q.lower() for q in quota_ids):
            return "inspect_quota", 0
    elif status not in (500, 502, 503, 504):
        return "fix_request", 0
    return "retry", max(delays, default=0)


def retry_after(value):
    if value is None:
        return 0
    try:
        seconds = float(value)
    except ValueError:
        try:
            seconds = (parsedate_to_datetime(value) - datetime.now(timezone.utc)).total_seconds()
        except (TypeError, ValueError, OverflowError):
            return 0
    return max(0, seconds) if math.isfinite(seconds) else 0


def generate(payload, model="gemini-3.1-pro-preview"):
    waited = 0.0
    for attempt in range(4):
        request = urllib.request.Request(
            f"https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent",
            data=json.dumps(payload).encode(),
            headers={"Content-Type": "application/json",
                     "x-goog-api-key": os.environ["GEMINI_API_KEY"]},
            method="POST"
        )
        try:
            with urllib.request.urlopen(request, timeout=20) as response:
                return json.load(response)
        except urllib.error.HTTPError as error:
            raw = error.read().decode("utf-8", errors="replace")
            try:
                body = json.loads(raw)
            except json.JSONDecodeError:
                body = {}
            action, hint = error_policy(error.code, body)
            print(f"第{attempt + 1}次,HTTP {error.code},处理:{action}")
            if action != "retry" or attempt == 3:
                raise RuntimeError(raw) from error
            delay = max(hint, retry_after(error.headers.get("Retry-After")),
                        random.uniform(0, min(8, 2 ** attempt)))
            if waited + delay > 30:
                raise RuntimeError("建议等待时间超出本轮预算,停止发送") from error
        time.sleep(delay)
        waited += delay
    raise RuntimeError("尝试次数已耗尽")


if __name__ == "__main__":
    result = generate({
        "contents": [{"parts": [{"text": "请只回复:连接检查完成"}]}],
        "generationConfig": {"thinkingConfig": {"thinkingLevel": "LOW"}}
    })
    candidates = result.get("candidates", [])
    if not candidates or candidates[0].get("finishReason") != "STOP":
        raise RuntimeError("生成未正常结束,请检查返回正文")
    parts = candidates[0].get("content", {}).get("parts", [])
    text = "".join(p.get("text", "") for p in parts if not p.get("thought"))
    if not text.strip():
        raise RuntimeError("没有最终文本,请检查返回正文")
    print(text)
    print("实际用量:", result.get("usageMetadata", {}))

30 秒限制的是代码主动退避的累计等待,单次连接另设 20 秒超时,二者不能相加当成严格的整轮截止时间。若业务要求“用户等待最多 30 秒”,应在调用层增加可取消的总超时,并停止后续尝试。

这份例子不会自动重发网络断连或已返回 200 但内容无法解析的请求,因为服务端可能已经完成生成。应先记录这种不确定结果,再决定如何处理。重试循环也不应包住订单写入、发邮件等业务操作;这些动作需要独立去重。

如果使用官方 SDK,先检查版本及重试配置。当前排障文档说明 SDK 自带部分暂时性错误重试。外层 3 轮、内层每轮 5 次实际发送,就可能变成 15 次请求;保留一层主要重试,才能看清真实尝试次数。

503 持续出现时,怎样恢复业务?

先检查官方服务状态,并用模型停用表确认模型仍受支持。然后保留同一项目、模型和接口,去掉复杂附件或可选工具,用一条简短输入观察。一次成功只说明小请求可完成,恢复正常负载后还要继续观察。

可以把恢复过程分成三个动作:暂停普通流量,冷却后只放行一个探测,成功后逐档增加发送速率。多线程程序需要共享探测许可,不能每个请求各建一个断路器;多进程或多台服务器则要通过共享存储或任务队列协调。本地线程锁不能限制整个集群。

若备用模型能够满足相同任务,在正常时期就验证它的输入、工具、输出结构和费用。切换后也要检查实际结果,不能只看状态码成功。图像任务可参考Gemini 图像生成过载排查;文本任务无需套用图片专属配置。

更换应用服务器的地理位置,不等于为 Gemini Developer API 选择了一份独立区域容量。第三方入口也可能使用同一上游。备用方案是否有效,要靠该方案当时实际完成请求来判断。

暂停批量请求、单个探测与逐步恢复 API 流量的顺序

怎样确认这次修复真的有效?

本文的重试例使用合成响应离线检查:每日额度立即停止,未知 429 不盲重试,分钟限额和暂时性 5xx 尊重等待提示,超出等待预算或发送次数后结束。这些检查验证的是示例控制逻辑,没有进行付费故障实测。

在自己的服务上,保存恢复前后相同条件的记录:实际发送次数、触发额度、等待时间、最终结束状态、结果是否符合任务要求,以及恢复正常流量后是否再次失败。流式接口还应检查最终事件,建立 HTTP 连接不等于生成完成。

如果低负载下仍持续失败,向支持提供发生时间、项目与模型、错误详情、请求标识和最小复现步骤。移除密钥及私人输入后再共享日志。这样支持方能核对具体请求,你也能区分额度问题、配置问题与服务端故障。

参考来源6

本文引用的外部页面,按正文出现顺序排列。最后更新于 2026年9月8日。

  1. 1.官方速率限制页ai.google.dev/gemini-api/docs/rate-limits
  2. 2.Google 排障指南ai.google.dev/gemini-api/docs/troubleshooting
  3. 3.QuotaFailure 与 RetryInfogithub.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto
  4. 4.官方错误页ai.google.dev/gemini-api/docs/api-errors
  5. 5.官方服务状态aistudio.google.com/status
  6. 6.模型停用表ai.google.dev/gemini-api/docs/deprecations
429 RESOURCE_EXHAUSTED 的停止条件与短时限流有限重试分流
故障排查

Nano Banana Pro RESOURCE_EXHAUSTED 429:排查与 Python、Node.js 恢复代码

Nano Banana Pro 的 429 不能一律靠重试解决:零额度、每日上限和计费阻塞应先停止,短时限流才按服务端最低等待时间重试。下面的 Python、Node.js 程序限制次数与请求等待总时长,验证并保存图片,续跑时跳过已确认完成的任务。

18 分钟