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

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

EvoLink Team
EvoLink Team
Product Team
2026年3月25日
15 分钟阅读
如果你的 Agent 不断遇到 429 Too Many Requests 错误,问题通常不在于你的团队"使用 AI 的方式不对"。问题在于 Agent 流量具有突发性,而大多数提供商的限制仍然是针对共享速率限制桶来执行的。
截至 2026 年 3 月 25 日,OpenAI、Anthropic 和 Google 的官方文档都以不同方式表达了相同的核心观点:
  • 速率限制是真实存在的
  • 限制在单个请求级别之上生效
  • 限制与组织或项目范围绑定
  • 即使月度使用量看起来正常,短时突发仍可能触发失败

本指南重点介绍可从官方文档验证的内容,然后将其转化为实际能减少 429 错误的生产模式。

要点总结

  • Agent 系统比简单应用更快触发 429,因为它们产生的是突发流量,而非平滑流量。
  • 你需要预算管理 Token 和并发数,而不仅仅是请求计数。
  • 重试逻辑应遵循提供商行为:可用时使用 retry-after,不可用时添加带抖动的退避策略。
  • 队列、检查点和优雅降级与原始吞吐量同等重要。
  • 当你想减少对单一上游限制桶的依赖时,路由会有所帮助。

为什么 Agent 工作负载遇到 429 的方式不同

传统应用通常是这样的:

  • 一个用户请求
  • 一次 LLM 调用
  • 一个响应

Agent 系统的行为方式不同。它们通常会触发:

  • 长上下文推理步骤
  • 工具调用扇出
  • 多 Agent 并发
  • 保持连接打开的流式响应
  • 与前台工作同时进行的后台重试
这意味着速率限制表现为一个突发管理问题,而不仅仅是"每分钟请求过多"的问题。

提供商文档实际上说了什么

提供商官方限制维度范围运营要点
OpenAIRPM, TPM, RPD, TPD, IPM组织和项目级别,按模型区分,部分限制共享一个高负载工作流仍可消耗其他请求所依赖的资源池
AnthropicRPM, ITPM, OTPM组织级别,基于层级的限制短时突发可在完整一分钟流量到来之前触发 429
Gemini APIRPM, TPM, RPD按项目、按模型、基于层级同一项目中的多个 Agent 仍然争夺相同的项目限制

OpenAI:项目级控制并不消除突发风险

OpenAI 当前的速率限制指南指出,限制定义在组织级别和项目级别,而非用户级别。API 参考文档还提供了按模型的项目速率限制对象。

实际意义很直接:

  • 在一个项目内按功能拆分流量并不能消除突发
  • 某些模型系列可能共享限制池
  • 高吞吐量的 Agent 流量如果不在客户端进行限流,可能会饿死无关请求

Anthropic:输入和输出压力是分开的

Anthropic 的速率限制文档对 Agent 系统特别有用,因为它们明确区分了:

  • RPM
  • ITPM 用于输入 Token
  • OTPM 用于输出 Token
文档还指出,速率限制在组织级别执行,使用令牌桶算法,并且仍可能在更短的时间间隔内失败。Anthropic 在 429 响应中返回 retry-after 头,这正是你的重试层应该遵循的信号。

对于 Agent 系统,这很重要,因为大型提示、长输出和并行工具调用对预算的不同部分施加压力。

Gemini API:项目范围仍意味着共享压力

Google 的 Gemini API 文档指出,速率限制通过 RPMTPMRPD 衡量,并且按项目应用,而非按 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 提供面向混合工作负载的自建路由层
  • 你可以发送 evolink/auto 作为模型 ID
  • 实际使用的模型在响应中返回
  • 请求格式保持 OpenAI 兼容
  • 路由层本身收取额外的路由费用
并不意味着你应该承诺零 429 错误。这意味着路由可以将更多选择和备选逻辑从应用代码移到网关层。

以下是仓库文案支持的请求格式:

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 时应该记录什么?

记录预估 Token 数、并发任务数、队列深度、重试次数、请求大小以及任何提供商等待值,如 retry-after

当你想保持 OpenAI 兼容的请求格式,同时将模型选择和混合工作负载路由移出应用代码时,它就很有用。

路由器能保证我再也不会看到 429 吗?

不能。路由器可以提高弹性和灵活性,但不能消除对客户端限流、重试预算和队列控制的需求。

在扩展之前构建控制层

如果你的 Agent 系统已经表现出突发行为,修复 429 通常首先是一个基础设施问题,然后才是提示问题。

Explore EvoLink Smart Router

相关文章

来源

准备好把 AI 成本降低 89% 吗?

现在就开始使用 EvoLink,体验智能 API 路由的强大能力。