Skip to main content
Dietro le quinte
Dietro le quinteEngineeringDecisions

Quando il nostro fornitore di IA ha ritirato il modello

Un cambio di modello, risposte vuote senza alcun errore e una bolletta improvvisamente molte volte più alta. Cosa si è rotto, e perché la causa era così difficile da vedere.

Pubblicato il di AlphaCloud4 min di lettura

A luglio 2026 diverse funzionalità hanno smesso di funzionare tutte insieme: la chat IA, le risposte IA nei ticket, i riassunti dei ticket, il costruttore di server, più la moderazione e la traduzione delle idee e delle segnalazioni di bug.

La causa non era il nostro codice. Il nostro fornitore di IA aveva ritirato il modello che stavamo usando.

Parte uno: il modello non c'è più

È la parte ovvia, ed è stata risolta in fretta. Un fornitore dismette un modello, inserisci il successore, fatto.

Il vero incidente è cominciato dopo.

Parte due: risposte vuote, senza errori

Dopo il cambio, le risposte arrivavano. Solo che a volte erano vuote. Non troncate, non malformate, ma una risposta completamente vuota senza alcun errore.

La causa sta in una differenza che il nome del modello non rivela: il successore è un modello di ragionamento. Prima della risposta vera e propria scrive un ragionamento interno in un campo separato. Entrambi attingono allo stesso budget di token.

Se il budget viene consumato dal ragionamento, torna una risposta formalmente corretta: il fornitore segnala "lunghezza raggiunta" e il campo del contenuto è vuoto. Nessun errore, nessun indizio, niente che un try/catch possa vedere.

L'abbiamo riprodotto con un test reale: un budget di cinque token basta già a produrre una risposta vuota a ogni richiesta.

Parte tre: la bolletta

Nel punto di chiamata più costoso, il costruttore di server IA, avevamo impostato un budget generoso perché lì vengono prodotte risposte lunghe. Quindi il ragionamento non incontrava un limite, semplicemente andava avanti.

Le conseguenze sono arrivate da due direzioni insieme. Le richieste duravano così tanto da finire in timeout. E costavano molte volte di più, perché ogni volta si pagava un intero ragionamento invisibile. Alla fine è arrivato un messaggio di errore che non avevamo previsto: saldo insufficiente.

La correzione è una riga. Il ragionamento si può disattivare nel corpo della richiesta, e il modello torna a comportarsi come quello vecchio. Da allora quella riga va in ogni punto di chiamata, e nel repository ce ne sono più di una manciata.

Parte quattro: cosa abbiamo trovato facendo pulizia

Se tocchi comunque ogni punto di chiamata dell'IA, li guardi. Così è emerso un secondo tema, non legato all'incidente ma altrettanto costoso.

I fornitori fanno pagare molto meno un prompt il cui inizio resta invariato e può essere servito da una cache. La differenza tra un hit e un miss è all'incirca di trenta volte.

Quello sconto non lo ottieni con un flag. L'abbiamo testato apposta: un campo nel corpo della richiesta pensato per questo ha avuto effetto zero, la cache si applica comunque in automatico. L'unica leva è l'ordine all'interno del prompt, dal più stabile al più variabile.

Quattro punti in cui avevamo fatto esattamente il contrario:

Un valore variabile dentro il blocco fisso di istruzioni. Il controllo dei duplicati per le segnalazioni di bug aveva il nome del modulo nel testo delle istruzioni. Così un blocco altrimenti identico aveva una propria linea di cache per ogni modulo. Il valore va nella parte variabile, dove cambia comunque.

La cosa nuova prima di quella stabile. Lo stesso controllo inviava la nuova segnalazione di bug prima dei fino a cinquanta candidati da confrontare. Questo rendeva il prompt più grande dell'API un miss completo permanente.

Dati per utente nella parte fissa. La chat IA pubblica aveva le note sul singolo utente nel blocco di istruzioni, quindi prima della cronologia condivisa del canale. Così ogni utente nello stesso canale aveva un proprio inizio, e la cronologia condivisa veniva pagata separatamente per ogni utente.

Una finestra scorrevole sulla cronologia. Inviare gli ultimi N messaggi a ogni messaggio sposta l'inizio a ogni messaggio. L'intera cronologia diventa allora un miss permanente. L'approccio giusto è accorciare a blocchi, quindi raramente e in modo consistente.

Più un dettaglio che sembra pignoleria e non lo è: un elenco dentro un prompt ordinato secondo un solo criterio può cambiare ordine in caso di parità. Una sola riga scambiata a metà del blocco di istruzioni costa l'hit per tutto ciò che viene dopo. Gli ordinamenti dentro i prompt hanno bisogno di un criterio di spareggio univoco.

Cosa ne abbiamo ricavato

Un cambio di modello non è un cambio di configurazione. Il nome sembra un valore in una variabile. Dietro c'era un comportamento diverso, e il comportamento ha rotto il nostro codice, non l'interfaccia.

Il guasto pericoloso era quello silenzioso. La sparizione del vecchio modello si è vista subito ed è stata risolta in pochi minuti. Le risposte vuote tornavano come risposte formalmente valide e sarebbero potute restare così a tempo indeterminato.

La misurabilità va nel punto di chiamata. Ora registriamo la percentuale di cache hit in ognuno. Un punto costruito bene si assesta su un valore alto dopo la prima richiesta, uno costruito male resta a zero. Lo vedi in una riga di log e da nessun'altra parte, perché funzionano entrambi.

E la conclusione scomoda: usare il modello di qualcun altro significa che una parte del tuo prodotto dipende da una decisione presa altrove. Per questo da agosto qualsiasi server può indirizzare le funzionalità IA verso il proprio endpoint invece di affidarsi al nostro.

Altri articoli