Capitolo 5 — Robustezza: il codice che assume il fallimento
C'è una differenza culturale tra il codice che funziona sul tuo computer e il codice che funziona nel mondo: il secondo assume che tutto possa fallire. Le chiamate API falliscono — non spesso, ma abbastanza: il servizio è sovraccarico (errore 529), hai superato il tuo limite di richieste al minuto (errore 429, rate limit), la rete singhiozza, una risposta non arriva mai. Il codice ingenuo muore alla prima di queste; il codice professionale le mette in conto.
Il kit di sopravvivenza ha quattro pezzi. Il retry con backoff esponenziale: sugli errori transitori non riprovi subito a raffica (peggiori il sovraccarico che ti ha respinto) — aspetti un secondo, poi due, poi quattro, con un tetto ai tentativi. Il timeout: ogni chiamata ha un tempo massimo di attesa, perché una richiesta appesa per sempre blocca tutto il programma. Il rispetto dei limiti: se devi fare mille chiamate, le metti in coda a ritmo sostenibile invece di spararle insieme. E il logging: ogni chiamata lascia una riga — quando, quale modello, quanti token dentro e fuori, quanto ci ha messo, com'è finita. Oggi il log ti sembra burocrazia; al primo problema in produzione sarà l'unica lanterna, e al capitolo 6 sarà anche il tuo contatore dei costi.
Merita una menzione la Batch API: per i lavori non urgenti — elaborare diecimila documenti stanotte, non adesso — i provider offrono una modalità differita a metà prezzo. Quando il volume cresce, metà prezzo è tanta roba.
Il modo giusto di pensarla: avvolgi tutto in una tua funzione chiamata_robusta() — retry, timeout, log dentro — e da lì in poi il resto del tuo codice chiama quella e vive sereno. La scrivi una volta, la usi per sempre.
Un'avvertenza prima di scriverla: gli SDK ufficiali fanno già qualche retry per conto tuo sugli errori transitori, e rispettano l'intestazione retry-after quando il server indica quanto aspettare. Se aggiungi il tuo ciclo sopra il loro ottieni due strati annidati che moltiplicano i tentativi: decidi chi comanda, e se gestisci tu i retry disattiva quelli dell'SDK (in Python, max_retries=0 alla creazione del client).
L'esperimento del giorno. Scrivi chiamata_robusta() e mettila alla prova con cattiveria: input enormi, richieste a raffica, la rete staccata a metà. Guarda il log raccontare la storia: tentativi, attese, esiti. Quel file di testo noioso è la differenza tra un esperimento e uno strumento.
Fonti
- Batch processing — Anthropic (Message Batches API) — come si spedisce un lavoro differito a metà prezzo: formato della richiesta, limiti, tempi e recupero dei risultati.
- OpenAI Cookbook — codice pronto per il retry con backoff esponenziale e per stare dentro i rate limit senza far cadere il programma.
- API errors — Anthropic — la fonte primaria su quali errori riprovare (429, 500, 529, 504) e quali no, sull'intestazione
retry-after, sui retry automatici dell'SDK e sullo streaming per le richieste lunghe. - Exponential Backoff and Jitter — AWS Architecture Blog — il testo classico sul perché al backoff serve una componente casuale: senza jitter i client riprovano tutti insieme e si scontrano di nuovo.
Correlati. Costi delle API · Osservabilità: log e costi · Retry e rate limit con le API LLM