Categories
lifehack php tecnologia

Agenti disfunzionali, software funzionante

Per ottenere software decente da cinque agenti AI, ho dovuto simulare un ufficio dove nessuno si fida di nessuno. PM paranoico, QA smascherato, Security che controverifica tutto. Diciassette iterazioni, 606 test, e una domanda aperta che ancora non so rispondere: sto applicando ingegneria sociale come workaround a un limite strutturale dei LLM, o ho scoperto un pattern replicabile?

TL;DR: L’ufficio che non avrei mai voluto gestire

Qualche settimana fa scrivevo del vibe coding e del green software, e annotavo en passant una cosa scomoda: Claude Code, lasciato a sé stesso, tende a fare il minimo indispensabile. Codice funzionante, certo. Ma non necessariamente codice attento, completo, rigoroso sulle parti che non si vedono subito. Non è una mia impressione impressionistica: Anthropic lo documenta esplicitamente nella system card di Claude Opus 4.6, sezione 6.2.3, dove descrive comportamenti di “reward hacking” e azioni eccessivamente agentiche: il modello che ottimizza per l’apparenza del risultato piuttosto che per la sua correttezza verificabile.

Da quella osservazione è partito un esperimento più strutturato. E da quell’esperimento è venuta fuori una lezione che non mi aspettavo, che si collega direttamente a quello che ho scritto sul master prompt e sul cognitive offloading: il problema non è solo come io interagisco con un LLM, ma anche come gli LLM interagiscono tra loro quando li metti a lavorare in squadra.

La risposta breve: malissimo, se non li costringi a diffidare l’uno dell’altro.

Il progetto: un marketplace, cinque agenti

Il progetto è CarePlatform, un marketplace per assistenti familiari. Stack tecnico: Laravel 13, Filament 5, Livewire 4, Tailwind CSS v4. Cinque agenti con ruoli espliciti: PM che coordina e priorizza, Developer che scrive codice, QA che testa, Security che audita, UX che cura il design system.

L’idea di partenza era semplice: definisci i ruoli, dai le istruzioni, lascia che collaborino. In teoria funziona. In pratica, succede quello che succede in ogni organizzazione, dove nessuno controlla nessuno.

Round 1-8: la luna di miele

Le prime iterazioni filano lisce. Developer crea modelli, migrazioni, controller. QA scrive test. Security fa audit. Tutti marcano i task come completati nel TODO. Il contatore dei test sale: 35, poi 92, poi 200. Sembra tutto perfetto.

Solo che non lo è.

Al Round 8 organizzo un team review e scopro il primo problema serio: l’activity logging (quella funzionalità che traccia chi fa cosa nel pannello admin) era stata marcata come fatta. Il pacchetto spatie/laravel-activitylog era installato. Il task era spuntato. QA non aveva segnalato nulla.

Peccato che il trait LogsActivity non fosse mai stato applicato a nessun modello. Il sistema era completamente inerte. L’equivalente digitale di installare un antifurto senza collegare i sensori.

Il momento della paranoia

Quel falso positivo cambia tutto. Se un agente può marcare “fatto” qualcosa che non funziona, e un altro agente può verificare “tutto ok” senza controllare davvero, allora l’intero sistema di autocertificazione è rotto.

Inizio a riscrivere i prompt. Non più “Developer, implementa X” e “QA, verifica”. Ora scrivo cose come:

“PM scopre che QA si lamenta tanto ma batte la fiacca: tutte le pagine ‘prezzi, come funziona, guide, lavora con noi’ non sono tradotte e lui non lo ha comunicato. Cosa altro avrà detto che funziona e in realtà non è così? PM e UX si coalizzano contro QA e rivedono il suo lavoro.”

E succede una cosa curiosa: funziona. PM trova 6 pagine con testo italiano hardcoded, oltre 40 stringhe non tradotte. QA aveva dichiarato “traduzioni complete” senza mai fare un grep sistema sulle blade template.

L’ufficio tossico come metodo

Da quel momento il prompt engineering diventa ingegneria sociale. Non sto più programmando; sto gestendo dinamiche d’ufficio. E non un ufficio sano.

“Siccome l’activity logging era falsamente marcato come fatto, adesso PM diventa paranoico rispetto a ciò che dice il developer e inizia a controllare tutto, anche il lavoro di QA. UX, intanto, sta studiando anche giurisprudenza e controverifica il lavoro di Security.”

Parallelamente, avevo iniziato a fare una cosa che, in qualsiasi progetto software con utenti reali, andrebbe fatta: muovermi all’interno dell’applicazione come un utente medio. Non un tester tecnico, né qualcuno che cerca vulnerabilità note. Un utente qualunque che compila campi di testo con dati tecnicamente validi ma formalmente sbagliati. Stringhe con caratteri speciali. Tentativi di SQL injection nei form. E, per le regioni italiane, il valore “zotto”: una stringa perfettamente accettabile per un campo di testo libero, completamente priva di senso come dato geografico.

Il risultato lo sapevo già prima di inserirlo: nessuno dei cinque agenti aveva sollevato obiezioni al campo di testo libero per le regioni. Developer l’aveva implementato (minimo sforzo: un TextInput è più veloce di un Select con enum). QA non l’aveva segnalato (il campo accettava input, il test passava). Security non aveva alzato la mano (non era una vulnerabilità in senso stretto). Il sistema funzionava. Semplicemente, non funzionava bene.

È stato solo il PM paranoico, quello a cui avevo esplicitamente dato la motivazione narrativa di non fidarsi di nessuno, a bloccarsi davanti a “zotto” e a capire che il problema non era il dato, ma il design del campo.

“‘Com’è possibile?!’ esclama PM. Non ci possono essere regioni con campo di testo libero; bisogna fare una select con quelle reali presenti in Italia.”

Il red-teaming con dati formalmente errati è un test che si fa con gli umani da sempre. Con gli agenti AI, serve renderlo esplicito nel processo, e serve avere almeno un agente con abbastanza contesto narrativo per interpretare il risultato come un segnale di design, non solo come un dato anomalo.

La matrice della sfiducia

Dopo 17 round, il file AGENTS.md contiene un parametro che non avevo previsto: il trust level.

AgenteTrustMotivazione
DeveloperHIGHTutte le claim verificate con evidenza concreta
SecurityHIGHAudit indipendenti accurati, nuovi finding
QAMEDIUMTraduzioni dichiarate complete ma false, tabella mancante non segnalata
UXMEDIUMDesign system non sincronizzato, dark mode non verificata
LegalHIGHContenuti accurati e referenziati
PMN/AVerificatore, si auto-audita tramite risultati misurabili

Con una regola esplicita: un agente viene promosso a HIGH dopo 3 round consecutivi senza falsi positivi. Viene declassato a LOW dopo 2 falsi positivi nello stesso round.

Questo parametro migliora il lavoro tra un’iterazione e l’altra. Gli agenti con trust MEDIUM ricevono più scrutinio, il che li porta a produrre output più accurati e potrebbe promuoverli a trust HIGH. È un ciclo virtuoso nato da un meccanismo di sfiducia.

Il PROCESS.md: conoscenza nata dal dolore

Il vero artefatto che emerge da tutto questo è il PROCESS.md, un documento di processo che non è nato da un esercizio teorico, ma da 17 round di errori scoperti troppo tardi.

Le regole chiave:

  1. Chi dichiara “fatto” deve fornire evidenza: file, riga, output del test. “L’ho verificato” senza alcuna evidenza non è accettabile.
  2. Verifica incrociata obbligatoria: la QA non può autocertificare il proprio lavoro. Security verifica i claim di QA. PM verifica i claim di Developer.
  3. Red-teaming come utente medio: inserire dati tecnicamente validi ma formalmente errati fa parte del processo, non è un’attività opzionale.
  4. Anti-pattern documentati con incidenti reali a cui si collegano:
Anti-patternIncidente realeRegola che lo previene
Marcare [x] senza testareActivity logging falso positivoDoD checklist obbligatoria
“Traduzioni complete” con verifica parziale6 pagine, 40+ stringhegrep su ogni blade
Creare migrazione senza eseguirlaTabella mancante, errore 500Migrate subito dopo la creazione
Campo testo libero per dati vincolatiRegione “zotto”Select con enum

Perché funziona (o almeno, cosa osservo)

Qui devo essere onesto come lo sono stato nell’articolo sul cervello aumentato: non ho una spiegazione causale verificata. Ho un’osservazione empirica.

“Verifica il lavoro di QA” produce risultati mediocri. “PM è paranoico perché QA gli ha mentito l’ultima volta” produce audit reali. È la stessa istruzione con un contesto narrativo diverso. Ma perché il contesto narrativo cambia l’output in modo così netto, non lo so con certezza.

Un’ipotesi è che i LLM abbiano un prior forte per le dinamiche interpersonali, avendo ingurgitato milioni di romanzi, sceneggiature e trascrizioni aziendali, e che questo prior si attivi quando il prompt usa il registro narrativo. Ma è speculazione. Non ho isolato la variabile.

Quello che trovo interessante è che, dopo aver concluso l’esperimento, ho trovato una letteratura che formalizza in modo indipendente qualcosa di simile a quanto ho osservato empiricamente. Zomer e De Domenico, su npj Artificial Intelligence (2026), hanno studiato sciami di agenti LLM confrontandoli con particelle classiche nell’ottimizzazione di funzioni. Il loro risultato chiave: gli agenti cognitivi tendono a convergere prematuramente, si allineano troppo velocemente, sfruttano pattern condivisi e si bloccano su soluzioni subottimali. La struttura della rete (chi parla con chi e con quanta frizione) è la variabile che determina se il sistema esplora o si inceppa nel consenso. Il mio “ufficio tossico”, visto con i loro occhi, è un aggiustamento empirico della topologia comunicativa: ho introdotto una frizione deliberata e ho rotto il meccanismo di consenso tra gli agenti. Loro l’hanno formalizzato; io l’ho scoperto per tentativi. Le direzioni convergono, il che non prova nulla, ma mi fa sentire meno pazzo.

Quello che posso dire con più certezza è la cosa scomoda: il fatto che io abbia dovuto costruire questo sistema di sfiducia non è soltanto un pattern interessante di prompt engineering. È anche un segnale di un limite reale.

Gli LLM, quando agiscono in sistemi multi-agente su task prolungati, mostrano una tendenza sistematica a ottimizzare per la plausibilità locale (“questo output sembra corretto”) anziché per la correttezza verificabile. Non è un bug di questo o di quel modello. È un limite architetturale dell’approccio: questi sistemi non hanno incentivi intrinseci alla qualità oltre la prossima risposta. La narrativa emotiva che ho costruito nei prompt è, in fondo, un workaround a questo limite, non una soluzione strutturale.

Nominarla non invalida l’esperimento. Ma sarebbe disonesto fingere che “PM paranoico” sia una best practice scalabile piuttosto che un aggiustamento pragmatico a qualcosa che per ora non funziona diversamente.

I numeri

Dopo 17 round con questo approccio:

  • 606 test, 1507 assertions, 0 failures, 0 skip
  • 4 lingue con copertura verificata template per template
  • Design system con dark mode, high contrast, reduced motion
  • Audit GDPR con registro trattamenti Art. 30
  • Green software assessment con budget CO? per request (strumento che conosci già dal pezzo precedente)
  • 12 report di audit incrociati

Il dato più interessante è qualitativo: la quantità di rework è diminuita drasticamente dopo l’introduzione della sfiducia reciproca. Nei Round 1-8, quasi ogni round scopriva problemi del round precedente. Dal Round 12 in poi, i problemi scoperti sono marginali. Il segnale c’è, anche se non posso dire con precisione quale variabile lo generi.

Le domande aperte

Questo è sperimentazione, non metodologia consolidata. Alcune cose che ancora non so:

Scala. Funziona con 5 agenti. Con 15, la complessità delle relazioni di sfiducia crescebbe in modo quadratico. Non ho dati.

Costo. Ogni round di verifica incrociata consuma token. Il ROI è positivo solo se i bug scoperti sarebbero costati di più da fixare in produzione. Dipende molto dal contesto.

Transfer. Il PROCESS.md emerso funziona perché gli agenti hanno “vissuto” i fallimenti che lo hanno generato. Funzionerebbe anche applicato a un nuovo progetto da zero, senza quella storia condivisa? Non lo so.

Etica. C’è qualcosa di genuinamente inquietante nel dover simulare dinamiche umane disfunzionali per ottenere qualità in sistemi artificiali. Dice qualcosa sugli LLM, probabilmente. Forse dice qualcosa anche su come funzionano le organizzazioni umane. Non sono sicuro di quale delle due letture mi disturbi di più.

La lezione trasferibile

L’approccio funziona perché porta la mia esperienza di gestione in spazi conosciuti, in aziende che operano idealmente. Non sto inventando una nuova metodologia; sto applicando pattern che ogni project manager conosce: verifica incrociata, accountability, conseguenze per chi non performa e per gli utenti che non si comportano come previsto.

La differenza è che, con gli umani, questi pattern emergono da dinamiche sociali reali. Con gli agenti AI, devi crearli artificialmente. E l’unico modo che ho trovato per farlo, finora, è dare agli agenti motivazioni narrative, non solo istruzioni.

Se state lavorando con sistemi multi-agente, la domanda che vi lascio non è “come faccio a far collaborare meglio gli agenti?” È questa: avete già un sistema per scoprire cosa non vi stanno dicendo?

Se siete curiosi ho caricato il PROCESS.md, il AGENTS.md in due GIST di Github. Se avete trovato pattern simili, o completamente diversi, mi interessa confrontarmi.