Oggi lo sviluppo software assistito dall'AI segue spesso un processo piuttosto lineare:
Scrivere la descrizione di un task (prompt).
Lasciare che l'AI produca un'analisi e una soluzione proposta.
Preparare skill, agenti e subagenti.
Avviare l'implementazione.
Lasciare che l'AI scriva il codice, lo testi e corregga i problemi rilevati.
A prima vista sembra un flusso di sviluppo ideale. L'AI opera in autonomia, distribuisce i compiti tra gli agenti, scrive test e completa gradualmente la funzionalità richiesta.
E per i progetti più piccoli questo approccio può funzionare estremamente bene.
Se stai costruendo un semplice e-shop, un sito aziendale di cinque pagine o un sistema di amministrazione di base, l'AI può spesso gestire una parte significativa del lavoro con ottimi risultati.
Perché?
Perché milioni di sviluppatori hanno già realizzato software simile.
Immagina due negozi online. Uno vende giocattoli, l'altro mele.
Dal punto di vista del cliente sono due attività diverse. Dal punto di vista dell'architettura software, però, funzionano in modo molto simile:
Prodotti organizzati in categorie.
Gestione di prezzi e magazzino.
Carrelli della spesa.
Elaborazione degli ordini.
Metodi di pagamento.
Gestione dei clienti.
Cambiano soprattutto i dati, alcune regole di business specifiche e certe funzionalità. I principi architetturali di base restano in gran parte gli stessi.
L'AI riconosce questi schemi perché ha incontrato strutture simili durante l'addestramento.
Il problema inizia quando smetti di costruire un'applicazione convenzionale e cominci a sviluppare software enterprise su larga scala.
Che cosa succede quando un sistema contiene da 300.000 a 500.000 righe di codice?
Immagina un'applicazione enterprise con centinaia di migliaia di righe di codice, decine di moduli, centinaia di dipendenze e regole di business complesse.
Un sistema del genere può essersi evoluto nel corso di diversi anni. In quel tempo si sono accumulate decisioni architetturali, eccezioni, dipendenze storiche e regole di business.
Non tutte sono documentate.
Un singolo metodo può influenzare altri dieci moduli. Cambiare un parametro può compromettere la fatturazione, i permessi degli utenti o l'elaborazione degli ordini.
Ora immagina di introdurre un agente AI in questo ambiente.
Gli assegni un compito:
"Modifica il processo di pagamento per supportare un metodo di pagamento aggiuntivo. Mantieni la retrocompatibilità e testa tutto."
L'agente crea un piano, distribuisce il lavoro tra i subagenti, implementa le modifiche, esegue i test e restituisce i risultati.
Tutto può sembrare corretto.
Ma il fatto che i test passino non significa necessariamente che il software abbia preservato tutte le regole di business esistenti.
E questo ci porta al problema che sei mesi fa ha cambiato completamente il mio approccio agli agenti AI.
L'esperimento che ha cambiato la mia visione dei sistemi agentici
Sei mesi fa ho condotto un esperimento che mi ha portato a scegliere una strada diversa, invece di limitarmi a costruire sempre più agenti e subagenti.
Fino ad allora avevo operato partendo da un presupposto condiviso da molti sviluppatori:
Quanto meglio distribuisco i compiti tra agenti specializzati e quanti più meccanismi di validazione introduco, tanto più affidabile sarà il risultato.
Ma durante i miei esperimenti mi sono scontrato con una domanda fondamentale:
Come può un agente implementare correttamente una regola di business se non sa nemmeno che quella regola esiste?
E come può un altro agente verificare in modo affidabile il risultato se anch'esso non dispone di informazioni complete su come il sistema dovrebbe comportarsi?
Ho iniziato a esaminare come viene trasferito il contesto tra gli agenti.
Ho scoperto che il modo in cui le informazioni vengono passate e interpretate può diventare uno dei punti più deboli dell'intero processo.
Come funzionano davvero agenti e subagenti?
In pratica esistono due approcci comuni alla comunicazione tra agenti AI.
1. Modello gerarchico - Un agente principale coordina i subagenti
Questa architettura è comunemente chiamata Hub-and-Spoke o Star Topology.
Il principio è semplice:
L'utente assegna un task all'agente principale.
L'agente principale analizza il task e lo scompone in parti più piccole.
Crea o attiva il subagente A e gli fornisce le istruzioni.
Il subagente A svolge il lavoro e restituisce un risultato.
L'agente principale valuta il risultato e può delegare altro lavoro al subagente B.
Quando tutte le parti sono completate, l'agente principale combina i risultati.
Il subagente A non sa necessariamente cosa sta facendo il subagente B. La comunicazione e lo scambio di informazioni sono coordinati dall'agente principale.
Vantaggio: controllo centralizzato, tracciamento dello stato più semplice, responsabilità più chiare e minor rischio di comunicazione incontrollata tra agenti.
Svantaggio: l'agente principale diventa il punto centrale attraverso cui vengono interpretate le istruzioni e i risultati dei task. Se omette informazioni importanti nel delegare il lavoro, un subagente può operare con un contesto incompleto.
2. Peer-to-Peer - Gli agenti comunicano tra loro
Il secondo approccio prevede una comunicazione diretta o continua tra gli agenti, ad esempio tramite un thread di conversazione condiviso o un sistema di messaggistica (*Message Bus*).
Immagina il seguente scenario:
L'agente A scrive codice e pubblica un evento CodeWritten.
L'agente B, responsabile dei test, riceve l'evento e avvia i test.
L'agente C prepara nel frattempo la documentazione.
Gli agenti si scambiano continuamente risultati e reagiscono ai cambiamenti.
Vantaggio: esecuzione parallela dei task, scambio rapido di informazioni e minore dipendenza da un singolo agente centrale.
Svantaggio: coordinamento più complesso, rischio di lavorare con informazioni obsolete, modifiche in conflitto e maggiore difficoltà nel risalire alla causa degli errori.
Entrambi gli approcci possono essere estremamente utili.
Ma nessuno dei due risolve da solo il problema fondamentale.
Un agente può avere un task perfettamente definito, ma senza comprendere la reale logica di business del sistema può produrre una soluzione tecnicamente corretta e sbagliata dal punto di vista del business.
Dove nascono gli errori nei flussi agentici?
L'AI non è un compilatore deterministico che traduce le istruzioni direttamente in codice sorgente. Un modello linguistico interpreta le informazioni disponibili e genera soluzioni in base a quel contesto.
Quando mancano informazioni, può fare supposizioni errate. Quando le informazioni disponibili sono incomplete o contraddittorie, può scegliere un approccio inadatto.
Esaminiamo un flusso tipico per un task più grande.
Passo 1 - Interpretazione del prompt dell'utente
L'agente principale riceve il task e cerca di capire la modifica richiesta.
In questa fase può trascurare una dipendenza, fraintendere un vincolo o dare per scontato qualcosa che non era mai stato dichiarato esplicitamente.
Passo 2 - Creazione delle istruzioni per un subagente
L'agente principale crea una descrizione del task più specifica. Seleziona dal prompt originale le informazioni che ritiene rilevanti.
Tuttavia, se non conosce certe regole di business, non può trasmetterle correttamente.
Passo 3 - Implementazione
Il subagente riceve le istruzioni, analizza una parte del codebase e sceglie una strategia di implementazione.
Può produrre codice sintatticamente corretto e di buona qualità, modificando però involontariamente un comportamento che doveva rimanere invariato.
Passo 4 - Valutazione del risultato
L'agente principale riceve l'output del subagente, lo valuta e decide se il task è completo.
Ma può ancora operare con le stesse ipotesi incomplete di prima.
Passo 5 - Test e correzione degli errori
Seguono unit test, test di integrazione, test E2E, analisi statica e revisioni della documentazione.
Questi meccanismi migliorano in modo significativo l'affidabilità del software, ma hanno dei limiti.
Un test verifica un comportamento atteso specifico. Se una regola di business importante manca dalla specifica del test, l'implementazione può superare ogni test violando quella regola.
E quando l'AI corregge un problema, può influire involontariamente su un'altra parte del sistema.
Si crea così un ciclo familiare:
Implementazione → Test → Correzione → Regressione → Altri test → Un'altra correzione.
Pertanto, aumentare semplicemente il numero di agenti o ripetere i test più spesso non garantisce automaticamente un risultato corretto.
Perché gli errori possono accumularsi lungo una catena di agenti?
Consideriamo un modello matematico semplificato.
Supponiamo di avere tre passi consecutivi, ciascuno con una probabilità ipotetica del 95% di essere eseguito correttamente.
Se questi passi sono indipendenti e tutti e tre devono riuscire, la probabilità diventa:
0,95 × 0,95 × 0,95 = 0,8574
Ciò rappresenta circa una probabilità dell'85,7% che tutti e tre i passi riescano.
Con dieci passi indipendenti di questo tipo, il risultato sarebbe:
0,95¹⁰ ≈ 59,9%
Questo è un calcolo illustrativo, non un tasso di successo misurato degli agenti AI. Nei sistemi reali gli errori non sono sempre indipendenti, i meccanismi di validazione possono intercettare gli errori e i singoli passi possono correggere fallimenti precedenti.
Tuttavia l'esempio mostra un principio importante:
L'affidabilità dei singoli agenti non garantisce automaticamente l'affidabilità dell'intera catena.
Quando istruzioni incomplete vengono interpretate ripetutamente a ogni fase, possono emergere ulteriori occasioni di decisioni sbagliate.
Per questo credo che aggiungere semplicemente più agenti, test e meccanismi di validazione non basti.
Dobbiamo cambiare il modo in cui l'AI riceve le informazioni sul sistema stesso.
La differenza chiave: i test verificano i risultati, la Business Logic definisce i confini
L'approccio convenzionale allo sviluppo assistito dall'AI è reattivo.
Si invia un requisito, l'AI implementa una soluzione e poi i test servono a stabilire se qualcosa si è rotto.
È certamente meglio che non avere alcun test.
Ma resta una debolezza fondamentale:
I test non possono convalidare in modo affidabile regole di business che nessuno conosce e che non fanno parte della specifica dei test.
Per questo credo che un approccio migliore sia fornire all'AI informazioni sul comportamento reale del sistema prima dell'inizio dell'implementazione.
Non solo cosa deve cambiare, ma anche:
Quali regole di business si applicano al codice interessato.
Quali altri moduli dipendono dalla funzionalità.
Quali input e output devono rimanere compatibili.
Quali scenari devono rimanere invariati.
Quali eccezioni e vincoli storici esistono.
Quali parti dell'implementazione l'AI può modificare e quali deve preservare.
Questo riduce in modo significativo la quantità di comportamento che l'AI deve dedurre da sola.
Due approcci allo stesso task
Approccio A - Prompt + Test
L'AI riceve un task, sceglie un'implementazione in base al contesto disponibile, produce la soluzione ed esegue i test.
Se i test sono incompleti, le violazioni delle regole di business esistenti possono passare inosservate.
Approccio B - Prompt + Business Logic + Test
L'AI riceve il task insieme alle regole, dipendenze, contratti e vincoli rilevanti.
Di conseguenza sa quale comportamento va preservato prima che inizi l'implementazione.
I test fanno allora più che rilevare errori. Verificano anche specifici contratti di business.
La differenza non è che smettiamo di testare.
La differenza è che cerchiamo di prevenire gli errori prima che vengano introdotti.

Esempio pratico: aggiungere un nuovo metodo di pagamento
Immagina di avere un file chiamato CheckoutService.ts, che gestisce i pagamenti in un'applicazione e-commerce.
Vogliamo aggiungere i pagamenti con carta come metodo di pagamento ulteriore.
Opzione A: un prompt convenzionale
Task:
> Aggiungi i pagamenti con carta a CheckoutService.ts. Mantieni le funzionalità esistenti ed esegui tutti i test.
L'AI modifica il codice, aggiunge un nuovo ramo di pagamento e aggiorna i test.
Tutti i test passano.
Il task viene segnato come completato.
Tuttavia il sistema contiene una regola di business importante:
Gli account aziendali devono usare il bonifico bancario come metodo di pagamento predefinito.
Questa regola è stata introdotta diversi anni fa. Lo sviluppatore che l'ha implementata non lavora più in azienda. La regola non è documentata chiaramente e non esiste alcun test di regressione dedicato.
L'AI introduce il pagamento con carta come metodo predefinito per tutti i clienti.
Dal punto di vista dell'implementazione, la nuova funzionalità funziona correttamente.
Dal punto di vista della logica di business, il sistema è rotto.
E i test non hanno rilevato il problema.
Opzione B: un task strutturato con Business Logic in AITM
Ora immagina che l'AI riceva la stessa richiesta, ma questa volta il task include il contratto di business rilevante, le variabili correlate, i collegamenti ai task storici e confini precisi per le modifiche consentite.
Il task potrebbe apparire così:
READ CLAUDE.md first.
TASK:
Add card payment as an additional payment method
in CheckoutService.ts.
Contract:
%CHECKOUT-019 — "For company accounts
(companyId != null), bank transfer must remain
the default payment method. Card payment may
be offered only as an additional option."
Related variables:
BL.CHECKOUT.PAYMENTMETHOD_DEFAULT
BL.CHECKOUT.PAYMENTMETHOD_OPTIONS
Related task:
#<link to the task that originally implemented bank-transfer-as-default checkout>
In scope:
- Add a new "card" option to the available payment methods in CheckoutService.ts.
- Expose it as a selectable option in the existing payment method selection flow.
Out of scope:
- Changing the default payment method for any account type.
- Any UI/checkout-flow redesign beyond adding the new option.
- New payment provider integration logic beyond the method registration itself.
Must not break:
- Existing default payment selection logic (company accounts → bank transfer stays default).
- Company account checkout behavior end-to-end.
- Existing bank transfer processing path.
- Compatibility with the current payment API contract.
File path:
src/Services/CheckoutService.ts
Confirm the exact path via contractsForFile before editing.
Verify:
- Company account checkout still selects bank transfer by default
(companyId != null).
- Card payment appears as a selectable, non-default option.
- Existing bank transfer processing is unchanged.
- Run unit and integration tests covering CheckoutService.
Maggiori informazioni su come funziona in AITM: https://aitm.cz/Docs/KnowledgeSharing
Perché questo formato è importante?
A prima vista può sembrare nulla più di un prompt più dettagliato.
Ma la vera differenza è che il task è collegato a informazioni che possono essere recuperate e verificate rispetto al progetto reale.
1. Contratto %CHECKOUT-019
L'identificatore %CHECKOUT-019 non è solo una nota testuale.
È un identificatore di contratto illustrativo che l'agente può recuperare tramite operazioni GraphQL come contractsForFile o contractsForVariable.
Invece di affidarsi solo alla regola scritta nel prompt, l'agente può recuperarne la rappresentazione strutturata e verificarla rispetto al codebase attuale.
2. Variabili di Business Logic _BL.
Identificatori come _BL.CHECKOUT.PAYMENT_METHOD_DEFAULT e _BL.CHECKOUT.PAYMENT_METHOD_OPTIONS rappresentano la logica di business espressa attraverso il linguaggio di comunicazione di AITM.
Aiutano a collegare un requisito specifico alle regole e alle variabili che determinano il comportamento del sistema.
3. Riferimento a un task correlato
La sezione Related task rimanda al task originale in cui è stata implementata la regola di business.
Questo fornisce all'AI un contesto aggiuntivo, non solo su come il sistema si comporta attualmente ma anche sul perché possa essere stata presa una certa decisione.
4. Confini della modifica chiaramente definiti
Le sezioni In scope, Out of scope e Must not break definiscono tre categorie distinte:
Che cosa l'AI deve implementare.
Che cosa l'AI non deve implementare.
Quale comportamento esistente l'AI deve preservare.
Invece di ricevere un task aperto che può interpretare o ampliare liberamente, l'AI riceve un perimetro di implementazione definito con precisione.
5. Verifica prima di scrivere codice
Il percorso del file non viene dato automaticamente per corretto.
All'agente viene indicato di usare prima contractsForFile, confermare il percorso effettivo e individuare i contratti associati.
Solo allora deve iniziare a modificare il codice.
6. Validazione del prompt tramite TPV
Una parte importante dell'approccio AITM è il validatore di prompt TPV.
Controlla le sezioni obbligatorie del task prima che il task venga inviato in esecuzione.
Ad esempio verifica la presenza di definizioni dell'ambito, restrizioni, contratti, percorsi dei file e requisiti di verifica.
Questo sposta parte della prevenzione degli errori dal testare il codice finito alla preparazione del task stesso.
Nota: Gli identificatori dei contratti e le variabili di business logic in questo esempio sono segnaposto illustrativi. In un progetto reale l'optimizer li recupera tramite GraphQL dallo specifico progetto. Non vanno indovinati né generati senza verifica.
Che cosa cambia con questo approccio?
Nell'approccio convenzionale l'agente interpreta prima un task aperto e decide da solo quali file, dipendenze e regole di business contano.
Con AITM il task è collegato a contratti specifici, variabili di business logic, task storici e confini di modifica chiaramente definiti.
L'agente può quindi prendere decisioni basate su informazioni verificabili anziché affidarsi principalmente a supposizioni.
Ed è qui che vedo la differenza fondamentale.
La business logic non è più soltanto parte della documentazione. Diventa parte del processo stesso di controllo dell'implementazione.
Questo è il principio alla base di AITM
Quando abbiamo iniziato a progettare AITM (AI Task Manager), non volevamo costruire solo un altro sistema che avvia agenti, distribuisce task e ne controlla i risultati a posteriori.
Ci siamo concentrati su un'altra domanda:
E se l'AI potesse ricevere la business logic rilevante direttamente dal codice sorgente esistente prima di fare qualsiasi modifica?
Non solo la documentazione scritta da qualcuno un anno fa.
Non solo istruzioni generiche conservate in una skill.
E non solo alcuni file che un agente sceglie per caso.
Ma informazioni strutturate che descrivono come si comporta realmente la parte interessata del sistema, quali contratti la governano e quali altri componenti ne dipendono.
Il principio fondamentale di AITM è quindi arricchire il prompt di lavoro con la business logic individuata nelle parti rilevanti del codebase.
L'agente riceve non solo le informazioni su cosa deve fare, ma anche su cosa deve preservare.
Questo è particolarmente importante nei sistemi software su larga scala, dove un singolo prompt può non contenere ogni dipendenza o vincolo rilevante.
La Business Logic come guardrail per l'AI
Pensa alla business logic come ai guardrail lungo una strada.
Senza guardrail, l'AI può prendere molte strade diverse. Alcune possono portare a una soluzione corretta, altre possono violare regole nascoste del sistema.
Fornendo contratti e vincoli rilevanti, restringiamo in modo significativo lo spazio delle decisioni indesiderate.
L'AI può comunque scegliere in autonomia strategie di implementazione, algoritmi e strutture del codice.
Ma deve rispettare le regole di business note.
I test successivi verificano poi se quelle regole sono state davvero preservate.
Questo rappresenta un cambiamento fondamentale di filosofia.
Non cerchiamo semplicemente di correggere gli errori che l'AI crea. Cerchiamo di ridurre la probabilità che quegli errori vengano introdotti fin dall'inizio.
Significa che non servono più agenti e test?
Assolutamente no.
Gli agenti sono utili per l'esecuzione parallela, per attività specializzate e per automatizzare task di grandi dimensioni.
Unit test, test di integrazione e test E2E restano componenti essenziali della garanzia di qualità del software.
Ma l'orchestrazione degli agenti e i test automatizzati non possono sostituire la conoscenza della business logic.
Se un agente non capisce cosa il sistema deve preservare, nemmeno un team perfettamente organizzato di subagenti risolverà il problema di fondo.
E se i test non coprono gli scenari rilevanti, ogni test può passare mentre l'applicazione continua a comportarsi in modo scorretto dal punto di vista del business.
L'approccio giusto non è scegliere tra business logic e test. È combinarli.
Prima, individuare il comportamento reale del sistema.
Poi, esprimere quel comportamento come regole e contratti chiari.
Quindi, fornire queste regole all'AI insieme al task.
Solo allora procedere con implementazione, validazione e test.
Questo approccio può ridurre correzioni inutili, regressioni e cicli di implementazione ripetuti.
Conclusione: non conta il numero di agenti. Conta la qualità delle informazioni.
Per le applicazioni semplici l'AI può offrire ottimi risultati anche con istruzioni relativamente brevi.
Ma con un software enterprise da mezzo milione di righe di codice non basta supporre che un agente capisca tutto correttamente, scopra ogni dipendenza e poi testi alla perfezione il proprio lavoro.
Più il sistema cresce, più è importante comprendere e proteggere il suo reale comportamento di business.
Puoi avere dieci agenti che collaborano alla perfezione. Ma se nessuno di loro conosce una regola di business critica, possono produrre collettivamente una soluzione perfettamente testata e fondamentalmente sbagliata.
Per questo con AITM adottiamo un approccio diverso.
Prima il contesto, le regole e i contratti.
Poi l'implementazione.
E infine la validazione e i test.
Perché l'obiettivo non è che l'AI scriva più codice possibile nel minor tempo possibile.
L'obiettivo è che l'AI cambi esattamente ciò che va cambiato, senza rompere ciò che già funziona.