
如何减少 Agent 工作负载中的 429 错误:路由、重试与故障转移模式

- 速率限制是真实存在的
- 限制在单个请求级别之上生效
- 限制与组织或项目范围绑定
- 即使月度使用量看起来正常,短时突发仍可能触发失败
本指南重点介绍可从官方文档验证的内容,然后将其转化为实际能减少 429 错误的生产模式。
要点总结
- Agent 系统比简单应用更快触发 429,因为它们产生的是突发流量,而非平滑流量。
- 你需要预算管理 Token 和并发数,而不仅仅是请求计数。
- 重试逻辑应遵循提供商行为:可用时使用
retry-after,不可用时添加带抖动的退避策略。 - 队列、检查点和优雅降级与原始吞吐量同等重要。
- 当你想减少对单一上游限制桶的依赖时,路由会有所帮助。
为什么 Agent 工作负载遇到 429 的方式不同
传统应用通常是这样的:
- 一个用户请求
- 一次 LLM 调用
- 一个响应
Agent 系统的行为方式不同。它们通常会触发:
- 长上下文推理步骤
- 工具调用扇出
- 多 Agent 并发
- 保持连接打开的流式响应
- 与前台工作同时进行的后台重试
提供商文档实际上说了什么
| 提供商 | 官方限制维度 | 范围 | 运营要点 |
|---|---|---|---|
| OpenAI | RPM, TPM, RPD, TPD, IPM | 组织和项目级别,按模型区分,部分限制共享 | 一个高负载工作流仍可消耗其他请求所依赖的资源池 |
| Anthropic | RPM, ITPM, OTPM | 组织级别,基于层级的限制 | 短时突发可在完整一分钟流量到来之前触发 429 |
| Gemini API | RPM, TPM, RPD | 按项目、按模型、基于层级 | 同一项目中的多个 Agent 仍然争夺相同的项目限制 |
OpenAI:项目级控制并不消除突发风险
实际意义很直接:
- 在一个项目内按功能拆分流量并不能消除突发
- 某些模型系列可能共享限制池
- 高吞吐量的 Agent 流量如果不在客户端进行限流,可能会饿死无关请求
Anthropic:输入和输出压力是分开的
Anthropic 的速率限制文档对 Agent 系统特别有用,因为它们明确区分了:
- RPM
- ITPM 用于输入 Token
- OTPM 用于输出 Token
retry-after 头,这正是你的重试层应该遵循的信号。对于 Agent 系统,这很重要,因为大型提示、长输出和并行工具调用对预算的不同部分施加压力。
Gemini API:项目范围仍意味着共享压力
这意味着:
- 同一项目下的多个 Agent 仍然共享限制
- 项目级别的层级升级有帮助,但不能解决应用内部的突发协调问题
- 你应该将生效限制视为基础设施约束,而非事后考虑
实际能减少 429 错误的模式
1. 预算管理 Token,而不仅仅是请求数
请求计数器对 Agent 系统来说过于粗糙。单个长上下文推理步骤消耗的实际预算可能超过许多小型请求。
使用 Token 感知预算:
import asyncio
import time
from collections import deque
class TokenBudget:
def __init__(self, tpm_limit: int):
self.tpm_limit = tpm_limit
self.window = deque()
async def reserve(self, estimated_tokens: int) -> None:
now = time.time()
while self.window and self.window[0][0] < now - 60:
self.window.popleft()
used = sum(tokens for _, tokens in self.window)
if used + estimated_tokens > self.tpm_limit and self.window:
wait_seconds = 60 - (now - self.window[0][0])
await asyncio.sleep(max(wait_seconds, 0))
self.window.append((time.time(), estimated_tokens))2. 在 Agent 循环周围限制并发
很多 429 风暴是自己造成的。工具调用、后台任务和重试都会相互叠加。
使用并发控制:
import asyncio
agent_slots = asyncio.Semaphore(5)
async def run_agent(task):
async with agent_slots:
return await execute_agent(task)这单独不会消除 429,但可以防止你的应用将一次峰值变成全面崩溃。
3. 让重试具有提供商感知能力
重试层不应该以相同方式处理每一个 429。
import asyncio
import random
async def retry_with_backoff(call, provider_name, attempts=5):
for attempt in range(attempts):
try:
return await call()
except Exception as exc:
retry_after = getattr(exc, "retry_after", None)
if retry_after is not None:
await asyncio.sleep(float(retry_after))
continue
# Jittered fallback when the provider does not give a wait value
delay = min(30, (2 ** attempt) + random.random())
await asyncio.sleep(delay)
raise RuntimeError(f"{provider_name} retry budget exhausted")生产指导:
- 当提供商返回
retry-after时遵循它 - 使用带抖动的指数退避作为备选策略,而不是唯一策略
- 不要无限重试
- 将重试量与主要流量分开跟踪
4. 分离前台和后台队列
当同一个资源池同时处理面向用户的 Agent 工作和后台分析任务时,低价值的积压任务可能会阻塞高价值流量。
至少使用两个队列:
- 一个前台队列用于面向用户的响应
- 一个后台队列用于批处理或追赶任务
这让你在提供商替你执行之前,有了一个可以丢弃或推迟低优先级流量的位置。
5. 为长时间运行的循环设置检查点
不要让一个 429 错误导致重新开始二十分钟的工作。
在每次昂贵调用之前设置检查点:
- 当前任务状态
- 已收集的工具结果
- 最后成功的推理步骤
- 重试计数和下次尝试时间戳
这将 429 从工作流失败转变为调度延迟。
6. 优雅降级而非硬性失败
你的 Agent 并不总是需要系统中最大的模型。
优雅降级可能意味着:
- 更小的上下文窗口
- 更少的并行工具
- 更便宜或更快的备选模型
- 将低优先级任务排队而非立即执行
正确的备选方案取决于工作流,但架构原则是相同的:部分答案通常优于崩溃的 Agent 会话。
路由在整体中的位置
正确理解路由的方式是:
- 限流控制你的应用发送什么
- 重试逻辑控制你的应用如何响应
- 路由控制当条件变化时你的应用可以将工作发送到哪里
简单的前后对比表
| 模式 | 高负载下会发生什么 | 主要弱点 |
|---|---|---|
| 单一提供商,无准入控制 | 请求堆积直到上游开始拒绝 | 429 风暴和级联重试 |
| 单一提供商,仅有重试 | 应用能抗住一些峰值 | 持续突发仍然阻塞同一个上游桶 |
| 单一提供商,带限流和队列 | 流量更平滑,故障更少混乱 | 你仍然依赖一个上游池 |
| 带限流和重试的路由网关 | 应用可以平滑突发并保持集成面稳定 | 需要评估更多基础设施选择 |
EvoLink Smart Router 的仓库文案支持的内容
EvoLink Smart Router 当前的仓库文案支持以下可发布声明:
- EvoLink 提供面向混合工作负载的自建路由层
- 你可以发送
evolink/auto作为模型 ID - 实际使用的模型在响应中返回
- 请求格式保持 OpenAI 兼容
- 路由层本身不收取额外的路由费用
以下是仓库文案支持的请求格式:
curl https://api.evolink.ai/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "evolink/auto",
"messages": [
{
"role": "user",
"content": "Summarize the latest deployment incident and suggest next steps."
}
]
}'实用上线检查清单
在责怪提供商之前,先验证以下内容:
| 检查项 | 重要原因 |
|---|---|
| 估算每个 Agent 步骤的 Token 量 | 很多 429 实际上是 TPM 或 ITPM 问题 |
| 限制并发 Agent 循环数 | 防止自我造成的突发放大 |
存在时遵循 retry-after | 减少无效的重试风暴 |
| 分离前台和后台队列 | 保护面向用户的延迟 |
| 为长时间运行的任务保存检查点 | 防止瞬时 429 后完全重启 |
| 决定何时路由或故障转移 | 让备选行为有意为之而非临时应对 |
常见问题
为什么 Agent 比普通聊天应用更快触发 429?
因为 Agent 产生突发流量:长提示、工具扇出、重试、后台任务和并发都会叠加在一起。
增加更多 API 密钥能解决问题吗?
通常仅靠这一点不行。OpenAI 记录了组织级和项目级限制,Anthropic 记录了组织级限制,Gemini 记录了项目级限制。同一范围内的额外密钥不会创建全新的容量池。
我应该对每个 429 都使用指数退避吗?
retry-after 时使用它。没有给出时再回退到带抖动的指数退避。我需要同时使用限流和路由吗?
是的,如果你在生产规模运营的话。限流在提供商拒绝之前平滑流量。路由帮助减少对单一上游路径的依赖。
调试 429 时应该记录什么?
retry-after。什么时候像 EvoLink 这样的网关有用?
当你想保持 OpenAI 兼容的请求格式,同时将模型选择和混合工作负载路由移出应用代码时,它就很有用。
路由器能保证我再也不会看到 429 吗?
不能。路由器可以提高弹性和灵活性,但不能消除对客户端限流、重试预算和队列控制的需求。
在扩展之前构建控制层
如果你的 Agent 系统已经表现出突发行为,修复 429 通常首先是一个基础设施问题,然后才是提示问题。
Explore EvoLink Smart Router

