Eval set: il test driven development per i sistemi AI
Senza un eval set scritto, ogni modifica a un prompt è una preghiera. Ecco come costruiamo eval realistici, li mettiamo in CI e perché trattiamo i prompt come codice di produzione.
lintedhub
redazione tecnicaEval set: il test driven development per i sistemi AI
C'è un momento, in ogni integrazione AI seria, in cui ci si rende conto che lo sviluppo classico non basta più. Tu modifichi una virgola in un prompt e l'output cambia. Cambi modello e cambia di nuovo. Aggiungi un esempio few-shot e non sai se hai migliorato qualcosa o rotto altro. È l'esatto momento in cui un sistema AI smette di essere "una feature" e diventa una superficie da regredire.
La risposta che noi diamo a quel momento ha un nome poco glamour: eval set. È la cosa più sottovalutata del settore, ed è anche la più utile.
Cos'è un eval set, in pratica
Un eval set è un insieme di casi reali che il sistema AI deve gestire correttamente. Ogni caso ha un input (la richiesta del cliente, il documento da classificare, la query da rispondere) e un output atteso, o almeno un criterio di validità.
Sembra ovvio. Non lo è, perché molti team saltano direttamente al deploy senza scrivere quel set. Risultato: la qualità si misura "a sentimento", e ogni modifica è una scommessa.
Il nostro template minimo:
type EvalCase = {
id: string;
input: unknown;
expected:
| { type: "exact"; value: string }
| { type: "contains"; values: string[] }
| { type: "schema"; schema: ZodSchema }
| { type: "judge"; criterion: string };
tags?: string[];
notes?: string;
};
I primi tre tipi (exact, contains, schema) sono validati programmaticamente. Il quarto (judge) è un altro modello che valuta la risposta secondo un criterio scritto. Più costoso, ma indispensabile per output di forma libera.
Come si costruisce in modo onesto
Un eval set inventato a tavolino è praticamente inutile. Deve nascere da casi reali, possibilmente difficili, possibilmente che hanno già rotto qualcosa.
Il nostro processo, applicato uguale su ogni progetto:
- 20-30 casi base: i flussi più frequenti del cliente, scritti insieme a chi userà il sistema.
- 10-15 casi adversariali: input ambigui, formattazioni anomale, lingue miste, dati mancanti.
- Tutti i bug di produzione: ogni volta che l'AI sbaglia in produzione, quel caso entra nell'eval set come regression. Non chiudiamo il bug finché il caso non è verde.
Dopo qualche settimana l'eval set arriva a 60-100 casi, ed è già più affidabile di qualsiasi tuning a occhio.
In CI, non in un notebook dimenticato
Un eval set che vive in un notebook locale è un eval set destinato a morire. Per questo lo mettiamo in CI: ogni modifica al prompt, al modello, alla pipeline di retrieval, deve passare la baseline.
Una pipeline che usiamo, semplificata:
import { describe, it, expect } from "vitest";
import { runAgent } from "@/agents";
import evalCases from "./eval-set.json";
describe("contract-classifier · eval set", () => {
for (const c of evalCases) {
it(`[${c.id}] ${c.notes ?? ""}`, async () => {
const out = await runAgent({ task: "classify", input: c.input });
switch (c.expected.type) {
case "exact":
expect(out.label).toBe(c.expected.value);
break;
case "contains":
for (const v of c.expected.values) expect(out.text).toContain(v);
break;
case "schema":
c.expected.schema.parse(out);
break;
case "judge":
const verdict = await llmJudge(out, c.expected.criterion);
expect(verdict.pass).toBe(true);
break;
}
}, 30_000);
}
});
Soglia di accettazione: il 95% dei casi deve passare. Sotto quella soglia, la build fallisce. Sopra il 95%, viene pubblicato il report con i casi falliti, così chi rivede il PR sa cosa sta accettando di lasciare aperto.
Cosa misurare oltre la correttezza
La correttezza è il minimo, non il fine. Un eval set serio raccoglie anche:
- Latency p50 / p95 per caso. Un agente preciso ma lento è inutile in chat.
- Token consumption. Una modifica al prompt che sembra innocua può raddoppiare il costo.
- Determinismo. Stesso input, output stabile? Se no, il modello è troppo "creativo" per un task strutturato.
- Failure mode. Quando sbaglia, sbaglia in modo prevedibile o in modo imprevedibile? Il primo è gestibile, il secondo no.
Tutte queste metriche escono dallo stesso run. Basta scriverle nel report.
Quando un eval set non basta
Onestamente: per output di forma molto libera (riassunti, scritture creative, conversazioni multi-turn) un eval set deterministico fatica. In quei casi affianchiamo:
- LLM-as-a-judge con criteri scritti per ogni dimensione (accuratezza, tono, completezza).
- Human review periodica su un campione casuale di output reali.
- Feedback in-app: l'utente finale può segnalare risposte sbagliate; quei casi entrano nell'eval set.
Non esiste eval set perfetto, esiste l'eval set che impedisce le regressioni che ti farebbero più male.
La regola pratica
Se non hai un eval set, non hai un sistema AI in produzione. Hai una demo che si comporta bene quando guardi tu, e potenzialmente male quando guardi altrove. La differenza fra le due cose è esattamente il tempo che passa prima che un cliente se ne accorga.
Per ogni progetto AI partiamo dall'eval set. Spesso è la prima cosa che scriviamo, prima ancora del prompt finale. Vincolarsi a una baseline misurabile è il modo più veloce per capire cosa funziona davvero, e per smettere di confondere "mi piace l'output" con "il sistema regge".
Hai un progetto in mente?
Trasformiamo scelte tecniche complesse in sistemi in produzione.
Se stai valutando stack, architetture o integrazioni AI, parliamone. Niente pitch: una conversazione tecnica.
ParliamoneContinua a leggere
Tutti gli articoliDirettive scritte: trattare i prompt come codice di produzione
Un prompt non è un messaggio in chat, è un artefatto di sistema. Come strutturiamo direttive, le versioniamo, le rivediamo in PR e perché evitiamo le "chat improvvisate" sui task seri.
MCP: collegare l'AI ai sistemi del cliente senza farsi male
Model Context Protocol è il modo serio per dare a un modello accesso a tool e dati interni. Come progettiamo server MCP custom, gestiamo permessi e teniamo l'audit trail.
Pattern di integrazione AI che abbiamo imparato
Dopo mesi di sviluppo con LLM, ecco i pattern che funzionano davvero in produzione e quelli che sembrano buone idee ma non lo sono.