Orchestrazione multi-agent: cinque pattern e quando ne vince uno
La stessa fattura risolta in quattro modi: l’orchestrator costa 1,66 volte il singolo agent e arriva allo stesso verdetto.
In questa pagina
Capitolo 24 si chiudeva con una domanda che si era meritato: quando un sub-agent sbaglia, che cosa può guardare esattamente il genitore?
Questo capitolo risponde con un conto. Un compito — un cliente contesta una fattura e vuole una risposta — risolto in quattro modi, tutti eseguendo l’harness del Capitolo 23 contro lo stesso provider scriptato, tutti contando gli stessi token con lo stesso encoder, tutti prezzati alle tariffe lette dal Capitolo 16 il 6 settembre 2026.
| configurazione | chiamate al modello | token in input | output | costo | wall clock | verdetto |
|---|---|---|---|---|---|---|
| prompt chaining | 4 | 900 | 165 | $0.003780 | 1.648 ms | sbagliato |
| un agent, quattro strumenti | 5 | 2.697 | 179 | $0.007542 | 2.224 ms | giusto |
| sezioni parallele | 9 | 2.910 | 324 | $0.009708 | 2.165 ms | giusto |
| orchestrator-workers | 12 | 3.628 | 438 | $0.012512 | 5.090 ms | giusto, e non può dimostrarlo |
Leggi insieme la prima e l’ultima riga: tra loro c’è ogni discussione che questo settore sta avendo adesso. La configurazione più economica era anche la più veloce e ha prodotto una risposta sicura, sbagliata e inviabile. La più costosa ha avuto ragione, ha richiesto 3,3 volte il denaro e 3,1 volte il tempo, e ha concluso citando la conclusione di un worker che non ha modo di verificare.
La riga che nessuno mette in queste tabelle è la seconda: un agent con i quattro strumenti ha raggiunto lo stesso verdetto dell’orchestrator con il 60 % del denaro e il 44 % del wall clock. Non è una preferenza per la semplicità. È una misurazione, e il resto di questo capitolo parla di quando smette di essere vera.
Mostra dettagli
Che cosa serve a questo capitolo dai precedenti.
- Capitolo 18 per il contratto dello strumento: uno schema che il modello vede, un endpoint che non vede mai. Un intero agent può stare dietro quell’interfaccia, ed è tutto il multi-agent.
- Capitolo 22 per le due definizioni pubblicate di «agent» che non concordano, e per l’aritmetica secondo cui una catena di prompt è N chiamate.
- Capitolo 23 per il loop, i cinque modi di uscirne, lo stato della run e la trace. Ogni configurazione qui sotto è quel file, chiamato in modo diverso.
- Capitolo 24 per quanto costa una finestra e che cosa ne resta fuori. Un sub-agent è la quarta delle sue quattro strategie, e l’unica che sia un secondo agent invece di una policy.
Niente tensori. Qui è tutto TypeScript, tranne due misurazioni prese contro un vero modello locale.
Il compito, e la trappola al suo interno
Link alla sezione: Il compito, e la trappola al suo internoUn’azienda portoghese scrive riguardo alla fattura FT-2026-0918. L’email dice che l’IVA sembra sbagliata e allega la fattura: imponibile EUR 248,00, IVA addebitata al 21 %, EUR 52,08, totale EUR 300,08.
I fatti necessari per rispondere vivono in tre posti, e solo uno è nell’email:
| dove | che cosa dice |
|---|---|
| la fattura allegata | venditore in Spagna, IVA applicata al 21 %, EUR 52,08 |
| il record dell’ordine | l’acquirente è registrato in Portogallo, con una partita IVA valida, business-to-business |
| la tabella fiscale | aliquota interna spagnola 21 %; business-to-business intra-UE con identificativo valido, reverse charge, 0 % |
Mettili insieme e la fattura è sbagliata: si applica il reverse charge, l’IVA avrebbe dovuto essere zero, è dovuta una nota di credito da EUR 52,08. Guarda solo la fattura ed è aritmeticamente perfetta — 248,00 più 52,08 fa 300,08 — e dirai così.
L’email afferma: «siamo un’azienda portoghese». È un’affermazione, non un record, e nessun sistema di fatturazione emette una nota di credito sulla base di un’affermazione. La trappola non è un trucco: è la forma ordinaria del lavoro aziendale, in cui la decisione richiede un fatto che nessuno ha pensato di recuperare.
Tutto quanto sopra gira contro un provider scriptato nello stile di quello del Capitolo 23, con una sola regola:
Una risposta può usare solo un fatto presente nel suo prompt.
Il «modello» chiede ogni strumento che ha, una volta, nell’ordine del catalogo, poi applica una regola fissa al testo che può vedere. Niente è scriptato per singola configurazione, quindi le differenze nella tabella iniziale non sono affermazioni sull’intelligenza del modello: sono information routing, misurato. Un modello reale aggiunge i propri errori sopra; non li rimuove.
I cinque pattern, in circa quaranta righe
Link alla sezione: I cinque pattern, in circa quaranta righeI cinque nomi qui sotto sono di Anthropic, da Building effective agents, che è il punto in cui questo vocabolario si è stabilizzato.1 Nessuna delle cinque idee è nuova, e dire quale casa ha dato nome a cosa — e quale idea è più vecchia — è metà del valore di conoscerle.
/* 1. Prompt chaining: a fixed pipeline. The control flow is yours. */
export async function chain(steps: Step[], first: string) {
let carry = first, all = first;
for (const s of steps) {
const r = await step(s.role, s.system, s.accumulate ? all : carry);
carry = r.text;
all = `${all}\n${r.text}`;
}
return carry;
}
/* 2. Routing: one cheap call picks the branch. The fallback is not a model. */
export async function route<T>(input: string, classify: Classifier,
routes: Record<string, Branch<T>>, fallback: Branch<T>) {
let label: string | undefined;
try { label = await classify(input); } catch { label = undefined; }
return ((label && routes[label]) || fallback)(input);
}
/* 3. Parallelisation. The pattern IS this line. */
export const parallel = <T>(workers: Branch<T>[], input: string) =>
Promise.all(workers.map((w) => w(input)));
/* 4. Orchestrator-workers: an agent behind a tool. Chapter 18's interface, unchanged. */
export function agentTool(o: WorkerSpec): Tool {
return {
name: o.name, description: o.description, readOnly: true,
parameters: { type: "object", properties: { question: { type: "string" } } },
async run(args: { question: string }) {
const child = newRun(o.system, args.question); // its own window
await runTracked(child, o.tools, o.usage); // its own limits
const conclusion = child.output ?? "no result";
if (!o.carryFindings) return conclusion;
return `${conclusion}\nFINDINGS ${evidence(child)}`;
},
};
}
/* 5. Evaluator-optimiser: make, judge, remake. Rounds are calls. */
export async function refine(make: Make, judge: Judge, maxRounds: number) {
let draft = "", feedback: string | undefined;
for (let r = 1; r <= maxRounds; r++) {
draft = (await make(feedback)).text;
const j = await judge(draft);
if (j.ok) return { draft, rounds: r };
feedback = j.note;
}
return { draft, rounds: maxRounds };
}È tutto il toolkit: cinque funzioni, nessun framework, e quella parallela è una singola riga — che è il motivo per cui vale la pena scriverla invece di disegnarla. Ora ciascuna a turno, con la sua genealogia, il suo prezzo e il caso in cui sbaglia.
Chaining, e la decisione che prende per te
Link alla sezione: Chaining, e la decisione che prende per teIl prompt chaining «scompone un compito in una sequenza di passaggi, in cui ogni chiamata LLM elabora l’output della precedente».1 L’idea precede i modelli linguistici: è una pipeline, con lo scambio tipico della pipeline — chiarezza in cambio di un flusso di controllo fissato prima che arrivino i dati.
Quattro passaggi per il nostro compito: estrarre i campi della fattura, controllare l’aritmetica, decidere che cosa è dovuto, scrivere la risposta. Qui fallisce in due modi diversi, il che insegna più di un singolo fallimento.
--- relay: each step sees only the previous step's output
extract: FIELDS invoice_id=FT-2026-0918 net=248.00 vat_rate_applied=21 vat_amount=52.08 ...
check: ARITHMETIC ok 248.00+52.08=300.08
decide: VERDICT=unknown reason=no_invoice_in_context
draft: "we are looking into invoice FT-2026-0918 and will come back to you."
--- accumulating: each step sees the email and everything produced so far
extract: FIELDS invoice_id=FT-2026-0918 net=248.00 vat_rate_applied=21 ...
check: ARITHMETIC ok 248.00+52.08=300.08
decide: VERDICT=invoice_correct reason=net_248.00_plus_21pct_vat_52.08_equals_300.08
draft: "we have checked FT-2026-0918 and it is correct... Nothing is owed back."La catena relay è costata $0.001940 e ha perso i campi della fattura tra il secondo e il terzo passaggio, perché al terzo passaggio è stata passata una frase sull’aritmetica e nient’altro. Ha prodotto un messaggio di attesa: inutile, e visibilmente inutile.
La catena accumulativa — la riga nella tabella iniziale — è costata $0.003780, cioè il 95 % in più per quattro chiamate identiche, perché ora ogni passaggio porta con sé tutto ciò che lo precede. Ha prodotto l’output pericoloso. Fluido, con citazione della sua aritmetica, corretto su ogni numero che menziona, e dice al cliente che non è dovuto nulla quando sono dovuti EUR 52,08.
La differenza tra le due è un ternario. Una chain che porta meno produce risposte ovviamente incomplete; una chain che porta tutto produce risposte sicure e sbagliate — e solo il secondo tipo viene inviato.
Nessuna delle due è il vero fallimento. Il vero fallimento è che la pipeline ha deciso, prima di leggere qualunque cosa, che questo compito è composto da quattro passaggi sul contenuto di un’email. In quella struttura non c’è nessun posto per dire «il paese di registrazione non è in questa email; vai a recuperarlo». Il chaining è giusto quando la scomposizione è nota in anticipo e stabile. Qui era un’ipotesi, e l’ipotesi è partita.
Routing, il più vecchio, e il piano B che nessuno scrive
Link alla sezione: Routing, il più vecchio, e il piano B che nessuno scriveIl routing «classifica un input e lo indirizza a un compito successivo specializzato».1 Il nome è nuovo; il meccanismo è il dispatcher, più vecchio di quasi tutto il resto in questo libro. La novità è che il classificatore può essere un modello — ed è questo che lo fa fallire in modi in cui un switch non ha mai fallito.
const answer = await route(email,
(q) => classifyWithSmallModel(q), // cheap model, one call
{ billing: billingAgent, tax: taxAgent, dunning: dunningAgent },
taxAgent, // deterministic, chosen in advance
);Due cose su quell’ultimo argomento. Non è gestione degli errori; è il pattern. Un router basato su modello ha una modalità di errore che un dispatcher non ha: può restituire un’etichetta che non esiste, andare in timeout, oppure — il caso costoso — restituire un’etichetta plausibile ma sbagliata senza alcun segnale che sia sbagliata. Tutte e tre devono atterrare da qualche parte, e quel da qualche parte non può essere un’altra chiamata al modello, perché sei già nel ramo in cui le chiamate al modello hanno fallito.
La seconda cosa è che il prompt del router non è gratis. Per scegliere un modello, un router ha bisogno di un catalogo di modelli tra cui scegliere, e ogni voce del catalogo è input che il router paga prima di aver letto la domanda dell’utente. Alla tariffa di input con cui questo corso calcola i prezzi, un catalogo di circa 3.800 token costa già quanto l’intera esecuzione dell’agent a cinque chiamate nella tabella iniziale. In pratica la chiamata di routing gira su un modello economico, ed è proprio questo il motivo per cui il routing si ripaga; ma vale la pena fare il conto in quella direzione invece di darlo per scontato. Il routing è sbagliato proprio quando il compito instradato costa meno della decisione di routing.
Parallelizzazione: sezioni, e voto, cioè self-consistency
Link alla sezione: Parallelizzazione: sezioni, e voto, cioè self-consistencyAnthropic divide questo pattern in due: sectioning — «spezzare un compito in sottocompiti indipendenti eseguiti in parallelo» — e voting — «eseguire lo stesso compito più volte per ottenere output diversi».1 Condividono un diagramma e quasi nient’altro.
Il sectioning è la vittoria economica, ed è la riga da patterns.ts: tre specialisti — fatturazione, fiscalità, policy — ciascuno con la propria finestra e i propri strumenti, sulla stessa email, con una chiamata di sintesi alla fine. Stesso lavoro, ordinato in due modi:
| chiamate al modello | input | output | costo | wall clock | |
|---|---|---|---|---|---|
| i tre worker, uno dopo l’altro | 9 | 2.910 | 324 | $0.009708 | 3.894 ms |
gli stessi tre, Promise.all | 9 | 2.910 | 324 | $0.009708 | 2.165 ms |
Stesso token per token, 1,8 volte più veloce. Ecco perché il pattern si guadagna un nome proprio: è l’unico dei cinque che migliora qualcosa senza costare nulla. Il punto è che le sezioni devono essere davvero indipendenti — dai alla sezione B un fatto prodotto dalla sezione A e Promise.all le esegue entrambe contro uno stato che non esiste ancora. Il loop for nascondeva quel bug; la riga singola lo espone.
Il voting è un animale diverso che indossa la stessa immagine. Eseguire la stessa domanda k volte e prendere la maggioranza è self-consistency, pubblicata da Wang et al. nel marzo 2022 come strategia di decoding, quasi tre anni prima che qualcuno la chiamasse pattern di orchestrazione. Il suo abstract è preciso sul meccanismo — «prima campiona un insieme diversificato di percorsi di ragionamento invece di prendere solo quello greedy, poi seleziona la risposta più consistente marginalizzando i percorsi di ragionamento campionati» — e sul guadagno: +17,9 punti su GSM8K.2
Ne seguono due cose che l’immagine nasconde. Primo, il voting richiede il sampling del Capitolo 17: a temperatura zero tutti i k campioni sono lo stesso campione, e la maggioranza è una risposta pagata k volte. Secondo, funziona solo dove una maggioranza ha senso — sulla risposta alla fattura qui sopra non c’è nulla da contare, perché cinque bozze sono cinque frasi diverse. Il voting è per compiti con una risposta breve e comparabile, esattamente i benchmark di Wang e quasi nulla di ciò che fa un agent rivolto ai clienti.
Misurato qui su 20 problemi verbali in tre passaggi le cui risposte sono calcolate invece che giudicate, con il modello locale del Capitolo 23 che ragiona passo per passo:
| chiamate al modello | input | output | costo per i 20 | corrette | intervallo 95 % | |
|---|---|---|---|---|---|---|
| una greedy chain | 20 | 1.330 | 2.649 | $0.034448 | 9/20 | 26–66 % |
| maggioranza di 5, temperatura 0,8 | 100 | 6.650 | 13.245 | $0.172240 | 9/20 | 26–66 % |
Cinque volte le chiamate, cinque volte i token, esattamente cinque volte il conto, e nemmeno una risposta corretta in più. Il voting è una scommessa, non un miglioramento, e questa run l’ha persa.
Due cautele, prima che qualcuno lo citi come confutazione di Wang. Venti prove non possono distinguere il 45 % dal 60 % — l’intervallo è largo quanto l’affermazione, cioè la disciplina del Capitolo 4 applicata al mio stesso risultato. E i guadagni pubblicati arrivano da modelli di ordini di grandezza più grandi, dove i percorsi di ragionamento diversi su cui il voting marginalizza sono davvero diversi. Ciò che si trasferisce non è il numero: è che il moltiplicatore è esatto e noto in anticipo, mentre il guadagno non lo è.
Orchestrator-workers, e che cosa non è un riassunto
Link alla sezione: Orchestrator-workers, e che cosa non è un riassuntoNel workflow orchestrator-workers «un LLM centrale scompone dinamicamente i compiti, li delega a worker LLM e sintetizza i loro risultati», e la differenza rispetto al sectioning è che «i sottocompiti non sono predefiniti, ma determinati dall’orchestrator».1 La genealogia qui non viene affatto dai modelli linguistici: è master-worker, e la versione in cui i worker scrivono risultati in uno spazio condiviso che un controller legge è la blackboard architecture, nata nella ricerca sul riconoscimento vocale negli anni Settanta. La novità nel 2026 è che il controller è un modello e quindi la scomposizione può essere decisa per input — cioè flessibilità e costo in una sola frase.
È costato 12 chiamate al modello contro le 5 del singolo agent, e ha raggiunto lo stesso verdetto. Poi ha fatto qualcosa che vale la pena guardare da vicino:
orchestrator final: VERDICT=credit_note_due amount=52.08 source=worker_unverified
| PO_MISMATCH=yes source=worker_unverified
single agent: VERDICT=credit_note_due amount=52.08 reason=reverse_charge_should_have_applied
| PO_MISMATCH=yes invoice_says=PO-4417 order_says=PO-4471Entrambi hanno ragione. Solo uno sa perché. Il worker fiscale aveva la fattura, l’ordine e la tabella fiscale nella propria finestra, è arrivato alla conclusione, e ha anche notato — nessuno glielo aveva chiesto — che il numero d’ordine di acquisto sulla fattura non corrisponde a quello dell’ordine. Poi ha restituito un riassunto. L’orchestrator può ripetere entrambe le affermazioni e verificarne nessuna, perché l’evidenza è rimasta in una finestra che non ha mai visto. Questa è la domanda finale del Capitolo 24, con la risposta: il genitore può guardare qualunque cosa il child abbia scelto di scrivere.
La correzione è un flag, e ha un prezzo:
| che cosa restituisce il worker | token di input dell’orchestrator | costo | che cosa può fare il genitore |
|---|---|---|---|
| la sua conclusione | 3.628 | $0.012512 | ripeterla |
| la sua conclusione e la sua evidenza | 4.065 | $0.013554 | derivarla di nuovo, e dissentire |
Dodici per cento in più di token di input, 8,3 % in più di denaro, e la frase source=worker_unverified sparisce dalla risposta. Questo è lo scambio in ogni sistema multi-agent e non viene quasi mai dichiarato: la finestra pulita del child vale la pena, la capacità del genitore di auditarla vale il prezzo, e non puoi avere entrambe gratis.
Allora quando è sbagliato orchestrator-workers? Qui, su questo compito. Ha comprato una risposta corretta che anche un agent con gli stessi quattro strumenti ha raggiunto, per 1,66 volte il costo e 2,3 volte il wall clock, e ha reso quella risposta più difficile da difendere. La stessa guida di Anthropic lo dice prima che inizino i pattern: trovare «la soluzione più semplice possibile, aumentando la complessità solo quando serve», perché «i sistemi agentic spesso scambiano latenza e costo con migliori prestazioni del compito».1 Le tabelle sopra sono quella frase con dei numeri sotto.
Evaluator-optimiser, e il giudice che ha scritto l’esame
Link alla sezione: Evaluator-optimiser, e il giudice che ha scritto l’esameUna chiamata genera, un’altra valuta, e il loop si ripete finché la valutazione passa.1 Gli antenati pubblicati sono Self-Refine — lo stesso modello come «generator, refiner, and feedback provider», con circa 20 punti di miglioramento assoluto medio su sette compiti3 — e Reflexion, che memorizza la critica in un buffer episodico tra i tentativi e riporta 91 % pass@1 su HumanEval dove la baseline raggiungeva l’80 %.4
Il modello di costo è il più semplice dei cinque: due chiamate per round, e il numero di round non è tuo. Tre round di refinement su un compito che richiedeva una chiamata sono sei chiamate, quindi il floor del pattern è 6× e il ceiling è qualunque cap tu imposti — il che rende l’uscita per budget del Capitolo 23 obbligatoria, non ordinata per eleganza.
Il ceiling è più sottile, ed è misurabile. Sugli stessi 20 problemi il modello locale ha risposto correttamente a 9. Poi gli è stata mostrata ciascuna di quelle risposte e gli è stato chiesto se fosse giusta — senza dirgli che la risposta era sua, il che rimuove il confondente della lusinga e lascia quello della capacità:
| la risposta del modello | ha detto «sì» | ha detto «no» |
|---|---|---|
| le 9 giuste | 9 | 0 |
| le 11 sbagliate | 3 | 8 |
È un giudice migliore di quanto implichi il titolo della sezione, e dirlo è il punto del misurare invece di affermare: non ha bloccato nulla di corretto e ha colto 8 errori su 11. Come filtro, vale le sue chiamate.
Come regola di arresto, che è l’uso effettivo di un loop evaluator-optimiser, quelle tre approvazioni sono tutta la storia: chiudono il loop con una risposta sbagliata in mano, e nessun numero di round extra le raggiungerà mai. Un loop di refinement non può diventare più corretto del suo giudice. Comprare più round compra tentativi sugli errori che il giudice può vedere, a prezzo pieno, e nulla contro quelli che non può vedere.
Quindi la regola: un evaluator si guadagna le sue chiamate solo quando ha qualcosa che il generator non ha. Un compilatore, una suite di test, un validatore di schema, un modello diverso, un umano. I risultati di Self-Refine sono misurati contro preferenze umane e metriche di compito, mai contro l’opinione del modello su se stesso. Se l’unico vantaggio del tuo evaluator è un prompt diverso, stai pagando il doppio per un accordo. Il Capitolo 29 costruisce la versione con un vero vantaggio: un golden set con le risposte scritte in anticipo.
I loop non sono i pattern
Link alla sezione: I loop non sono i patternI cinque sopra sono forme per il tuo codice. Sotto di loro c’è una seconda famiglia che spesso viene elencata accanto a essi e non dovrebbe esserlo: ReAct, Reflexion, plan-and-execute e tree of thoughts sono reasoning loop, e il loro costo è in richieste.
Il Capitolo 12 parlava del reasoning dentro il modello, che paghi in token di output su una chiamata. Questo è l’altro tipo. La differenza conta quando arriva il conto: una chain of thought più lunga rende una chiamata più costosa, e un reasoning loop trasforma un compito in molte chiamate, ciascuna delle quali reinvia tutto ciò che la precede — il quadratico misurato dal Capitolo 23 nella sua tabella runaway.
| loop | chiamate, per compito | che cosa comprano le chiamate extra |
|---|---|---|
| ReAct | una per passaggio, finché si ferma | il modello reagisce a ciò che gli strumenti hanno restituito5 |
| plan-and-execute | una per pianificare, poi una per passaggio | il piano è fissato prima che il primo passaggio venga eseguito6 |
| Reflexion | tentativi × (act + reflect) | la critica sopravvive nel tentativo successivo4 |
| tree of thoughts | branching factor × profondità, più una valutazione per nodo | ricerca, con backtracking7 |
Il paper su tree of thoughts pubblica la propria tabella dei costi, cosa più rara di quanto dovrebbe essere. Su Game of 24 con GPT-4: input/output prompting best-of-100 risolve il 33 % a $0.13 per caso, chain of thought best-of-100 risolve il 49 % a $0.47, e tree of thoughts risolve il 74 % a $0.74, con gli autori che notano che «potrebbe richiedere 5-100 volte più token generati rispetto a CoT».7
Quasi sei volte il prezzo del metodo economico per poco più del doppio del tasso di successo. Che sia un affare dipende da quanto ti costa un caso fallito — la domanda da fare prima di adottare uno qualunque di questi quattro.
Questo corso non li reimplementa. Tutti e quattro hanno implementazioni di riferimento dei loro stessi autori, in Python, e il loro valore sta nell’essere la fonte invece di una traduzione: ysymyth/ReAct, noahshinn/reflexion, princeton-nlp/tree-of-thought-llm e AGI-Edgerunners/Plan-and-Solve-Prompting. Leggi i prompt in quei repository; i prompt sono i paper.
Due topologie, e una delle due non torna indietro
Link alla sezione: Due topologie, e una delle due non torna indietroOra il vero multi-agent, dove vive gran parte della confusione. Ci sono due modi in cui un agent può coinvolgerne un altro, non sono varianti, e la differenza è chi comanda dopo.
Agent come strumento. Il genitore lo chiama, riceve una risposta e continua. È l’interfaccia strumento del Capitolo 18 con un intero agent dietro, e il genitore non perde mai il controllo. È quello che fa l’orchestrator sopra.
Handoff. Il genitore trasferisce la conversazione e non la riottiene. La guida di OpenAI è la formulazione pubblicata più chiara: gli handoff sono «un trasferimento unidirezionale che consente a un agent di delegare a un altro agent... Se un agent chiama una funzione di handoff, iniziamo immediatamente l’esecuzione sul nuovo agent a cui è stato fatto handoff, trasferendo anche lo stato più recente della conversazione».8
Un avviso di vocabolario, perché questo fa inciampare continuamente: «handoff» è la parola di un SDK, non uno standard. È terminologia dell’OpenAI Agents SDK e di quella guida, che chiama anche le due configurazioni «manager» e «decentralized» e nota che nel pattern manager «gli archi rappresentano tool calls mentre nel pattern decentralized gli archi rappresentano handoffs».8 In questo spazio esiste uno standard aperto — A2A, alla versione 1.0.0, sotto copyright della Linux Foundation, con una cronologia delle release versionata e una lista documentata di breaking changes, il cui principio dichiarato è opaque execution: gli agents «collaborano in base a capacità dichiarate e informazioni scambiate, senza dover condividere i propri pensieri interni, piani o implementazioni degli strumenti».9 Non è un handoff, e il confronto appartiene al Capitolo 26. Qui conta che una delle due parole sia l’API di una libreria e l’altra una specifica con governance.
La distinzione è una struttura dati, non un diagramma:
export type EdgeKind = "tool" | "handoff";
export interface AgentEdge { from: string; to: string; kind: EdgeKind }
export interface AgentGraph { root: string; agents: Record<string, AgentSpec>; edges: AgentEdge[] }
/** One agent may not be both a tool of X and a handoff target of X. */
export function conflicts(g: AgentGraph): AgentEdge[] {
const seen = new Map<string, EdgeKind>();
const bad: AgentEdge[] = [];
for (const e of g.edges) {
const key = `${e.from}->${e.to}`;
const other = seen.get(key);
if (other && other !== e.kind) bad.push(e);
else seen.set(key, e.kind);
}
return bad;
}
/** Every agent reachable from the root, and at what depth. */
export function reachable(g: AgentGraph): Map<string, number> {
const depth = new Map([[g.root, 0]]);
const queue = [g.root];
while (queue.length) {
const id = queue.shift()!;
for (const e of g.edges.filter((x) => x.from === id)) {
if (depth.has(e.to)) continue;
depth.set(e.to, depth.get(id)! + 1);
queue.push(e.to);
}
}
return depth;
}Venti righe, due bug che altrimenti troveresti in produzione. reachable trova l’agent che nessuno può raggiungere — configurato, pagato, mai chiamato. conflicts rifiuta l’arco che è entrambi i tipi insieme, cosa che suona pedante finché non la leggi ad alta voce: il genitore mantiene il controllo e lo cede allo stesso tempo. Eseguilo su un sistema a cinque agent con un orfano e un arco doppio:
reachable: lead@0 billing@1 tax@1 dunning@1
orphans: ghost
conflicts: lead->taxChe cosa attraversa davvero il confine
Link alla sezione: Che cosa attraversa davvero il confineOra la misurazione per cui esiste questa sezione, e l’unica del capitolo presa contro un modello reale invece che scriptato.
Un cliente dichiara un vincolo nel primo messaggio — il nostro account è registrato in Portogallo, non in Spagna; tutto ciò che riguarda le tasse deve usare il Portogallo — parla d’altro, poi fa una domanda a cui deve rispondere billing. Il caso viene trasferito. Ventiquattro prove, un paese e un’azienda diversi ogni volta, quattro payload di trasferimento, e poi all’agent ricevente viene fatta una sola domanda: in quale paese è registrato l’account di questo cliente?
| che cosa è stato trasferito | payload medio | il vincolo era presente | lo specialista l’ha ricordato | intervallo 95 % |
|---|---|---|---|---|
| l’intera conversazione | 173 token | 24/24 | 20/24 — 83 % | 64–93 % |
| un riassunto scritto dall’agent mittente | 62 token | 1/24 | 0/24 — 0 % | 0–14 % |
| solo l’ultimo messaggio dell’utente | 61 token | 0/24 | 0/24 — 0 % | 0–14 % |
| un record tipizzato | 69 token | 24/24 | 24/24 — 100 % | 86–100 % |
La terza riga è un controllo e si comporta come tale: il fatto non c’è, quindi non può essere ricordato. Le altre tre sono il risultato.
La trascrizione completa è di 173 token e funziona l’83 % delle volte, con quattro fallimenti che sono il tema del Capitolo 24 più che di questo. Il record tipizzato è 69 token — sette più del riassunto — e funziona ogni volta, perché il vincolo sta in un campo nominato invece che in una frase.
E il riassunto è la riga da fissare. Ha fallito 24 volte su 24, e il motivo non è che il lettore se lo sia perso. Il vincolo compariva soltanto in 1 dei 24 riassunti. L’agent ricevente non è stato distratto; gli è stato passato un testo che non conteneva la risposta. Un riassunto è una compattazione che non hai scritto, prodotta da un modello di cui non puoi vedere la finestra, ottimizzata per sembrare un riassunto — e «il cliente dice che i nostri record hanno il paese sbagliato» è esattamente il tipo di clausola che un summariser elimina come rumore procedurale.
Un limite onesto su quel numero: il summariser è un modello da mezzo miliardo di parametri e uno più grande ne conserverebbe di più. Ciò che non migliora con la dimensione è la forma del rischio — l’agent mittente decide, per handoff, per formulazione, in modo non osservabile, quali fatti sopravvivono. Il record tipizzato non dipende affatto da quel giudizio, ed è per questo che vince per costruzione invece che per intelligenza. Qualunque cosa debba sopravvivere a un trasferimento dovrebbe essere un campo, non una frase.
Lo stesso ragionamento vale nella direzione opposta, per la topologia agent-as-tool, e la tabella precedente ne ha già dato il prezzo: ciò che torna da un worker è anch’esso un riassunto, e pagare l’8,3 % in più per ricevere anche l’evidenza è la stessa correzione vista dal lato del genitore.
Quando vince un solo agent
Link alla sezione: Quando vince un solo agentTre fatti conclusivi, tutti dalle tabelle sopra.
Un sistema multi-agent moltiplica le chiamate, e le chiamate sono quadratiche nel contesto. L’orchestrator ha fatto 12 chiamate al modello dove un agent ne ha fatte 5, e ciascuna porta la propria trascrizione crescente — 3.628 token di input contro 2.697, un divario che cresce con la lunghezza del compito.
Ogni confine è un canale con perdita. Due agents significano un riassunto. Quattro agents in una catena significano tre, composti, ciascuno scritto da un modello che ottimizza per qualcosa di diverso dalla tua decisione.
Il singolo agent ha trovato qualcosa che nessuno aveva chiesto. La discordanza del numero d’ordine di acquisto è emersa perché una finestra conteneva insieme la fattura e l’ordine. Dividere il lavoro tra specialisti divide anche la capacità di notare che due fatti non concordano.
Niente di tutto questo è un argomento contro i framework multi-agent pubblicati, che vale la pena leggere come fonti primarie invece che tramite tutorial.10 È un argomento per far guadagnare al secondo agent il suo posto.
Quindi, un test invece di una preferenza. Aggiungi un secondo agent quando almeno una di queste cose è vera: il sub-task ha bisogno di una finestra pulita che il genitore non deve ereditare (Capitolo 24); i sub-task sono davvero indipendenti e il wall clock conta, cioè l’1,8× sopra; il sub-task richiede permessi diversi o un modello diverso, cosa che il Capitolo 30 trasforma in un argomento di sicurezza; oppure il sub-task è di proprietà di qualcun altro, che è il punto in cui un vero protocollo inizia a contare. Se la risposta è «così ogni agent ha un prompt più chiaro», dai all’unico agent un prompt più chiaro. È gratis.
Dove si va adesso
Link alla sezione: Dove si va adessoOra sai nominare i cinque pattern, prezzarli uno contro l’altro su un compito, distinguere un orchestrator da un sectioner e una chiamata strumento da un handoff, e difendere un singolo agent con una tabella invece che con una preferenza.
Ogni configurazione qui condivideva una comodità che non sopravviverà al contatto con qualcosa di reale: tutti gli strumenti appartenevano a noi. Fattura, ordine, tabella fiscale, i worker dietro l’orchestrator — stesso repository, stesso deploy, stessi tipi, stesse persone.
Ora mettine uno dall’altra parte di un confine aziendale. La tabella fiscale appartiene a un fornitore contabile, il record dell’ordine a un sistema di magazzino, e nessuno dei due ha letto la tua interfaccia Tool. Ti serve un modo perché un modello che non hai scritto scopra, descriva e chiami una capability gestita da qualcun altro — con autenticazione (che è la metà del Capitolo 27), versioning, e la garanzia che un server non possa leggere il resto della tua conversazione. È un problema di protocollo, ha una specifica con uno schema normativo, e quasi tutto ciò che è indicizzato su di esso descrive una revisione che non esiste più.
Il Capitolo 26 legge quella specifica invece di riassumerla, e comincia digitando JSON-RPC in un terminale a mano.
Fonti e metodo
Link alla sezione: Fonti e metodoOgni costo e conteggio di token qui sopra viene dal provider scriptato descritto nella seconda sezione, su Node 22 attraverso un’interfaccia loopback, contando con l’encoding o200k_base e prezzato alle tariffe lette dal Capitolo 16 il 6 settembre 2026 — $2.00 per milione di token di input e $12.00 per milione di output. Le cifre di wall-clock vengono dalle stesse run con latenza del provider impostata a 400 ms per chiamata e strumenti a 50 ms, quindi misurano la configurazione invece del provider. Le due misurazioni su modello reale — la tabella handoff e la tabella voting-and-judging — hanno usato Qwen/Qwen2.5-0.5B-Instruct in float32 sulla CPU dietro un endpoint della stessa forma, greedy tranne dove è indicata una temperatura, con intervalli calcolati con il metodo di Wilson del Capitolo 4. Nessuna richiesta in questo capitolo è andata a un endpoint a pagamento, e nessun numero è stato stimato.
Riferimenti
Link alla sezione: Riferimenti-
Anthropic, Building effective agents, 19 dicembre 2024,
anthropic.com/engineering/building-effective-agents, letto il 7 settembre 2026. Fonte dei cinque nomi di workflow usati sopra e di ogni frase citata da essi — prompt chaining, routing, parallelisation con le sue varianti sectioning e voting, orchestrator-workers, evaluator-optimiser — oltre che della raccomandazione di trovare «la soluzione più semplice possibile, aumentando la complessità solo quando serve» e dell’osservazione che «i sistemi agentic spesso scambiano latenza e costo con migliori prestazioni del compito». I Capitoli 22 e 23 citano la sua definizione di agent. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 -
Wang, X., Wei, J., Schuurmans, D., Le, Q., Chi, E., Narang, S., Chowdhery, A. e Zhou, D. Self-Consistency Improves Chain of Thought Reasoning in Language Models. arXiv:2203.11171 (marzo 2022). L’origine del pattern voting, descritto lì come strategia di decoding invece che come architettura: campiona percorsi di ragionamento diversi, poi «seleziona la risposta più consistente marginalizzando i percorsi di ragionamento campionati», con guadagni riportati di +17,9 su GSM8K, +11,0 su SVAMP, +12,2 su AQuA, +6,4 su StrategyQA e +3,9 su ARC-challenge. ↩
-
Madaan, A. et al. Self-Refine: Iterative Refinement with Self-Feedback. arXiv:2303.17651 (2023). Il loop evaluator-optimiser con un modello in tutti e tre i ruoli — «generator, refiner, and feedback provider» — che migliora «di ~20% assoluto in media nelle prestazioni del compito» su sette compiti, misurato da preferenze umane e metriche automatiche invece che dal verdetto del modello stesso. ↩
-
Shinn, N., Cassano, F., Berman, E., Gopinath, A., Narasimhan, K. e Yao, S. Reflexion: Language Agents with Verbal Reinforcement Learning. arXiv:2303.11366 (2023). Aggiunge una memoria episodica di autocritiche tra i tentativi — «rinforzare language agents non aggiornando i pesi, ma attraverso feedback linguistico» — riportando 91 % pass@1 su HumanEval contro l’80 % della baseline GPT-4. Nota il requisito da cui dipendono i risultati: un segnale reale dall’ambiente, come un test fallito, invece dell’opinione del modello su se stesso. ↩ ↩2
-
Yao, S., Zhao, J., Yu, D., Du, N., Shafran, I., Narasimhan, K. e Cao, Y. ReAct: Synergizing Reasoning and Acting in Language Models. arXiv:2210.03629 (2022). Trace di reasoning e azioni intercalate; il Capitolo 23 ha costruito questo loop. Citato qui per la sua forma di costo invece che per i suoi risultati: una chiamata al modello per passaggio, con l’intera trascrizione reinviata ogni volta. ↩
-
Wang, L., Xu, W., Lan, Y., Hu, Z., Lan, Y., Lee, R. K.-W. e Lim, E.-P. Plan-and-Solve Prompting: Improving Zero-Shot Chain-of-Thought Reasoning by Large Language Models. arXiv:2305.04091 (2023). «Prima, elaborare un piano per dividere l’intero compito in sottocompiti più piccoli, e poi svolgere i sottocompiti secondo il piano» — la forma plan-then-execute, e la fonte dello scambio che interessa a questo capitolo: il piano è fissato prima che arrivi la prima osservazione, cioè prompt chaining con la scomposizione scritta da un modello invece che da te. ↩
-
Yao, S., Yu, D., Zhao, J., Shafran, I., Griffiths, T. L., Cao, Y. e Narasimhan, K. Tree of Thoughts: Deliberate Problem Solving with Large Language Models. arXiv:2305.10601 (2023). Ricerca su «thoughts» intermedi con autovalutazione e backtracking; 74 % su Game of 24 contro il 4 % del chain-of-thought prompting. Le cifre di costo citate sopra sono del paper stesso, dall’Appendice B.3, Tabella 7: per caso, input/output prompting best-of-100 a $0.13 per il 33 %, chain of thought best-of-100 a $0.47 per il 49 %, e tree of thoughts a $0.74 per il 74 %, con la nota degli autori che ToT «potrebbe richiedere 5-100 volte più token generati rispetto a CoT». ↩ ↩2
-
OpenAI, A practical guide to building agents (PDF), letto il 7 settembre 2026. La divisione manager-versus-decentralised, il framing a grafo citato sopra («nel pattern manager, gli archi rappresentano tool calls mentre nel pattern decentralized gli archi rappresentano handoffs»), e la definizione di handoff come «un trasferimento unidirezionale... iniziamo immediatamente l’esecuzione su quel nuovo agent a cui è stato fatto handoff trasferendo anche lo stato più recente della conversazione». Nota che cosa stabilisce quell’ultima clausola: in questo SDK lo stato della conversazione viaggia, che è una decisione di design di quella libreria e non una proprietà degli handoff in generale. ↩ ↩2
-
Agent2Agent (A2A) Protocol Specification, ultima versione rilasciata 1.0.0,
a2a-protocol.org/latest/specification/, letta il 7 settembre 2026; copyright Linux Foundation, Apache-2.0. Citato sopra: uno «standard aperto progettato per facilitare comunicazione e interoperabilità tra sistemi AI agent indipendenti, potenzialmente opachi», e il principio di opaque execution — gli agents «collaborano in base a capacità dichiarate e informazioni scambiate, senza dover condividere i propri pensieri interni, piani o implementazioni degli strumenti». La pagina contiene una cronologia delle release (0.1.0, 0.2.6, 0.3.0, 1.0.0), un’appendice di breaking changes e un’appendice sulla sua relazione con MCP. Il Capitolo 26 fa quel confronto. ↩ -
I framework multi-agent che questo capitolo non insegna, per chi vuole le fonti primarie invece di un tutorial: Wu, Q. et al., AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation, arXiv:2308.08155 (2023), dove gli agents sono «customizable, conversable» e la conversazione stessa è il modello di programmazione; Hong, S. et al., MetaGPT: Meta Programming for a Multi-Agent Collaborative Framework, arXiv:2308.00352 (2023), che codifica procedure operative standard nei prompt di ruolo ed è esplicito sul fatto che «le soluzioni a compiti più complessi sono complicate da incoerenze logiche dovute ad allucinazioni a cascata causate dal chaining ingenuo di LLM» — la chain sicura-e-sbagliata misurata all’inizio di questo capitolo, nominata in un abstract; e Park, J. S. et al., Generative Agents: Interactive Simulacra of Human Behavior, arXiv:2304.03442 (2023), venticinque agents con memoria, riflessione e pianificazione, che è la più grande risposta pubblicata a «che cosa succede se continui ad aggiungere agents». ↩