Aller au contenu principal

Rate limits, quotas et tiers

Mis à jour le 29 juillet 2026

Rate limits, quotas et tiers

Les rate limits définissent combien de requêtes vous pouvez envoyer à l’API par minute. Comprendre et gérer ces limites est crucial pour éviter les interruptions de service en production. Le scénario redouté est toujours le même : une intégration validée en développement, où vous envoyiez trois requêtes à la minute, part en production et traite d’un coup une file de plusieurs milliers de documents. Les 429 arrivent en rafale, et la moitié du traitement est perdue faute d’avoir anticipé le débit.

Le système de tiers

OpenAI organise les limites en tiers (niveaux) basés sur votre historique de facturation. Vous ne choisissez pas votre tier : vous y accédez en cumulant des paiements et en laissant s’écouler un délai. Cette progression a une conséquence pratique importante — un compte tout juste créé pour une démonstration client n’aura pas les mêmes capacités que le compte de production, même si le code est identique.

# Les tiers déterminent vos limites
# Tier 1 : Après premier paiement réussi
# Tier 2 : Après 50$ de paiements cumulés + 7 jours
# Tier 3 : Après 100$ de paiements cumulés + 7 jours
# Tier 4 : Après 250$ de paiements cumulés + 14 jours
# Tier 5 : Après 1000$ de paiements cumulés + 30 jours

# Les limites augmentent significativement avec chaque tier

Types de rate limits

Trois compteurs s’appliquent simultanément, et c’est le premier atteint qui vous bloque. Un traitement de textes courts saturera le RPM bien avant le TPM ; à l’inverse, une analyse de longs documents épuisera le TPM alors que vous n’aurez envoyé que quelques dizaines de requêtes. Regardez toujours l’ordre de grandeur de vos prompts avant de dimensionner votre parallélisme.

# 1. RPM — Requests Per Minute (requêtes par minute)
# 2. TPM — Tokens Per Minute (tokens par minute)
# 3. RPD — Requests Per Day (requêtes par jour)

# Ordres de grandeur pour un Tier 3 (vérifiez vos limites réelles
# dans platform.openai.com > Settings > Limits) :
# RPM : 5 000 requêtes/minute
# TPM : 2 000 000 tokens/minute
# RPD : 10 000 requêtes/jour

Lire les headers de rate limit

Vous n’avez pas besoin de deviner votre consommation : chaque réponse la transporte dans ses headers HTTP. Le SDK les masque par défaut pour ne vous rendre que l’objet parsé, mais le mode with_raw_response vous donne accès à la réponse brute, puis parse() reconstitue l’objet habituel. Un tableau de bord alimenté par ces valeurs vous prévient de l’approche du plafond au lieu de vous le faire découvrir par une erreur.

from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="gpt-5.6-terra",
    input="Bonjour !"
)

# Accéder aux headers via la réponse HTTP brute
# En utilisant le mode with_raw_response
raw = client.responses.with_raw_response.create(
    model="gpt-5.6-terra",
    input="Bonjour !"
)

print(f"Limite RPM : {raw.headers.get('x-ratelimit-limit-requests')}")
print(f"Restant RPM : {raw.headers.get('x-ratelimit-remaining-requests')}")
print(f"Limite TPM : {raw.headers.get('x-ratelimit-limit-tokens')}")
print(f"Restant TPM : {raw.headers.get('x-ratelimit-remaining-tokens')}")
print(f"Reset dans : {raw.headers.get('x-ratelimit-reset-requests')}")

response = raw.parse()
print(f"Réponse : {response.output_text}")

Rate limiter côté client

Mieux vaut ralentir soi-même que se faire refuser. Deux implémentations couvrent la plupart des besoins.

Limiter le débit avec un sémaphore

La première combine un sémaphore, qui plafonne le nombre d’appels simultanés, et une temporisation calculée à partir du débit visé. Dans l’exemple, cinquante résumés sont lancés d’un bloc mais seuls cinq progressent en parallèle, espacés du délai correspondant à cent requêtes par minute. Le code appelant reste un simple asyncio.gather : toute la discipline est encapsulée dans la classe.

import asyncio
from openai import AsyncOpenAI

async_client = AsyncOpenAI()

class RateLimiter:
    """Limite le nombre de requêtes simultanées."""

    def __init__(self, max_concurrent: int = 10, rpm: int = 500):
        self.semaphore = asyncio.Semaphore(max_concurrent)
        self.rpm = rpm
        self.delay = 60.0 / rpm  # Délai entre chaque requête

    async def appeler(self, prompt: str) -> str:
        async with self.semaphore:
            await asyncio.sleep(self.delay)
            response = await async_client.responses.create(
                model="gpt-5.6-terra",
                input=prompt
            )
            return response.output_text

async def traitement_batch():
    limiter = RateLimiter(max_concurrent=5, rpm=100)

    prompts = [f"Résumez le concept {i}" for i in range(50)]
    tasks = [limiter.appeler(p) for p in prompts]
    resultats = await asyncio.gather(*tasks)

    for i, r in enumerate(resultats):
        print(f"Résultat {i}: {r[:50]}...")

# asyncio.run(traitement_batch())

Token bucket simple

Le token bucket est plus souple parce qu’il autorise les rafales. Le seau se remplit à débit constant et se vide à chaque appel : si votre application est restée inactive une minute, elle peut repartir à pleine vitesse sur cinquante requêtes, puis retombe naturellement au rythme de remplissage. C’est exactement le comportement que vous voulez pour un service qui alterne pics et creux, et il fonctionne en environnement multithread grâce au verrou.

import time
import threading

class TokenBucket:
    """Rate limiter basé sur le token bucket algorithm."""

    def __init__(self, tokens_par_seconde: float, capacite_max: int):
        self.tokens_par_seconde = tokens_par_seconde
        self.capacite_max = capacite_max
        self.tokens = capacite_max
        self.last_refill = time.monotonic()
        self.lock = threading.Lock()

    def attendre(self, tokens_necessaires: int = 1):
        """Attend qu'assez de tokens soient disponibles."""
        while True:
            with self.lock:
                now = time.monotonic()
                elapsed = now - self.last_refill
                self.tokens = min(
                    self.capacite_max,
                    self.tokens + elapsed * self.tokens_par_seconde
                )
                self.last_refill = now

                if self.tokens >= tokens_necessaires:
                    self.tokens -= tokens_necessaires
                    return

            time.sleep(0.1)

# Utilisation : 50 requêtes par minute max
bucket = TokenBucket(tokens_par_seconde=50/60, capacite_max=50)

def appel_limite(prompt: str) -> str:
    bucket.attendre(1)
    response = client.responses.create(
        model="gpt-5.6-terra",
        input=prompt
    )
    return response.output_text

Stratégies pour les gros volumes

1. Répartir entre plusieurs projets

Chaque projet dispose de ses propres rate limits. Si votre plafond est atteint alors que votre tier est déjà élevé, distribuer les appels entre plusieurs projets multiplie mécaniquement la capacité disponible. Le round-robin ci-dessous illustre le principe ; en production, sortez le cycle de la fonction pour qu’il persiste entre les appels.

from openai import OpenAI

# Chaque projet a ses propres rate limits
clients = [
    OpenAI(project="proj-aaaa"),  # Projet 1
    OpenAI(project="proj-bbbb"),  # Projet 2
    OpenAI(project="proj-cccc"),  # Projet 3
]

def round_robin_call(prompt: str, clients: list) -> str:
    """Distribue les appels entre plusieurs projets."""
    import itertools
    client_cycle = itertools.cycle(clients)
    client = next(client_cycle)
    return client.responses.create(
        model="gpt-5.6-terra",
        input=prompt
    ).output_text

2. Utiliser le bon modèle pour le bon volume

Le choix du modèle est aussi une décision de capacité, pas seulement de qualité. Réserver les modèles les plus lourds aux tâches critiques et router le volume vers un modèle à limites élevées libère du débit là où vous en avez réellement besoin.

# Les modèles économiques (gpt-5.6-luna) ont les limites les plus hautes
# Utilisez-les pour les tâches à haut volume

# Le modèle phare (gpt-5.6-sol) a les limites les plus basses
# Réservez-le pour les tâches critiques

3. Mise en file d’attente

Enfin, la file d’attente découple la production des demandes de leur consommation. Un thread unique dépile à cadence fixe pendant que le reste de l’application soumet librement ; l’appelant, lui, bloque sur un événement jusqu’à ce que son résultat arrive. Ce pattern absorbe les pics sans jamais dépasser le débit configuré.

import queue
import threading

class APIQueue:
    """File d'attente pour les appels API."""

    def __init__(self, rpm: int = 100):
        self.queue = queue.Queue()
        self.delay = 60.0 / rpm
        self.running = True
        self.worker = threading.Thread(target=self._process, daemon=True)
        self.worker.start()

    def _process(self):
        while self.running:
            try:
                prompt, future = self.queue.get(timeout=1)
                response = client.responses.create(
                    model="gpt-5.6-terra",
                    input=prompt
                )
                future["result"] = response.output_text
                future["event"].set()
                time.sleep(self.delay)
            except queue.Empty:
                continue

    def submit(self, prompt: str) -> str:
        future = {"result": None, "event": threading.Event()}
        self.queue.put((prompt, future))
        future["event"].wait()
        return future["result"]

Points clés à retenir

  • Les rate limits s’appliquent en RPM, TPM et RPD simultanément
  • Votre tier détermine vos limites — il augmente avec vos paiements cumulés
  • Lisez les headers x-ratelimit-* pour connaître votre consommation en temps réel
  • Implémentez un rate limiter côté client pour éviter les erreurs 429
  • Répartissez la charge entre projets pour les gros volumes
  • Luna offre les rate limits les plus élevés pour le traitement en masse