Punti chiave
- Il testo proviene dal client, quindi riproduci la chiamata con curl per vedere il corpo dell'errore reale e lo stato.
- HTTP 429 con codice rate_limited o concurrency è la causa più comune su un account attivo, e uno stream mantiene la sua slot fino alla fine.
- Controlla URL base, chiave, ID modello uncensored, dimensione del corpo (8 MB) e token totali (100.000) prima di qualsiasi altra cosa.
- Riprova solo per 429 e cadute di rete, attendi Retry-After e mantieni la concorrenza sotto il limite della chiave.
Cosa dice realmente il messaggio
Se hai cercato errore sconosciuto dallo streaming LLM, probabilmente stai guardando un toast o una riga rossa in un'interfaccia chat, un plugin editoriale o un framework agent. La dicitura proviene da quel client. Significa che l'app ha richiesto una risposta in streaming, qualcosa è andato storto prima o durante lo streaming, e l'app non sapeva come descriverlo. L'API segnala i problemi con uno stato HTTP e un corpo di errore JSON, e il client ha scartato quel dettaglio.
Questa è una buona notizia, perché significa che puoi recuperare il dettaglio. Invia la stessa richiesta al di fuori del client, leggi la riga di stato e il corpo, e la causa è di solito ovvia entro uno o due tentativi. Il resto di questa pagina passa attraverso le cause nell'ordine in cui tendono a verificarsi su questa API, poi ti offre un piccolo client di streaming che stampa l'errore reale invece di nasconderlo.
Una cosa da tenere a mente fin dall'inizio: una richiesta in streaming ha due punti di fallimento. Può fallire prima del primo byte, quando il server rifiuta la richiesta (chiave errata, URL errato, un limite). O può fallire nel mezzo, quando la connessione cade dopo che è già arrivato del testo. Le soluzioni sono diverse, quindi nota quale delle due vedi. Se la risposta non inizia mai, guarda le sezioni due, tre e quattro. Se inizia e poi si ferma, guarda la sezione sui proxy e i timeout.
Controlla prima l'URL base, la chiave e il modello
La maggior parte degli errori di streaming su una configurazione nuova deriva da tre piccoli errori. Ci vuole un minuto per escluderli.
- URL base. Deve essere
https://api.uncensoredllmhub.com/v1, includendo/v1e senza un/chat/completionsfinale. I client aggiungono il percorso da soli. Se incolli l'endpoint completo in un campo che si aspetta un base, il client richiede un percorso che non esiste e segnala un errore vago. - Chiave. L'intestazione è
Authorization: Bearer YOUR_KEY. Uno spazio errato, una nuova riga copiata con la chiave, o una chiave di un altro servizio falliscono allo stesso modo. Crea o copia di nuovo la chiave dalla pagina delle chiavi API se non sei sicuro. - ID modello. L'unico modello è
uncensored. I client che offrono un menu a discesa spesso precompilano un nome di un altro provider. Digita l'ID a mano, e chiamaGET /v1/modelsse vuoi confermare cosa elenca il server.
Un modo rapido per testare tutti e tre insieme è la chiamata models. Non fa streaming, quindi separa un problema di connessione o chiave da un problema di streaming:
curl -i https://api.uncensoredllmhub.com/v1/models -H "Authorization: Bearer $API_KEY"
Se restituisce un elenco normale, l'URL e la chiave sono corretti e puoi smettere di sospettare di loro. Se fallisce, correggi il problema prima di toccare qualsiasi cosa relativa allo streaming. Controlla anche che il tuo account abbia credito: l'API invia il tuo saldo residuo nell'header X-Balance-USD delle risposte, il che è utile quando una chiave smette improvvisamente di funzionare dopo un uso intenso. La pagina prezzi spiega come ricaricare, e i nuovi account possono richiedere un credito di prova di $0,50 dalla pagina delle chiavi.
Limiti di velocità e lo stream che mantiene la sua slot
La causa successiva più comune è HTTP 429. Ci sono tre varianti, e il tuo client le raggrupperà tutte nello stesso messaggio poco utile.
| Segnale | Significato | Cosa fare |
|---|---|---|
429, codice rate_limited | Troppe richieste al minuto per la chiave | Rallenta; una chiave completa permette 300 al minuto, una chiave di prova 60 |
429, codice concurrency | Troppe richieste in esecuzione contemporaneamente | Accodale; una chiave completa permette 8 alla volta, una chiave di prova 2 |
429 con Retry-After: 5 | Sovraccarico temporaneo lato servizio | Attendi 5 secondi, poi riprova |
Il limite di concorrenza è quello che sorprende le persone, a causa del funzionamento dello streaming. Una richiesta in streaming occupa la sua slot fino alla fine dello stream, non fino all'arrivo del primo token. Se la tua app apre uno stream per ogni messaggio e non chiude mai quello vecchio, ad esempio perché l'utente ha navigato via e l'interfaccia utente ha dimenticato di cancellare la richiesta, quelle slot rimangono occupate. Su una chiave di prova con un limite di 2, due stream abbandonati sono sufficienti per far fallire il terzo messaggio.
I sintomi sono coerenti. I primi pochi messaggi funzionano, poi iniziano gli errori, poi tutto funziona di nuovo dopo un breve attesa. Se questo corrisponde, interrompi gli stream che non ti servono più (un AbortController nel browser, chiudendo la risposta in un server), e limita il numero di chiamate parallele nel tuo codice. Gli agent sono i colpevoli più comuni: un pianificatore che avvia dieci chiamate di funzioni contemporaneamente colpirà il limite su una chiave di prova immediatamente.
Gli header della risposta ti aiutano a vedere dove sei. X-RateLimit-Limit-Requests e X-RateLimit-Limit-Concurrency mostrano i limiti applicati alla chiave che hai usato, e X-Request-Id identifica la chiamata se devi chiedere assistenza a riguardo.
Dimensione della richiesta e lunghezza del contesto
Una richiesta può anche essere rifiutata per essere troppo grande. Due numeri sono importanti. Il corpo può essere al massimo 8 MB, e il prompt più il completamento devono adattarsi in una finestra di contesto di 100.000 token. Le interfacce chat che inviano di nuovo l'intera conversazione ad ogni turno colpiscono questi limiti lentamente e poi tutte insieme: la chat funziona per un'ora, poi un messaggio lungo o un file incollato la supera, e ogni turno successivo fallisce perché la cronologia è ancora nella richiesta.
Se l'errore inizia dopo una sessione lunga, testa con una nuova conversazione breve. Se questo funziona, la cronologia è la causa. Riducila eliminando i turni vecchi, riassumendoli in un messaggio, o iniziando una chat nuova. I documenti incollati di grandi dimensioni sono l'altra causa scatenante. Un file di testo di poche centinaia di kilobyte va bene, ma i blob base64 o i log molto grandi possono raggiungere 8 MB più velocemente del previsto.
Non devi impostare max_tokens, poiché il completamento può usare tutto ciò che rimane della finestra. Se lo imposti, assicurati che i token del prompt più max_tokens rimangano sotto 100.000. Un client che imposta in modo fisso un grande max_tokens sopra una lunga cronologia può spingere la somma oltre la finestra anche quando il prompt da solo sembra a posto.
Proxy, buffering e timeout
Lo streaming utilizza eventi inviati dal server: una risposta HTTP a lunga durata che consegna piccoli blocchi man mano che vengono prodotti. Qualsiasi cosa tra te e l'API che attende l'intera risposta prima di inoltrarla la romperà. Il risultato è o un lungo silenzio seguito da un blocco, o un timeout e l'errore generico.
Cerca questi nella tua configurazione:
- Proxy inversi. Se instradi l'API attraverso nginx o un proxy simile, disattiva il buffering della risposta per quella posizione, e aumenta il timeout di lettura sopra la risposta più lunga che ti aspetti. Le risposte lunghe da una finestra di 100.000 token possono richiedere un po' di tempo.
- Proxy aziendali o antivirus. Alcuni ispezionano il traffico HTTPS e trattengono il corpo. Testa da un hotspot telefonico per escludere questo.
- Funzioni serverless. Molte piattaforme limitano il tempo di esecuzione o memorizzano le risposte a meno che tu non opti per lo streaming. Se lo stream muore allo stesso numero di secondi ogni volta, un limite di piattaforma è la causa probabile.
- Estensioni del browser e VPN. Raro, ma possono interrompere le connessioni inattive.
L'indizio che punta qui è un errore nel mezzo di una risposta, con lo stesso tempo di taglio su ogni tentativo. Un limite di richieste rifiuterebbe la richiesta all'inizio, quindi un taglio a metà streaming che accade sempre, ad esempio, a 30 secondi non è quasi mai un limite.
Un client che mostra l'errore reale
Usa questo quando vuoi la verità invece del messaggio amichevole. Cattura le eccezioni SDK OpenAI, stampa lo stato e il corpo dell'errore, e legge l'indicazione di retry quando c'è.
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)
La stessa idea in Node, con un segnale di abort così che gli stream abbandonati rilascino il loro slot di concorrenza:
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
E una chiamata curl grezza, che rimuove ogni client dal contesto. -N disattiva il buffering interno di curl e -i stampa la riga di stato e gli header, incluso 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."}]}'
Se curl trasmette il testo bene e la tua app no, l'API è sana e il problema risiede nell'app, nel suo proxy o nelle sue impostazioni. Se curl mostra un 429 o un altro stato, ora hai la causa esatta.
Regole di retry che non peggiorano le cose
I retry aiutano con problemi transitori e peggiorano con quelli permanenti. Una politica breve ti tiene fuori dai guai.
- Riprova per 429 e connessioni interrotte. Attendi
Retry-Afterquando è presente, altrimenti aumenta il backoff per alcuni secondi e aggiungi un po' di jitter così i lavoratori paralleli non riprovano in sincrono. - Non ritentare i fallimenti di autenticazione o le richieste di dimensioni eccessive. Il risultato non cambierà, e ogni ritentativa aggiunge solo rumore.
- Limita i tentativi a tre o quattro, poi mostra all'utente il testo dell'errore reale.
- Limita il tuo parallelismo sotto il limite della chiave. Un semaforo di 6 su una chiave completa lascia spazio per un secondo tool che usa la stessa chiave.
- Se uno stream si rompe a metà, mantieni il testo parziale. Invia di nuovo con quel testo come messaggio dell'assistente e chiedi al modello di continuare, invece di rigenerare da zero.
Le richieste fallite o rifiutate non vengono addebitate, quindi il debug con chiamate di test ripetute non consuma il tuo credito. Le chiamate riuscite vengono fatturate a $0,15 per 1M token di input e $0,50 per 1M token di output, e uno stream parziale che si completa normalmente è semplicemente una risposta breve. Più dettagli sul formato della richiesta sono nella documentazione API.
Se hai fatto tutto quanto sopra e vedi ancora il messaggio, invia l'X-Request-Id di una chiamata fallita alla pagina di supporto, con l'ora del tentativo e se il fallimento è venuto prima o dopo il primo token. Quelle informazioni sono sufficienti per tracciare cosa è successo.
