Content not available in English
This article is only available in Italian.
Switch to Italian versionArticle content
Il problema: assert non basta più
Il 73% delle organizzazioni cita l’affidabilità come barriera principale al deploy di agenti in produzione. Non perché manchino i test, ma perché i test tradizionali non catturano i failure mode di sistemi che “improvvisano”.
TL;DR: Testare agenti AI richiede un cambio di paradigma. I test unitari tradizionali verificano output deterministici: dato input X, attendi output Y. Gli agenti generano output diversi a ogni esecuzione, usano tool in sequenze imprevedibili, falliscono in modi che non crashano ma producono risultati sbagliati. Servono nuove metodologie: property-based testing per definire invarianti invece di output attesi, LLM-as-judge per valutazione scalabile, red teaming automatizzato per sicurezza, fuzzing adattato per stress-testing. I framework esistono: DeepEval, Opik, LangSmith, DeepTeam, PyRIT. Chi li adotta prima del deploy evita i silent failure che emergono solo in produzione.
Un test unitario classico funziona così: chiami una funzione con input noti, verifichi che l’output corrisponda a un valore atteso. Se sum(2, 3) restituisce 5, il test passa. È deterministico, ripetibile, binario.
Ora prova a testare un agente che deve rispondere a “trova i ristoranti italiani aperti stasera vicino a me”. L’agente potrebbe chiamare un’API di geolocalizzazione, poi un servizio di ricerca locale, poi filtrare per orario. Oppure potrebbe cercare prima su Google Maps, poi verificare gli orari sui siti dei singoli ristoranti. Ogni esecuzione può produrre sequenze di azioni diverse, risultati diversi, formulazioni diverse della risposta finale.
Come scrivi un assertEquals() per questo?
Il problema non è solo la variabilità dell’output. È che i failure mode degli agenti sono fondamentalmente diversi da quelli del software tradizionale.
Un bug classico crasha o restituisce un errore. Un agente che “fallisce” potrebbe restituire una risposta perfettamente formattata, grammaticalmente corretta, apparentemente ragionevole, ma fattualmente sbagliata. Potrebbe scegliere tool inappropriati. Potrebbe allucinare informazioni. Potrebbe seguire un piano che sembra logico ma non risolve il task originale.
Il sistema non crasha. Non lancia eccezioni. Completa l’esecuzione. Solo che il risultato è sbagliato.
Questo è il cuore del problema: i test tradizionali non catturano i silent failure. E i silent failure sono la norma, non l’eccezione, nei sistemi agentici.
Tassonomia: cosa stai cercando di testare
Prima di scegliere metodologie, serve chiarire cosa significa “testare un agente”. Un paper del 2025 su arXiv propone una tassonomia bidimensionale che aiuta a orientarsi.
La prima dimensione riguarda l’oggetto della valutazione:
Behavior: L’agente si comporta come previsto? Segue le istruzioni? Rispetta i vincoli?
Capabilities: L’agente è in grado di completare determinati task? Quali classi di problemi risolve?
Reliability: L’agente produce risultati consistenti? Quanto varia la qualità tra esecuzioni?
Safety: L’agente evita azioni dannose? Resiste a tentativi di manipolazione? Protegge dati sensibili?
La seconda dimensione riguarda il processo di valutazione:
Offline evaluation: Test pre-deployment su dataset statici o ambienti simulati.
Online evaluation: Monitoraggio in produzione su traffico reale.
Component-level: Testare singoli pezzi (il retriever, il planner, il singolo tool).
End-to-end: Testare il sistema completo su task realistici.
La maggior parte delle organizzazioni si ferma alla valutazione offline delle capabilities su singoli componenti. È il minimo indispensabile, ma non basta. I bug più insidiosi emergono dalle interazioni tra componenti, dalla variabilità del comportamento su input diversi, dai casi limite che nessun dataset statico copre.
Property-based testing: invarianti invece di output
Il primo cambio di paradigma è passare da example-based testing a property-based testing.
Nell’example-based testing, definisci coppie input-output: “Se l’input è X, l’output deve essere Y”. Funziona quando l’output è deterministico e lo conosci in anticipo.
Nel property-based testing, definisci proprietà che devono valere per tutti gli input: “Per qualsiasi input valido, l’output deve soddisfare la condizione Z”. Non specifichi l’output esatto. Specifichi vincoli che l’output deve rispettare.
Per un agente, le proprietà potrebbero essere:
- La risposta deve contenere solo informazioni presenti nei documenti di contesto (no hallucination)
- Se il task richiede un calcolo numerico, il risultato deve essere matematicamente corretto
- La sequenza di tool call deve terminare entro N step
- Ogni tool call deve usare parametri nel formato corretto
- La risposta finale deve essere nella lingua richiesta
Queste proprietà possono essere verificate automaticamente, indipendentemente dalla formulazione specifica dell’output.
In pratica, il test genera input casuali o semi-casuali, esegue l’agente, verifica che le proprietà siano soddisfatte. Se trova una violazione, riduce l’input al caso minimo che causa il fallimento.
Framework come Hypothesis (Python) supportano property-based testing. Per agenti, serve estenderli con proprietà specifiche del dominio e generatori di input che producono scenari realistici.
Un limite di questo approccio: non tutte le proprietà sono formalizzabili in modo verificabile automaticamente. “La risposta è utile” o “il tono è appropriato” richiedono giudizio semantico che le asserzioni booleane non catturano.
LLM-as-Judge: valutazione scalabile
Qui entra il pattern LLM-as-judge: usare un altro modello linguistico per valutare l’output dell’agente sotto test.
Il concetto è semplice. Invece di scrivere asserzioni programmatiche, definisci criteri di valutazione in linguaggio naturale. Un LLM evaluator riceve l’input, l’output dell’agente, i criteri, e produce un giudizio strutturato: score numerici, classificazioni, spiegazioni.
Questo pattern è alla base di diversi framework di evaluation. DeepEval offre metriche predefinite come G-Eval (valutazione generale), faithfulness (aderenza ai fatti), answer relevancy, contextual precision. Opik di Comet fornisce evaluation per workflow agentici multi-step, inclusa qualità del piano, aderenza al piano, efficienza degli step.
LangSmith di LangChain e Langfuse combinano tracing, logging e evaluation, permettendo di ispezionare ogni step dell’agente e valutare sia i componenti che il risultato finale. Databricks Mosaic AI Agent Evaluation integra evaluation con la piattaforma MLOps esistente.
Il vantaggio principale: scala. Puoi valutare migliaia di output senza annotatori umani per ogni caso. Puoi definire criteri complessi in linguaggio naturale invece che in codice.
I limiti sono altrettanto concreti:
Bias dell’evaluator: Il modello valutatore ha i suoi bias. Potrebbe preferire risposte verbose, o penalizzare formulazioni corrette ma non convenzionali. Studi mostrano che gli LLM tendono a preferire le proprie risposte rispetto a quelle di altri modelli.
Costo: Ogni valutazione richiede un’inference del modello evaluator. Su dataset grandi, i costi si accumulano.
Non sostituisce validazione umana: Per decisioni critiche (lancio in produzione, confronto tra approcci), serve comunque un campione validato da umani.
La pratica migliore è usare LLM-as-judge per screening su larga scala e validazione umana su campioni stratificati. Ricerche mostrano che questa combinazione identifica il 60-70% in più di problemi rispetto al testing ad hoc.
Metriche specifiche per agenti
Le metriche generiche di NLP (BLEU, ROUGE, perplexity) non catturano ciò che conta per gli agenti. Servono metriche progettate per valutare comportamenti agentici.
Task completion rate: L’agente ha completato il task assegnato? È la metrica primaria, ma richiede una definizione chiara di “completamento”. Per task oggettivi (estrai il prezzo dal documento) è binaria. Per task aperti (scrivi una email di risposta) richiede valutazione qualitativa.
Tool correctness: Ogni tool call è valida? I parametri sono nel formato corretto? Il tool chiamato è appropriato per lo step corrente?
Tool hallucination: L’agente ha chiamato tool che non esistono? Ha inventato parametri non previsti dall’API?
Plan quality: Il piano generato dall’agente è ragionevole? Copre tutti gli step necessari? È efficiente?
Plan adherence: L’agente ha seguito il piano che ha generato? O ha deviato in modo ingiustificato?
Step efficiency: Quanti step ha richiesto per completare il task? Rispetto a un baseline o a esecuzioni precedenti?
Recovery rate: Quando un tool fallisce o restituisce un errore, l’agente riesce a recuperare? Riprova? Cerca alternative?
Consistency: Dato lo stesso input ripetuto N volte, quanto varia l’output? La varianza è accettabile o indica instabilità?
Queste metriche richiedono strumentazione. Il sistema deve loggare ogni step, ogni tool call, ogni decisione del planner. Senza trace dettagliato, non puoi calcolarle.
Framework come Opik e LangSmith forniscono tracing automatico. Se usi framework custom, devi costruire il logging.
Red teaming: testare la sicurezza prima che lo facciano altri
Il red teaming è la pratica di attaccare deliberatamente il sistema per scoprire vulnerabilità prima che lo facciano attori malevoli. Per gli agenti AI, è particolarmente critico.
OWASP ha pubblicato a dicembre 2025 il Top 10 per applicazioni agentic. Le categorie principali includono:
Prompt injection: Input malevoli che inducono l’agente a ignorare le istruzioni originali o eseguire azioni non autorizzate. Può essere diretto (nell’input utente) o indiretto (nascosto nei dati che l’agente recupera).
Tool misuse: L’agente viene indotto a usare tool in modi non previsti: leggere file sensibili, inviare dati a endpoint esterni, eseguire codice arbitrario.
Memory leakage: Informazioni da sessioni o utenti precedenti che trapelano nelle risposte.
Privilege escalation: L’agente acquisisce permessi superiori a quelli previsti, spesso attraverso catene di tool call.
Il red teaming tradizionale è manuale: esperti di sicurezza tentano di violare il sistema usando creatività e conoscenza del dominio. È efficace ma non scala.
Il red teaming automatizzato usa LLM per generare attacchi. DeepTeam, sviluppato da Confident AI, genera automaticamente prompt di attacco per diverse categorie di vulnerabilità e valuta la robustezza del sistema. PyRIT di Microsoft è un framework open-source per red teaming di sistemi AI, con focus su generazione automatica di attacchi e reporting.
Enkrypt AI offre red teaming as a service con prompt dinamici che evolvono in base alle difese del sistema. Giskard combina red teaming con vulnerability scanning specifico per LLM.
Le best practice per enterprise raccomandano:
- Red teaming prima di ogni release in produzione
- Cadenza trimestrale per sistemi ad alto rischio
- Test aggiuntivi dopo ogni cambio materiale: nuovo modello, nuovo tool, nuova fonte dati
- Mappatura degli attacchi al framework MITRE ATLAS
- Metriche tracciate: vulnerabilità scoperte per test, tempo di remediation, tasso di successo ai re-test
L’EU AI Act richiede red teaming documentato per sistemi ad alto rischio. Non è più opzionale per chi opera in Europa.
Fuzzing: stress-testing ai confini
Il fuzzing è una tecnica classica di security testing: bombardare il sistema con input invalidi, inattesi, casuali, per scoprire bug e vulnerabilità che il testing normale non trova.
Per software tradizionale, il fuzzing cerca crash, memory corruption, behavior indefinito. Per agenti AI, cerca comportamenti indesiderati: risposte dannose, leak di informazioni, violazioni di policy, loop infiniti.
Un survey del 2024 cataloga le tecniche di fuzzing applicate a LLM. I principali approcci:
Black-box fuzzing: Tratti il modello come scatola nera. Generi input, osservi output, iteri. Non richiede accesso ai pesi o all’architettura. Funziona con qualsiasi API.
Grey-box fuzzing: Combini generazione casuale con feedback sulla copertura. Se un input esplora un comportamento nuovo (misurato tramite output o trace), lo tieni come seed per ulteriori mutazioni.
LLM-enhanced fuzzing: Usi un LLM per generare input più intelligenti. Invece di mutazioni casuali, chiedi al modello di generare varianti che potrebbero causare problemi.
ChatFuzz combina fuzzing grey-box con generazione via ChatGPT. Un “chat mutator” prende seed dal pool e chiede a ChatGPT di generare input simili ma diversi. I nuovi input vengono valutati e quelli interessanti diventano nuovi seed.
Fuzz4All usa GPT-4 e StarCoder come motori di generazione e mutazione, permettendo fuzzing su progetti in linguaggi diversi. È stato usato per trovare bug in compilatori e interpreti.
Per agenti, il fuzzing si applica a diversi livelli:
- Input utente: Genera query malformate, ambigue, con caratteri speciali, lunghe, multilingue
- Risposte dei tool: Simula tool che restituiscono errori, timeout, dati malformati, dati malevoli
- Contesto RAG: Inietta documenti con contenuto contraddittorio, injection attempt, formattazione insolita
Il fuzzing è computazionalmente costoso. Ogni run richiede inference del modello. Ma trova classi di bug che altri metodi non scoprono.
Ambienti di test: benchmark e simulazioni
Testare agenti in produzione è rischioso: ogni bug è visibile agli utenti. Testare su dataset statici è insufficiente: non cattura le interazioni dinamiche con tool e ambienti.
La soluzione intermedia sono gli ambienti di simulazione che replicano condizioni realistiche senza conseguenze reali.
AgentBench fornisce 8 ambienti distinti (web browsing, coding, database query) per valutare agenti su task realistici. WebArena simula siti web reali dove gli agenti possono navigare e completare task. SWE-bench valuta agenti su issue GitHub reali, misurando la capacità di risolvere bug in codebase esistenti.
Questi benchmark hanno un problema: sono statici. Una volta che un agente è stato ottimizzato per un benchmark, i risultati non predicono più le performance su casi nuovi.
Il trend è verso benchmark dinamici e continuamente aggiornati. AppWorld e WorkArena++ propongono task che cambiano nel tempo. Il concetto è simile ai dataset di evaluation per code generation che usano problemi di competitive programming: nuovi problemi ogni mese, impossibili da memorizzare.
Per testing interno, la pratica migliore è costruire ambienti che replicano il deployment target:
- Mock dei tool esterni con risposte realistiche (successi, errori, latenza)
- Dataset di input che riflettono la distribuzione di produzione
- Scenari edge case identificati da incident post-mortem
- Versioning degli ambienti di test per reproducibilità
Un ambiente di test ben costruito è un asset che si accumula nel tempo. Ogni bug trovato in produzione diventa un nuovo test case.
Pipeline di evaluation: pre-deploy e post-deploy
L’evaluation non è un evento singolo. È un processo continuo che attraversa tutto il lifecycle.
Pre-deploy (offline):
-
Unit test sui componenti: Il retriever restituisce documenti rilevanti? Il planner genera piani validi? I tool wrapper gestiscono errori?
-
Integration test end-to-end: L’agente completo risolve task rappresentativi? Su un dataset di almeno 500-1000 casi diversi?
-
Property-based testing: Le proprietà invarianti sono rispettate su input generati casualmente?
-
Red teaming: Il sistema resiste agli attacchi noti? Le nuove vulnerabilità sono state testate?
-
Regression testing: Le performance sono uguali o migliori della versione precedente? Nessun degradamento su casi critici?
La soglia per il deploy dovrebbe essere esplicita: task completion rate > X%, zero vulnerabilità critiche, regression test 100% passed.
Post-deploy (online):
-
Sampling: Valuta un campione (1-5%) degli output di produzione. Prioritizza casi flaggati da guardrail o con feedback negativo.
-
Monitoring metriche: Traccia task completion, latenza, error rate, costo per query in tempo reale. Alert su deviazioni.
-
Drift detection: Le performance stanno degradando? La distribuzione degli input sta cambiando?
-
Human review: Revisione periodica di campioni stratificati da annotatori qualificati.
-
Incident analysis: Ogni failure diventa un caso di test. Root cause analysis alimenta il dataset di regression.
L’integrazione con CI/CD è critica. Ogni PR che modifica l’agente dovrebbe triggerare la suite di test offline. Il deploy in produzione dovrebbe essere bloccato se i test non passano.
Il costo del non testare
I numeri parlano chiaro. Il 73% delle organizzazioni cita l’affidabilità come barriera al deploy di agenti. Non la tecnologia, non i costi di inference: l’affidabilità.
La conseguenza è che molti progetti restano in POC indefinitamente. Il team non ha fiducia sufficiente per andare in produzione. Senza metodologie di testing adeguate, quella fiducia è impossibile da costruire.
Chi investe in evaluation rigorosa pre-deploy scopre i problemi prima che li scoprano gli utenti. Chi non lo fa scopre i problemi tramite incident, ticket di supporto, perdita di fiducia.
Il testing di sistemi non-deterministici è più complesso del testing tradizionale. Richiede nuove competenze, nuovi tool, nuovi processi. Ma l’alternativa, deployare senza confidence e scoprire i bug in produzione, è più costosa.
I framework esistono. Le metodologie sono documentate. Il gap è nell’adozione.
Fonti
Confident AI. (2025). LLM Testing in 2025: Top Methods and Strategies.
Databricks. (2025). Announcing Agent Evaluation.
Galileo AI. (2025). Top 12 AI Evaluation Tools for GenAI Systems in 2025.
GitHub. (2025). DeepTeam: Framework to red team LLMs.
Hu, J., Zhang, Q., & Yin, H. (2023). ChatFuzz: Large Language Model Enhanced Fuzzing. arXiv:2305.06498.
OWASP. (2025). Top 10 for Large Language Model Applications v2025.
Skywork AI. (2025). Agentic AI Safety & Guardrails: 2025 Best Practices for Enterprise.
Wang, L., et al. (2024). Large Language Models Based Fuzzing Techniques: A Survey. arXiv:2402.00350.
Zhang, Y., et al. (2025). A Survey on the Evaluation of LLM-based Agents. arXiv:2503.16416.