Do której usługi należą limity
Nazwy łatwo pomylić. Groq to firma, która hostuje modele na własnym sprzęcie. Grok to rodzina modeli od xAI. Ta strona nie jest ani jednym, ani drugim: to API kompatybilne z OpenAI dla jednego modelu o otwartych wagach (ID modelu uncensored), obsługiwane przez niezależnego dostawcę. Jeśli chodzi o limit zapytań dla samego API Groq, np. liczbę zapytań lub tokenów na minutę w danym planie, otwórz konsolę lub dokumentację Groq i sprawdź wartości dla swojego konta. Zmieniają się, a ja nie zgaduję.
To, co następuje, jest dokładne dla naszego API, a nawyki przenoszą się na dowolnego dostawcę: szanuj nagłówki limitów, ponawiaj tylko przy właściwych błędach i ogranicz własną równoległość przed serwerem. Jeśli przyszedłeś tutaj w celu konfiguracji Grok NSFW, nasza instrukcja integracji obejmuje również błędy otoczenia.
Limity na pierwszy rzut oka
| Limit | Pełny klucz | Klucz próbny |
|---|---|---|
| Zapytania równoległe | 8 | 2 |
| Zapytania na minutę | 300 | 60 |
| Treść żądania | 8 MB | 8 MB |
| Okno kontekstu (prompt plus odpowiedź) | 100 000 tokenów | 100 000 tokenów |
Dwa z nich to limity zapytań w ścisłym sensie: zapytania na minutę i równoległość. Dwa pozostałe to limity rozmiaru pojedynczego zapytania i są niezależne od limitów zapytań. Zapytanie z promptem 90 000 tokenów liczy się jako jedno zapytanie wobec 300 na minutę, tak samo jak prompt z jednej linii, choć zajmie więcej czasu i dłużej utrzyma swój slot.
Kredyt próbny w wysokości $0.50 aktywujesz jednym kliknięciem na stronie klucz API po zalogowaniu się, a do niego stosują się limity próbne. Limity pełnego klucza obowiązują po doładowaniu.
Trzy rodzaje 429
Wszystkie błędy limitu przychodzą jako HTTP 429, ale oznaczają różne rzeczy i wymagają różnych reakcji.
rate_limited: wysłałeś więcej zapytań niż pozwala limit zapytań na minutę. Zwolnij; okno trwa minutę, więc równomierne rozłożenie zapytań pomaga bardziej niż długie pauzy.concurrency: zbyt wiele zapytań było przetwarzanych jednocześnie. Poczekaj, aż jedno z wcześniejszych się zakończy. Jest to powszechne przy strumieniowaniu, gdzie każde zapytanie trwa przez całe generowanie.- Tymczasowe przeciążenie: również 429, z nagłówkiem
Retry-After: 5. To nie Twoja wina i nie jest powiązane z limitami Twojego klucza. Poczekaj wskazane 5 sekund i ponów próbę.
Nieudane zapytania nie są rozliczane, więc pętla ponawiania kosztuje tylko jedno zapytanie, które w końcu się powiedzie. Odpowiedzi zawierają również X-RateLimit-Limit-Requests i X-RateLimit-Limit-Concurrency, więc Twój klient może odczytać swoje własne sufity zamiast wpisywać je na stałe w kodzie, plus X-Balance-USD dla pozostałego kredytu i X-Request-Id, który powinieneś logować i cytować, jeśli skontaktujesz się z wsparciem.
Matematyka przepustowości: dlaczego 300 na minutę jest trudne do osiągnięcia
Dwa limity oddziałują na siebie. Przy 8 slotach równoległych, najwięcej, co możesz ukończyć na minutę, to 8 x 60 podzielone przez średni czas trwania zapytania w sekundach. Aby faktycznie osiągnąć 300 zapytań na minutę, potrzebujesz zapytań, które kończą się w średnim czasie 8 x 60 / 300 = 1,6 sekundy. Wolniejsze zapytania są ograniczone przez równoległość.
| Średni czas zapytania | Maks. na minutę, pełny klucz (8 slotów) | Maks. na minutę, próbny (2 sloty) |
|---|---|---|
| 2 sekundy | 240 | 60 |
| 10 sekund | 48 | 12 |
| 20 sekund | 24 | 6 |
Są to arytmetyczne górne granice dla hipotetycznego czasu zapytania, nie pomiary naszej usługi; zmierz własne zapytania. Wniosek jest taki, że długie generowanie kreatywne 20 sekund na pełnym kluczu osiąga szczyt 24 zapytań na minutę, daleko poniżej dozwolonych 300. Jeśli potrzebujesz większej przepustowości, skróć odpowiedzi za pomocą max_tokens lub żądaj mniej tekstu na wywołanie, zamiast liczyć na wyższy limit zapytań.
Klient obsługujący wszystkie trzy przypadki
Ten klient Python ogranicza własną równoległość semaforem, odczytuje Retry-After, gdy jest obecny, a w przeciwnym razie stosuje backoff z małym jitterem. Używa oficjalnego pakietu openai.
import random
import threading
import time
from concurrent.futures import ThreadPoolExecutor
from openai import OpenAI, RateLimitError
client = OpenAI(
base_url="https://api.groknsfw.top/v1",
api_key="YOUR_KEY",
max_retries=0, # we handle retries ourselves
)
slots = threading.BoundedSemaphore(8) # use 2 on the trial key
def ask(prompt, tries=6):
for attempt in range(tries):
with slots:
try:
r = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": prompt}],
max_tokens=400,
)
return r.choices[0].message.content
except RateLimitError as e:
wait = e.response.headers.get("retry-after")
body = e.response.text
# sleep outside the slot so others can proceed
delay = float(wait) if wait else min(2 ** attempt, 30)
if "rate_limited" in body:
delay = max(delay, 5)
time.sleep(delay + random.random())
raise RuntimeError("still rate limited after retries")
with ThreadPoolExecutor(max_workers=8) as pool:
results = list(pool.map(ask, ["Write one line about the sea."] * 20))
print(len(results))
Ta sama koncepcja w Node to mała kolejka, która pozwala na maksymalnie 8 oczekujących promise'ów, a poniższe sprawdzenie curl drukuje nagłówki limitów, abyś mógł potwierdzić sufity swojego klucza:
curl -s -D - -o /dev/null https://api.groknsfw.top/v1/models \
-H "Authorization: Bearer YOUR_KEY" | grep -i "x-"Strumieniowanie, długie prompty i kontekst
Zapytanie strumieniowane z stream: true utrzymuje swój slot równoległości do momentu przybycia ostatniego zdarzenia. Oznacza to, że wolny czytnik liczy się przeciwko Tobie: jeśli Twój kod pauzuje podczas obsługi każdego chunka, slot pozostaje zajęty. Pobieraj strumień niezwłocznie.
Długie prompty oddziałują na limity na dwa sposoby. Po pierwsze, przetwarzanie zajmuje więcej czasu, więc zmniejszają one przepustowość według powyższego wzoru. Po drugie, muszą zmieścić się w oknie 100 000 tokenów wraz z odpowiedzią, więc zachowaj margines. Ograniczenie historii starych rozmów pomaga w obu problemach, a to samo ograniczenie zmniejsza koszt: przy cenie $0.15 za 1M tokenów wejściowych historia 20 000 tokenów kosztuje $0.003 za każdym razem, gdy ją ponownie wyślesz.
Szczegóły formatu zapytania są w szybkim starcie, a stawki na stronie cenowej.
Pokazywanie limitów własnym użytkownikom
Limit zapytań to również decyzja produktowa. Jeśli Twoja aplikacja stoi między końcowymi użytkownikami a API, surowe 429 nigdy nie powinno do nich dotrzeć. Zdecyduj wcześniej, co zobaczą zamiast tego.
- Dla aplikacji czatu, pokaż krótki stan "pisanie" i zakolejkuj wiadomość. Czekanie kilku sekund jest niewidoczne dla większości użytkowników, jeśli na ekranie dzieje się coś.
- Dla narzędzi batchowych, pokaż postęp jako liczbę ukończonych elementów i pozwól zadaniu działać w tle. Ponowienia są wewnętrzne i nie powinny pojawiać się jako błędy.
- Dla wdrożeń współdzielonych, przydziel każdemu użytkownikowi niewielki limit na użytkownika we własnym kodzie, aby jeden intensywny użytkownik nie zajął pozostałym wszystkich 8 slotów.
Loguj trzy rzeczy dla każdego błędu: X-Request-Id, kod błędu i liczbę zapytań, które Twoja aplikacja przetwarzała w tym momencie. Dzięki temu możesz odróżnić źle zachowującego się klienta od rzeczywistego obciążenia w kilka minut. Jeśli problem wygląda na po stronie serwera, ID zapytania jest tym, o co wsparcie zapyta jako pierwsze.
Na koniec, celowo przetestuj ścieżkę awarii. Uruchom swojego klienta z celowo niskim semaforem, a następnie z wysokim, i obserwuj, co pokazują logi. Pętla ponawiania, która nigdy nie wystąpiła, to pętla ponawiania, której nie możesz ufać. Klucz próbny to wygodne miejsce na to, ponieważ przy tylko 2 równoległych zapytaniach łatwo jest trafić na błąd concurrency krótkim skryptem i zobaczyć, jak reaguje Twój kod, przy koszcie kilku dziesiątych centa za zapytanie.
Typowe błędy
Kilka wzorców powoduje większość problemów z 429, o które zgłaszają się ludzie.
- Natychmiastowe ponawianie. Pętla wysyłająca ponownie przy każdej awarii zamienia jeden moment przekroczenia limitu w lawinę. Poczekaj, dodaj jitter i ogranicz liczbę prób.
- Ponawianie wszystkiego. Tylko 429 i przejściowe błędy serwera zasługują na ponowienie. Złe zapytanie lub zły klucz zawiodą tak samo za każdym razem.
- Pomijanie strumieni w liczniku. Dziesięć otwartych okien czatu na pełnym kluczu może być dziesięcioma strumieniami, a to dwa więcej niż 8 slotów.
- Brak ustawionego timeoutu. Zawieszone połączenie trzyma zajęty slot. Ustaw rozsądny timeout dla każdego zapytania w swoim kliencie HTTP.
- Dopasowanie do średniej. Ruch przychodzi w falach. Zaplanuj na swoją najgorętszą minutę, nie średnią dzienną.
Planowanie pojemności przed uruchomieniem
Rozpocznij od szczytowych obciążeń. Jeśli oczekujesz 30 użytkowników czatujących jednocześnie, a każda odpowiedź jest strumieniowana przez około 15 sekund, potrzebujesz 30 slotów w momencie, gdy wszyscy wyślą zapytanie, a pełny klucz ma 8 slotów. Zakolejkuj resztę w swojej aplikacji, pokaż krótki czas oczekiwania i przetwarzaj je, gdy sloty się zwolnią. Przy 8 slotach i 15-sekundowych odpowiedziach możesz obsłużyć 8 x 60 / 15 = 32 odpowiedzi na minutę.
W przypadku zadań batchowych uruchom stałą pulę workerów równą Twojemu limitowi równoległości i pozwól logice ponawiania obsługiwać okresowe przeciążenia. Zamiast omijać limity, zbuduj kolejkę: daje to przewidywalne zachowanie i pozwala pokazać rzeczywiste czasy oczekiwania użytkownikom.
