spicyapiDokumentacja
Materiały referencyjne
Treść główna

Limity żądań

Jak działają osobne limity odczytu i zapisu, co zużywa każdy z nich, jakie inne ograniczenia możesz napotkać i dlaczego współbieżność to osobna kwestia.

Limit żądań określa, ile żądań możesz wysłać w krótkim czasie. Po jego przekroczeniu API odpowiada 429 („zbyt wiele żądań”), nie wykonuje operacji i informuje, jak długo należy czekać. To zabezpieczenie przed skryptami wymykającymi się spod kontroli, a nie limit ilości generowanych treści.

Zestawienie limitów

LimitWartość domyślnaOdpowiedź po osiągnięciu limituSzczegóły
Żądania na konto1 000 na 10 sekund dla odczytów i osobno tyle samo dla zapisów429 z Retry-Afterponiżej
Żądania adresów do przesyłania plików1 000 na 10 sekund429 z Retry-Afterponiżej
Zamówione, ale jeszcze niewykorzystane adresy do przesyłania plików128 plików lub 1 GiB429, czekanie nie pomożeponiżej
Raport użycia30 na minutę; zakres 92 dni429 / 400poniżej, Rozliczenia
Dostępne saldo—40201Rozliczenia
Limity wydatków klucza (dzienny / miesięczny / łączny)Brak, dopóki ich nie ustawisz40202Rozliczenia
Dzienne / miesięczne limity zespołuBrak40202Rozliczenia
Zespoły, których jesteś właścicielem / członkowie jednego zespołu10 / 100409 w konsoliKonsola i zespoły

Dwa osobne limity na konto: odczyty i zapisy

Limit żądań API — wszystkich endpointów w /api/v1/* oraz zgodnych endpointów /v1/* i /v1beta/* — jest liczony na konto, a nie na klucz: limit na klucz dałoby się obejść przez tworzenie kolejnych kluczy.

Odczyty i zapisy są liczone w dwóch osobnych pulach o tej samej wielkości. Domyślny próg zabezpieczenia wynosi 1 000 żądań na 10 sekund w każdej z nich: około 100 RPS (żądań na sekundę) przy stałym ruchu, z możliwością krótkiego skoku do 1 000. To ogólne zabezpieczenie przed nadużyciami i klientem wysyłającym niekontrolowany ruch, a nie niski limit zwykłego płatnego generowania.

Mechanizm wykorzystuje token bucket, a nie licznik ze stałym oknem: pojemność wynosi 1 000, a uzupełnianie trwa 10 sekund (około 100 tokenów na sekundę). Każde żądanie zużywa jeden token; tokeny wracają równomiernie. W przeciwieństwie do stałego okna token bucket wygładza uzupełnianie na granicach okien czasowych.

Odczyty i zapisy korzystają z osobnych pul

Odczyty to wszystkie żądania GET — recordInfo, lista jobs, chat/credit, usage, models — oraz jobs/quote, które jedynie wycenia żądanie. Zapisy to wszystkie pozostałe operacje: createTask, retry, stream, purge, common/upload-url, common/download-url i zgodne endpointy generowania chat/completions, messages oraz Gemini. Endpointy natywne i zgodne z innymi protokołami dzielą te same dwie pule, więc przeniesienie integracji tekstowej z /api/v1 do /v1 nie daje dodatkowego limitu.

Odpytywanie nie może już wyczerpać limitu wysyłania zadań. Niekontrolowana pętla odpytywania wyczerpuje tylko pulę odczytów: recordInfo zaczyna zwracać 429, podczas gdy createTask nadal jest przyjmowane. Odpytywanie wciąż zużywa żądania, dlatego integracje produkcyjne powinny nadal preferować webhooki, aby ograniczyć zbędne wywołania i opóźnienia.

Katalog modeli korzysta z puli odczytów. Nie pobieraj niezmienionego schematu przed każdym zadaniem; przechowuj go w pamięci podręcznej według czasu aktualizacji i odświeżaj po błędach walidacji.

Oprócz powyższej puli zapisów upload-url ma własne ogólne zabezpieczenie 1 000 żądań na 10 sekund. Osobno chroni ono autoryzację zapisu w magazynie obiektowym; zwykłe przesyłanie plików nie powinno zbliżać się do tego progu.

usage ma dodatkowe zabezpieczenie w przeciwną stronę: znacznie niższy limit 30 żądań na minutę, oprócz opisanej powyżej puli odczytów. Endpoint agreguje historyczne zadania, więc pojedyncze wywołanie jest znacznie kosztowniejsze obliczeniowo od zwykłego odczytu i samo ogólne zabezpieczenie nie wystarcza. Używaj go do uzgadniania rozliczeń, nie jako endpointu odpytywanego w pętli. Ta pula nigdy też nie przepuszcza żądań przy awarii mechanizmu limitów: gdy nie można rozstrzygnąć limitu, zawsze zwraca 429, podczas gdy inne pule mogą być skonfigurowane tak, aby przepuszczać ruch.

Niewykorzystane adresy do przesyłania plików

Niezależnie od powyższego jedno konto może mieć najwyżej 128 jeszcze niewykorzystanych adresów do przesyłania plików lub łącznie 1 GiB zadeklarowanego rozmiaru plików powiązanych z tymi adresami. Zamówienie kolejnego zwraca 429 z Too many pending uploads; finish existing uploads before requesting more i bez Retry-After.

Czekanie tu nie pomaga, więc nie pozwól ogólnej pętli ponowień nieustannie powtarzać tego żądania. Prześlij i zatwierdź pliki, dla których adresy już zamówiono (lub poczekaj, aż te adresy wygasną, co trwa około 20 minut), a miejsce zostanie natychmiast zwolnione. Zwykle taka sytuacja oznacza, że skrypt zamawia adresy hurtowo, lecz ich nie wykorzystuje. Zobacz Media.

Wszystkie pule limitów

Limity są przypisywane do poszczególnych obszarów API, dlatego wszystko w jednym obszarze przechodzi przez ten sam łańcuch middleware. Jako użytkownik API możesz napotkać pierwszych pięć:

PulaObejmujeLiczona wedługDomyślny limit
(sieć)każde żądanie API, przed sprawdzeniem kluczaźródłowy adres IP (IPv6: jego sieć /64)6 000 na minutę — znacznie więcej niż przy zwykłym użyciu; wiele osób w jednej sieci firmowej dzieli ten limit
open_apizapisy w /api/v1/*, /v1/* i /v1beta/* (każda metoda poza GET/HEAD, z wyjątkiem jobs/quote)konto1 000 na 10 sekund (około 100 RPS przy stałym ruchu)
open_api_readodczyty w tych samych ścieżkach: GET/HEAD (w tym katalog models) i jobs/quotekonto1 000 na 10 sekund (około 100 RPS przy stałym ruchu)
upload_url/api/v1/common/upload-urlkonto1 000 na 10 sekund (oprócz open_api)
api_usage/api/v1/usagekonto30 na minutę (oprócz open_api_read)
obszar konsoliuwierzytelnione endpointy /console/v1/*konto120 na minutę dla odczytów i osobno tyle samo dla zapisów
catalogpubliczny, anonimowy katalog używany przez stronę marketingową (nie /api/v1/models)źródłowy IP300 na minutę

Na konto, nie na klucz

open_api i open_api_read są liczone względem konta. Tworzenie kolejnych kluczy nic nie daje — gdyby limit był liczony na klucz, można byłoby go obejść jednym kliknięciem w konsoli.

Natomiast upload_url i api_usage rzeczywiście są osobnymi pulami: przesłanie obrazu referencyjnego zużywa token z open_api oraz z upload_url, jeden odczyt usage zużywa token z open_api_read oraz z api_usage, a wyczerpanie dowolnej z tych pul zwraca 429.

Podane wartości są domyślne i możemy je zmienić bez wydania nowej wersji. Aktualny limit jest zawsze wskazany w nagłówku X-RateLimit-Limit i w sekcji Overview w konsoli. Ufaj nagłówkowi i nie wpisuj wartości domyślnych na stałe do kodu klienta.

Nagłówki odpowiedzi

NagłówekKiedy jest obecnyZnaczenie
X-RateLimit-LimitW każdej odpowiedziLimit w aktualnym oknie
X-RateLimit-RemainingW każdej odpowiedziPozostałe tokeny
Retry-AfterPrzy 429 z mechanizmu limitówLiczba sekund oczekiwania, co najmniej 1

Zwykła odpowiedź dla konta z domyślnym limitem zawiera:

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

X-RateLimit-Remaining jest wysyłany także w odpowiedziach zakończonych powodzeniem, więc możesz zwolnić przed otrzymaniem 429, a nie dopiero po nim.

Przy 401 te nagłówki opisują pulę sieciową (6000), nie pulę konta, ponieważ nie rozpoznano klucza.

Jak wygląda przekroczenie limitu

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

Status HTTP 429, z Retry-After.

Żądania ponad limit są odrzucane, a nie kolejkowane

Odpowiedź wraca natychmiast. Kolejkowanie tylko zwiększałoby opóźnienia i pozostawiało otwarte połączenie, które nigdy nie zwraca odpowiedzi — co jest trudniejsze w obsłudze niż jednoznaczne 429. Odrzucone żądanie nigdy nie zostało zaakceptowane, więc nic nie kosztuje.

Obsługa limitów

Odczytuj Retry-After. Nie ponawiaj bez przerwy w stałym odstępie. Przykłady kończą się po pięciu próbach, co zapobiega też nieskończonej pętli przy opisanym wyżej 429 dotyczącym oczekujących plików.

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")

Współbieżność to osobna kwestia

Limit dotyczy tempa wysyłania, a nie liczby trwających zadań

Po przyjęciu zadania do kolejki przestaje ono zużywać limit żądań. Sto jednocześnie generujących zadań nie spowoduje 429.

Liczbę trwających zadań faktycznie ograniczają poniższe czynniki, z których żaden nie jest limitem żądań:

  • Dostępne saldo — każde trwające zadanie blokuje środki. Gdy saldo się wyczerpie, nowe zadania otrzymują 40201.
  • Limity wydatków — dzienny, miesięczny i łączny limit klucza, dzienny i miesięczny limit zespołu (dla kluczy należących do zespołu) oraz dzienny limit platformy. Osiągnięcie dowolnego z nich powoduje 40202. Zobacz Limity wydatków.
  • Możliwość wykonania — gdy model w ogóle nie może wykonać zadania, otrzymujesz 50301.

Dlatego odpowiedzią na „chcę więcej zadań działających naraz” jest zwykle doładowanie konta lub podniesienie limitu wydatków, a nie zwiększenie limitu żądań.

Prośba o zwiększenie limitu

Aktualny limit jest widoczny w sekcji Overview w konsoli. Aby poprosić o większy, rozpocznij rozmowę w sekcji Support (temat: API integration) i opisz swój ruch: szczytową liczbę żądań na sekundę, czy uruchamiasz partie zadań i jak duże są te partie. Znacznie przyspieszy to rozpatrzenie prośby.

Do tego czasu ogranicz współbieżność klienta i przestrzegaj Retry-After. Wybieraj liczbę równoczesnych zadań na podstawie obciążenia, czasu generowania i dostępnego salda, zamiast sztucznie obniżać ją do wartości dopasowanej do domyślnego limitu żądań.

Gdy sam mechanizm limitów jest niedostępny

Mechanizm limitów zależy od zewnętrznego licznika. Gdy licznik zawiedzie, ustawiona strategia określa dalsze działanie: przepuszczanie (dalsza obsługa) lub odrzucanie (ochrona limitu). Domyślnie żądania są odrzucane — „nie mogliśmy odczytać konfiguracji” nigdy nie może oznaczać „nie ma limitu”.

Przy strategii odrzucania otrzymujesz 429 z Retry-After: 1, a nie 500. To celowe: 500 oznacza „mamy awarię”, a większość klienckich SDK natychmiast ponawia takie żądania, zwiększając obciążenie podczas incydentu. 429 z Retry-After oznacza „odczekaj i wróć”, czyli właśnie właściwe działanie.

Nie traktuj więc 429 jako dowodu, że wysyłano żądania zbyt szybko. Przestrzeganie Retry-After jest poprawną reakcją w obu przypadkach.

Na tej stronie