Skip to content

429/容量错误:账号轮换的正确预期与模型容量耗尽的误区

学完你能做什么

  • 正确区分「配额不足」和「上游限流」,避免误判
  • 理解 Antigravity Tools 的自动轮换机制和预期行为
  • 遇到 429 错误时,知道如何快速定位问题并优化配置

你现在的困境

  • 看到返回 429 错误,误以为是"模型没容量了"
  • 配了多个账号,却还是频繁遇到 429,不知道是配置问题还是账号问题
  • 不清楚系统什么时候会自动切换账号,什么时候会"卡住"

核心思路

什么是 429 错误?

429 Too Many Requests 是 HTTP 状态码。在 Antigravity Tools 里,429 不只代表“请求太频繁”,还可能是配额耗尽、模型临时过载等一类“你暂时用不了”的信号。

代理会尝试识别 429 的原因

代理会从响应体里尝试解析 error.details[0].reasonerror.message,把 429 粗分为几类(实际以返回为准):

代理识别的类型常见 reason / 线索典型特征
配额耗尽QUOTA_EXHAUSTED / 文本包含 exhaustedquota可能需要等到配额刷新
速率限制RATE_LIMIT_EXCEEDED / 文本包含 per minuterate limittoo many requests通常是几十秒级别的冷却
模型容量不足MODEL_CAPACITY_EXHAUSTED / 文本包含 model_capacity常见是短暂过载,稍后可恢复
未知无法解析走默认冷却策略

Antigravity Tools 的自动处理

当一次请求遇到 429(以及部分 5xx/过载状态)时,代理通常会在服务端侧做两件事:

  1. 记录冷却时间:把这次错误写入 RateLimitTracker,后续选账号时会主动避开“仍在冷却”的账号。
  2. 在重试里轮换账号:Handlers 会在单次请求内进行多次尝试,重试时会 force_rotate=true,从而触发 TokenManager 选择下一个可用账号。

你怎么知道它有没有换号?

即使你的请求 body 不变,响应里通常会带 X-Account-Email(以及 X-Mapped-Model),你可以用它验证“这次请求到底用的是哪个账号”。

什么时候会遇到 429 错误?

场景 1:单个账号请求过快

现象:即使只有一个账号,短时间内发送大量请求也会触发 429。

原因:每个账号都有自己的速率限制(RPM/TPM),超过就会限流。

解决

  • 增加账号数量
  • 降低请求频率
  • 使用固定账号模式分散压力(详见「固定账号模式」)

场景 2:所有账号同时限流

现象:有多个账号,但所有账号都返回 429。

原因

  • 账号总数不足以支撑你的请求频率
  • 所有账号几乎同时触发限流/过载

解决

  • 增加更多账号
  • 调整调度模式为「性能优先」(跳过粘性会话与 60s 窗口复用)
  • 检查配额保护是否误将可用账号排除

场景 3:账号被配额保护误判

现象:某个账号的配额很充足,但系统一直跳过它。

原因

  • 开启了配额保护,阈值设置偏高
  • 该账号的特定模型配额低于阈值
  • 账号被手动标记为 proxy_disabled

解决

  • 检查配额保护设置(Settings → Quota Protection),按你的使用强度调整阈值与监控模型
  • 在账号数据中检查 protected_models,确认是不是被保护策略跳过

跟我做

第 1 步:识别 429 错误类型

为什么:不同类型的 429 错误需要不同的处理方式。

在 Proxy Monitor 中查看 429 错误的响应体,重点看两类信息:

  • 原因error.details[0].reason(例如 RATE_LIMIT_EXCEEDEDQUOTA_EXHAUSTED)或 error.message
  • 等待时间RetryInfo.retryDelaydetails[0].metadata.quotaResetDelay(如果存在)
json
{
  "error": {
    "details": [
      {
        "reason": "RATE_LIMIT_EXCEEDED",
        "metadata": {
          "quotaResetDelay": "42s"
        }
      }
    ]
  }
}

你应该看到

  • 如果响应体里能找到等待时间(例如 RetryInfo.retryDelayquotaResetDelay),代理通常会先等待一小段时间再重试。
  • 如果没有等待时间,代理会按内置策略给这个账号加一个“冷却期”,并在重试里直接换下一个账号。

第 2 步:检查账号调度配置

为什么:调度配置直接影响账号轮换频率和优先级。

进入 API Proxy 页面,查看调度策略:

配置项说明默认值/建议
Scheduling Mode调度模式Balance(默认)
Preferred Account固定账号模式未选中(默认)

调度模式对比

模式账号复用策略限流处理适用场景
CacheFirst启用粘性会话与 60s 窗口复用优先等待,极大提升 Prompt Caching 命中率对话类/需要高缓存命中率
Balance启用粘性会话与 60s 窗口复用立即切换到备选账号,兼顾成功率和性能通用场景,默认
PerformanceFirst跳过粘性会话与 60s 窗口复用,纯轮询模式立即切换,账号负载最均衡高并发、无状态请求

缓存优先 vs 平衡模式

如果你使用 Prompt Caching 且希望提升缓存命中率,选择 CacheFirst —— 限流时它会优先等待而不是立即换号。如果你更看重请求成功率而不是缓存,选择 Balance —— 限流时它会立即换号。

性能优先模式

如果你的请求是无状态的(如图片生成、独立查询),可以试试 PerformanceFirst。它会跳过粘性会话与 60s 窗口复用,让连续请求更容易落到不同账号。

第 3 步:验证账号轮换是否正常工作

为什么:确认系统能够自动切换账号。

方法 1:看响应 Header

用 curl 或你自己的客户端把响应头打印出来,观察 X-Account-Email 是否会变化。

方法 2:查看日志

打开日志文件(根据你的系统位置),搜索 🔄 [Token Rotation]

🔄 [Token Rotation] Accounts: [
  "[email protected](protected=[])",
  "[email protected](protected=[])",
  "[email protected](protected=[])"
]

方法 3:使用 Proxy Monitor

Monitor 页面查看请求日志,关注:

  • Account 字段是否在不同账号间切换
  • Status 为 429 的请求后,是否有成功的请求使用了不同账号

你应该看到

  • 当某个账号返回 429 后,后续请求自动切换到其他账号
  • 如果看到多个请求使用同一账号且都失败,可能是调度配置问题

第 4 步:优化账号优先级

为什么:让系统优先使用高配额/高等级账号,减少 429 概率。

在 TokenManager 里,系统会在选择账号前对账号池做一次排序(会打印 🔄 [Token Rotation] Accounts: ...):

  1. 订阅等级优先:ULTRA > PRO > FREE
  2. 配额百分比优先:同等级内,配额高的在前
  3. 排序入口:这个排序发生在代理侧,最终用哪个账号以代理侧排序+可用性判断为准。

智能排序原理(代理侧)

优先级是 ULTRA > PRO > FREE;同一订阅等级内按 remaining_quota(账号最大剩余配额百分比)降序。

操作

  • 拖拽账号调整显示顺序(可选)
  • 刷新配额(Accounts → 刷新所有配额)
  • 检查账号的订阅等级和配额

踩坑提醒

❌ 错误 1:误将 429 当成"模型没容量"

现象:看到 429 错误就以为模型没容量了。

正确理解

  • 429 是限流,不是容量问题
  • 增加账号可以降低 429 概率
  • 调整调度模式可以提升切换速度

❌ 错误 2:配额保护阈值设置过高

现象:配额充足但系统一直跳过账号。

原因:Quota Protection 会把低于阈值的模型加入账号的 protected_models,代理在调度时会跳过“被保护的模型”。阈值过高时,可能导致可用账号被过度排除。

修正

  • 回到 Settings → Quota Protection,调整监控模型与阈值
  • 如果你想搞清楚它到底保护了哪些模型,去账号数据里看 protected_models

❌ 错误 3:固定账号模式导致无法轮换

现象:设置了 Preferred Account,但该账号限流后系统"卡住"。

原因:固定账号模式下,系统优先使用指定账号,只有在账号不可用时才降级到轮询。

修正

  • 如果不需要固定账号,清空 Preferred Account
  • 或确保固定账号的配额充足,避免限流

检查点 ✅

  • [ ] 能区分配额不足和上游限流
  • [ ] 知道如何在 Proxy Monitor 中查看 429 错误详情
  • [ ] 理解三种调度模式的区别和使用场景
  • [ ] 知道如何检查账号轮换是否正常工作
  • [ ] 能优化账号优先级并检查配额保护策略

常见问题

Q1:为什么我有多个账号,还是会遇到 429?

A:可能的原因:

  1. 所有账号同时触发限流(请求频率过高)
  2. 连续请求在“60s 窗口复用”下反复复用同一账号,更容易把单账号打到限流
  3. 配额保护误将可用账号排除
  4. 账号总数不足以支撑你的请求频率

解决

  • 增加更多账号
  • 使用 PerformanceFirst 模式
  • 检查 Quota Protection 是否把你要用的模型加入了 protected_models(必要时调整监控模型与阈值)
  • 降低请求频率

Q2:429 错误会自动重试吗?

A:会在单次请求内自动重试。重试次数上限通常是 3 次,具体计算方式为 min(3, 账号池大小),且至少尝试 1 次。

重试次数示例

  • 账号池 1 个账号 → 尝试 1 次(不重试)
  • 账号池 2 个账号 → 尝试 2 次(重试 1 次)
  • 账号池 3 个或更多账号 → 尝试 3 次(重试 2 次)

大致流程

  1. 记录限流/过载信息(进入 RateLimitTracker
  2. 如果能解析到等待时间(例如 RetryInfo.retryDelay / quotaResetDelay),会先等待一小段时间再继续
  3. 重试时强制轮换账号(attempt > 0force_rotate=true),尝试用下一个可用账号发起上游请求

如果所有尝试都失败,代理会把错误返回给客户端;同时你仍然可以从响应头(如 X-Account-Email)或 Proxy Monitor 看到实际使用过的账号。

Q3:如何查看某个账号被限流了多久?

A:有两种方式:

方式 1:查看日志,搜索 rate-limited

🔒 [FIX #820] Preferred account [email protected] is rate-limited, falling back to round-robin

方式 2:日志中会显示剩余等待时间

All accounts are currently limited. Please wait 30s.

Q4:配额保护和限流是一回事吗?

A:不是。

特性配额保护限流跟踪
触发条件模型配额低于阈值收到 429 错误
作用范围特定模型整个账号
持续时间直到配额恢复由上游决定(通常几秒到几分钟)
行为跳过该模型跳过该账号

Q5:如何强制立即切换账号?

A:可以从“让下一次请求更容易换号”的角度入手:

  1. 调度层面:切到 PerformanceFirst,跳过粘性会话与 60s 窗口复用
  2. 固定账号:如果启用了 Preferred Account,先清空它,否则会优先用固定账号(直到它限流/被保护)
  3. 账号池:增加账号数量,单账号被限流时更容易找到替代账号

单次请求里,代理本身也会在重试时强制轮换(attempt > 0 会触发 force_rotate=true),但重试次数受上限控制。

本课小结

  • 429 在 Antigravity Tools 里是一类“上游暂时不可用”的信号,可能是速率限制、配额耗尽、模型容量不足等原因
  • 代理会记录冷却时间,并在单次请求的重试里尝试轮换账号(但重试次数有限)
  • 调度模式、Quota Protection、账号数量都会影响你遇到 429 的概率与恢复速度
  • 用 Proxy Monitor、响应头 X-Account-Email 和日志可以快速定位问题

下一课预告

下一课我们学习 404/路径不兼容:Base URL、/v1 前缀与"叠路径"客户端

你会学到:

  • 最常见的接入错误(404)是如何产生的
  • 不同客户端对 base_url 的拼接差异
  • 如何快速修复 404 问题

附录:源码参考

点击展开查看源码位置

更新时间:2026-01-23

功能文件路径行号
429 重试延迟解析(RetryInfo / quotaResetDelay)src-tauri/src/proxy/upstream/retry.rs38-67
Duration 解析工具src-tauri/src/proxy/upstream/retry.rs11-35
调度模式枚举(CacheFirst/Balance/PerformanceFirst)src-tauri/src/proxy/sticky_config.rs3-12
限流原因解析与默认冷却策略src-tauri/src/proxy/rate_limit.rs5-258
MAX_RETRY_ATTEMPTS 常量定义(OpenAI handler)src-tauri/src/proxy/handlers/openai.rs14
重试次数计算(max_attempts = min(MAX_RETRY_ATTEMPTS, pool_size))src-tauri/src/proxy/handlers/openai.rs830
OpenAI handler:429/5xx 时标记限流并重试/轮换src-tauri/src/proxy/handlers/openai.rs349-389
账号排序优先级(ULTRA > PRO > FREE + remaining_quota)src-tauri/src/proxy/token_manager.rs504-538
60s 窗口复用 + 避开限流/配额保护src-tauri/src/proxy/token_manager.rs624-739
限流记录入口(mark_rate_limited)src-tauri/src/proxy/token_manager.rs1089-1113
429 精确锁定/实时配额刷新/降级策略(mark_rate_limited_async)src-tauri/src/proxy/token_manager.rs1258-1417

关键常量

  • MAX_RETRY_ATTEMPTS = 3:单次请求内最大重试次数(OpenAI/Gemini handler)
  • 60:60 秒窗口复用(仅在 PerformanceFirst 之外的模式启用)
  • 5:Token 获取超时时间(秒)
  • 300:Token 提前刷新阈值(秒,5 分钟)

关键函数

  • parse_retry_delay():从 429 错误响应中提取重试延迟
  • get_token_internal():账号选择与轮换的核心逻辑
  • mark_rate_limited():标记账号为限流状态