
에이전트 워크로드에서 429 에러를 줄이는 방법: 라우팅, 재시도, 페일오버 패턴

- 제한은 실재한다
- 제한은 개별 요청 수준 위에서 적용된다
- 제한은 조직 또는 프로젝트 범위에 연결되어 있다
- 월간 사용량이 정상으로 보여도 짧은 버스트는 여전히 실패를 유발할 수 있다
이 가이드는 공식 문서에서 검증 가능한 내용에 초점을 맞추고, 이를 실제로 429를 줄이는 프로덕션 패턴으로 변환합니다.
요약
- 에이전트 시스템은 버스트를 생성하기 때문에 단순한 앱보다 더 빨리 429에 도달합니다. 평탄한 트래픽이 아닙니다.
- 요청 수뿐만 아니라 토큰과 동시성을 예산 관리해야 합니다.
- 재시도 로직은 프로바이더 동작을 따라야 합니다: 가능할 때
retry-after를 사용하고, 불가능할 때 지터가 추가된 백오프를 적용합니다. - 큐, 체크포인트, 그레이스풀 디그레이데이션은 원시 처리량만큼 중요합니다.
- 단일 업스트림 제한 버킷에 대한 의존도를 줄이고 싶을 때 라우팅이 도움됩니다.
에이전트 워크로드가 429를 다르게 만나는 이유
전통적인 애플리케이션은 보통 이렇게 동작합니다:
- 하나의 사용자 요청
- 하나의 LLM 호출
- 하나의 응답
에이전트 시스템은 그렇게 동작하지 않습니다. 다음을 자주 트리거합니다:
- 긴 컨텍스트 추론 단계
- 도구 호출 팬아웃
- 멀티 에이전트 동시 실행
- 연결을 유지하는 스트리밍 응답
- 포그라운드 작업과 동시에 진행되는 백그라운드 재시도
프로바이더 문서가 실제로 말하는 것
| 프로바이더 | 공식 제한 차원 | 범위 | 운영 핵심 사항 |
|---|---|---|---|
| OpenAI | RPM, TPM, RPD, TPD, IPM | 조직 및 프로젝트 수준, 모델별, 일부 공유 제한 | 하나의 과부하 워크플로우가 다른 요청이 의존하는 풀을 소비할 수 있음 |
| Anthropic | RPM, ITPM, OTPM | 조직 수준, 티어 기반 제한 | 짧은 버스트가 1분 전체 트래픽이 경과하기 전에 429를 트리거할 수 있음 |
| Gemini API | RPM, TPM, RPD | 프로젝트별, 모델별, 티어 기반 | 하나의 프로젝트 내 여러 에이전트가 여전히 동일한 프로젝트 제한을 공유 |
OpenAI: 프로젝트 수준 제어가 버스트 위험을 제거하지는 않는다
실질적인 의미는 명확합니다:
- 하나의 프로젝트 내에서 기능별로 트래픽을 분할해도 버스트는 사라지지 않는다
- 일부 모델 패밀리는 제한 풀을 공유할 수 있다
- 높은 처리량의 에이전트 트래픽이 클라이언트 측에서 스로틀링하지 않으면 무관한 요청을 고갈시킬 수 있다
Anthropic: 입력과 출력 압력은 분리되어 있다
Anthropic의 레이트 리밋 문서는 다음을 명시적으로 구분하기 때문에 에이전트 시스템에 특히 유용합니다:
- RPM
- ITPM (입력 토큰)
- OTPM (출력 토큰)
retry-after 헤더를 반환하는데, 이는 재시도 레이어가 준수해야 할 정확한 신호입니다.에이전트 시스템에서는 큰 프롬프트, 긴 출력, 병렬 도구 호출이 예산의 서로 다른 부분에 부하를 가하기 때문에 이것이 중요합니다.
Gemini API: 프로젝트 범위는 여전히 공유 압력을 의미한다
이는 다음을 의미합니다:
- 하나의 프로젝트 아래 여러 에이전트가 여전히 제한을 공유한다
- 프로젝트 수준 티어 업그레이드가 도움이 되지만, 앱 내부의 버스트 조정은 해결하지 못한다
- 활성 제한을 사후 고려가 아닌 인프라 제약으로 취급해야 한다
실제로 429 에러를 줄이는 패턴
1. 요청 수뿐만 아니라 토큰을 예산 관리하라
요청 카운터는 에이전트 시스템에는 너무 조잡합니다. 하나의 긴 컨텍스트 추론 단계가 많은 작은 요청보다 더 많은 실질적 예산을 소비할 수 있습니다.
토큰 인식 예산을 사용하세요:
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. 에이전트 루프 주위에 동시성을 제한하라
많은 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. 포그라운드와 백그라운드 큐를 분리하라
동일한 풀이 사용자 대면 에이전트 작업과 백그라운드 분석 작업을 처리하면, 낮은 가치의 밀린 작업이 높은 가치의 트래픽을 차단할 수 있습니다.
최소 두 개의 큐를 사용하세요:
- 사용자 대면 응답을 위한 포그라운드 큐
- 배치 또는 캐치업 작업을 위한 백그라운드 큐
이를 통해 프로바이더가 대신하기 전에 낮은 우선순위 트래픽을 제거하거나 연기할 수 있는 지점이 생깁니다.
5. 장시간 실행 루프에 체크포인트를 설정하라
429 하나로 20분의 작업을 다시 시작하게 만들지 마세요.
각 비용이 큰 호출 전에 체크포인트를 설정하세요:
- 현재 작업 상태
- 이미 수집된 도구 결과
- 마지막으로 성공한 추론 단계
- 재시도 횟수와 다음 시도 타임스탬프
이렇게 하면 429가 워크플로우 실패가 아닌 스케줄링 지연으로 바뀝니다.
6. 하드 실패 대신 그레이스풀하게 디그레이드하라
에이전트가 항상 시스템에서 가장 큰 모델을 필요로 하는 것은 아닙니다.
그레이스풀 디그레이데이션은 다음을 의미할 수 있습니다:
- 더 작은 컨텍스트 윈도우
- 더 적은 병렬 도구
- 더 저렴하거나 빠른 폴백 모델
- 즉시 실행 대신 낮은 우선순위 작업 큐잉
올바른 폴백은 워크플로우에 따라 다르지만, 아키텍처 원칙은 동일합니다: 부분적인 답변이 보통 크래시된 에이전트 세션보다 낫습니다.
라우팅이 전체 그림에서 차지하는 위치
라우팅을 올바르게 생각하는 방법:
- 스로틀링은 앱이 무엇을 보내는지 제어한다
- 재시도 로직은 앱이 어떻게 반응하는지 제어한다
- 라우팅은 조건이 변할 때 앱이 작업을 어디로 보낼 수 있는지 제어한다
간단한 전후 비교 표
| 패턴 | 고부하 시 발생하는 일 | 주요 약점 |
|---|---|---|
| 단일 프로바이더, 승인 제어 없음 | 업스트림이 거부를 시작할 때까지 요청이 쌓임 | 429 폭풍과 연쇄 재시도 |
| 단일 프로바이더, 재시도만 | 앱이 일부 스파이크에 견딤 | 지속적인 버스트는 여전히 동일한 업스트림 버킷을 차단 |
| 단일 프로바이더, 스로틀링과 큐 포함 | 트래픽이 더 평탄해지고 장애가 덜 혼란스러움 | 여전히 하나의 업스트림 풀에 의존 |
| 스로틀링과 재시도가 포함된 라우팅 게이트웨이 | 앱이 버스트를 평탄화하고 통합 표면을 안정적으로 유지 가능 | 평가해야 할 인프라 선택지가 더 많음 |
EvoLink Smart Router의 저장소 카피가 지원하는 내용
EvoLink Smart Router의 현재 저장소 카피는 다음과 같은 공개 가능한 주장을 지원합니다:
- EvoLink는 혼합 워크로드를 위한 자체 구축 라우팅 레이어를 제공한다
- 모델 ID로 **
evolink/auto**를 보낼 수 있다 - 실제 사용된 모델은 응답에서 반환된다
- 요청 형식은 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."
}
]
}'실용적인 롤아웃 체크리스트
프로바이더를 탓하기 전에 먼저 다음을 확인하세요:
| 확인 항목 | 중요한 이유 |
|---|---|
| 에이전트 단계별 토큰 볼륨 추정 | 많은 429는 실제로 TPM 또는 ITPM 문제 |
| 동시 에이전트 루프 수 제한 | 자초한 버스트 증폭 방지 |
retry-after가 있을 때 준수 | 불필요한 재시도 폭풍 감소 |
| 포그라운드와 백그라운드 큐 분리 | 사용자 대면 지연 시간 보호 |
| 장시간 실행 작업에 체크포인트 저장 | 일시적 429 후 완전 재시작 방지 |
| 라우팅 또는 페일오버 시점 결정 | 폴백 동작을 임시방편이 아닌 의도적으로 유지 |
FAQ
에이전트가 일반 챗 앱보다 왜 더 빨리 429에 도달하나요?
에이전트가 버스트 트래픽을 생성하기 때문입니다: 긴 프롬프트, 도구 팬아웃, 재시도, 백그라운드 작업, 동시성이 모두 겹칩니다.
API 키를 더 추가하면 문제가 해결되나요?
보통 그것만으로는 해결되지 않습니다. OpenAI는 조직 수준과 프로젝트 수준 제한을, Anthropic은 조직 수준 제한을, Gemini는 프로젝트 수준 제한을 문서화하고 있습니다. 동일한 범위 내의 추가 키는 완전히 새로운 용량 풀을 생성하지 않습니다.
모든 429에 대해 지수 백오프를 사용해야 하나요?
retry-after를 제공하면 그것을 사용하세요. 제공하지 않을 때 지터가 추가된 지수 백오프로 폴백하세요.스로틀링과 라우팅 둘 다 필요한가요?
프로덕션 규모로 운영하고 있다면 그렇습니다. 스로틀링은 프로바이더가 거부하기 전에 트래픽을 평탄화합니다. 라우팅은 하나의 업스트림 경로에 대한 의존도를 줄이는 데 도움이 됩니다.
429 디버깅 시 무엇을 로깅해야 하나요?
retry-after 같은 프로바이더 대기 값을 로깅하세요.EvoLink 같은 게이트웨이는 언제 유용한가요?
OpenAI 호환 요청 형식을 유지하면서 모델 선택과 혼합 워크로드 라우팅을 앱 코드 밖으로 옮기고 싶을 때 유용합니다.
라우터가 429를 다시는 보지 않을 것이라고 보장할 수 있나요?
아니요. 라우터는 회복력과 유연성을 향상시킬 수 있지만, 클라이언트 측 스로틀링, 재시도 예산, 큐 제어의 필요성을 없애지는 않습니다.
스케일하기 전에 제어 레이어를 구축하라
에이전트 시스템이 이미 버스트 동작을 보이고 있다면, 429 수정은 보통 프롬프트 문제이기 전에 인프라 문제입니다.
Explore EvoLink Smart Router

