spicyapiDocumentazione
Riferimento
Contenuto principale

Limiti di frequenza

Come funzionano i limiti separati di lettura e scrittura, quali richieste conteggiano, gli altri limiti e perché la concorrenza è diversa.

Un limite di frequenza stabilisce quante richieste puoi inviare in un breve periodo. Quando lo superi, l'API risponde 429 («troppe richieste») invece di eseguire il lavoro e indica quanto attendere. È una protezione contro script fuori controllo, non una quota sulla quantità di contenuti che puoi generare.

Panoramica dei limiti

LimiteValore predefinitoCosa ricevi quando lo raggiungiDettagli
Richieste per account1.000 ogni 10 secondi per le letture e altrettante per le scritture429 con Retry-Aftersotto
Richieste di URL di caricamento1.000 ogni 10 secondi429 con Retry-Aftersotto
URL di caricamento richiesti ma non ancora usati128 file oppure 1 GiB429, aspettare non aiutasotto
Rapporto di utilizzo30 al minuto; intervallo di 92 giorni429 / 400sotto, Fatturazione
Saldo disponibile—40201Fatturazione
Limiti di spesa della chiave (giornaliero / mensile / totale)Nessuno, a meno che tu lo imposti40202Fatturazione
Limiti giornalieri / mensili del teamNessuno40202Fatturazione
Team di cui sei proprietario / membri per team10 / 100409 nella consoleConsole e team

Due contenitori per account: letture e scritture

L'API, cioè tutto sotto /api/v1/* e gli endpoint compatibili /v1/* e /v1beta/*, applica i limiti di frequenza per account, non per chiave: con limiti per chiave chiunque potrebbe aggirarli creando altre chiavi.

Letture e scritture vengono conteggiate in due contenitori separati con la stessa disponibilità. La soglia di protezione predefinita è 1.000 richieste ogni 10 secondi per ciascuno: circa 100 RPS sostenute (richieste al secondo) con un picco di 1.000. È una protezione generale contro abusi e client fuori controllo, non una quota bassa per il normale traffico di generazione a pagamento.

Si tratta di un token bucket, non di un contatore a finestra fissa: capacità di 1.000, reintegrata nell'arco di 10 secondi (circa 100 token al secondo). Ogni richiesta consuma un token; i token tornano costantemente disponibili. A differenza di una finestra fissa, il token bucket rende graduale il reintegro ai confini delle finestre.

Letture e scritture consumano disponibilità separate

Le letture sono tutte le richieste GET — recordInfo, l'elenco jobs, chat/credit, usage, models — più jobs/quote, che calcola soltanto il prezzo di una richiesta. Le scritture sono tutto il resto: createTask, retry, stream, purge, common/upload-url, common/download-url e gli endpoint compatibili chat/completions, messages e di generazione Gemini. Endpoint nativi e compatibili condividono gli stessi due contenitori, quindi spostare un'integrazione di testo da /api/v1 a /v1 non fornisce una seconda disponibilità.

Il polling non può più impedire l'invio delle attività. Un ciclo di polling fuori controllo esaurisce soltanto il contenitore delle letture: recordInfo comincia a restituire 429, mentre createTask continua a essere accettato. Il polling consuma comunque richieste, quindi le integrazioni di produzione dovrebbero ancora preferire i webhook per ridurre chiamate inutili e latenza.

Il catalogo dei modelli usa il contenitore delle letture. Non recuperare uno schema invariato prima di ogni attività; memorizzalo in cache in base alla data di aggiornamento e aggiornalo dopo errori di validazione.

upload-url ha una propria protezione generale di 1.000 richieste ogni 10 secondi, aggiuntiva rispetto al contenitore delle scritture descritto sopra. Protegge separatamente l'autorizzazione alla scrittura nello storage degli oggetti; i caricamenti normali non dovrebbero avvicinarsi a quel limite.

usage ha una protezione aggiuntiva nella direzione opposta: 30 richieste al minuto, molto più restrittive, in aggiunta al contenitore delle letture. Aggrega attività storiche, quindi una chiamata costa molto più di una lettura ordinaria e una sola protezione generale non basta. Usalo per riconciliare i dati, non come endpoint di polling. Inoltre questo contenitore non lascia mai passare richieste in caso di guasto: quando la decisione sul limite non è disponibile restituisce sempre 429, mentre altri contenitori possono essere configurati per consentire il traffico.

URL di caricamento non ancora usati

Separatamente, un account può avere al massimo 128 URL di caricamento non ancora usati, oppure 1 GiB di dimensione dichiarata dei file complessivamente associati a essi. Chiederne un altro restituisce 429 con Too many pending uploads; finish existing uploads before requesting more e senza Retry-After.

Qui aspettare non aiuta, quindi non lasciare che un ciclo generico di tentativi continui inutilmente. Carica e conferma i file già richiesti (oppure lascia scadere gli URL di caricamento, cosa che richiede circa 20 minuti) e lo spazio si libera immediatamente. Di solito significa che uno script richiede URL in blocco senza usarli. Consulta Media.

Tutti i contenitori

I limiti sono applicati per area di API, quindi tutto sotto una stessa area condivide una catena di middleware. Come utente dell'API puoi incontrare i primi cinque:

ContenitoreCoperturaConteggiato perDisponibilità predefinita
(rete)Ogni richiesta API, prima del controllo della chiaveIndirizzo IP sorgente (IPv6: la sua rete /64)6.000 al minuto, molto oltre l'uso normale; molte persone sulla stessa rete aziendale lo condividono
open_apiScritture sotto /api/v1/*, /v1/* e /v1beta/* (ogni metodo tranne GET/HEAD, a parte jobs/quote)account1.000 ogni 10 secondi (circa 100 RPS sostenute)
open_api_readLetture sotto gli stessi percorsi: GET/HEAD (incluso il catalogo models) e jobs/quoteaccount1.000 ogni 10 secondi (circa 100 RPS sostenute)
upload_url/api/v1/common/upload-urlaccount1.000 ogni 10 secondi (in aggiunta a open_api)
api_usage/api/v1/usageaccount30 al minuto (in aggiunta a open_api_read)
area della consoleEndpoint autenticati /console/v1/*account120 al minuto per le letture e altrettante per le scritture
catalogCatalogo pubblico anonimo del sito commerciale (non /api/v1/models)IP sorgente300 al minuto

Per account, non per chiave

open_api e open_api_read vengono conteggiati per account. Creare altre chiavi non fornisce nulla: se il limite fosse per chiave, aggirarlo richiederebbe un clic nella console.

upload_url e api_usage sono però contenitori effettivamente separati: caricare un'immagine di riferimento consuma un token da open_api e uno da upload_url, leggere una volta usage ne consuma uno da open_api_read e uno da api_usage, e l'esaurimento di uno dei due restituisce 429.

Questi numeri sono valori predefiniti che possiamo cambiare senza un rilascio. La disponibilità attuale è sempre nell'header X-RateLimit-Limit e nella Panoramica della console. Fidati dell'header e non scrivere i valori predefiniti in modo fisso nel client.

Header di risposta

HeaderPresente suSignificato
X-RateLimit-LimitOgni rispostaDisponibilità per la finestra corrente
X-RateLimit-RemainingOgni rispostaToken rimanenti
Retry-After429 dovuto a un limite di frequenzaSecondi da attendere, minimo 1

Una risposta normale di un account con la disponibilità predefinita contiene:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 997

X-RateLimit-Remaining viene inviato anche nelle risposte riuscite, così puoi rallentare prima di ricevere un 429 anziché dopo.

Su un 401, questi header descrivono il contenitore per rete (6000), non quello dell'account, perché la chiave non è stata identificata.

Come appare un limite

{
  "code": 429,
  "msg": "Too many requests. Retry in a moment",
  "request_id": "req_…"
}

Stato HTTP 429, con Retry-After.

Le richieste oltre il limite vengono rifiutate, non messe in coda

Restituiscono subito una risposta. Metterle in coda accumulerebbe soltanto latenza, lasciandoti una connessione che non risponde mai: più difficile da gestire di un chiaro 429. Una richiesta rifiutata non è mai stata accettata, quindi non costa nulla.

Gestirlo

Leggi Retry-After. Non inviare richieste incessanti a intervalli fissi. Gli esempi si fermano dopo cinque tentativi, evitando anche che il 429 per i «caricamenti in attesa» descritto sopra crei un ciclo infinito.

JavaScript
async function callRespectingLimits(url, init) {
  for (let i = 0; i < 5; i++) {
    const res = await fetch(url, init);

    if (res.status !== 429) return res;

    // The server already told you how long to wait; don't guess
    const wait = Number(res.headers.get('retry-after') ?? 1);
    await new Promise((r) => setTimeout(r, wait * 1000));
  }
  throw new Error('persistently rate-limited');
}
Python
import time, requests


def call_respecting_limits(method: str, url: str, **kwargs) -> requests.Response:
    for _ in range(5):
        res = requests.request(method, url, **kwargs)

        if res.status_code != 429:
            return res

        # The server already told you how long to wait; don't guess
        time.sleep(float(res.headers.get("retry-after", 1)))

    raise RuntimeError("persistently rate-limited")

La concorrenza è una questione separata

Il limite riguarda la velocità di invio, non quante attività sono in esecuzione

Una volta accettata in coda, un'attività smette di consumare la disponibilità del limite di frequenza. Cento attività che generano contemporaneamente non producono un 429.

Ciò che limita davvero le attività in corso, senza riguardare il limite di frequenza:

  • Saldo disponibile: ogni attività in corso blocca fondi. Quando il saldo finisce, le nuove attività ricevono 40201.
  • Limiti di spesa: giornaliero, mensile e totale della chiave, limiti giornalieri e mensili del team (per chiavi appartenenti a un team) e limite giornaliero della piattaforma. Quando uno di questi raggiunge la soglia, ricevi 40202. Consulta Limiti di spesa.
  • Capacità di esecuzione: quando un modello non può funzionare affatto, ricevi 50301.

Quindi la risposta a «voglio più attività in esecuzione contemporaneamente» è di solito aggiungere fondi o aumentare un limite di spesa, non aumentare il limite di frequenza.

Chiedere un aumento

La disponibilità attuale è indicata nella Panoramica della console. Per chiedere un aumento, apri una conversazione sotto Assistenza (argomento: Integrazione API) e descrivi il traffico: picco di richieste al secondo, se usi batch e quanto può diventare grande un batch. Questo rende la valutazione molto più rapida.

Nel frattempo, mantieni limitata la concorrenza del client e rispetta Retry-After. Scegli il limite di concorrenza in base al lavoro, al tempo di generazione e al saldo disponibile, anziché abbassarlo artificialmente per adattarlo al limite di frequenza predefinito.

Quando il sistema di limitazione non è disponibile

Il limite di frequenza dipende da un contatore esterno. Se fallisce, la modalità configurata decide cosa succede: consentire (continuare a servire) oppure rifiutare (proteggere la disponibilità). Il rifiuto è la scelta predefinita: «non abbiamo potuto leggere la configurazione» non deve mai diventare «non c'è alcun limite».

Quando è configurato il rifiuto, ricevi 429 con Retry-After: 1, non 500. È intenzionale: 500 significa «abbiamo un guasto» e la grande maggioranza degli SDK client riprova immediatamente, aumentando il carico durante un incidente. 429 con Retry-After significa «rallenta e torna», cioè ciò che serve.

Non leggere quindi 429 come prova che stessi andando troppo veloce. Rispettare Retry-After è la risposta corretta in entrambi i casi.

In questa pagina