LLM API Rate Limit 13곳 비교, 429를 재시도하지 않는 SDK 2개
목차
조사한 13개 LLM API(벤더 10곳과 Bedrock, Vertex AI, Azure OpenAI) 중 모든 응답에서 남은 한도를 알려 주는 곳은 4곳이다. Mistral은 남은 횟수 하나만 보내고, 나머지 8곳은 요청이 실패하기 전까지 아무 정보도 주지 않는다. “429”는 서로 다른 네 가지 상황을 뜻한다. 재시도해야 하는 throttle, 요청 증가 속도를 낮춰야 하는 acceleration limit, 재시도해도 소용없는 quota 또는 spend cap, 그리고 벤더에 따라 429, 503, 529로 보고되는 overload다. 벤더보다 client 동작이 더 큰 영향을 미치기도 한다. OpenAI, Anthropic, Groq SDK는 429를 두 번 재시도하지만 Retry-After가 60초 또는 120초를 넘으면 포기한다. 반면 Google GenAI와 Mistral SDK는 기본적으로 재시도하지 않는다. 이 글은 각 벤더의 limit 차원, 산정되는 token, header, 429 의미, 공식 SDK의 실제 동작을 source code로 확인해 정리한 자료다.
TL;DR
- LLM API는 분당 request 수와 token 수를 제한한다. Anthropic은 input과 output을 나눠 제한하고, DeepSeek은 concurrency만 제한한다.
- OpenAI, Azure, Bedrock은
max_tokens를 먼저 차감한다. Anthropic은 cache read를 제외하고, xAI는 reasoning token도 산정한다. Bedrock에서 Claude 5 output token 1개는 quota token 10개를 소모한다. - OpenAI, Anthropic, Groq, Azure는 모든 200 응답에 남은 한도와 reset header를 반환한다. 8개 API는 관련 header를 문서화하지 않았다.
- google-genai와 Mistral SDK는 기본적으로 429를 재시도하지 않는다. OpenAI, Anthropic, Groq는 두 번 재시도하며 Retry-After 상한은 60초 또는 120초다.
RPM, TPM과 다른 limit는 무엇을 뜻하나?
모두 일정 window 안에서 보낼 수 있는 양의 상한이다. 어떤 항목을 제한할지는 provider마다 다르다.
| 그룹 | 용어 | 의미와 적용 provider |
|---|---|---|
| Request meter | RPM, RPD, RPS, concurrency | 분당 또는 일일 request 수다. request 크기와 관계없이 호출당 1건으로 센다. RPS는 보통 RPM을 60으로 나눈 값이며 burst 방지용으로 적용된다(xAI, Alibaba, Mistral, Azure). Concurrency는 window별 호출 수 대신 처리 중인 request 수를 센다. DeepSeek은 concurrency만 제한한다 |
| Token meter | TPM, TPD, ITPM, OTPM, burndown rate | 분당 또는 일일 token 수다. 일부 provider는 input(ITPM)과 output(OTPM)을 나눠 제한한다. Burndown rate는 output token에 배수를 적용한 뒤 quota에서 차감한다(Bedrock). 어떤 token을 산정하는지는 provider마다 다르며 다음 절에서 다룬다 |
| 다른 단위의 meter | IPM, audio seconds, OCR pages | Image model의 분당 image 수(OpenAI, Gemini), 시간당 또는 일일 audio 초 수(Groq, Mistral), document OCR의 분당 page 수(Mistral) |
| Window 적용 방식 | Token bucket, acceleration limit | Token bucket은 분 단위로 초기화되지 않고 계속 채워진다. 따라서 분당 총량 이내여도 burst가 발생하면 bucket이 바닥날 수 있다(Anthropic, Alibaba와 Azure도 같은 효과를 설명한다). Acceleration limit는 사용량이 증가하는 속도를 별도로 검사한다. 한도 이내여도 갑자기 사용량을 늘리면 걸릴 수 있다(Anthropic, OpenAI의 slow_down) |
| Limit 수치를 정하는 기준 | Tier, spend cap 또는 quota, provisioned capacity | Tier는 위 meter의 수치를 결정하는 구간이다. Credit 충전액이 아니라 유료 사용량이나 사용 이력에 따라 올라간다. Spend cap이나 daily quota는 비용 또는 사용량의 상한이지 rate limit가 아니므로 1분을 기다려도 해결되지 않는다. Provisioned capacity는 단위당 시간제로 과금되는 예약 throughput이다(Bedrock과 Vertex AI Provisioned Throughput, Azure PTU). 여기서 429는 quota 소진이 아니라 예약 용량이 가득 찼다는 뜻이다 |
페이지에 표시된 수치는 window 전체의 허용량이 아니라 상한이다. Anthropic은 60 RPM이 “초당 request 1건으로 적용될 수 있다”고 설명한다. Azure도 “분당 총량이 한도 이내여도 1초 또는 10초 window 안의 burst가 429를 유발할 수 있다”고 명시한다.
LLM API는 무엇을 기준으로 rate limit를 적용하나?
대부분 분당 request 수와 token 수를 제한한다. 세 클라우드는 각 벤더의 규칙을 그대로 중계하지 않는다. 아래 정의는 2026-09-03과 2026-09-04 기준으로 각 provider가 연결된 페이지에 직접 명시한 내용이다.
| Provider | 제한 차원 | Limit 증가 방식 | 출처 |
|---|---|---|---|
| OpenAI | RPM, RPD, TPM, TPD, IPM, 분당 audio 시간. Batch API queue는 대기 중인 input token 기준 | 누적 결제액에 따라 Tier 1-5 | rate limit |
| Anthropic | Model class별 RPM, ITPM, OTPM. Token bucket과 acceleration limit | 사용 이력에 따라 Start, Build, Scale tier | rate limit |
| Google Gemini | RPM, TPM(input), RPD. Image model의 IPM | Free 이후 10분당 지출 한도가 있는 Tier 1-3 | rate limit |
| xAI | Model별 RPS(RPM / 60)와 TPM | Tier 0-4 및 Enterprise | rate limit |
| Alibaba Model Studio | Model별 RPM과 TPM. Burst 방지용 RPS = RPM / 60, TPS = TPM / 60 | Model별 적용. 일부 model은 batch 제외 | rate limit |
| DeepSeek | Concurrency만 제한: V4 Pro는 500 connection, V4 Flash는 2,500 connection | Model별 고정 | rate limit |
| Mistral | Model과 workspace별 RPS, 분당 token, 월간 token | 누적 청구액에 따라 Tier 1-4. “Credit을 추가해도 rate limit는 올라가지 않는다” | 사용량과 limit, 도움말 센터 |
| MiniMax | Model별 RPM과 TPM. MiniMax M3는 200 RPM, 10M TPM | 영업팀 문의 | rate limit |
| Moonshot Kimi | Concurrency, RPM, TPM, TPD. Tier 0은 concurrency 1, 3 RPM이고 Tier 5는 100, 300 | 누적 충전액 $1-$3,000에 따른 6개 tier | limit |
| Groq | RPM, RPD, TPM, TPD, ITPM, OTPM, 시간당 및 일일 audio 초 수 | Model별 적용 | rate limit |
| Amazon Bedrock | Region과 model별 RPM, TPM, TPD. TPD 기본값은 TPM x 1,440 | Service Quotas에서 요청해 상향. 신규 account는 낮은 값으로 시작 | quota |
| Google Vertex AI | Pay-as-you-go에는 project별 수치가 없다. “조직의 과거 지출액에 따라 Usage Tier와 baseline throughput(TPM)이 정해지는” shared pool이며 best-effort bursting을 제공한다 | 지출액에 따른 usage tier. Provisioned Throughput은 “shared PayGo pool과 격리된 용량을 제공한다” | Google Cloud 블로그 |
| Azure OpenAI | Deployment별로 TPM을 할당하고 RPM은 TPM에서 계산한다. 이전 model은 1,000 TPM당 6 RPM, 현재 model은 1,000 TPM당 1 RPM이다. PTU deployment는 utilization으로 제한 | Quota Tier 0-6, 자동 상향 | quota와 limit, quota 관리 |
이 중 두 항목은 분 단위 window가 아니다. DeepSeek은 열린 connection 수를 제한한다. 부하가 높으면 request를 거부하는 대신 빈 줄(stream에서는 : keep-alive comment)을 보내며 최대 10분 동안 connection을 유지한다. Vertex AI pay-as-you-go에는 확인할 quota 수치가 없다. 429는 해당 시점에 shared pool 용량이 부족했다는 뜻이다.
어떤 token이 limit에 산정되나?
과금되는 token과 rate limit에 산정되는 token은 같지 않다. 이 차이 때문에 실제 처리량이 페이지에 표시된 수치보다 훨씬 작아지거나 몇 배로 커질 수 있다.
| Provider | Token limit에 산정되는 항목 | 결과 |
|---|---|---|
| OpenAI | Request 도착 시 max_tokens와 prompt 기반 예상치 중 큰 값을 차감한다. “max_tokens를 너무 높게 설정하면 실제 response가 훨씬 짧아도 사용량이 과대 산정될 수 있다”(Cookbook) | 답변이 50 token이어도 max_tokens가 4,000이면 TPM 4,000을 소모한다 |
| Azure OpenAI | ”prompt text와 개수, max_tokens parameter 설정, best_of parameter 설정”을 바탕으로 추정하며 일부는 문자 수에 따라 계산한다. PTU deployment에서는 “cached token에 100% 할인이 적용된다”(quota 가이드) | “예상보다 먼저 rate limit에 걸릴 수 있다.” max_tokens를 설정하지 않으면 Azure가 값을 추정한다 |
| Amazon Bedrock | 시작 시 “전체 input token + max_tokens”를 차감하고 종료 시 InputTokenCount + CacheWriteInputTokens + (OutputTokenCount x burndown rate)로 보정한다. Cache read는 제외한다. Burndown은 Claude 4.7 이하에서 5x, Sonnet 5, Opus 5, Fable 5.1, GPT-5.6 model에서 10x, Claude 4.8에서 15x다(token 산정) | 문서의 예에서 5x model에 input 1,000 token과 output 100 token을 사용하면 quota token 1,500개를 소모하고 1,100개가 과금된다 |
| Anthropic | ITPM은 input_tokens와 cache_creation_input_tokens를 산정한다. cache_read_input_tokens는 “ITPM에 산정되지 않는다.” OTPM은 실제 output만 산정하며 “max_tokens는 OTPM에 영향을 주지 않는다”(문서) | 문서의 예에서 cache hit rate가 80%라면 2M ITPM으로 분당 input token 10M개를 처리할 수 있다 |
| xAI | ”Request가 소비한 모든 token이 TPM limit에 산정된다. Prompt token(text, image, audio), completion token, reasoning model의 reasoning token, cached prompt token” | 사용자에게 보이지 않는 reasoning token도 TPM을 소모한다. Caching으로 throughput이 늘어나지 않는다 |
| Google Gemini | Input token | Output 길이는 limit를 줄이지 않는다 |
| Alibaba, Mistral, MiniMax | Input과 output | |
| Kimi, Groq, DeepSeek, Vertex AI | 명시되지 않음 | Groq는 ITPM과 OTPM을 별도로 측정한다. DeepSeek에는 token limit가 없다. Vertex AI는 usage tier의 baseline만 공개한다 |
같은 request도 limit 기준으로는 800-6,000 token까지 크기가 달라진다. 여러 vendor에 workload를 분산하는 router라면 vendor별 meter가 필요하다.
각 provider는 어떤 header를 반환하나?
모든 응답에 limit 상태를 넣는 API는 4개다. Mistral은 한 개 field만 보내고, 나머지 8개는 client가 직접 사용량을 세야 한다.
| Provider | 정상 response의 header | 형식 |
|---|---|---|
| OpenAI | x-ratelimit-limit-requests, x-ratelimit-limit-tokens, x-ratelimit-remaining-requests, x-ratelimit-remaining-tokens, x-ratelimit-reset-requests, x-ratelimit-reset-tokens, 그리고 -project-tokens header 3개 | Reset은 “rate limit가 초기화될 때까지 남은 시간”. 429에는 Retry-After |
| Azure OpenAI | 모든 호출에 동일한 6개 x-ratelimit-* header. 429에는 retry-after-ms와 retry-after | x-ratelimit-limit-tokens가 설정한 TPM보다 낮으면 “temporary rate limit adjustment”가 적용 중이다 |
| Anthropic | anthropic-ratelimit-requests-{limit,remaining,reset}, tokens, input-tokens, output-tokens에도 같은 3개 header. 해당 tier에는 anthropic-priority-*와 anthropic-fast-*도 추가 | Reset은 RFC 3339 형식. Remaining은 가장 가까운 1,000 단위로 반올림한다. tokens-* 3개는 “현재 적용 중인 가장 엄격한 limit”를 표시한다 |
| Groq | x-ratelimit-limit-requests(일일), x-ratelimit-limit-tokens(분당), x-ratelimit-remaining-*, x-ratelimit-reset-*. “항상 포함된다” | Reset은 "2m59.56s", "7.66s" 같은 duration 형식. retry-after는 초 단위이며 429에만 포함 |
| Mistral | X-RateLimit-Remaining | |
| Gemini, xAI, Alibaba, DeepSeek, MiniMax, Kimi, Bedrock, Vertex AI | 문서화된 header 없음 | Gemini, Alibaba, Bedrock은 error body에 원인을 넣는다. Kimi는 overload 시 Retry-After를 명시한다. AWS SDK는 service가 제공하는 경우 millisecond 단위의 x-amz-retry-after를 읽는다 |
실무에서는 하나의 field에 형식이 세 가지라는 점이 문제다. OpenAI의 duration, Anthropic의 timestamp, Groq의 2m59.56s를 각각 parsing해야 한다. SDK가 retry-after만 읽는 이유 중 하나다. 2026-09-03에 두 intermediary를 각각 한 번 요청해 측정했다. 대형 multi-provider aggregator는 200 응답에서 rate-limit header를 전혀 반환하지 않고 429 응답에만 넣었다. Synthorai gateway는 request 비용과 함께 x-ratelimit-remaining-requests와 x-ratelimit-reset-requests를 반환했다.
429는 무엇을 뜻하며 재시도해야 하나?
429에는 네 가지 의미가 있다. 이 중 재시도할 가치가 있는 것은 두 가지뿐이다.
| 의미 | 재시도 여부 | Provider별 표현 |
|---|---|---|
| Throttle: limit 초과 | Retry-After 또는 backoff 이후 재시도 | OpenAI와 Anthropic의 429 rate_limit_error, Anthropic은 retry-after 포함. Gemini와 Vertex AI는 429 RESOURCE_EXHAUSTED, Vertex AI에서는 shared pool 부족을 의미. Kimi rate_limit_reached_error. Bedrock ThrottlingException, 그리고 SDK가 최대 5번 재시도하는 ModelNotReadyException. Azure “Rate limit is exceeded”. xAI RateLimitError. Alibaba “Requests rate limit exceeded”. DeepSeek과 Mistral의 429 |
| Acceleration: 사용량을 너무 빨리 늘림 | 증가 속도를 낮춘 뒤 재시도 | OpenAI slow_down. Anthropic “acceleration limits”. Alibaba “Request rate increased too quickly”. Azure는 1초 또는 10초 window 안의 burst |
| Quota 또는 spend cap: 기다려도 용량이 생기지 않음 | 재시도하지 말고 billing을 수정하거나 reset 날짜까지 대기 | OpenAI insufficient_quota, credit_balance_exhausted, organization_spend_limit_exceeded. Anthropic은 retry-after가 없는 enforced_spend_limit_reached, 단 사용자가 설정한 spend limit는 400. Gemini quota_exceeded(일일). Kimi exceeded_current_quota_error. Bedrock 400 ServiceQuotaExceededException. Aggregator와 DeepSeek은 402. Azure는 deployment 시 quota를 할당하므로 quota 소진이 429가 아니다 |
| Overload: 사용자의 limit가 아니라 provider의 capacity 부족 | Backoff 후 재시도 | OpenAI 503 server_is_overloaded. Anthropic 529 overloaded_error. Gemini 503 UNAVAILABLE. Kimi는 Retry-After가 있는 429 engine_overloaded_error. Bedrock 503 ServiceUnavailableException과 529 overloaded_error. Azure “System is experiencing high demand”, shared pool의 “temporary rate limit adjustment”, 또는 retry-after-ms를 포함한 PTU utilization 100%. DeepSeek 503 |
문제는 세 번째 행이다. Anthropic의 spend-cap 429는 throttle과 동일한 rate_limit_error type을 사용한다. 문서에는 “SDK의 자동 재시도를 포함해 재시도해도 access가 복구될 때까지 실패한다”고 적혀 있다. OpenAI의 insufficient_quota도 429다. Status code만 보고 분기하는 client는 둘 다 재시도하며, 다음 절에서 보듯 모든 공식 SDK가 그렇게 동작한다. Error code로 분기하고, Retry-After가 없는 429는 기다려도 해결되지 않을 가능성이 있다는 신호로 처리해야 한다.
네 번째 행에서 cloud별 차이가 드러난다. Azure troubleshooting guide는 “많은 고객이 capacity 관련 429를 quota 문제로 잘못 해석해 잘못된 조치를 취한다”고 명시한다. Azure에서 x-ratelimit-limit-tokens가 설정한 limit보다 낮은 429는 shared pool의 보호 동작이다. Vertex AI의 pay-as-you-go에서 발생하는 모든 429도 같은 의미다. Bedrock에서는 동일한 상황이 ThrottlingException이 아니라 503 또는 529로 나타난다. Aggregator를 통하면 body에서 확인할 수 있다. Header 측정 중 발생한 한 429는 provider_error_code: insufficient_quota, limit_source: upstream_provider_shared_pool로 wrapping되어 있었다. Status는 throttle을 가리켰지만 body는 다른 사용자의 quota 문제임을 나타냈다.
SDK는 429를 어떻게 처리하나?
SDK마다 다르며, 널리 쓰이는 SDK 중 두 개는 아무 동작도 하지 않는다. 문서가 아니라 2026-09-04 기준 각 공식 client의 source code를 확인한 결과다.
| SDK | 기본 재시도 | 재시도하는 status | Backoff | Retry-After 처리 |
|---|---|---|---|---|
| openai-python(Azure OpenAI 포함) | 2회 | 408, 409, 429, 5xx 또는 x-should-retry가 지정한 status | min(0.5 × 2^n, 8)초와 jitter | retry-after-ms를 먼저 읽은 뒤 retry-after를 초 또는 날짜로 해석한다. 120초를 넘으면 아예 재시도하지 않는다 |
| anthropic-sdk-python, groq-python | 2회 | 동일 | 동일 | Parsing 방식은 동일하다. 60초를 넘으면 header를 무시하고 backoff 공식을 적용한다 |
| openai-node, anthropic-sdk-typescript | 2회 | 동일 | 동일 | 동일하다. 60초를 넘으면 기본 backoff를 적용한다 |
| google-genai(Python, Gemini API와 Vertex AI) | 0회. retry_options의 기본값은 None이고 1회 시도로 처리된다 | 활성화 시 408, 429, 500, 502, 503, 504 | 활성화 시 5회 시도. 1초에서 시작해 60초까지 두 배로 늘리며 jitter 적용 | Retry-After를 읽지 않는다 |
| mistralai(Python) | 0회. retry_config는 기본적으로 설정되지 않음 | 설정 시 429, 500, 502, 503, 504 | 설정 시 500 ms × 1.5^n, 최대 60초, 전체 1시간 | 초 또는 날짜 형식의 모든 Retry-After를 따른다 |
| boto3(Bedrock) | Legacy mode는 최초 시도를 포함해 5회. Standard mode는 3회 | ThrottlingException 및 유사 error, 429, 5xx | Standard mode는 base factor 2, 상한 20초. 2026 동작은 AWS_NEW_RETRIES_2026=true로 활성화하며 full jitter, throttle용 1,000 ms base, retry token bucket을 사용한다 | Retry-After를 사용하지 않는다. 2026 동작은 millisecond 단위의 x-amz-retry-after를 읽고 backoff + 5초 이내로 제한한다 |
| xai-sdk(Python, gRPC) | UNAVAILABLE에만 5회 시도 | gRPC의 429인 RESOURCE_EXHAUSTED는 재시도하지 않음 | 0.1초에서 시작해 1초까지 두 배로 증가 | 해당 없음 |
| dashscope(Alibaba) | HTTP status는 재시도하지 않는다. Pooled connection이 byte를 하나도 받기 전에 끊어지면 한 번 다시 전송 | |||
| DeepSeek, Kimi, MiniMax | First-party chat SDK가 없다. DeepSeek 문서는 base URL을 바꿔 “OpenAI/Anthropic SDK를 사용”하라고 안내한다 |
여기서 세 가지 결론이 나온다. 첫째, Gemini, Vertex AI, Mistral의 429는 retry option을 넘기지 않으면 첫 발생부터 사용자 code로 전달된다. Google-genai source comment의 client가 “4번 재시도한다”는 설명은 활성화된 설정에 대한 것이며 기본 동작이 아니다. 둘째, Retry-After 상한은 vendor가 실제로 요구하는 긴 대기 시간과 맞지 않는다. Anthropic SDK에 90초 대기를 요청하면 header를 무시하고 8초 이내에 다시 요청한다. OpenAI SDK에 150초 대기를 요청하면 재시도를 중단한다. 셋째, Stainless가 생성한 SDK(OpenAI, Anthropic, Groq client의 code generator)는 status code보다 문서화되지 않은 x-should-retry header를 먼저 확인하고, retry-after보다 retry-after-ms를 먼저 읽는다. 따라서 vendor나 gateway는 status code를 바꾸지 않고도 재시도 동작을 제어할 수 있다.
어떤 SDK도 spend-cap 429와 throttle을 구분하지 않는다. insufficient_quota 응답을 두 번 재시도하면 각 request가 몇 초만 낭비하지만, fleet 전체가 대규모로 같은 동작을 하면 스스로 burst를 만든다.
Gateway는 무엇을 바꾸나?
Gateway에서는 이 모든 처리를 한 번만 구현할 수 있다. Upstream에서는 vendor별 header를 읽어 세 가지 reset 형식과 네 가지 429 의미를 gateway가 처리한다. 각 client가 따로 구현할 필요가 없다. Downstream에는 통일된 header set과 error 형식을 제공한다. 앞에서 측정한 Synthorai header가 이 방식이다. 하지만 gateway도 vendor의 산정 방식을 바꾸지는 못한다. OpenAI 뒤에서는 client의 max_tokens가 여전히 TPM에서 먼저 차감되고, Bedrock 뒤에서는 Claude output token 하나가 여전히 10개를 소모한다. 또한 여러 client를 하나의 vendor key로 묶는 gateway는 개별 client보다 vendor의 acceleration limit에 더 빨리 도달한다. 이 경우 하나의 shared counter가 아니라 key별 bucket을 사용해야 한다.
FAQ
max_tokens는 rate limit에 산정되나?
OpenAI, Azure OpenAI, Bedrock에서는 산정된다. Request가 도착하면 max_tokens를 차감하므로 답변이 짧아도 값을 크게 잡으면 TPM을 낭비한다. Bedrock은 response가 끝나면 차감량을 보정한다. Anthropic에서는 산정되지 않는다. OTPM은 실제 생성된 token만 세며 max_tokens는 “영향을 주지 않는다.”
Cached token은 rate limit에 산정되나?
Anthropic, Bedrock, Azure PTU deployment에서는 cache read를 제외한다. xAI에서는 전부 산정한다. OpenAI와 Gemini는 명시하지 않았다.
429에는 항상 Retry-After가 포함되나?
아니다. OpenAI, Azure(retry-after-ms), Groq는 throttle에 포함한다. Anthropic은 throttle에는 포함하지만 spend cap에는 포함하지 않는다. Kimi와 Bedrock은 overload에만 포함한다. Gemini, Vertex AI, xAI, Alibaba, DeepSeek, MiniMax는 관련 header를 문서화하지 않았다. 이 provider에는 client 자체 backoff가 필요하다.
SDK가 429를 재시도하지 않은 이유는 무엇인가?
Google GenAI 또는 Mistral Python SDK라면 기본적으로 재시도가 꺼져 있다. retry_options 또는 RetryConfig를 전달해야 한다. OpenAI Python SDK에서 server가 120초를 넘는 대기를 요청했다면 SDK가 의도적으로 재시도하지 않는다. 429가 quota 또는 spend cap이라면 재시도하지 않는 것이 맞다.
관련 글: 과금 단위 실전 가이드, 긴 컨텍스트 가격 tier, token 사용량 구조, gateway cache 점검.