429/容量错误:账号轮换的正确预期与模型容量耗尽的误区
学完你能做什么
- 正确区分「配额不足」和「上游限流」,避免误判
- 理解 Antigravity Tools 的自动轮换机制和预期行为
- 遇到 429 错误时,知道如何快速定位问题并优化配置
你现在的困境
- 看到返回 429 错误,误以为是"模型没容量了"
- 配了多个账号,却还是频繁遇到 429,不知道是配置问题还是账号问题
- 不清楚系统什么时候会自动切换账号,什么时候会"卡住"
核心思路
什么是 429 错误?
429 Too Many Requests 是 HTTP 状态码。在 Antigravity Tools 里,429 不只代表“请求太频繁”,还可能是配额耗尽、模型临时过载等一类“你暂时用不了”的信号。
代理会尝试识别 429 的原因
代理会从响应体里尝试解析 error.details[0].reason 或 error.message,把 429 粗分为几类(实际以返回为准):
| 代理识别的类型 | 常见 reason / 线索 | 典型特征 |
|---|---|---|
| 配额耗尽 | QUOTA_EXHAUSTED / 文本包含 exhausted、quota | 可能需要等到配额刷新 |
| 速率限制 | RATE_LIMIT_EXCEEDED / 文本包含 per minute、rate limit、too many requests | 通常是几十秒级别的冷却 |
| 模型容量不足 | MODEL_CAPACITY_EXHAUSTED / 文本包含 model_capacity | 常见是短暂过载,稍后可恢复 |
| 未知 | 无法解析 | 走默认冷却策略 |
Antigravity Tools 的自动处理
当一次请求遇到 429(以及部分 5xx/过载状态)时,代理通常会在服务端侧做两件事:
- 记录冷却时间:把这次错误写入
RateLimitTracker,后续选账号时会主动避开“仍在冷却”的账号。 - 在重试里轮换账号: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_EXCEEDED、QUOTA_EXHAUSTED)或error.message - 等待时间:
RetryInfo.retryDelay或details[0].metadata.quotaResetDelay(如果存在)
{
"error": {
"details": [
{
"reason": "RATE_LIMIT_EXCEEDED",
"metadata": {
"quotaResetDelay": "42s"
}
}
]
}
}你应该看到:
- 如果响应体里能找到等待时间(例如
RetryInfo.retryDelay或quotaResetDelay),代理通常会先等待一小段时间再重试。 - 如果没有等待时间,代理会按内置策略给这个账号加一个“冷却期”,并在重试里直接换下一个账号。
第 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: ...):
- 订阅等级优先:ULTRA > PRO > FREE
- 配额百分比优先:同等级内,配额高的在前
- 排序入口:这个排序发生在代理侧,最终用哪个账号以代理侧排序+可用性判断为准。
智能排序原理(代理侧)
优先级是 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:可能的原因:
- 所有账号同时触发限流(请求频率过高)
- 连续请求在“60s 窗口复用”下反复复用同一账号,更容易把单账号打到限流
- 配额保护误将可用账号排除
- 账号总数不足以支撑你的请求频率
解决:
- 增加更多账号
- 使用
PerformanceFirst模式 - 检查 Quota Protection 是否把你要用的模型加入了
protected_models(必要时调整监控模型与阈值) - 降低请求频率
Q2:429 错误会自动重试吗?
A:会在单次请求内自动重试。重试次数上限通常是 3 次,具体计算方式为 min(3, 账号池大小),且至少尝试 1 次。
重试次数示例:
- 账号池 1 个账号 → 尝试 1 次(不重试)
- 账号池 2 个账号 → 尝试 2 次(重试 1 次)
- 账号池 3 个或更多账号 → 尝试 3 次(重试 2 次)
大致流程:
- 记录限流/过载信息(进入
RateLimitTracker) - 如果能解析到等待时间(例如
RetryInfo.retryDelay/quotaResetDelay),会先等待一小段时间再继续 - 重试时强制轮换账号(
attempt > 0时force_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:可以从“让下一次请求更容易换号”的角度入手:
- 调度层面:切到
PerformanceFirst,跳过粘性会话与 60s 窗口复用 - 固定账号:如果启用了
Preferred Account,先清空它,否则会优先用固定账号(直到它限流/被保护) - 账号池:增加账号数量,单账号被限流时更容易找到替代账号
单次请求里,代理本身也会在重试时强制轮换(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.rs | 38-67 |
| Duration 解析工具 | src-tauri/src/proxy/upstream/retry.rs | 11-35 |
| 调度模式枚举(CacheFirst/Balance/PerformanceFirst) | src-tauri/src/proxy/sticky_config.rs | 3-12 |
| 限流原因解析与默认冷却策略 | src-tauri/src/proxy/rate_limit.rs | 5-258 |
| MAX_RETRY_ATTEMPTS 常量定义(OpenAI handler) | src-tauri/src/proxy/handlers/openai.rs | 14 |
| 重试次数计算(max_attempts = min(MAX_RETRY_ATTEMPTS, pool_size)) | src-tauri/src/proxy/handlers/openai.rs | 830 |
| OpenAI handler:429/5xx 时标记限流并重试/轮换 | src-tauri/src/proxy/handlers/openai.rs | 349-389 |
| 账号排序优先级(ULTRA > PRO > FREE + remaining_quota) | src-tauri/src/proxy/token_manager.rs | 504-538 |
| 60s 窗口复用 + 避开限流/配额保护 | src-tauri/src/proxy/token_manager.rs | 624-739 |
| 限流记录入口(mark_rate_limited) | src-tauri/src/proxy/token_manager.rs | 1089-1113 |
| 429 精确锁定/实时配额刷新/降级策略(mark_rate_limited_async) | src-tauri/src/proxy/token_manager.rs | 1258-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():标记账号为限流状态