Rate limit ed errore 429: cosa fare quando l’API ti dice di no

8 min di lettura

Prima o poi succede a tutti: l’integrazione con le API di un modello IA funziona benissimo per settimane, poi un giorno arriva un picco di traffico e i log si riempiono di errore 429. È il modo in cui il provider ti dice che stai andando troppo veloce. Il problema è che lo stesso codice può voler dire cose molto diverse, e se lo tratti sempre allo stesso modo o riprovi quando non serve a niente, o ti arrendi quando bastava aspettare un secondo.

In questo articolo ti spiego come funzionano i rate limit di OpenAI e Anthropic, come leggere gli header che ti dicono quanto margine hai, quali errori vale la pena ritentare e quali no, e ti lascio una funzione PHP per riprovare nel modo giusto, provata sul server di questo blog.

Cosa sono i rate limit

I rate limit sono dei tetti a quanto puoi usare l’API in un certo intervallo di tempo. Servono al provider per evitare abusi e dividere la capacità tra tutti i clienti. Si misurano in più modi contemporaneamente, e scatta quello che raggiungi per primo:

  • richieste al minuto (RPM), il numero di chiamate;
  • token al minuto: OpenAI ha un unico limite (TPM), Anthropic ne ha due separati, uno per l’input (ITPM) e uno per l’output (OTPM);
  • su OpenAI anche limiti giornalieri, su richieste e token.

I limiti valgono per organizzazione e, su Anthropic, separatamente per ogni modello: puoi usare Haiku e Sonnet insieme, ognuno fino al suo tetto.

Il limite al minuto non è un contatore che si azzera

Questo è il dettaglio che frega più gente. Uno pensa: ho 500 richieste al minuto, quindi posso mandarne 500 nel primo secondo e poi aspettare. No. I provider usano un sistema a “secchio” (token bucket) che si riempie in continuazione: la capacità si ricarica un po’ alla volta, non tutta allo scadere del minuto. Anthropic lo scrive chiaramente nella documentazione sui rate limit: un limite di 60 richieste al minuto può essere applicato come una richiesta al secondo, e brevi raffiche possono farti sforare anche se sul minuto saresti sotto.

L’ho visto negli header di una chiamata a GPT-6 Luna dal server del blog: con un limite di 500 richieste al minuto, il tempo per recuperare la richiesta appena fatta era di 120 millisecondi. Cioè esattamente 60 secondi diviso 500.

I livelli: i limiti crescono con la spesa

I limiti non sono uguali per tutti. Entrambi i provider ti mettono in un livello (tier) e ti fanno salire in automatico man mano che usi l’API e paghi.

  • OpenAI ha sei livelli, da Free a Tier 5, legati a quanto hai pagato in totale: si passa al Tier 1 con 5 dollari di credito e al Tier 5 con mille. Ogni livello ha anche un tetto di spesa mensile.
  • Anthropic ha i livelli Start, Build e Scale, con tetti di spesa mensili di 500, 1.000 e 200.000 dollari. Le organizzazioni nuove possono partire da un livello di prova con limiti più bassi, che crescono da soli con la storia dell’account.

La conseguenza pratica: un’applicazione che in sviluppo non ha mai visto un 429 può incontrarlo il giorno del lancio, perché il traffico vero arriva tutto insieme su un account ancora “giovane”. Se prevedi un picco, controlla i limiti del tuo livello prima, non dopo.

Leggere gli header: quanto margine hai

Non serve indovinare: ogni risposta dell’API porta con sé degli header che dicono qual è il tuo limite, quanto ne resta e quando si ricarica. Questi sono quelli arrivati con la chiamata a GPT-6 Luna di cui parlavo sopra:

x-ratelimit-limit-requests: 500
x-ratelimit-remaining-requests: 499
x-ratelimit-reset-requests: 120ms
x-ratelimit-limit-tokens: 200000
x-ratelimit-remaining-tokens: 199997
x-ratelimit-reset-tokens: 0s
x-request-id: req_5d56e4cea82c42c7876a56338821c523

Anthropic fa lo stesso con gli header anthropic-ratelimit-requests-*, anthropic-ratelimit-input-tokens-* e anthropic-ratelimit-output-tokens-*, ognuno con -limit, -remaining e -reset. Quando sfori, entrambi aggiungono un header retry-after con i secondi da aspettare.

Un consiglio: salva sempre nei log l’ID della richiesta (x-request-id su OpenAI, request-id su Anthropic). Se devi aprire un ticket al supporto, è la prima cosa che ti chiedono.

Non tutti i 429 sono uguali

Qui sta il punto dell’articolo. Davanti a un errore, la domanda da farsi è una sola: se riprovo tra poco, può andare meglio? Ecco la risposta per gli errori che vedrai più spesso.

ErroreCosa vuol direRiprovare?
400Richiesta sbagliata: parametro errato, prompt troppo lungo, modello che non supporta un’opzioneNo, va corretta
401 / 403Chiave API sbagliata, revocata o senza permessiNo
429 rate limitStai andando troppo veloceSì, dopo il retry-after
429 “slow down”Il traffico è cresciuto troppo in frettaSì, e aumenta il ritmo gradualmente
429 credito o tetto di spesaHai finito il credito o raggiunto il tetto mensileNo, finché non ricarichi o cambi livello
500Errore interno del providerSì, con attese crescenti
503 (OpenAI) / 529 (Anthropic)Server sovraccarichi per tuttiSì, con attese crescenti
504La richiesta ci ha messo troppoMeglio usare lo streaming o la Batch API
Dalla documentazione sugli errori di Anthropic e OpenAI.

La riga da stampare e appendere al monitor è la quinta. Il 429 per credito esaurito ha lo stesso codice di un normale rate limit, ma riprovare non serve a niente: su Anthropic, quando raggiungi il tetto di spesa del tuo livello, la risposta non ha nemmeno l’header retry-after e le richieste falliscono fino al primo del mese successivo. Per distinguerli bisogna leggere il corpo dell’errore: OpenAI usa il codice insufficient_quota, Anthropic enforced_spend_limit_reached.

Come riprovare nel modo giusto

La strategia consigliata da tutti i provider ha tre ingredienti:

  1. Rispetta il retry-after quando c’è: il provider ti sta dicendo esattamente quanto aspettare.
  2. Attese crescenti (exponential backoff) quando non c’è: 1 secondo, poi 2, poi 4, poi 8.
  3. Un po’ di caso (jitter): se cento processi ricevono il 429 nello stesso istante e riprovano tutti dopo esattamente un secondo, sbattono di nuovo contro il muro tutti insieme. Aggiungere qualche centinaio di millisecondi casuali li sparpaglia.

Più un quarto ingrediente che spesso manca: un numero massimo di tentativi, e nessun tentativo per gli errori che non si risolvono da soli. Ecco una funzione per WordPress che fa tutto questo:

function chiama_con_retry( $url, array $args, $tentativi = 5 ) {
	for ( $i = 0; $i < $tentativi; $i++ ) {
		$res  = wp_remote_post( $url, $args );
		$code = (int) wp_remote_retrieve_response_code( $res );
		if ( 200 === $code ) {
			return $res;
		}
		$json  = json_decode( wp_remote_retrieve_body( $res ), true );
		$err   = $json['error'] ?? array();
		$tipo  = $err['code'] ?? $err['details']['error_code'] ?? '';
		$quota = in_array( $tipo, array(
			'insufficient_quota',           // OpenAI
			'enforced_spend_limit_reached', // Anthropic
		), true );
		// 400, 401, 403 e credito finito: riprovare non serve
		if ( $quota || ( $code && 429 !== $code && $code < 500 ) ) {
			return $res;
		}
		if ( $i + 1 === $tentativi ) {
			break;
		}
		// Retry-After se c'è, se no 1, 2, 4, 8 s, più un po' di caso
		$dopo = (float) wp_remote_retrieve_header( $res, 'retry-after' );
		$sec  = $dopo > 0 ? $dopo : 2 ** $i;
		usleep( (int) ( ( $sec + mt_rand( 0, 1000 ) / 1000 ) * 1000000 ) );
	}
	return $res;
}

L’ho provata sul server del blog in tre situazioni. Con una chiave finta ha restituito il 401 in 0,16 secondi, senza perdere tempo a riprovare. Con una richiesta valida ha risposto al primo colpo. Contro un indirizzo di test che risponde sempre 503, con tre tentativi, ha rinunciato dopo 5,5 secondi, dopo due attese di circa uno e due secondi. Nella prima versione aspettava anche dopo l’ultimo tentativo, sprecando altri quattro secondi per niente: è il genere di dettaglio che si nota solo provando.

Se usi gli SDK ufficiali, buona parte di questo lavoro è già fatta: quello di Anthropic, per esempio, ritenta da solo due volte gli errori temporanei con attese crescenti, rispettando il retry-after, e il numero di tentativi si configura con max_retries.

Quanti tentativi? Dipende da chi aspetta

Il numero giusto non è universale. Nel chatbot di questo blog ho fatto una scelta minima: un solo nuovo tentativo dopo due secondi, perché dall’altra parte c’è una persona che aspetta la risposta, e dopo dieci secondi di attesa è meglio un messaggio di scuse onesto. Per un processo notturno che elabora documenti, invece, cinque o sei tentativi con attese lunghe vanno benissimo: nessuno sta aspettando.

Come non arrivare al 429

Riprovare bene è importante, ma è meglio non sbattere contro il limite. Le leve che conosco:

  • Usa la cache. Su Anthropic, per quasi tutti i modelli, i token letti dalla cache non contano nel limite di input al minuto: con tanta cache il tuo limite effettivo si moltiplica. Ne parlo nell’articolo su prompt caching e Batch API.
  • Imposta un max_tokens realistico su OpenAI. OpenAI calcola il consumo del limite prendendo il valore più alto tra il tuo max_tokens e la stima dei token della richiesta: un max_tokens esagerato ti “prenota” capacità che non userai. Su Anthropic invece non incide: l’output si conta mentre viene generato.
  • Sposta sul batch quello che non è urgente. La Batch API ha limiti suoi, separati da quelli delle chiamate normali, oltre a costare la metà.
  • Metti una coda. Invece di lanciare cento chiamate in parallelo, tienine in volo un numero fisso, per esempio cinque, e fai partire la successiva quando una finisce.
  • Cresci con gradualità. Anthropic avverte che un aumento brusco del traffico può far scattare dei 429 anche sotto i limiti nominali. Se lanci una funzione nuova, aumenta il traffico un po’ alla volta.
  • Separa gli ambienti. Su Anthropic puoi dare limiti propri a ogni workspace: così un test impazzito in sviluppo non si mangia la capacità della produzione.

In sintesi

Un 429 non è un guasto, è un semaforo. Leggi gli header per sapere quanto margine hai, distingui il “vai più piano” dal “hai finito il credito”, riprova con attese crescenti e un po’ di caso, e non riprovare mai gli errori che non si risolvono da soli. Poi lavora a monte, con cache, batch e una coda, per incontrarlo il meno possibile.

Se sei arrivato qui dall’inizio della serie, il quadro generale è nella guida alle API di intelligenza artificiale, e per i costi c’è l’articolo su cosa sono i token. Il prossimo parla di output strutturato e tool use: come far lavorare il modello con il tuo codice.

Newsletter

Ti è stato utile? Il prossimo te lo mando io.

La rassegna AI ogni mattina oppure il digest della domenica: scegli tu.

Cosa vuoi ricevere
Che differenza c’è tra le due newsletter?

Rassegna AI quotidiana: ogni mattina alle 8:30, le notizie sull'IA del giorno.

Digest settimanale: la domenica, gli articoli e le rassegne della settimana in una sola mail.

Puoi sceglierle anche tutte e due.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *