Il numero di agenti è un costo, non una capacità

Due articoli fa sostenevo che le decisioni che non scrivi diventano debito. La settimana scorsa, che un confine che non fai rispettare è solo un desiderio. Sono la stessa idea in vesti diverse: la complessità che non governi non sparisce, si accumula.

Questa settimana mi si è presentata davanti con l'ennesimo travestimento.

Un post sull'orchestrazione dell'AI è passato nel mio feed, uno di quelli fatti bene, costruito sull'immagine di un'orchestra: decine di agenti specializzati e un direttore che li trasforma in una sinfonia invece che in rumore. Elegante. Contrabbanda però un assunto che costa denaro vero: che la risposta a un problema difficile siano più musicisti.

Quell'assunto lo conosco bene. Il suo conto l'ho pagato una volta, e mi ci è voluta la parte migliore di un decennio per estinguerlo.

L'architettura che mi fu chiesto di costruire

Agli inizi dei miei anni da technical architect per un grande retailer, mi fu chiesto di gettare le fondamenta di una nuova piattaforma front-end e, esplicitamente, di spezzarla in moduli NPM con ownership separate: una toolchain di build, un core di interfacce e classi astratte condivise, uno strato auth, un ui-kit Angular, uno strato common per logging e notifiche, e le app sopra. Ogni modulo doveva avere il proprio owner, un team, ed essere consumato dalle app come dipendenza versionata.

Se il cliente ti suona familiare, è giusto così: è la stessa piattaforma le cui decisioni fondative hanno aperto questa serie, due articoli fa. Questo è ciò che quelle fondamenta sono diventate.

Sulla carta è un diagramma pulito: confini chiari, ownership chiara, tutto disaccoppiato. Non ne sono mai stato del tutto convinto, ma i riquadri sembravano giusti, e i riquadri che sembrano giusti sono persuasivi.

Al suo apice la struttura contava dodici team su due continenti. È rimasta in piedi nove anni.

Il conto arriva al momento del cambiamento

Ecco cosa un diagramma non ti mostra mai: la decomposizione sembra gratis quando la disegni. Il conto arriva ogni volta che qualcosa deve cambiare attraverso le giunture.

La voce di spesa più cara era di routine. Ogni volta che Angular o Angular Material rilasciavano una versione major, l'aggiornamento toccava ogni modulo in una volta sola. Un bump del framework, il tipo di cosa che dovrebbe essere una singola spinta coordinata, diventava una trattativa a dodici team su calendari di rilascio mai allineati.

Poi c'erano i cambiamenti che semplicemente si impantanavano. Abbiamo avuto bug rimasti aperti per un anno perché serviva sistemare un componente grafico condiviso, e il team che possedeva lo ui-kit non aveva buffer e aveva altre priorità. Altri team avevano la competenza per fare la modifica. Non avevano l'autorizzazione. L'ownership si era trasformata in silenzio in un veto, e un veto che non costa nulla a chi lo detiene è solo un collo di bottiglia con un nome sopra.

Sotto tutto correva un telefono senza fili. I requisiti di business arrivavano ai team delle app, i team più vicini al bisogno reale. Ma non potevano agire da soli: dovevano tradurre ogni requisito in una richiesta astratta, passarla giù a un owner di modulo e aspettare un ciclo di rilascio che correva su un altro orologio. Il contesto si perdeva a ogni passaggio. Le persone che capivano il requisito non erano le persone autorizzate a soddisfarlo.

Non era colpa di nessun team in particolare. Erano tutti competenti e occupati. Il problema era la struttura, e la struttura era la decomposizione stessa.

Adesso di' "agente" invece di "modulo"

Sostituisci "modulo NPM posseduto da un altro team" con "agente autonomo". Stesso conto, nuova valuta.

Ogni giuntura tra unità con ownership separate è un punto dove si accumula costo, e l'entusiasmo multi-agente di oggi lo paga in tre valute:

  • Token: due agenti che si parlano sono due context window da riempire, a ogni turno. Il contesto che un solo loop stabilisce una volta viene ripassato e ri-ragionato a ogni handoff. Una flotta non condivide un cervello: ne fotocopia uno, ripetutamente.
  • Latenza: una catena di agenti è una catena di round-trip, la stessa tassa da cicli di rilascio disallineati che ho pagato per nove anni, ora misurata in secondi invece che in sprint, ma strutturalmente identica.
  • Disallineamento: quello caro. Ogni agente decide su contesto parziale. L'agente A risolve un'ambiguità in un modo; l'agente B, che ha visto solo l'output di A e mai il suo ragionamento, la risolve in un altro. È il mio telefono senza fili, compilato. Nessun singolo agente ha torto: il sistema semplicemente non è d'accordo con se stesso, con sicurezza, su larga scala.

La "concatenazione" è solo una pipeline

Il post sull'orchestrazione si appoggiava a una parola che ora è ovunque: concatenazione. L'output di ogni agente diventa l'input verificato del successivo; l'intera catena si può rieseguire dall'inizio alla fine. Tracciabile, ricostruibile.

È una buona proprietà. È anche la definizione di una pipeline deterministica: qualcosa che sappiamo costruire da decenni e che per funzionare non ha bisogno di un solo agente autonomo. Se i passi sono fissi e l'ordine è noto, non hai un sistema multi-agente. Hai un workflow con un buon logging, e come tale dovresti costruirlo.

L'orchestrazione è sistemi distribuiti in un vestito più elegante

La metafora dell'orchestra nasconde la parte che ha fatto davvero male. Nel momento in cui i tuoi agenti agiscono in modo asincrono e dipendono l'uno dall'altro, non hai costruito un'orchestra: hai costruito un sistema distribuito, ed hai ereditato ogni problema che abbiamo passato decenni a imparare a rispettare: fallimenti parziali, retry, idempotenza, ordine dei messaggi, consistenza eventuale.

Un agente chiama una API di pagamento. Va in timeout. L'agente riprova. Il pagamento passa due volte. Non è un problema di AI che risolvi con un modello più intelligente: è un problema di sistemi distribuiti che risolvi con idempotenza e progettazione delle transazioni. Il direttore non fa sparire il problema di coordinamento. Il direttore è il problema di coordinamento, con in mano una bacchetta.

Quando un secondo agente si guadagna davvero il posto

Niente di tutto questo significa "sempre un solo agente". Significa che un secondo agente deve guadagnarsi il suo costo, e il test onesto è breve. Prendi un altro agente solo quando un sotto-compito è:

  • Davvero indipendente: gira in parallelo senza aspettare gli altri, quindi stai comprando tempo reale, non solo spendendolo.
  • Con contesto isolato: ha bisogno di una propria memoria di lavoro, e mescolarlo nel loop principale inquinerebbe entrambi.
  • Con privilegi diversi: ha bisogno di strumenti o permessi che l'agente principale non dovrebbe mai avere.
  • Più grande di una singola context window: il lavoro davvero non ci sta.

Ricerca in ampiezza, map-reduce su un corpus grande, un passo che ha bisogno di credenziali che il loop principale non deve mai vedere: quelli si ripagano da soli. "Sembrava più modulare" e "rispecchia il nostro organigramma" no. Quest'ultimo è esattamente l'errore che ho contribuito a costruire: un'architettura a forma di organizzazione, non a forma di problema.

Come è finita la storia

C'è voluto anni per districarla, ma alla fine i moduli sono confluiti in un unico monorepo Nx ben governato. Nota cosa non è successo: non ho buttato via i confini. core, auth, ui-kit esistono ancora, come progetti dentro un solo repo, con un unico rilascio condiviso.

Ciò che è sparito è l'autonomia: owner separati, calendari di rilascio separati, l'autorizzazione come cancello. Una modifica allo ui-kit ora viene revisionata da chi lo conosce meglio, non bloccata perché non è l'unico team autorizzato a toccarlo. Un upgrade di Angular è di nuovo una singola pull request. La specializzazione è sopravvissuta; la tassa di coordinamento no.

È tutta qui la lezione, ed è la stessa per gli agenti: tieni separate le tue responsabilità, non renderle autonome.

La regola che ti lascio

Le decisioni che non scrivi diventano debito. I confini che non fai rispettare diventano desideri. E le unità che rendi autonome senza motivo, moduli, servizi, agenti, diventano un sistema distribuito che non volevi costruire, e un conto di coordinamento che paghi a ogni cambiamento per tutto il tempo in cui resta in piedi.

Il numero di agenti è un costo, non una capacità. Il miglior direttore è quello che tiene l'orchestra piccola.

Prima di spezzare un problema tra una flotta di agenti, chiediti se hai davvero una flotta di problemi indipendenti, o un solo problema e una pipeline che semplicemente non hai ancora scritto.

Dove, nel tuo sistema, stai pagando per un'autonomia di cui non hai mai avuto bisogno?