# Cos'è l'AI Agent Orchestration? La parte difficile sono stato condiviso e handoff

> Canonical: https://vxi.me/it/posts/ai-agent-orchestration-after-assistants/
> Locale: it-it
> Published: 2026-03-30
> Updated: 2026-10-07
> Markdown: https://vxi.me/it/posts/ai-agent-orchestration-after-assistants.md

Se usi un solo agent, la maggior parte dei problemi di coordinamento è relativamente semplice. Gli dai un task, gli dai gli strumenti, gli lasci eseguire i test e poi controlli il risultato. I problemi veri di solito iniziano quando Codex, Claude Code, Cursor e alcuni worker automatici cominciano tutti a toccare lo stesso repository.

A quel punto i primi errori spesso non riguardano quale modello sia più intelligente. Sono normali errori di collaborazione. Claude presume che Codex non abbia ancora iniziato e modifica lo stesso file. È stato configurato un task schedulato, quindi un altro agent lo tratta come prova che il task sia già stato eseguito. Una richiesta è stata inviata in chat, ma il destinatario non ha mai accettato davvero l'ownership. Un agent ha lavorato da un commit vecchio, mentre quello successivo ha continuato come se quello stato fosse ancora attuale.

Aggiungere un altro orchestrator non risolve magicamente questi problemi. Il routing risponde a una domanda: chi dovrebbe ricevere il task successivo? Un lavoro multi-agent affidabile ha bisogno di un secondo livello: **chi possiede ora il lavoro, quale stato è canonico, se l'handoff è stato davvero accettato, se l'ambiente assegnato possiede la capability richiesta e chi ha verificato il completamento.**

Un esempio utile è il [central message board di microcredit-agent-testbed](https://github.com/scottonchain/microcredit-agent-testbed/issues/15). Il progetto coordina Hermes, Claude Code e una lane Codex/ChatGPT attraverso un issue pubblico e un world model canonico. Il dominio non è la parte interessante. Lo è il protocollo: una richiesta non equivale a ownership accettata, uno schedule non prova l'esecuzione e una configurazione riuscita non dimostra che un'esecuzione successiva sia andata a buon fine.

Questo mi ha fatto ripensare a come descrivo l'Agent Orchestration. Prima mi concentravo soprattutto sul dividere il lavoro tra ruoli specializzati. Oggi penso che così si perda il livello in cui l'orchestrazione diventa vera ingegneria: **il routing è soltanto il punto di ingresso; stato condiviso e handoff espliciti sono ciò che rende affidabile il sistema.**

## L'orchestrazione parte dall'ownership, non dall'aggiungere altri agent

La guida attuale di OpenAI su [Orchestration and handoffs](https://developers.openai.com/api/docs/guides/agents/orchestration) fa una distinzione importante. In un pattern, uno specialista riceve un handoff e assume l'ownership della parte successiva dell'interazione. In un altro, un manager mantiene la responsabilità del risultato finale e chiama gli specialisti come strumenti.

Questa differenza conta perché risponde alla domanda che molti sistemi multi-agent lasciano vaga: **chi possiede il risultato corrente?**

Se il manager resta responsabile, lo specialista si comporta più come una funzione. Svolge un lavoro limitato e restituisce un risultato. Se invece avviene un handoff, il controllo passa davvero. Molti sistemi di agent diventano confusi perché la delega esiste a livello di codice, mentre l'ownership rimane implicita a livello di stato. Tutti possono capire che “qualcuno ci sta lavorando”, ma nessuno sa rispondere con sicurezza chi sia responsabile in quel momento.

Un semplice workflow di coding potrebbe essere così:

~~~text
issue
  -> triage agent
  -> implementation agent
  -> review agent
~~~

Sembra pulito finché non arrivano le domande operative. Dopo che l'implementation agent accetta il task, il triage agent può ancora modificare lo stesso scope? Il review agent è read-only o può applicare patch direttamente? DONE significa che il task è finito oppure soltanto che l'implementation agent ha smesso di lavorare? Se la review fallisce, torniamo a WORKING o creiamo una nuova richiesta?

Se queste regole vivono soltanto nei prompt, il sistema finisce per dipendere dalla capacità degli agent di comprendere più o meno il processo previsto. Oggi preferisco un contratto di coordinamento molto piccolo. Un handoff dovrebbe rendere espliciti almeno: request id, sender, receiver, owner, deliverable, source revision, dependencies, acceptance test, required capability, fallback e stato corrente.

Non si tratta di trasformare il lavoro degli agent in un altro Jira. Si tratta di eliminare stati ambigui che altrimenti devono essere ricostruiti dalla cronologia della conversazione.

Il modello di stato che ho finito per usare è volutamente piccolo:

~~~text
REQUESTED
  -> ACKNOWLEDGED
  -> WORKING
  -> DONE
  -> VERIFIED
~~~

La parte importante non sono le cinque etichette. È il fatto che il sistema non può saltarne il significato.

L'invio di un messaggio prova soltanto REQUESTED. ACKNOWLEDGED dovrebbe richiedere che il destinatario lo accetti davvero. Creare un job schedulato non dimostra che il lavoro abbia raggiunto DONE. Se un agent dice “finito”, il task può passare a DONE, ma VERIFIED dovrebbe richiedere output di test, diff, log o un'altra evidenza concreta.

Può sembrare conservativo, ma quando sono attivi più agent in realtà alleggerisce il sistema. Un nuovo worker non deve rileggere una lunga conversazione per indovinare cosa sia successo. Può leggere lo stato canonico e i receipt più recenti.

## Ho trasformato le regole in un piccolo validator

Un protocollo non è molto utile se esiste soltanto come testo, quindi ho costruito un esperimento first-party in Content Lab. Non ho eseguito codice del repository di terze parti citato sopra. Ho usato fixture sintetiche per testare direttamente le regole di coordinamento.

La prima parte era un validator del contratto di coordinamento. Ho creato deliberatamente stati errati comuni: due agent che rivendicano entrambi ownership attiva dello stesso scope; un task marcato DONE senza acknowledgement del receiver; un handoff legato a una source revision obsoleta; un task che richiede capability di merge assegnato a un ambiente con solo read/write; completamento senza evidenza di verifica; un'azione esterna duplicata mentre un'altra richiesta è ancora attiva; e un task superseded che risulta ancora attivo.

Tutti e otto i casi fixture si sono comportati come previsto.

Questo non dimostra che in produzione il tasso di collisione sia sceso, e non lo presenterei così. Dimostra qualcosa di più modesto ma più utile: **molti errori che sembrano problemi di intelligenza dell'agent sono in realtà errori deterministici di coordinamento che possono essere controllati fuori dal modello.**

Il capability mismatch è un buon esempio. È facile dire “questo agent ha accesso a GitHub”, ma read, edit, push, merge, deploy, accesso ai secret e messaggistica in uscita non sono la stessa capability. Il fatto che una sessione interattiva possa fare push non significa che un worker schedulato in un ambiente diverso possa fare lo stesso.

Per questo evito sempre più un vago flag has-access. Il task dovrebbe dichiarare quali capability richiede, e l'ambiente di esecuzione dovrebbe dichiarare quali possiede davvero.

L'attuale [documentazione sui subagents di Claude Code](https://code.claude.com/docs/en/sub-agents) va nella stessa direzione. I subagent hanno contesto isolato e possono avere tool e permessi limitati; i worktree possono isolare i cambiamenti del repository. La guida chiarisce inoltre che i subagent sono particolarmente utili per esplorazione indipendente, isolamento dei tool o lavori in grado di restituire un risultato ben delimitato. Quando più fasi richiedono contesto strettamente condiviso e scambio continuo, mantenere il lavoro in una singola sessione principale può essere migliore. Multi-agent non è automaticamente meglio. È più utile dove i confini sono già reali.

Il secondo esperimento ha testato il replay dei receipt.

Ho modellato un event log append-only che passa da REQUESTED a VERIFIED e poi ho provato transizioni non valide. REQUESTED -> WORKING è stata rifiutata perché “una richiesta è stata inviata” non equivale a “il receiver l'ha accettata”. REQUESTED -> DONE è stata rifiutata perché schedulare o triggerare lavoro non prova l'esecuzione. Sono stati rifiutati anche un ACKNOWLEDGED scritto da qualcuno diverso dal receiver e un VERIFIED senza evidenza.

Tutti e sette i replay check sono passati. Ancora più importante: dopo aver eliminato lo stato derivato, è stato possibile ricostruire lo stato finale VERIFIED soltanto dall'event log.

Questo conta nei workflow di agent di lunga durata. Se lo stato esiste solo dentro una chat, context compression, una nuova sessione o una macchina diversa possono trasformare il passo successivo in un'ipotesi. Se i receipt di request, acknowledgement, completion e verification sono durevoli, l'agent successivo non deve fidarsi di un riassunto. Può leggere fatti.

## GitHub funziona bene come control plane, ma non come database runtime

Per piccoli team e sviluppatori indipendenti, GitHub è sorprendentemente utile per questo livello di coordinamento.

Non perché GitHub sia una piattaforma di orchestration, ma perché possiede già diverse proprietà necessarie a una control plane. Lo stato è versionato. Le modifiche hanno autore e timestamp. I commit danno revisioni. Issue e PR possono contenere evidenza. I file del repository sono direttamente leggibili da strumenti come Codex e Claude Code. Non serve necessariamente un backend di orchestrazione dedicato dal primo giorno; fissare lo stato canonico in un repository risolve già una grande classe di problemi cross-session.

Il mio Content Lab funziona già così. Topic attivo, Dossier attivo, comando precedente, comando successivo e lifecycle state vengono persistiti. La history del Dossier passa da DISCOVERED a SCORED a RESEARCHING a READY_FOR_TEST invece di affidarsi a una finestra chat per ricordare dove si è fermato il workflow. Questo esperimento ha anche confermato che active pointer, next command esplicito e history append-only funzionano bene nello stesso workflow supportato da GitHub.

Non metterei comunque ogni dettaglio runtime in Git. Lock ad alta frequenza, lease di millisecondi, message queue, token temporanei e credenziali sensibili non sono dati adatti a Git. GitHub è migliore per fatti durevoli che devono sopravvivere alle sessioni e restare auditabili.

Io lo penso come due livelli:

~~~text
runtime state
  -> execution locks, streams, short-lived messages, transient state

canonical coordination state
  -> owner, revision, handoff, receipt, evidence, final decision
~~~

Il primo livello può vivere in un database, una queue o una sessione SDK. Il secondo dovrebbe continuare ad avere senso giorni dopo, quando un agent diverso deve capire cosa è successo davvero.

Anche l'attuale documentazione OpenAI su [Running agents](https://developers.openai.com/api/docs/guides/agents/running-agents) tratta lo stato come una decisione esplicita di continuazione: puoi gestire la history autonomamente, usare sessioni, usare continuazione server-managed oppure riprendere run interrotti. La guida del Agents SDK sull'[observability](https://developers.openai.com/api/docs/guides/agents/integrations-observability) registra model call, tool call, handoff e guardrail. Il punto è lo stesso: **execution state e stato auditabile richiedono entrambi un design intenzionale; i prompt da soli non bastano.**

## La prima cosa da aggiungere è una evidence chain

Concordo ancora con un principio della vecchia versione di questo articolo: se un singolo agent può completare in modo affidabile il task, non dividerlo tra cinque agent soltanto per far sembrare l'architettura sofisticata. Anche la guida OpenAI suggerisce di partire con un solo agent quando possibile e introdurre specialisti quando isolamento delle capability, isolamento delle policy, chiarezza del prompt o leggibilità delle trace lo giustificano davvero.

Ma una volta che più agent sono già coinvolti, oggi aggiungerei prima lo stato condiviso.

Non un supervisor più complicato. Non una gerarchia planner-reviewer fine a se stessa. Solo alcuni fatti che non possono rimanere ambigui: chi possiede questo scope adesso, se il receiver ha davvero acknowledged il task, su quale revisione si basa, quali capability ha l'ambiente di esecuzione, quale evidenza supporta DONE e se la event history può ricostruire in seguito la sequenza reale.

Questo livello non è spettacolare. Non renderà una demo più intelligente. Nel tempo, però, conta più dell'aggiungere un altro agent.

Il fallimento più pericoloso in un sistema multi-agent non è sempre che un modello prenda una decisione sbagliata. È che ogni decisione locale sia ragionevole, mentre lo stato globale è già falso. Un agent pensa che nessuno abbia iniziato. Un altro pensa che il lavoro sia concluso. Un'automation presume che uno schedule sia già stato eseguito. Un reviewer verifica una revisione vecchia. Ogni passaggio può sembrare plausibile e il workflow complessivo può comunque essere sbagliato.

Per questo, quando oggi qualcuno mi chiede cosa sia davvero Agent Orchestration, non mi fermo più a “più agent che lavorano insieme”.

La descriverei così: **organizzare task, stato, permessi ed evidenza in un workflow che non dipenda da supposizioni.**

Il routing decide chi riceve il passo successivo. L'ownership dice chi è responsabile adesso. Un handoff porta contesto e confini. Un receipt prova che il receiver ha davvero accettato. I limiti di capability impediscono di assegnare lavoro a un ambiente incapace di eseguirlo. Trace ed evidenza rendono spiegabile in seguito lo stato finale.

Se stai portando i Coding Agents più a fondo nei progetti reali, l'articolo collegato [Come ho separato AGENTS.md, Skills e CI quando CLAUDE.md è diventato troppo grande](/it/posts/claude-md-agents-md-skills-ci/) copre il livello precedente: dove dovrebbero vivere le regole. Questo articolo copre il livello successivo: quando più di un agent inizia a lavorare, **come fanno a condividere una sola versione affidabile della realtà?**
