PL ▾
Uzyskaj klucz API

Przewodnik po błędach API bez cenzury

Błędy nie są straszne, straszny jest brak pewności, czy retry, czy zmiana kodu. Przewodnik rozkłada błędy wg kodów statusu: warunki wyzwalające, kryteria decyzji i sposób naprawy. Odpowiedź to zawsze JSON z obiektem error zawierającym code i message, więc pierwszy krok to analiza body, a nie tylko kodu statusu. Na końcu znajdziesz kod retry z backoffem eksponencjalnym, kod limitu zapytań po stronie klienta i listę kontrolną.

Zaktualizowano

Kluczowe informacje

  • Tylko 429 i 503 są warte automatycznego ponowienia; inne kody to marnowanie żądań.
  • 402 no_credit to brak środków lub wygaśnięcie kredytu próbnego; 403 content_blocked to zablokowanie treści. To nie są błędy sieciowe.
  • Ponawiaj z wykładniczym opóźnieniem i losowym jitterem, ustawiając limit prób.
  • Limit to 300 żądań na minutę na klucz; zadania batchowe wymagają limitu po stronie klienta.

Format błędu i kolejność odczytu

Wszystkie odpowiedzi z błędem mają tę samą strukturę:

{"error":{"code":"...","message":"..."}}

Kolejność odczytu to trzy kroki:

  1. Kod stanu HTTP decyduje o kategorii;
  2. error.code określa konkretną przyczynę i służy do warunków w kodzie programu;
  3. error.message jest przeznaczony do wyświetlania użytkownikowi i zapisu w logach; nie używaj go do dopasowywania ciągów znaków.

Zdefiniuj granicę: błędy, które rozwiążesz przez ponowne wysłanie (429, 503 i timeouty sieciowe) oraz błędy, które rozwiążesz poprzez zmianę (pozostałe). Mieszanie ich to najczęstsza przyczyna awarii, np. ciągłe ponawianie 402, co generuje dziesiątki niepotrzebnych zapytań na sekundę.

W logach zapisuj cztery pola: czas, kod stanu, error.code i szacowaną liczbę tokenów w promptcie. Dzięki temu od razu widać, czy wzrosła liczba konkretnych błędów, czy ogólna liczba niepowodzeń. Ustaw regułę alertu: 402 wywołuje natychmiastowe powiadomienie (usługa jest niedostępna), a 429 sprawdzaj pod kątem proporcji — pojedyncze nie wymagają interwencji, ale utrzymujący się limit oznacza problem z projektowaniem współbieżności.

Szybki podgląd kodów

Kod stanuerror.codeZnaczeniePonowić?
400—Nieprawidłowe zapytanie, np. suma długości promptu i max_tokens przekracza 100kNie
401—Nieprawidłowy lub brakujący kluczNie
402no_creditBrak środków lub wygaśnięcie kredytu próbnegoNie
403content_blockedTreść zablokowanaNie
404—Endpoint nie istniejeNie
429—Przekroczenie limituTak, z opóźnieniem
503upstream_busySerwer tymczasowo zajętyTak, po kilku sekundach

Znak „—” w tabeli oznacza brak stałego ciągu znaków code, który wymagałby specjalnej obsługi; wystarczy obsłużyć kod statusu.

4xx: zmień żądanie, nie ponawiaj

400 Nieprawidłowe żądanie

  • Przyczyna 1: Błąd formatu JSON, często wynikający z ręcznego budowania ciągu znaków bez odpowiedniego escapowania cudzysłowów.
  • Przyczyna 2: prompt + max_tokens > 100,000 tokenów. Długie konwersacje to częsta przyczyna.
  • Przyczyna 3: ciało żądania > 8 MB.
  • Poprawka: serializuj przez bibliotekę JSON; oszacuj tokeny przed wysłaniem; obetnij historię lub zmniejsz max_tokens; zob. Długi kontekst w praktyce.

401 Problemy z kluczem

  • Brak nagłówka lub prefiksu Bearer .
  • Wygeneruj ponownie klucz API, przez co stary przestaje być ważny, ale jakaś maszyna nadal go używa.
  • Zmienne środowiskowe nie są dostępne w kontenerze lub zadaniach cyklicznych.

402 no_credit

Saldo się wyczerpało lub 7-dniowy kredyt próbny wygasł. Przejdź do strony konta, aby doładować przedpłacony kredyt. Zalecamy monitorowanie salda przez własny serwis, aby nie czekać na zgłoszenie błędu przez użytkownika.

403 content_blocked

Treść została zablokowana. Legalna treść dla dorosłych, fikcja i tematy kontrowersyjne nie są odrzucane, ale treści seksualne z udziałem małoletnich są zawsze blokowane, w tym w powieściach i roleplay. Przy błędzie 403 sprawdź prompt i historię pod kątem takich treści zamiast zmieniać sformułowanie i ponawiać.

404 endpoint nie istnieje

Dostępne są tylko dwa endpointy: POST /v1/chat/completions i GET /v1/models. Błąd 404 wystąpi przy błędnej ścieżce (brak /v1, zbędny slash, literówka) lub próbie użycia nieobsługiwanych interfejsów embeddings, obrazów itp.

Kolejną kategorią błędów 400, którą łatwo błędnie zdiagnozować, jest liniowy wzrost liczby tokenów w długich rozmowach. Testy w ciągu dnia przebiegają poprawnie, ale po kilkunastu turach nagle pojawia się błąd 400. Nie wynika to z niestabilności interfejsu, lecz z wyczerpania okna kontekstu. Rozwiązaniem jest ustawienie limitu historii: gdy próg zostanie przekroczony, należy odrzucać najstarsze tury lub kompresować starsze treści w postaci streszczenia. Nie oczekuj na błąd, lecz oszacuj zużycie przed wysłaniem zapytania.

Praktyczna wskazówka przy debugowaniu błędu 401: wypisz do logów pierwsze i ostatnie cztery znaki klucza API, nie wypisuj go w całości i porównaj z danymi na stronie konta. Dzięki temu zweryfikujesz, czy proces odczytuje ten klucz, którego się spodziewasz. W środowiskach kontenerowych i zadań cyklicznych najczęstszą przyczyną jest brak zmiennych środowiskowych lub odczytanie przestarzałej wartości.

429 i 503: kiedy należy zastosować retry

429 limit zapytań

Limit to 300 zapytań na minutę na klucz. Wywołują go zadania batchowe, współdzielenie jednego klucza przez wiele instancji oraz burza ponownych prób. Rozwiązanie ma dwa etapy: najpierw zastosuj limit zapytań po stronie klienta (kod poniżej), a następnie zastosuj wykładnicze ponawianie dla 429.

503 upstream_busy

Serwer jest tymczasowo obciążony. Spróbuj ponownie po kilku sekundach. Nie wysyłaj zapytań natychmiast za sobą i nie powtarzaj ich dziesięciokrotnie w ciągu sekundy, co może pogorszyć sytuację.

Przekroczenie limitu czasu sieci

Generowanie długich tekstów trwa dłużej, dlatego timeout nie powinien być zbyt krótki; w przykładzie ustawiono go na 120 sekund. Przy retry’ach po przekroczeniu limitu czasu pamiętaj, że pierwsze zapytanie mogło zostać już wykonane po stronie serwera, co może skutkować podwójnym obciążeniem kredytu. W przypadku generowania tekstu ogranicz liczbę retry’i i rozważ użycie strumieniowania, aby skrócić czas oczekiwania na pojedynczą odpowiedź.

import os
import random
import time
import requests

URL = "https://api.wushenchaapi.com/v1/chat/completions"
HEADERS = {
    "Authorization": "Bearer " + os.environ["API_KEY"],
    "Content-Type": "application/json",
}
RETRYABLE = {429, 503}          # 只重试这两类
FATAL = {400, 401, 402, 403, 404}

class ApiError(Exception):
    def __init__(self, status, code, message):
        super().__init__(f"{status} {code}: {message}")
        self.status, self.code = status, code

def call(payload, max_retries=5, base=1.0, cap=30.0):
    for attempt in range(max_retries + 1):
        try:
            r = requests.post(URL, headers=HEADERS, json=payload, timeout=120)
        except (requests.ConnectionError, requests.Timeout):
            r = None                      # 网络层失败,按可重试处理
        if r is not None and r.ok:
            return r.json()
        if r is not None:
            try:
                err = r.json().get("error", {})
            except ValueError:
                err = {}
            if r.status_code in FATAL or r.status_code not in RETRYABLE:
                raise ApiError(r.status_code, err.get("code"), err.get("message"))
        if attempt == max_retries:
            raise ApiError(r.status_code if r is not None else 0, "retry_exhausted", "重试次数用尽")
        delay = min(cap, base * (2 ** attempt)) * random.uniform(0.5, 1.0)
        time.sleep(delay)

if __name__ == "__main__":
    out = call({"model": "uncensored", "max_tokens": 100,
                "messages": [{"role": "user", "content": "回复一个字:好"}]})
    print(out["choices"][0]["message"]["content"])

Kluczowa zasada: wzór na opóźnienie to min(cap, base × 2^n) × współczynnik losowy. Losowe zakłócenia zapobiegają kolizji, gdy klienci ponawiają zapytania jednocześnie. Kodów z kolekcji FATAL nie ponawia się nigdy.

Ograniczanie ruchu po stronie klienta i zapytania diagnostyczne

Zamiast czekać na błąd 429 i stosować retry, lepiej ograniczyć ruch wcześniej. Poniższe narzędzie zapewnia, że liczba zapytań w ciągu minuty nie przekroczy ustalonego limitu i jest bezpieczne dla wątków:

import threading
import time

class RateGate:
    """简单的客户端限速:保证一分钟内请求数不超过 limit。"""
    def __init__(self, limit=240):          # 留出余量,低于 300/分钟
        self.limit, self.stamps, self.lock = limit, [], threading.Lock()

    def wait(self):
        while True:
            with self.lock:
                now = time.time()
                self.stamps = [t for t in self.stamps if now - t < 60]
                if len(self.stamps) < self.limit:
                    self.stamps.append(now)
                    return
                sleep_for = 60 - (now - self.stamps[0])
            time.sleep(max(sleep_for, 0.05))

Najczystszą metodą diagnostyczną jest wykonanie minimalnego zapytania za pomocą curla, niezależnie od kodu biznesowego. Opcja -i pozwala zobaczyć zarówno wiersz statusu, jak i nagłówki odpowiedzi:

curl -i https://api.wushenchaapi.com/v1/chat/completions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"uncensored","max_tokens":20,"messages":[{"role":"user","content":"ping"}]}'

Jeśli curl działa, a kod biznesowy nie, problem leży w Twoim kodzie lub środowisku (proxy, zmienne środowiskowe, kodowanie). Jeśli curl również nie działa, sprawdź klucz API, stan konta i sieć.

Dlaczego limit ustawiono na 240, a nie 300? W przypadku wdrożeń wieloinstancyjnych każda instancja stosuje własny limit, co może prowadzić do przekroczenia łącznego limitu. Dodatkowo retry’e zużywają dodatkową pulę. Zostawienie 20% marginesu bezpieczeństwa jest rozsądnym podejściem. Jeśli masz wiele instancji, podziel limit równomiernie między nie lub użyj współdzielonego licznika do koordynacji.

Lista kontrolna debugowania

  1. Sprawdź error.code w ciele odpowiedzi, a nie tylko kod statusu HTTP.
  2. 401: prefiks klucza, zmienne środowiskowe, czy klucz został wygenerowany ponownie.
  3. 400: czy JSON jest poprawny, czy prompt + max_tokens nie przekraczają 100,000 tokenów, czy ciało zapytania nie przekracza 8 MB.
  4. 402: stan konta i ważność okresu próbnego.
  5. 403: czy prompt i historia zawierają zablokowane treści.
  6. 404: czy ścieżka to /v1/chat/completions lub /v1/models.
  7. 429: czy wiele instancji współdzieli jeden klucz API, czy zastosowano limit po stronie klienta.
  8. 503: Czy zastosowano backoff retry, czy odstępy między zapytaniami wynoszą co najmniej kilka sekund.
  9. Timeout: czy limit czasu jest wystarczający, czy można przełączyć się na strumieniowanie.
  10. Jeśli wykluczono powyższe przyczyny: powtórz błąd za pomocą minimalnego zapytania curl.

Jeśli dopiero zaczynasz, przeczytaj przewodnik po integracji. Więcej parametrów znajdziesz w dokumentacji.

Jak korzystać z listy kontrolnej: przy wystąpieniu problemu eliminuj przyczyny kolejno od góry do dołu, nie przeskakuj punktów. Większość „dziwnych” błędów wynika z pierwszych czterech pozycji.

Dodatkowa rada: zapisuj wnioski z debugowania w dokumentacji zespołu. Dzięki temu przy kolejnym wystąpieniu tego samego błędu będziesz mógł go szybko zidentyfikować.

Najczęściej zadawane pytania

Jak długo czekać na ponowne wysłanie zapytania po otrzymaniu 503?

Wystarczy kilka sekund. Zalecamy oczekiwanie 1–2 sekund przy pierwszym ponownym wysłaniu, następnie stosowanie wykładniczego wzrostu opóźnienia z losowym drżeniem i ustawienie maksymalnej liczby retry’i.

Dlaczego moje zapytania zwracają błąd 402?

Stan konta został wyczerpany lub wygasł 7-dniowy okres próbny. Po doładowaniu przedpłaconego kredytu dostęp zostanie przywrócony; kredyt nie wygasa.

Czy błąd 403 content_blocked można ominąć poprzez zmianę promptu?

Nie próbuj tego. Treści o charakterze seksualnym z udziałem małoletnich są zawsze blokowane, niezależnie od kontekstu, w tym w powieściach i grach RPG. Prawidłowe treści dla dorosłych nie powinny wywoływać tego błędu.

Czy limit 429 dotyczy konta, czy klucza API?

Limit wynosi 300 zapytań na minutę na każdy klucz API. Ponieważ każde konto posiada tylko jeden klucz, przy współdzieleniu go przez wiele usług należy stosować wspólny limit zapytań.

Wypełnij formularz, aby uzyskać klucz

Utwórz konto, skopiuj klucz i zmień Base URL. Konfiguracja jest bardzo prosta.