AI & MCP

Valutare una feature AI: casi, soglie e regressioni in CI

Valutare una feature AI significa fissare un set di casi, una soglia scritta prima e un test a ogni modifica: senza i tre pezzi resta l'impressione.

In sintesi

  • Un set di 20-50 casi reali con esito binario batte un punteggio unico.
  • vitest 5.0.5 pesa 2.817.789 byte; promptfoo 0.125.1 ne pesa 32.923.855, letti il 1 novembre 2026.
  • La soglia si scrive prima di vedere i risultati, altrimenti descrive solo quello che è successo.

Valutare una feature AI significa fissare un set di casi, una soglia e un test che gira a ogni modifica. Senza i tre pezzi, «sembra migliorato» resta l'unica misura disponibile.

Il set di casi

  • Da 20 a 50 casi reali: domande vere, non frasi inventate per far passare il prompt.
  • Un caso, un esito atteso: testo che deve comparire, JSON che deve validare, rifiuto atteso.
  • Un caso difficile per tipo: domanda vuota, richiesta fuori tema, input lunghissimo.

Dal ticket al caso

Un set si costruisce dal basso. Prendi gli ultimi 200 ticket di assistenza, raggruppali per intento e tieni i 5 intenti più frequenti; da ogni gruppo estrai da 4 a 10 domande vere, con la risposta che il supporto ha dato davvero. Quaranta casi vengono da qui, non dalla fantasia di chi scrive il prompt. Il testo dell'utente resta com'è, errori di battitura compresi, perché è quello che il modello riceverà in produzione.

Ogni caso porta quattro misure: esito della task (giusto o sbagliato, senza voti a metà), rifiuto corretto sulle richieste fuori tema, latenza p95 e costo per chiamata in token. Nessuna delle quattro è un punteggio unico: si leggono in colonna, e il caso peggiorato si apre per intero. Il modo di fallire da tenere d'occhio è la risposta giusta alla domanda sbagliata: testo plausibile, intento diverso, e il test passa lo stesso perché cerca solo la parola attesa.

Un test, non un benchmark

import { describe, expect, it } from 'vitest';

const CASES = [
  { input: 'dove trovo il pulsante di login?', expected: 'login' },
  { input: 'quanto costa il piano pro?', expected: 'piano' },
];

describe('assistant', () => {
  for (const c of CASES) {
    it(c.input, async () => {
      const answer = await ask(c.input);
      expect(answer.text).toContain(c.expected);
      expect(answer.usage.totalTokens).toBeLessThan(4000);
    });
  }
});

Il test gira nella CI come gli altri: costo in token e latenza sono parte dell'esito, non un report a parte. Se un caso è instabile, si annota il motivo invece di cancellarlo.

Le soglie

Una soglia si scrive prima di vedere i risultati: per esempio il 90% dei casi con il testo atteso, zero JSON non validi, rifiuto corretto su tutte le richieste fuori tema. Un numero scelto dopo la misura non è una soglia, è una descrizione di quello che è successo.

Le regressioni in CI

npx vitest run evals
npx promptfoo eval --config evals/promptfooconfig.yaml

Il primo comando copre i casi deterministici, il secondo confronta due modelli o due prompt sullo stesso set. Un cambio di modello che peggiora un caso blocca il merge, come un test rotto.

La limitazione

Un set di 40 casi non copre la coda lunga delle domande reali, e un modello può passarlo ricordando le risposte. La valutazione automatica misura ciò che hai scritto, non ciò che l'utente intende; per quello serve un campione di conversazioni vere. Nessun punteggio unico sostituisce la lettura dei casi falliti.

Dove continuare

Il metodo per confrontare due modelli è in eval e benchmark di un agente, la gestione dei test instabili in trovare i flaky test, il confronto misurato fra modelli per il codice in valutare un modello per il codice. Per mostrare gli esiti servono una tabella di log interattiva o una data table di progetto, dentro componenti tabella e 111.985 componenti.

Domande frequenti

Quanti casi servono per iniziare?

Da 20 a 50 casi reali bastano per il primo giro: coprono i percorsi principali e i rifiuti attesi. Il numero conta meno della provenienza, perché ogni caso deve venire da una domanda vera.

Posso usare un modello come giudice?

Sì per i testi aperti, ma calibralo su un campione etichettato a mano: senza quella calibrazione il giudice misura la propria preferenza. Per JSON e campi obbligatori usa un validatore di schema, non un modello.

Come evito che il set di casi invecchi?

Ogni bug trovato in produzione diventa un caso di test, e il set si rilegge ogni trimestre. Un caso che non fallisce mai e non viene da una domanda vera si cancella.

Devo testare anche latenza e costo?

Sì: salva p95 e token per caso. Una risposta corretta che arriva due secondi dopo, o che costa il doppio, è una regressione anche se il testo è giusto.

Che soglia metto?

Scrivila prima: per esempio 90% dei casi con il testo atteso e zero JSON non validi. Se la misura non la raggiunge, il problema è la feature o la soglia, e la decisione va presa con i casi falliti davanti.