Rate limits
Rate limits
Rate limits는 API가 특정 시간 안에 사용자·클라이언트가 서비스를 접근할 수 있는 횟수에 두는 제한이에요.
출처: 문서
본문
왜 rate limit이 있나요
Rate limit은 API의 일반적인 관행이고, 여러 이유로 적용돼요.
- API 남용·오용으로부터 보호해요. 예를 들어 악의적인 행위자가 서비스를 과부하시키거나 중단시키려고 요청을 쏟아낼 수 있어요. rate limit을 설정하면 OpenAI가 이런 활동을 막을 수 있어요.
- 모두가 API에 공평하게 접근할 수 있게 해요. 한 사람이나 조직이 과도한 요청을 보내면 다른 전원을 위해 API가 느려질 수 있어요. 단일 사용자의 요청 수를 제한하면 최대한 많은 사람이 지연 없이 API를 쓸 수 있어요.
- OpenAI가 인프라에 가해지는 전체 부하를 관리할 수 있게 해요. API 요청이 급증하면 서버에 부담이 가고 성능 문제가 생길 수 있어요. rate limit으로 모든 사용자에게 매끄럽고 일관된 경험을 유지할 수 있어요.
OpenAI의 rate limit 시스템이 어떻게 동작하는지 문서 전체를 읽어보면 좋아요. 일반적인 문제를 다루는 코드 예시와 가능한 해결책, 그리고 아래 usage tiers 섹션에서 rate limit이 어떻게 자동으로 올라가는지도 설명해요.
어떻게 동작하나요
Rate limit은 RPM(requests per minute), RPD(requests per day), TPM(tokens per minute), TPD(tokens per day), IPM(images per minute), 일부 스트리밍 오디오 모델의 분당 오디오 시간 같은 지표를 사용해요. 무엇이 먼저 일어나느냐에 따라 어느 옵션에서든 rate limit에 걸릴 수 있어요. 예를 들어 100 토큰만 담은 요청 20개를 ChatCompletions 엔드포인트로 보냈다면, 20개 요청 안에 150k 토큰을 보내지 않았더라도(RPM이 20이라면) 한도에 도달하게 돼요.
Batch API 큐 한도는 주어진 모델에 큐에 넣은 총 입력 토큰 수를 기준으로 계산돼요. 보류 중인 batch 작업의 토큰은 큐 한도에 집계되고, 작업이 완료되면 그 모델의 한도에서 빠져요.
주의할 다른 사항:
- Rate limit은 조직 수준과 프로젝트 수준에서 정의되고, 사용자 수준이 아니에요.
- Rate limit은 사용하는 모델에 따라 달라져요.
- GPT-5.5 같은 긴 컨텍스트 모델은 긴 컨텍스트 요청에 별도의 rate limit이 있어요. 개발자 콘솔에서 볼 수 있어요.
- OpenAI는 각 조직에 승인된 월 사용량 한도를 설정해요. 이것은 조직·프로젝트에 설정할 수 있는 지출 한도(spend limits)와는 별개예요.
- 일부 모델 계열은 rate limit을 공유해요. 조직 한도 페이지에서 "shared limit" 아래 나열된 모델들은 그 사이에 rate limit을 공유해요. 예를 들어 공유 TPM이 3.5M라면, 그 "shared limit" 목록의 어떤 모델 호출도 그 3.5M에 집계돼요.
- Vector store 수집도 vector store ID별로 rate limit이 적용돼요.
/vector_stores/{vector_store_id}/files와/vector_stores/{vector_store_id}/file_batches는 각 vector store에 대해 분당 300회 요청 한도를 공유해요. 더 큰 수집에는/vector_stores/{vector_store_id}/file_batches를 권장해요.
Usage tiers
조직의 rate·usage 한도는 계정 설정의 limits 섹션에서 볼 수 있어요. API 지출이 오르면 다음 usage tier로 자동 승급돼요. 보통 대부분의 모델에서 rate limit이 올라가요.
| Tier | 자격 | Usage 한도 |
|---|---|---|
| Free | 허용 지역에 있어야 함 | $100 / month |
| Tier 1 | $5 paid | $100 / month |
| Tier 2 | $50 paid | $500 / month |
| Tier 3 | $100 paid | $1,000 / month |
| Tier 4 | $250 paid | $5,000 / month |
| Tier 5 | $1,000 paid | $200,000 / month |
모델별 rate limit 요약을 보려면 모델 페이지를 방문하세요.
헤더의 rate limit
rate limit을 계정 페이지에서 보는 것 외에도, HTTP 응답 헤더에서 남은 요청·토큰 등 중요한 rate limit 정보를 확인할 수 있어요.
| 필드 | 샘플 값 | 설명 |
|---|---|---|
| Retry-After | 56 | 일시적 rate-limit 오류를 재시도하기 전에 기다려야 하는 최소 초 수(있을 때). |
| x-ratelimit-limit-requests | 60 | rate limit을 소진하기 전 허용되는 최대 요청 수. |
| x-ratelimit-limit-tokens | 150000 | rate limit을 소진하기 전 허용되는 최대 토큰 수. |
| x-ratelimit-remaining-requests | 59 | rate limit을 소진하기 전 남은 허용 요청 수. |
| x-ratelimit-remaining-tokens | 149984 | rate limit을 소진하기 전 남은 허용 토큰 수. |
| x-ratelimit-reset-requests | 1s | rate limit(요청 기준)이 초기 상태로 리셋될 때까지의 시간. |
| x-ratelimit-reset-tokens | 6m0s | rate limit(토큰 기준)이 초기 상태로 리셋될 때까지의 시간. |
| x-ratelimit-limit-project-tokens | 60000 | 프로젝트의 토큰 한도. |
| x-ratelimit-remaining-project-tokens | 57000 | 프로젝트 범위 토큰 rate limit을 소진하기 전 남은 토큰 수. |
| x-ratelimit-reset-project-tokens | 3s | 프로젝트 범위 토큰 rate limit이 초기 상태로 리셋될 때까지의 시간. |
프로젝트 토큰 헤더는 프로젝트 범위 토큰 한도가 적용될 때 표시될 수 있어요. Retry-After는 일시적 rate limit으로 인한 429 응답과 일시적 모델 과부하로 인한 503 응답에 있을 수 있어요. 이것은 사용자 행동이 필요한 할당량·청구·기타 오류가 재시도로 해결된다는 뜻은 아니에요.
Fine-tuning rate limits
조직의 fine-tuning rate limit은 대시보드에서 볼 수 있고, API로도 조회할 수 있어요.
curl https://api.openai.com/v1/fine_tuning/model_limits \
-H "Authorization: Bearer ***"
오류 완화
빠른 트래픽 증가와 모델 과부하 처리하기
요청 속도가 너무 빠르게 증가하면 API가 slow_down을, 요청한 모델이 일시적으로 과부하되면 server_is_overloaded를 반환할 수 있어요. HTTP 상태와 error.code를 확인해 두 상황을 구분하세요.
| HTTP 상태 | 오류 유형 | 오류 코드 | 의미 | 대처 |
|---|---|---|---|---|
429 |
rate_limit_error |
slow_down |
요청 속도가 너무 빠르게 증가했어요. | Retry-After가 있으면 따르고, 요청 속도를 줄인 뒤 점진적으로 늘리세요. |
503 |
service_unavailable_error |
server_is_overloaded |
요청한 모델이 일시적으로 과부하됐어요. | Retry-After가 있으면 따르고 재시도하세요. 계속되면 재시도 사이 지연을 늘리세요. |
Retry-After가 없으면 재시도 사이 지연을 늘리고 작은 무작위 지연을 추가하세요.
slow_down 오류는 트래픽이 분당 요청·토큰 한도 안에 있을 때도 발생할 수 있어요. 이것은 한도를 소진했는지가 아니라 트래픽이 얼마나 빠르게 증가했는지를 반영해요.
경험상 트래픽이 분당 100만 입력 토큰(TPM)에 도달하면, 15분마다 50% 이하로만 늘리세요. ramp-rate 한도가 적용되는 정확한 지점은 모델과 트래픽 조건에 따라 달라질 수 있어요.
pay-as-you-go 트래픽이 일상적으로 ramp-rate 한도를 넘는 엔터프라이즈 고객은, 지원 모델에서 더 예측 가능한 용량을 위해 Scale Tier를 고려할 수 있어요. GPT-5.6 이후 모델은 Reserved Tier를 보세요. 용량 티어는 slow_down 응답 처리 방식을 바꾸지 않아요. Retry-After가 있으면 따르고 트래픽을 줄인 뒤 점진적으로 올리세요.
기존 오류 처리기 업데이트하기
앱이 이전 스로틀링·과부하 응답을 처리했다면 HTTP 상태와 error.code를 모두 확인하세요.
- 이전에 두 조건 모두에서
503과slow_down코드를 반환하던 엔드포인트에서, 빠른 트래픽 증가는 이제429와slow_down을 반환해요. 모델 과부하는503을 유지하지만server_is_overloaded를 사용해요. - 작업 생성 전에 거부되던 비디오 요청은 이전에
429와invalid_request_error유형·rate_limit_exceeded코드를 반환했어요. 빠른 트래픽 증가는 이제429와rate_limit_error·slow_down을, 모델 과부하는503과service_unavailable_error·server_is_overloaded를 반환해요. 비디오 작업 상태에서 보고되는 오류는 별도 사례예요.
SDK 오류 처리기에서 429와 503을 모두 처리하세요. 예를 들어 Python·TypeScript·Ruby는 429에 RateLimitError, 503에 InternalServerError를 쓰고, Java는 RateLimitException과 InternalServerException을 써요. 앱이 여전히 이전 응답 코드를 받을 수 있는 동안은 그 지원을 유지하세요. 다른 오류도 같은 HTTP 상태를 쓸 수 있으므로, 복구 동작을 고르기 전에 오류 본문을 검사하세요.
스트리밍 요청의 경우 이런 HTTP 오류 응답은 스트림이 시작되기 전에 적용돼요. 스트리밍 시작 후 오류는 스트림 이벤트로 도착할 수 있으니, 출력을 소비한 뒤 요청을 자동으로 재생하지 마세요.
완화를 위해 할 수 있는 단계
OpenAI Cookbook에 rate limit 오류를 피하는 방법을 설명한 Python 노트북과, rate limit 안에서 batch 처리하는 Python 스크립트 예시가 있어요.
프로그래매틱 접근, 대량 처리 기능, 자동화된 소셜 미디어 게시를 제공할 때는 주의하고, 신뢰할 수 있는 고객에게만 활성화하는 걸 고려하세요. 자동화·대량 오용을 막으려면 지정된 시간 프레임(일·주·월) 안에서 개별 사용자에 사용 한도를 설정하세요. 한도를 넘는 사용자에게는 하드 캡이나 수동 검토 프로세스를 구현하는 걸 고려하세요.
지수 백오프로 재시도하기
요청이 일시적 rate limit을 넘으면 API는 429 오류를 반환해요. 응답에는 재시도 전에 기다려야 하는 초 수를 알려주는 Retry-After 헤더가 포함될 수 있어요. 이 값을 최소값으로 취급하세요. 적어도 그만큼 기다리고 작은 무작위 지연을 추가해서 여러 클라이언트가 동시에 재시도하지 않게 해요.
각 공식 OpenAI SDK는 자체 재시도 설정에 따라 적격한 429·503 응답을 자동으로 재시도해요. Retry-After 특히 긴 지연의 처리는 SDK 버전·설정에 따라 달라져요. 모든 서버 지연이 지원된다고 가정하지 말고 설치한 버전의 재시도 동작을 확인하세요.
유효한 서버 지연이 지원되거나 구성된 최대 재시도 지연을 넘으면, 더 빨리 재시도하기보다 재시도를 멈추고 요청을 연기하세요. SDK는 상한을 넘는 지연을 거부할 때 원래 HTTP 오류를 반환할 수 있어요. 취소·타임아웃 오류는 별도로 계속 처리하세요. 취소된 요청이나 만료된 마감은 그 HTTP 오류 없이 재시도를 멈출 수 있어요. 각 시도의 타임아웃이 전체 작업의 마감은 아닐 수 있어요.
자체 HTTP 클라이언트를 쓴다면, 헤더에 유효한 값이 있으면 Retry-After를 따르세요. 없거나 유효하지 않으면 jitter가 있는 지수 백오프로 폴백하세요. 시도 횟수와 재시도에 쓰는 총 시간을 둘 다 제한하세요. 앱에서 재시도를 관리한다면 SDK 재시도를 비활성화하거나 그 한도에 반영해서 중첩 재시도 루프가 요청을 곱하지 않게 하세요. 할당량·청구·사용자 행동이 필요한 다른 오류는 재시도하지 마세요.
지수 백오프는 실패한 요청 후 잠시 기다렸다가, 재시도가 실패할 때마다 지연을 늘리는 방식이에요. 요청이 성공하거나 설정한 재시도 한도에 도달할 때까지 계속돼요. 이 접근의 이점은 분명해요.
- 자동 재시도로 크래시나 데이터 누락 없이 rate limit 오류에서 복구할 수 있어요.
- 지수 백오프로 처음 재시도를 빠르게 시도하면서도, 처음 몇 번 실패하면 긴 지연의 이점을 얻을 수 있어요.
- 지연에 무작위 jitter를 추가하면 재시도가 동시에 몰리는 걸 막아요.
실패한 요청도 분당 한도에 집계되므로, 요청을 계속 재전송하는 건 효과가 없어요.
예시 1: Tenacity 라이브러리 사용
Tenacity는 Apache 2.0 라이선스의 범용 재시도 라이브러리로, 어떤 것에도 재시도 동작을 쉽게 추가하게 해줘요. tenacity.retry 데코레이터로 지수 백오프를 추가할 수 있고, tenacity.wait_random_exponential로 무작위 지수 백오프를 더할 수 있어요.
from openai import OpenAI
from tenacity import (
retry,
stop_after_attempt,
wait_random_exponential,
) # for exponential backoff
client = OpenAI()
@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
def completion_with_backoff(**kwargs):
return client.completions.create(**kwargs)
completion_with_backoff(
model="gpt-3.5-turbo-instruct",
prompt="Once upon a time,",
)
Tenacity는 서드파티 도구라 OpenAI가 신뢰성·보안을 보장하지 않아요.
예시 2: backoff 라이브러리 사용
backoff와 재시도를 위한 함수 데코레이터를 제공하는 또 다른 파이썬 라이브러리는 backoff예요.
import backoff
import openai
from openai import OpenAI
client = OpenAI()
@backoff.on_exception(backoff.expo, openai.RateLimitError)
def completions_with_backoff(**kwargs):
return client.completions.create(**kwargs)
completions_with_backoff(
model="gpt-3.5-turbo-instruct",
prompt="Once upon a time,",
)
Tenacity처럼 backoff도 서드파티 도구라 OpenAI가 신뢰성·보안을 보장하지 않아요.
예시 3: 수동 백오프 구현
서드파티 라이브러리를 쓰고 싶지 않다면 직접 백오프 로직을 구현할 수 있어요.
import random
import time
import openai
from openai import OpenAI
client = OpenAI()
def retry_with_exponential_backoff(
func,
initial_delay: float = 1,
exponential_base: float = 2,
jitter: bool = True,
max_retries: int = 10,
errors: tuple = (openai.RateLimitError,),
):
"""Retry a function with exponential backoff."""
def wrapper(*args, **kwargs):
num_retries = 0
delay = initial_delay
while True:
try:
return func(*args, **kwargs)
except errors:
num_retries += 1
if num_retries > max_retries:
raise Exception(
f"Maximum number of retries ({max_retries}) exceeded."
)
delay *= exponential_base * (1 + jitter * random.random())
time.sleep(delay)
except Exception:
raise
return wrapper
@retry_with_exponential_backoff
def completions_with_backoff(**kwargs):
return client.completions.create(**kwargs)
이 솔루션의 보안·효율도 OpenAI가 보장하지 않지만, 나만의 솔루션을 시작하는 좋은 출발점이 될 수 있어요.
max_tokens를 completions 크기에 맞게 줄이기
rate limit은 max_tokens와 요청의 문자 수 기반 추정 토큰 수 중 큰 값으로 계산돼요. max_tokens 값을 예상 응답 크기에 최대한 가깝게 설정하세요.
요청 일괄 처리
즉시 응답이 필요 없는 경우에는 Batch API로 대량 요청을 더 쉽게 제출·실행하면서 동기 요청 rate limit에 영향을 주지 않을 수 있어요.
동기 응답이 필요한 경우, OpenAI API는 분당 요청 수와 분당 토큰 수에 별도 한도가 있어요. 분당 요청 한도에 걸렸는데 분당 토큰 한도에 여유가 있다면, 각 요청에 여러 과업을 묶어서 처리량을 늘릴 수 있어요. 특히 작은 모델에서 분당 처리 토큰 수를 늘릴 수 있어요. 프롬프트 배치를 보내는 건 일반 API 호출과 동일하되, prompt 파라미터에 단일 문자열 대신 문자열 목록을 전달해요. 자세한 내용은 Batch API 가이드에서 확인하세요.