Per anni la regola è stata una: prendi il modello più potente e fagli scrivere il codice. È lì che spendi l'intelligenza.

Il riflesso sbagliato

Io quella regola l'ho ribaltata. Il modello più forte che ho in mano non scrive una riga. Scrive le direttive. Il codice lo lascio a un modello molto più economico, e volutamente più limitato.

Non è una provocazione. È l'unico modo che ho trovato per rendere l'output di un'AI prevedibile invece che casuale.

Il punto non è quale modello scrive il codice. È quanto è densa la direttiva che gli metti davanti. Meno spazio lasci all'esecutore per interpretare, più il codice generato smette di essere una scommessa.

Tre fasi, non un prompt

Il flusso con cui lavoro ha tre fasi nette.

Design — le direttive. Cosa va costruito, i vincoli, i contratti, i casi limite. Qui va l'intelligenza.

Orchestrazione — come quelle direttive arrivano agli esecutori, e in che ordine.

Esecuzione — il codice vero e proprio. Un modello economico che riempie i binari.

Quando ho disegnato questo flusso, il modello che oggi mi scrive le direttive non esisteva ancora. Ma la fase che conta era già chiara: è la prima. Sposto tutto il peso a monte, sulla direttiva. A valle l'esecuzione non è più una scommessa.

Il contesto viene prima della direttiva

Ho commesso l'errore che fanno tutti: chiedere la direttiva partendo da una pagina bianca.

Il risultato era codice elegante e contratto sbagliato. Il modello inventava interfacce plausibili che non erano le mie. Suonava bene, non sopravviveva all'impatto col codebase.

Una direttiva vale quanto il contesto che il modello legge prima di scriverla. Prompt pulito, contesto vuoto: ottieni una direttiva decorativa.

Oggi, prima della direttiva, assemblo un dossier. Non un prompt:

  • i contratti reali — tipi, schema, firme delle funzioni che il codice nuovo deve rispettare
  • il codice intorno in cui deve incastrarsi, non una versione idealizzata
  • gli invarianti che non si toccano, e i casi limite che ci hanno già morso
  • cosa il codice NON deve fare, esplicito

Solo su quel contesto faccio scrivere la direttiva. A quel punto è vincolante.

In una riga

Il determinismo non nasce dal modello più intelligente. Nasce dal togliergli ogni scusa per indovinare.

La direttiva è chirurgica

Sul contesto costruisco la direttiva: interfacce, vincoli, comportamento atteso e, soprattutto, cosa il codice non deve fare.

È lavoro lento e noioso. Sembra rallentarti. Ma è qui che decido se l'output sarà prevedibile o casuale. Il modello esecutore, a questo punto, ha un solo percorso ragionevole davanti. Non gli chiedo di essere bravo. Gli tolgo lo spazio per essere creativo dove non serve.

Il test è la direttiva resa eseguibile

Non mi fido dell'output dell'esecutore. Non lo rileggo riga per riga: se il mio lavoro fosse rileggere tutto quello che genera, non avrei scalato niente.

Mi fido di un altro strato: una batteria di test che lo inchioda a ciò che avevo chiesto.

E qui c'è il ribaltamento. I test non vanno a caccia di bug a caso. Sono la direttiva resa eseguibile. La direttiva disegna i binari; i test sono i binari che puoi far girare. Il codice generato o combacia, o non passa. Non c'è una terza via.

Così la domanda "quando mi fermo?" smette di essere una sensazione. La condizione di fine non la decide chi guarda. La decide la suite: verde, o non è finito. In concreto è un comando — l'agente lancia flutter test, legge l'esito, e se è rosso non mi passa nemmeno l'output.

Il loop moltiplica, non aggiunge

Su tutto questo, alla fine, metto un loop. Ma il loop è l'ultima cosa, non la prima.

Un loop, ridotto all'osso, è un ciclo while: manda la direttiva, legge l'output, controlla se il test è verde, se no rilancia. Cinque righe. La parte difficile non è il ciclo. È cosa gira dentro ogni giro.

Un loop non aggiunge intelligenza. È un moltiplicatore senza segno: amplifica quello che gli metti dentro. Contesto denso, direttiva chiara, condizione di stop netta e converge. Direttiva vaga, e ottieni l'output sbagliato prodotto quattordici volte invece di una. Più veloce a sbagliare, non più intelligente.

Scrivere il loop è facile. Rendere ogni giro degno di girare è il lavoro.

Il trade-off, detto onesto

Tutto questo costa. Assemblare il contesto, scrivere direttive a questo livello, scrivere i test prima: è lavoro a monte, noioso, che nessuno vede mentre lo fai.

Su uno script usa-e-getta è over-engineering puro. Non lo faccio. Ha senso solo dove l'affidabilità vale più della velocità del singolo task — dove un output sbagliato costa più del tempo che risparmi saltando la preparazione.

E c'è un modo di fregarsi da soli: se la direttiva è vaga, la suite è teatro. L'output sbagliato passa verde e ti sei ingannato con più passaggi di prima. Il test vale quanto il contratto che ci hai scritto dentro.

Il principio

Il modello scrive il codice. Il contratto decide se quel codice ha il diritto di esistere.

Il determinismo non è un modello più bravo. È un sistema che non lascia spazio all'interpretazione: dal contesto che il modello vede prima di partire, fino al test che lo dimostra dopo.

Takeaway

"Un output AI senza un test che lo regge non è una feature. È un'opinione con dei punti e virgola."

— Savino Fiore, Tech Lead @ Finanz