Kluczowe punkty
- Tekst pochodzi od klienta, więc odtwórz wywołanie za pomocą curl, aby zobaczyć rzeczywiste ciało błędu i status.
- HTTP 429 z kodem rate_limited lub concurrency to najczęstsza przyczyna na zatłoczonym koncie, a strumień zajmuje swój slot do końca.
- Sprawdź bazowy URL, klucz, ID modelu uncensored, rozmiar ciała (8 MB) i liczbę tokenów (100,000) przed wszystkim innym.
- Ponawiaj tylko przy błędach 429 i utracie połączenia, odczekaj Retry-After i utrzymuj współbieżność poniżej limitu klucza.
Co komunikat mówi Ci naprawdę
Jeśli wyszukałeś unknown error from llm stream learn more, prawdopodobnie widzisz powiadomienie (toast) lub czerwoną linię w interfejsie czatu, wtyczce edytora lub frameworku agenta. Słownictwo pochodzi od tego klienta. Oznacza to, że aplikacja poprosiła o strumieniowaną odpowiedź, coś poszło nie tak przed lub w trakcie strumieniowania, a aplikacja nie wiedziała, jak to opisać. Same API raportuje problemy kodem statusu HTTP i ciałem błędu JSON, a klient odrzucił te szczegóły.
To dobra wiadomość, ponieważ oznacza to, że możesz odzyskać szczegóły. Wyślij to samo zapytanie poza klientem, odczytaj linię statusu i ciało, a przyczyna będzie zwykle jasna po jednej lub dwóch próbach. Reszta tej strony omawia przyczyny w kolejności ich występowania w tym API, a następnie przedstawia prostego klienta strumieniowego, który wypisuje prawdziwy błąd zamiast go ukrywać.
Jedną rzeczą, o której warto pamiętać od początku: zapytanie strumieniowe ma dwa punkty awarii. Może nie powieść się przed pierwszym bajtem, gdy serwer odrzuci zapytanie (zły klucz, zły URL, limit). Może też nie powieść się w trakcie, gdy połączenie zostanie zerwane po dostarczeniu części tekstu. Rozwiązania różnią się, więc zwróć uwagę, który z tych przypadków obserwujesz. Jeśli odpowiedź w ogóle się nie zaczyna, przejdź do sekcji dwóch do czterech. Jeśli się zaczyna, a potem się zatrzymuje, przejdź do sekcji o proxy i limitach czasu.
Sprawdź bazowy URL, klucz i model
Większość błędów strumieniowania przy świeżej konfiguracji wynika z trzech drobnych błędów. Ich wykluczenie zajmuje minutę.
- Bazowy URL. Musi to być
https://api.uncensoredllmhub.com/v1, w tym/v1i bez końcowego/chat/completions. Klienci dołączają ścieżkę sami. Jeśli wkleisz pełny endpoint do pola oczekującego bazowego URL, klient zapyta o ścieżkę, która nie istnieje i zwróci niejasny błąd. - Klucz. Nagłówek to
Authorization: Bearer YOUR_KEY. Przypadkowa spacja, znak nowej linii skopiowany razem z kluczem lub klucz z innej usługi spowodują ten sam błąd. Utwórz lub skopiuj klucz ponownie ze strony klucza API, jeśli masz wątpliwości. - ID modelu. Jedynym modelem jest
uncensored. Klienci oferujący listę rozwijaną często wstępnie wypełniają nazwę od innego dostawcy. Wpisz ID ręcznie i wywołajGET /v1/models, aby potwierdzić, jakie modele serwer wylicza.
Szybkim sposobem przetestowania wszystkich trzech jest wywołanie models. Nie strumieniuje, więc oddziela problem połączenia lub klucza od problemu strumieniowania:
curl -i https://api.uncensoredllmhub.com/v1/models -H "Authorization: Bearer $API_KEY"
Jeśli zwróci normalną listę, URL i klucz są poprawne i możesz przestać je podejrzewać. Jeśli to się nie powiedzie, napraw to przed przystąpieniem do strumieniowania. Sprawdź też, czy Twoje konto ma kredyt: API wysyła Twoje pozostałe saldo w nagłówku X-Balance-USD w odpowiedziach, co jest przydatne, gdy klucz nagle przestaje działać po intensywnym użytkowaniu. Strona cennika wyjaśnia doładowania, a nowe konta mogą uzyskać $0.50 kredytu próbnego ze strony klucza.
Limity szybkości i strumień zajmujący slot
Najczęstszą kolejną przyczyną jest HTTP 429. Istnieją trzy jego odmiany, a Twój klient złoży je wszystkie w ten sam nieprzydatny komunikat.
| Sygnał | Znaczenie | Co zrobić |
|---|---|---|
429, kod rate_limited | Zbyt wiele zapytań na minutę dla klucza | Zwolnij; pełny klucz pozwala na 300 na minutę, klucz próbny na 60 |
429, kod concurrency | Zbyt wiele zapytań wysłanych jednocześnie | Kolejkuj je; pełny klucz pozwala na 8 jednocześnie, klucz próbny na 2 |
429 z Retry-After: 5 | Tymczasowe przeciążenie po stronie usługi | Poczekaj te 5 sekund, a następnie ponów próbę |
Limit współbieżności to ten, który zaskakuje ludzi ze względu na działanie strumieniowania. Zapytanie strumieniowe zajmuje swój slot do końca strumienia, a nie do momentu dostarczenia pierwszego tokena. Jeśli Twoja aplikacja otwiera strumień dla każdej wiadomości i nigdy nie zamyka starego, na przykład dlatego, że użytkownik przeszedł do innego ekranu, a interfejs zapomniał anulować zapytanie, te sloty pozostają zajęte. Przy kluczu próbnym z limitem 2 dwa porzucone strumienie wystarczą, aby trzecia wiadomość zawiodła.
Objawy są spójne. Pierwsze kilka wiadomości działa, potem pojawiają się błędy, a potem wszystko działa ponownie po krótkim oczekiwaniu. Jeśli to pasuje, przerwij strumienie, których już nie potrzebujesz (AbortController w przeglądarce, zamknięcie odpowiedzi na serwerze) i ogranicz liczbę równoległych wywołań we własnym kodzie. Agenci są zwykle winni: planer, który wyśle dziesięć wywołań narzędzi jednocześnie, natychmiast uderzy w limit na kluczu próbnym.
Nagłówki odpowiedzi pomogą Ci zobaczyć, na czym stoisz. X-RateLimit-Limit-Requests i X-RateLimit-Limit-Concurrency pokazują limity obowiązujące dla użytego klucza, a X-Request-Id identyfikuje wywołanie, jeśli będziesz potrzebować zapytać wsparcie o to.
Rozmiar zapytania i długość kontekstu
Zapytanie może zostać również odrzucone za zbyt duży rozmiar. Liczą się dwie liczby. Ciało może mieć maksymalnie 8 MB, a prompt plus uzupełnienie muszą zmieścić się w oknie kontekstu 100,000 tokenów. Front-endy czatu, które wysyłają całą rozmowę przy każdym obrocie, uderzają w te limity powoli, a potem nagle: czat działa godzinę, potem jedna długa wiadomość lub wklejony plik go przeciąża, i każde kolejne zapytanie się nie powiedzie, ponieważ historia nadal znajduje się w zapytaniu.
Jeśli błąd zaczyna się po długiej sesji, przetestuj krótką nową rozmowę. Jeśli to działa, przyczyną jest historia. Przytnij ją poprzez usunięcie starych obrotów, podsumowanie ich w jednej wiadomości lub rozpoczęcie nowej rozmowy. Duże wklejone dokumenty to inny wyzwalacz. Plik tekstowy o wielkości kilkuset kilobajtów jest OK, ale bloby base64 lub bardzo duże logi mogą osiągnąć 8 MB szybciej, niż się spodziewasz.
Nie musisz ustawiać max_tokens, ponieważ uzupełnienie może użyć tego, co zostało z okna. Jeśli je ustawisz, upewnij się, że tokeny promptu plus max_tokens pozostają poniżej 100,000. Klient, który na sztywno ustawia duży max_tokens na długiej historii, może przekroczyć okno nawet wtedy, gdy sam prompt wygląda OK.
Proxy, buforowanie i limity czasu
Strumieniowanie używa zdarzeń wysłanych przez serwer: długotrwałej odpowiedzi HTTP, która dostarcza małe fragmenty w miarę ich powstawania. Cokolwiek między Tobą a API, co czeka na całą odpowiedź przed jej przesłaniem dalej, to zepsuje. Rezultatem jest albo długa cisza, po której następuje wybuch danych, albo timeout i ogólny błąd.
Szukaj tego we własnej konfiguracji:
- Proxy odwrotne. Jeśli kierujesz API przez nginx lub podobne proxy, wyłącz buforowanie odpowiedzi dla tej lokalizacji i podnieś timeout odczytu powyżej najdłuższej odpowiedzi, jakiej się spodziewasz. Długie odpowiedzi z okna 100,000 tokenów mogą zająć trochę czasu.
- Proxy korporacyjne lub antywirusowe. Niektóre sprawdzają ruch HTTPS i zatrzymują ciało. Przetestuj z hotspotu telefonicznego, aby to wykluczyć.
- Funkcje serverless. Wiele platform ogranicza czas wykonania lub buforuje odpowiedzi, chyba że wybierzesz strumieniowanie. Jeśli strumień umiera po tej samej liczbie sekund za każdym razem, limit czasu platformy jest prawdopodobną przyczyną.
- Rozszerzenia przeglądarki i VPN-y. Rzadkie, ale mogą przerywać połączenia bezczynne.
Podpowiedzią wskazującą na to jest błąd w środku odpowiedzi, z tym samym czasem odcięcia przy każdej próbie. Limit szybkości odrzuciłby zapytanie na początku, więc odcięcie w trakcie strumieniowania, które zawsze dzieje się np. po 30 sekundach, to prawie nigdy nie limit.
Klient pokazujący prawdziwy błąd
Użyj tego, gdy chcesz prawdy zamiast uprzejmego komunikatu. Łapie wyjątki SDK OpenAI, wypisuje status i ciało błędu oraz odczytuje wskazówkę ponownej próby, jeśli jest.
import time
from openai import OpenAI, APIConnectionError, APIStatusError, RateLimitError
client = OpenAI(
base_url="https://api.uncensoredllmhub.com/v1",
api_key="YOUR_API_KEY",
)
def stream_once(messages):
stream = client.chat.completions.create(
model="uncensored",
messages=messages,
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if getattr(chunk, "usage", None):
print("\n[usage]", chunk.usage)
messages = [{"role": "user", "content": "Write two sentences about harbours."}]
for attempt in range(4):
try:
stream_once(messages)
break
except RateLimitError as e:
wait = int(e.response.headers.get("retry-after", 5))
print("429:", e.body, "- waiting", wait, "s")
time.sleep(wait)
except APIStatusError as e:
print("status", e.status_code, e.body)
print("request id:", e.response.headers.get("x-request-id"))
break
except APIConnectionError as e:
print("connection problem:", e)
time.sleep(2)
Ta sama koncepcja w Node, z sygnałem anulowania, aby porzucone strumienie zwolniły swój slot:
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.uncensoredllmhub.com/v1",
apiKey: process.env.API_KEY,
});
const controller = new AbortController();
try {
const stream = await client.chat.completions.create(
{
model: "uncensored",
messages: [{ role: "user", content: "Write two sentences about harbours." }],
stream: true,
},
{ signal: controller.signal }
);
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
} catch (err) {
console.error("status:", err.status, "body:", err.error);
}
// call controller.abort() when the user leaves the page
A surowe wywołanie curl, które usuwa każdego klienta z obrazu. -N wyłącza buforowanie curla, a -i wypisuje linię statusu i nagłówki, w tym X-Request-Id:
curl -N -i https://api.uncensoredllmhub.com/v1/chat/completions -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{"model":"uncensored","stream":true,"messages":[{"role":"user","content":"Say hello."}]}'
Jeśli curl strumieniuje tekst dobrze, a Twoja aplikacja nie, API jest zdrowe, a problem leży w aplikacji, jej proxy lub jej ustawieniach. Jeśli curl pokazuje 429 lub inny status, masz teraz dokładną przyczynę.
Zasady ponawiania, które nie pogarszają sytuacji
Ponawianie pomaga przy problemach przejściowych, a szkodzi przy stałych. Krótka strategia ponawiania uchroni Cię przed kłopotami.
- Ponów 429 i utracone połączenia. Odczekaj
Retry-After, jeśli jest obecny, w przeciwnym razie zwolnij tempo na kilka sekund i dodaj losowy jitter, aby wątki równoległe nie powtarzały wywołań synchronicznie. - Nie powtarzaj niepowodzeń uwierzytelniania lub zbyt dużych zapytań. Wynik się nie zmieni, a każde ponowienie tylko dodaje szumu.
- Ogranicz próby do trzech lub czterech, a następnie pokaż użytkownikowi prawdziwy tekst błędu.
- Ogranicz własną równoległość poniżej limitu klucza. Semafor o wartości 6 na pełnym kluczu zostawia miejsce na drugie użycie narzędzia tym samym kluczem.
- Jeśli strumień się zerwie w połowie, zachowaj częściowy tekst. Wyślij go ponownie z tym tekstem jako wiadomością asystenta i poproś model o kontynuację, zamiast generować od nowa.
Nieudane lub odrzucone zapytania nie są naliczane, więc debugowanie za pomocą powtórzonych wywołań testowych nie wyczerpuje kredytu. Udane wywołania są rozliczane po $0.15 za 1M tokenów wejściowych i $0.50 za 1M tokenów wyjściowych, a częściowy strumień, który normalnie się kończy, jest po prostu krótką odpowiedzią. Więcej szczegółów na temat formatu zapytania znajdziesz w dokumentacji API.
Jeśli zrobiłeś wszystko powyżej i nadal widzisz komunikat, wyślij X-Request-Id nieudanego wywołania na stronę wsparcia, wraz z czasem próby i tym, czy niepowodzenie nastąpiło przed czy po pierwszym tokenie. Te informacje wystarczają do prześledzenia tego, co się stało.
