Hai costruito uno strumento interno che permette a un team di eseguire 28 unit test su una funzionalità basata su LLM senza mai chiamare l'API del modello. Ci sei riuscito avvolgendo il modello in un'interfaccia simulabile (fakeable) e aggiungendo tre livelli di valutazione: deterministica, euristica e basata su LLM.

Le asserzioni standard si rompono nel momento in cui un LLM genera della prosa. Lo stesso prompt può produrre una frase diversa a ogni esecuzione, quindi assertEqual(output, expected) segnala un errore anche quando il modello si è comportato correttamente. La maggior parte dei team di ingegneria rilascia la funzionalità senza alcuna verifica o prova a testare il modello stesso, trattando un bersaglio in continuo mutamento come se fosse una libreria statica.

Perché il problema è importante

Gli LLM oggi sono integrati in workflow rivolti al cliente: outreach via email, risposte di supporto, generazione di contenuti. Un singolo fatto allucinato o un identificatore trapelato possono danneggiare la reputazione del brand, esporre dati privati o causare violazioni di conformità. Senza una strategia di test affidabile, i team perdono tempo a inseguire errori intermittenti (flaky) o rilasciano bug che emergono solo in produzione.

L'approccio: ridurre la responsabilità del modello

Il primo passo è stato limitare ciò che l'LLM deve effettivamente fare. Nel sistema dell'autore, il modello si occupa solo di bozzare i messaggi di outreach. Tutta la logica di routing, la gestione dello stato e i controlli di sicurezza rimangono nel codice ordinario. Confinando il modello a un singolo output ben definito, il sistema circostante rimane deterministico e testabile.

Per rendere possibile questo approccio, l'LLM risiede dietro un'interfaccia del provider, che permette di utilizzare una versione "fake" nei test. In produzione, l'implementazione chiama l'API esterna; nella suite di test, un "fake" leggero restituisce una risposta predefinita. Poiché il resto del codice interagisce solo con l'interfaccia, l'intero workflow può essere esercitato tramite unit test che non toccano mai la rete. Il risultato è un nucleo prevedibile che i 28 test vanno a verificare.

Un harness di valutazione onesto

Anche con un ambito ristretto, l'output del modello rimane non deterministico. L'autore ha quindi costruito un harness di valutazione a tre livelli, dove ogni livello gestisce una diversa classe di rischio.

  • Livello 1 – Controlli deterministici Semplici regole basate su espressioni regolari intercettano errori concreti, come un ID edificio errato o token proibiti. Questi controlli sono veloci e forniscono un risultato binario (pass/fail).

  • Livello 2 – Controlli euristici Gli script cercano numeri o date allucinate, segnalando palesi fabbricazioni fattuali. Possono però mancare affermazioni false che non presentano indizi numerici, e l'autore riconosce apertamente questo limite.

  • Livello 3 – LLM judge Un modello secondario valuta il tono e la professionalità. Poiché questo passaggio si affida a un altro sistema probabilistico, viene utilizzato solo per gli aspetti soggettivi dove le regole deterministiche sarebbero impossibili da applicare.

La chiave dell'harness è il dataset utilizzato per la valutazione. L'autore ha codificato pattern di errore noti — trappole specifiche e conoscenze di dominio — in modo che l'harness testi esattamente gli errori che si sono manifestati nella pratica. Non è un "acchiappa-tutto" magico, ma una rete di sicurezza mirata.

Cosa significa per i team

  • Mantieni limitati i compiti dell'LLM. Meno responsabilità rendono l'isolamento e il testing più semplici.
  • Inserisci routing, stato e sicurezza nel codice. La logica tradizionale rimane deterministica e pienamente testabile.
  • Esponi il modello tramite un'interfaccia simulabile. Gli unit test girano senza chiamate esterne, mantenendo la suite veloce e affidabile.
  • Stratifica le valutazioni. Inizia con regole deterministiche, aggiungi euristiche per le allucinazioni note e riserva gli "LLM judge" per i controlli di qualità soggettivi.
  • Dichiara i limiti. Nessun livello garantisce la perfezione; l'harness intercetta solo ciò che è stato esplicitamente programmato per rilevare.

Controargomentazione: non puoi comunque testare il modello stesso

L'autore ammette che un modello è un bersaglio mobile. Persino il livello dell'LLM judge eredita lo stesso non determinismo che cerca di valutare. Di conseguenza, il sistema non può mai garantire che ogni allucinazione o violazione delle policy venga intercettata prima del rilascio. L'approccio riduce il rischio, non lo elimina, e si basa sulla capacità del team di mantenere aggiornati i dati di valutazione man mano che compaiono nuovi modi di fallimento.

In sintesi

Non è possibile scrivere un classico unit test che asserisca l'output esatto di un LLM, ma è possibile costruire un sistema in cui l'influenza del modello è limitata, la sua interfaccia è sostituibile e il suo output è filtrato attraverso controlli stratificati e trasparenti. Questa combinazione trasforma un componente altrimenti instabile in una parte prevedibile di un'applicazione più ampia e testabile.