AI Agent 一跑就 429?真正耗尽的可能是并发连接,不是额度
同一个 API Key,普通聊天连续问几十次都没事,一换成 Codex、Claude Code 或多 Agent 工作流,就开始出现:
429 Too Many Requests
529 Overloaded
503 Service Unavailable
stream disconnected before completion
很多人的第一反应是“余额没了”或者“RPM 超了”,于是不断充值、换 Key、重启客户端。
但在长时间流式 Agent 场景中,真正被耗尽的可能不是每分钟请求数,而是并发连接槽位。
最近有 AI Gateway 开始为整个组织增加“并发中的请求数”限制:请求从发出开始占用槽位,直到完整响应结束或连接关闭才释放。长流式请求会一直占着位置,这正是传统 RPM 指标容易漏掉的部分。
这篇文章会说明:
- RPM、TPM 和并发请求到底有什么区别;
- 429、529、503 应该如何判断;
- 为什么多 Agent 比普通聊天更容易触发限流;
- 客户端怎样正确重试、限制并发和设计 Fallback。
说明:本文包含作者使用的 OpenAI 兼容 API 配置示例。统一 Base URL 可以减少客户端配置差异,但是否提供自动故障转移、并发扩容或模型路由,应以具体服务说明和实测结果为准。
[TOC]
一、先看结论:429 不一定代表余额不足
不同服务可能使用同一个 429 表达不同限制:
- RPM 超限:一分钟内请求次数过多;
- TPM 超限:一分钟内输入和输出 Token 过多;
- 并发超限:仍在运行的请求数量过多;
- 账号或项目额度限制;
- 月度预算或硬性消费上限;
- 上游账号池暂时没有可用通道。
因此,看到 429 后不能只看状态码,还要同时检查:
- 响应体中的
message、type和code; Retry-After响应头;- 限流相关响应头;
- 错误发生在请求开始、流式中途还是工具调用之后;
- 同一时间运行了多少 Agent 和子 Agent;
- 单个流式请求持续了多长时间。
529 则通常表示服务端或网关处于瞬时过载状态。它不是所有平台都会使用的通用状态码,但部分模型服务和 AI Gateway 会用它明确区分“你的账号触发限制”和“服务端当前太忙”。
二、RPM 看起来没超,为什么还是会被限流
假设一个系统允许每分钟 600 个请求。
如果每个请求 1 秒结束,平均并发量大约是:
10 requests/sec × 1 sec = 10 concurrent requests
但如果 Agent 的流式响应平均持续 120 秒:
10 requests/sec × 120 sec = 1200 concurrent requests
RPM 完全相同,并发连接数却相差 120 倍。
可以使用一个简化关系理解:
avg concurrency ≈ arrival rate (req/sec) × avg request duration
这就是长流式 Agent 的特殊之处:请求不是发出去就结束,而是会保持 SSE 或其他流式连接,等待模型持续输出、调用工具或完成长推理。
需要注意的是,一个 Agent 会话不一定始终占用同一个 HTTP 请求。标准工具调用流程通常是:
model request
-> returns tool call
-> client runs tool
-> next model request
每次模型请求都会单独占用槽位。真正迅速放大并发的,通常是多个会话、子 Agent 和并行任务同时运行。
三、多 Agent 为什么特别容易触发 429
假设你同时运行 4 个主 Agent,每个主 Agent 又创建 3 个子 Agent。
理论上的活跃执行单元可能达到:
4 main agents + 12 sub-agents = 16 active units
如果每个执行单元同时发起模型请求,就可能瞬间占用 16 个并发槽位。再叠加以下行为,并发量还会继续增加:
- 自动重试没有退避,失败后立刻再次请求;
- 工具调用结束后多个子 Agent 同时恢复;
- 长上下文让单次首 Token 等待时间变长;
- 上游模型变慢,旧请求迟迟不释放;
- 客户端断开了,但网关或上游没有及时取消;
- 多个开发者共用一个组织、项目或 API Key 池。
所以会出现一种看似矛盾的现象:
normal chat works
single agent works
many 429 when running agents in parallel
这通常应该优先检查并发,而不是继续增加重试次数。
四、429、529、503 应该怎么区分
| 状态码 | 常见含义 | 首要动作 |
|---|---|---|
429 | 账号、Key、项目的速率、Token、并发或预算限制 | 解析错误体,降低并发并遵守 Retry-After |
529 | 网关或模型服务瞬时过载 | 短暂退避后重试,必要时切换健康上游 |
503 | 服务暂不可用、没有健康实例或上游池耗尽 | 检查服务状态,退避并限制重试次数 |
状态码只能提供第一层判断,错误体更重要。
下面这种 429 明确指向并发:
{
"error": {
"message": "Too many concurrent requests. Retry shortly or reduce request concurrency.",
"type": "rate_limit_error",
"code": "rate_limit_exceeded"
}
}
而下面这种错误更像服务端过载:
{
"error": {
"message": "Gateway overloaded, please retry",
"type": "overloaded",
"code": "overloaded"
}
}
如果错误体写着 insufficient_quota、billing 或 spend limit,才应该重点检查余额和预算,而不是单纯调整并发。
五、先用最小请求检查接口和响应头
设置测试环境变量:
export API_BASE="https://genvis.xyz/v1"
export API_KEY="YOUR_API_KEY"
export MODEL="YOUR_MODEL_ID"
发送一个非流式最小请求:
curl -i --max-time 60 \
-X POST "$API_BASE/responses" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
--data "{\"model\":\"$MODEL\",\"input\":\"Reply with exactly OK\"}"
检查以下信息:
- HTTP 状态码;
Retry-After;- 是否有剩余额度或限流响应头;
Content-Type是否为 JSON;- 错误体中的
message和code; - 是否返回请求 ID,便于联系服务方排查。
再测试流式响应:
curl -N -i --max-time 120 \
-X POST "$API_BASE/responses" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
--data "{\"model\":\"$MODEL\",\"input\":\"Explain what an API gateway does in 200 words\",\"stream\":true}"
不要为了测试并发,直接在生产 Key 上一次启动几十或几百个请求。先用 1、2、4 的阶梯逐步增加,并观察响应时间、错误比例和连接释放情况。
六、正确重试:指数退避、抖动和 Retry-After
最危险的重试方式是:
request fails
-> retry immediately
-> fails again
-> all agents retry immediately at once
这会形成“重试风暴”,让已经过载的服务更难恢复。
下面是一个简化的 Python 示例:
import os
import random
import time
import requests
API_URL = "https://genvis.xyz/v1/responses"
API_KEY = os.environ["GENVIS_API_KEY"]
MODEL = os.environ.get("MODEL", "YOUR_MODEL_ID")
retryable_statuses = {429, 500, 502, 503, 504, 529}
for attempt in range(5):
response = requests.post(
API_URL,
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json={
"model": MODEL,
"input": "Reply with exactly OK",
},
timeout=60,
)
if response.status_code < 400:
print(response.json())
break
if response.status_code not in retryable_statuses:
raise RuntimeError(
f"Non-retryable error: {response.status_code} {response.text}"
)
retry_after = response.headers.get("Retry-After")
if retry_after and retry_after.isdigit():
delay = float(retry_after)
else:
delay = min(30, 2 ** attempt) + random.uniform(0, 1)
print(
f"Retryable error: {response.status_code}; "
f"retrying in {delay:.1f}s"
)
time.sleep(delay)
else:
raise RuntimeError("Request failed after 5 attempts")
这个示例做了三件事:
- 只重试明确的临时错误;
- 优先遵守服务端返回的
Retry-After; - 没有响应头时使用指数退避和随机抖动。
生产环境还要注意:如果流已经输出了一部分,盲目重新发送整个请求可能产生重复内容、重复工具调用或重复计费。涉及写数据库、发消息、下单等副作用时,必须配合幂等键或业务去重。
七、限制并发比增加重试更有效
Python 异步任务可以使用信号量限制同时运行的模型请求:
import asyncio
MAX_CONCURRENT_REQUESTS = 4
semaphore = asyncio.Semaphore(MAX_CONCURRENT_REQUESTS)
async def call_model(client, payload):
async with semaphore:
return await client.responses.create(**payload)
并发值不要直接照抄。合理值取决于:
- API 服务允许的组织级并发;
- 每个请求的平均持续时间;
- 是否启用流式响应;
- 主 Agent 和子 Agent 数量;
- 上游模型延迟;
- 业务可以接受的排队时间。
一个实用做法是从 2 或 4 开始,记录以下指标后再提高:
success rate
429/529 ratio
time to first token
total response time
in-flight requests
retry count
cost per task
如果并发从 4 提高到 8 后吞吐没有明显增加,429 和延迟却大幅上升,就说明系统已经接近有效容量上限。
八、什么时候应该切换模型或上游
Fallback 不应该是“任何错误都换模型”。
适合触发临时切换的情况包括:
- 多次收到 529 或 503;
- 429 明确表示当前上游并发已满;
- 服务状态异常且短时间无法恢复;
- 模型首 Token 延迟持续超过阈值;
- 当前模型不可用,但备用模型满足相同协议和工具能力。
下面这些错误通常不应该直接切换:
400请求结构错误;401Key 无效;403权限不足;- 模型不支持当前工具或输入模态;
- 业务参数本身不合法。
因为配置错误不会通过换上游自动消失,还可能把同一个错误扩散到更多通道。
设计 Fallback 时至少要核对:
API protocol matches
model ID correctly mapped
context window is enough
streaming and tool calls supported
structured output compatible
image/audio modalities match
billing and data policy allow switching
统一 Base URL 的价值,是把客户端改动控制在配置层,让模型接入、日志和鉴权更集中。但“一个入口”并不自动等于“任何错误都会智能切换”,具体路由规则仍然需要验证。
九、排查 Agent 429 的推荐顺序
遇到问题时,可以按下面的顺序检查:
read full error body and response headers
-> identify RPM, TPM, concurrency, or budget limit
-> count in-flight requests and sub-agents
-> drop concurrency to 1 to verify single request
-> raise concurrency step by step: 1, 2, 4
-> honor Retry-After and add exponential backoff
-> check whether stream connections close in time
-> only then consider switching model or upstream
如果单请求稳定、并行就失败,优先检查并发。
如果所有请求都立即 401 或 403,优先检查鉴权和权限。
如果请求运行固定时长后断开,优先检查网关总超时、SSE 空闲超时和反向代理配置。
如果只有特定模型失败,优先检查模型权限、能力和上游状态。
十、总结
Agent 时代的 API 限流,已经不能只看 RPM。
长时间流式响应、多个子 Agent、慢上游和同步重试,会共同推高“仍在运行的请求数”。即使一分钟请求总量没有变化,也可能耗尽并发槽位。
看到 429、529 或 503 时,正确处理方式是:
parse the error first
-> then reduce concurrency
-> honor Retry-After
-> use jittered exponential backoff
-> log in-flight requests and stream duration
-> only then do model or upstream Fallback
稳定的 Agent 调用链,靠的不是无限重试,而是可观测的限流、明确的并发边界和经过验证的降级路径。
参考资料
- LLM Gateway:Concurrent Request Limits and Overload Protection
- LLM Gateway:Rate Limits
- LLM Gateway:Request Timeouts
- agentgateway:Streaming
- Cloudflare:HTTP 429
- Cloudflare AI Gateway:Coding agents
更新记录
- 2026-08-25:根据近 72 小时 AI Gateway 并发限制与 529 过载保护动态整理;补充 Agent 流式请求、并发估算、重试、限流和 Fallback 示例。
更多推荐


所有评论(0)