Routing API LLM affidabile: timeout, nuovi tentativi e fallback del modello senza regressioni semantiche
Un'architettura pratica per classificare gli errori dell'API LLM, applicare un budget di latenza, selezionare modelli di fallback compatibili, proteggere gli effetti collaterali e convalidare ogni risposta accettata.
Una richiesta di fallback non ha esito positivo semplicemente perché un altro modello ha restituito HTTP 200. La sostituzione potrebbe superare il budget di latenza originale, omettere i campi JSON richiesti, chiamare uno strumento diverso o produrre una risposta con una semantica sostanzialmente diversa. Un routing API LLM affidabile richiede quindi più di un elenco ordinato di modelli: richiede un contratto, un classificatore di errori, una politica di tentativi limitati e una convalida prima dell'accettazione.
La regola centrale è semplice: riprovare solo quando l'errore è plausibilmente temporaneo e ricorrere solo quando il percorso successivo può ancora soddisfare il contratto di richiesta originale.
Definire il contratto di instradamento prima di scegliere i modelli
Inizia descrivendo cosa deve fornire una risposta efficace. Questo contratto di instradamento deve essere leggibile dalla macchina e allegato a ciascun carico di lavoro o classe di richiesta.
{ "carico di lavoro": "invoice_extraction", "modalità": ["testo", "immagine"], "max_input_tokens": 50000, "requires_tools": falso, "output_strutturato": { "richiesto": vero, "schema_id": "fattura-v3", "severo": vero }, "allowed_model_classes": ["estrazione documenti"], "max_cost_usd": 0,08, "scadenza_ms": 8000 }
Il contratto dovrebbe coprire le modalità richieste, la capacità del contesto, il supporto degli strumenti, il comportamento dell'output strutturato, le classi di modelli accettabili, il costo massimo e la scadenza end-to-end. Aggiungi vincoli specifici dell'applicazione dove necessario, come regioni consentite, lunghezza minima dell'output o un motivo di fine richiesto.
Raccomandazione: mantieni gruppi di percorsi separati e testati per testo semplice, output vincolato dallo schema, utilizzo di strumenti, visione e richieste con contesto lungo. Un modello che rappresenta un testo di riserva accettabile non è automaticamente un fallback accettabile per la chiamata di strumenti o l'input di immagini.
Classificare l'errore prima di agire
Errori di autenticazione, richieste non valide, limiti di velocità e guasti del server richiedono risposte diverse. Trattare ogni risposta non riuscita come riprovabile spreca capacità e può nascondere difetti.
Fatto: le richieste con velocità limitata non riuscite possono comunque essere conteggiate ai fini dei limiti del fornitore. Tentativi immediati aggressivi potrebbero quindi accentuare la limitazione invece di risolverla. I nuovi tentativi consumano inoltre capacità aggiuntiva durante un'interruzione e le policy di ripetizione a diversi livelli dell'applicazione possono moltiplicare il carico risultante.
Raccomandazione: lascia che sia un livello a gestire i tentativi di generazione del modello. In un'architettura tipica, il gateway API AI è il proprietario giusto perché rileva lo stato del percorso, la cronologia dei tentativi, la latenza e i costi. Disattiva i tentativi automatici nei client di livello inferiore, ove possibile, o conteggiali esplicitamente nello stesso budget di tentativi.
Spendi un budget per la latenza end-to-end
I timeout per tentativo non sono sufficienti. Tre tentativi con un timeout di cinque secondi possono trasformare un'operazione prevista di cinque secondi in una risposta di quindici secondi, prima che vengano inclusi il backoff e la convalida.
Registra una scadenza assoluta quando la richiesta entra nel gateway. Prima di ogni tentativo, calcola il tempo rimanente:
rimanente = scadenza - ora_corrente
richiesto = indennità_connessione + indennità_generazione + indennità_validazione
se rimanente < richiesto:
stop_without_launching_another_attempt
Per una scadenza di otto secondi, un'allocazione iniziale ragionevole potrebbe riservare 300 ms per il lavoro del gateway e la convalida finale, consentire fino a 4,5 secondi per il percorso principale e conservare circa 3,2 secondi per un fallback. Questi valori sono un esempio, non un punto di riferimento. Devono derivare dalle distribuzioni di latenza misurate per i fornitori, i modelli, le regioni e le dimensioni di output effettivi.
Utilizza backoff esponenziale limitato con jitter per tentativi temporanei:
ritardo = casuale(0, min(cap, base * 2^retry_index))
I suggerimenti per i nuovi tentativi del fornitore, ad esempio il valore riprova dopo, dovrebbero avere la precedenza quando rientrano nella scadenza rimanente. Arrestarsi dopo un numero limitato di tentativi. Una policy comune prevede un tentativo principale più un fallback, con un tentativo facoltativo sullo stesso percorso solo in caso di errore di connessione anticipato che non avrebbe potuto generare output fatturabile.
Compromesso: il fallback sequenziale migliora la disponibilità ma aumenta la latenza della coda. Le richieste parallele o coperte possono ridurre la latenza durante i rallentamenti, ma consumano più capacità e possono comportare addebiti per più generazioni riuscite. La copertura dovrebbe essere limitata ai carichi di lavoro critici in termini di latenza e privi di effetti collaterali, con cancellazione e controllo dei costi.
Seleziona i fallback in base alla capacità, non al ranking
Una tabella di fallback dovrebbe codificare la compatibilità anziché un ordine di preferenza globale. Filtra i percorsi candidati in base al contratto prima di considerare integrità, latenza o prezzo.
candidati = percorsi
.filter(supporta_modalità_richieste)
.filter(limite_contesto >= dimensione_input_stimata)
.filter(supports_required_tools)
.filter(supports_requested_schema_mode)
.filter(classe_modello in classi_modello_consentite)
.filter(costo_stimato <= budget_costo_rimanente)
.filter(non_temporaneamente_soppresso)
selezionato = rango (candidati, salute, latenza, costo)
Il supporto dell'output strutturato merita un test esplicito. Anche quando due route pubblicizzano la generazione vincolata dallo schema, potrebbero supportare diversi sottoinsiemi di schemi JSON o interpretare i casi limite in modo diverso. Allo stesso modo, i modelli compatibili con gli strumenti possono differire nella selezione dello strumento, nella costruzione degli argomenti e nel comportamento delle chiamate parallele.
Fatto: cambiare famiglia di modelli può preservare la disponibilità del trasporto modificando allo stesso tempo lo stile, la qualità del ragionamento, il comportamento di sicurezza, la tokenizzazione e la selezione degli strumenti. Il successo dell'HTTP non è una prova di equivalenza semantica.
Previsione: con l'espansione dei cataloghi di modelli, le policy di routing della produzione utilizzeranno sempre più profili di capacità con versione e test di accettazione specifici del carico di lavoro invece di elenchi di modelli statici. Considera questo come un'indicazione di progettazione, non una garanzia sul comportamento del fornitore.
Convalida la risposta prima di accettarla
Esegui ogni risposta, inclusa la risposta primaria, attraverso la stessa pipeline di accettazione. La convalida dovrebbe avvenire prima che il risultato venga memorizzato nella cache, fatturato internamente come riuscito o passato a un esecutore dello strumento.
- Conferma che il trasporto è stato completato e che la busta di risposta può essere analizzata.
- Controlla il motivo della fine e rifiuta il troncamento quando è richiesto l'output completo.
- Convalida l'output strutturato rispetto allo schema originale.
- Verifica i campi obbligatori, i valori enum e le invarianti dell'applicazione.
- Consenti solo nomi di strumenti registrati e convalida gli argomenti rispetto a ciascuno schema di strumenti.
- Applicare controlli semantici specifici del carico di lavoro laddove la falsa accettazione sarebbe costosa.
Per l'estrazione delle fatture, i controlli semantici potrebbero richiedere un totale non negativo, un codice valuta supportato e totali delle voci entro una tolleranza esplicitamente definita. Per la classificazione, richiedere un'etichetta dal set consentito. Per la generazione del codice, l'analisi o la compilazione potrebbero essere appropriate. Questi controlli non dimostrano la qualità, ma impediscono che le prevedibili violazioni contrattuali vengano trattate come successi.
Non riparare silenziosamente ogni risposta non valida. La normalizzazione deterministica, come la rimozione degli spazi bianchi circostanti innocui, può essere accettabile. Indovinare campi finanziari mancanti o riscrivere gli argomenti dello strumento cambia il significato del modello e dovrebbe innescare il rifiuto o la revisione umana.
Tentativi di generazione separati dagli effetti collaterali
Le richieste LLM utilizzano comunemente HTTP POST, che non è intrinsecamente idempotente. Ancora più importante, una risposta del modello può avviare un’azione esterna come l’addebito di un metodo di pagamento, l’invio di un messaggio, la creazione di un ticket o la modifica dell’infrastruttura. Riprovare la generazione e riprodurre l'azione sono decisioni separate.
Assegna un ID operazione al limite dell'applicazione e un ID tentativo a ogni chiamata del modello. Mantieni lo stato di esecuzione dello strumento rispetto a una chiave deterministica, ad esempio:
chiave_esecuzione = ID_operazione + nome_strumento + hash_argomenti_canonici
Prima di eseguire uno strumento, controlla se la chiave è in sospeso, completata o non riuscita. Restituisce il risultato memorizzato per un'esecuzione completata anziché eseguirla nuovamente. Per le operazioni i cui argomenti possono cambiare legittimamente, è richiesta l'approvazione a livello di applicazione o un nuovo ID operazione.
Un timeout ambiguo richiede una gestione speciale. Se la connessione fallisce dopo la trasmissione di una richiesta, il gateway potrebbe non sapere se è avvenuta la generazione. Una chiave di idempotenza supportata dal provider può essere utile, se disponibile. Altrimenti, registra il risultato come sconosciuto e applica una policy di riproduzione specifica del carico di lavoro invece di dare per scontato che non sia successo nulla.
Elimina percorsi non integri ed esponi ogni tentativo
Un interruttore automatico o una soppressione temporanea dell'integrità impedisce a ogni nuova richiesta di ritrovare lo stesso percorso in errore. Aprire il circuito dopo un tasso di errore definito o una soglia di guasto consecutivo, quindi ammettere sonde limitate in uno stato semiaperto. Ottimizza le soglie in base al percorso e alla classe di errore in modo che una richiesta del client in formato errato non possa far sembrare non disponibile un modello integro.
Registra un evento a livello di richiesta e un evento per tentativo. I campi utili includono ID operazione, ID tentativo, provider e modello selezionati, classe di errore, codice di stato, latenza, conteggi di token, costo stimato, motivo del fallback, risultato della convalida, stato del circuito e risultato finale. Redigere o eseguire l'hashing di prompt, output e argomenti dello strumento in base ai requisiti di sensibilità e conservazione.
I parametri operativi utili includono tasso di fallback, tentativi per richiesta completata, tasso di esaurimento della scadenza, tasso di rifiuto della convalida, risultati ambigui, costo per risposta accettata e latenza per percorso finale. Un tasso di successo HTTP in aumento insieme a un tasso di rifiuto della convalida in aumento è un avvertimento che la disponibilità del trasporto sta mascherando i fallimenti dei contratti.
Elenco di controllo per l'implementazione della produzione
- Definire un contratto di routing con versione per ogni classe di carico di lavoro.
- Mappa gli errori del fornitore in categorie permanenti, temporanee, incompatibili, con risposte non valide e ambigue.
- Scegli un proprietario per i nuovi tentativi e limita il numero totale di tentativi.
- Propagare una scadenza assoluta tramite gateway, client del fornitore, convalida ed esecuzione dello strumento.
- Crea gruppi di fallback con funzionalità testate anziché una catena di modelli globale.
- Convalida schemi, chiamate agli strumenti, motivi di finitura e invarianti di dominio.
- Deduplica gli effetti collaterali con le chiavi operative ed di esecuzione.
- Aggiungi la soppressione del percorso con sonde semiaperte delimitate.
- Registra la latenza a livello di tentativo, i token, i costi, gli errori e i risultati di accettazione.
- Timeout di inserimento, 429, errori 5xx selezionati, JSON non valido, overflow del contesto e lentezza nella gestione temporanea.
Inizia con un percorso principale e un fallback compatibile per un singolo carico di lavoro a basso rischio. Confronta la qualità, la latenza e i costi delle risposte accettate prima di espandere la policy. L’obiettivo non è il tasso di fallback più alto possibile. È un sistema limitato che restituisce una risposta che soddisfa il contratto originale o fallisce chiaramente prima di causare lavoro duplicato o danni semantici.