Orquestração multi-agent: cinco padrões e quando um vence
A mesma fatura resolvida de quatro formas e comparada numa tabela: o orquestrador custou 1,66× mais e chegou ao mesmo veredicto.
Nesta página
Capítulo 24 terminou com uma pergunta que tinha conquistado: quando um sub-agent se engana, o que é que o pai pode exatamente ver?
Este capítulo responde com uma conta. Uma tarefa — um cliente contesta uma fatura e quer uma resposta — resolvida de quatro formas, todas a correr o Capítulo 23 harness contra o mesmo fornecedor com script, todas a contar os mesmos tokens com o mesmo codificador, todas calculadas aos preços que o Capítulo 16 leu em 6 de setembro de 2026.
| configuração | chamadas ao modelo | input tokens | output | custo | tempo decorrido | veredicto |
|---|---|---|---|---|---|---|
| prompt chaining | 4 | 900 | 165 | $0.003780 | 1,648 ms | errado |
| um agent, quatro tools | 5 | 2,697 | 179 | $0.007542 | 2,224 ms | certo |
| secções em paralelo | 9 | 2,910 | 324 | $0.009708 | 2,165 ms | certo |
| orchestrator-workers | 12 | 3,628 | 438 | $0.012512 | 5,090 ms | certo, e não consegue prová-lo |
Leia a primeira e a última linha em conjunto: entre elas está todos os argumentos que esta indústria está a ter neste momento. A configuração mais barata também foi a mais rápida e produziu uma resposta confiante, errada e pronta a enviar. A mais cara acertou, custou 3,3 vezes mais dinheiro e 3,1 vezes mais tempo, e terminou a citar a conclusão de um trabalhador que não tem forma de verificar.
A linha que ninguém põe nestas tabelas é a segunda: um agent com as quatro tools chegou ao mesmo veredicto que o orquestrador por 60 % do dinheiro e 44 % do tempo decorrido. Isto não é uma preferência pela simplicidade. É uma medição, e o resto deste capítulo trata de quando ela deixa de ser verdadeira.
Mostrar detalhes
O que este capítulo precisa dos anteriores.
- Capítulo 18 pelo contrato da tool: um schema que o modelo vê, um endpoint que nunca vê. Um agent inteiro cabe atrás dessa interface, que é a totalidade do multi-agent.
- Capítulo 22 pelas duas definições publicadas de "agent" que discordam, e pela aritmética de que uma cadeia de prompts são N chamadas.
- Capítulo 23 pelo ciclo, pelas cinco formas de sair dele, pelo estado de execução e pelo trace. Todas as configurações abaixo são esse ficheiro, chamado de forma diferente.
- Capítulo 24 pelo que custa uma window e pelo que dela cai. Um sub-agent é a quarta das suas quatro estratégias, e a única que é um segundo agent em vez de uma política.
Sem tensores. Tudo aqui é TypeScript, exceto duas medições feitas contra um modelo local real.
A tarefa, e a armadilha dentro dela
Ligação para a secção: A tarefa, e a armadilha dentro delaUma empresa portuguesa escreve sobre a fatura FT-2026-0918. O email diz que o IVA parece errado, e anexa a fatura: valor líquido EUR 248.00, IVA cobrado a 21 %, EUR 52.08, total EUR 300.08.
Os factos necessários para responder vivem em três sítios, e só um deles está no email:
| onde | o que diz |
|---|---|
| a fatura anexada | vendedor em Espanha, IVA aplicado a 21 %, EUR 52.08 |
| o registo da encomenda | o comprador está registado em Portugal, com um identificador de IVA válido, business-to-business |
| a tabela fiscal | taxa doméstica espanhola 21 %; business-to-business intra-UE com identificador válido, autoliquidação, 0 % |
Junte os três e a fatura está errada: aplica-se a autoliquidação, o IVA devia ter sido zero, é devida uma nota de crédito de EUR 52.08. Olhe apenas para a fatura e ela está aritmeticamente perfeita — 248.00 mais 52.08 é 300.08 — e é isso que dirá.
O email diz de facto "somos uma empresa portuguesa". Isso é uma afirmação, não um registo, e nenhum sistema de faturação emite uma nota de crédito com base numa afirmação. A armadilha não é um truque: é a forma normal do trabalho empresarial, em que a decisão precisa de um facto que ninguém se lembrou de ir buscar.
Tudo acima corre contra um fornecedor com script ao estilo do Capítulo 23, com exatamente uma regra:
Uma resposta só pode usar um facto que esteja no seu prompt.
O "modelo" pede cada tool que tem, uma vez, por ordem de catálogo, e depois aplica uma regra fixa ao texto que consegue ver. Nada é programado por configuração, por isso as diferenças na tabela inicial não são afirmações sobre inteligência do modelo: são encaminhamento de informação, medido. Um modelo real acrescenta as suas próprias falhas por cima; não remove estas.
Os cinco padrões, em cerca de quarenta linhas
Ligação para a secção: Os cinco padrões, em cerca de quarenta linhasOs cinco nomes abaixo são da Anthropic, de Building effective agents, que foi onde este vocabulário assentou.1 Nenhuma das cinco ideias é nova, e dizer que casa deu que nome — e que ideia é mais antiga — é metade do valor de as conhecer.
/* 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 };
}Este é o toolkit completo: cinco funções, sem framework, e a paralela é uma única linha — que é precisamente a razão para a escrever em vez de a desenhar. Agora cada uma por sua vez, com a sua ascendência, o seu preço e o caso em que está errada.
Chaining, e a decisão que toma por si
Ligação para a secção: Chaining, e a decisão que toma por siPrompt chaining "decompõe uma tarefa numa sequência de passos, em que cada chamada ao LLM processa o output da anterior".1 A ideia é anterior aos modelos de linguagem: é uma pipeline, com a troca da pipeline — clareza em troca de um fluxo de controlo fixado antes de os dados chegarem.
Quatro passos para a nossa tarefa: extrair os campos da fatura, verificar a aritmética, decidir o que é devido, escrever a resposta. Aqui falha de duas formas diferentes, o que ensina mais do que falhar uma vez.
--- 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."A cadeia de retransmissão custou $0.001940 e perdeu os campos da fatura entre os passos dois e três, porque ao passo três foi entregue uma frase sobre aritmética e nada mais. Produziu uma mensagem de espera: inútil, e visivelmente inútil.
A cadeia acumulativa — a linha da tabela inicial — custou $0.003780, ou seja, mais 95 % por quatro chamadas idênticas, porque cada passo agora carrega tudo o que veio antes. Produziu o output perigoso. Fluente, citando a sua aritmética, correto em todos os números que menciona, e a dizer a um cliente que nada é devido quando são devidos EUR 52.08.
A diferença entre as duas é um ternário. Uma cadeia que transporta menos produz respostas obviamente incompletas; uma cadeia que transporta tudo produz respostas confiantemente erradas — e só o segundo tipo é enviado.
Nenhuma delas é a verdadeira falha. A verdadeira falha é que a pipeline decidiu, antes de ler qualquer coisa, que esta tarefa são quatro passos sobre o conteúdo de um email. Em parte alguma dessa estrutura existe um lugar para dizer "o país de registo não está neste email; vai buscá-lo". Chaining é adequado quando a decomposição é conhecida antecipadamente e estável. Aqui foi um palpite, e o palpite foi enviado.
Routing, o mais antigo, e o plano B que ninguém escreve
Ligação para a secção: Routing, o mais antigo, e o plano B que ninguém escreveRouting "classifica um input e encaminha-o para uma tarefa de seguimento especializada".1 O nome é novo; o mecanismo é o despachante, mais antigo do que quase tudo o resto neste livro. O que é novo é que o classificador pode ser um modelo — e é isso que o faz falhar de formas que um switch nunca falhou.
const answer = await route(email,
(q) => classifyWithSmallModel(q), // cheap model, one call
{ billing: billingAgent, tax: taxAgent, dunning: dunningAgent },
taxAgent, // deterministic, chosen in advance
);Duas coisas sobre esse último argumento. Não é tratamento de erros; é o padrão. Um router baseado em modelo tem um modo de falha que um despachante não tem: pode devolver uma etiqueta que não existe, fazer timeout ou — a opção cara — devolver uma etiqueta plausível mas errada, sem qualquer sinal de que está errada. As três têm de cair em algum lado, e esse algum lado não pode ser outra chamada ao modelo, porque já está no ramo em que as chamadas ao modelo falharam.
A segunda coisa é que o prompt do próprio router não é grátis. Para escolher um modelo, um router precisa de um catálogo de modelos por onde escolher, e cada entrada nele é input que o router paga antes de ter lido a pergunta do utilizador. À taxa de input com que este curso calcula preços, um catálogo de cerca de 3,800 tokens já custa tanto como toda a execução de cinco chamadas do agent na tabela inicial. Na prática, a chamada de routing corre num modelo barato, que é a razão inteira pela qual routing se paga; mas a aritmética vale a pena ser feita nessa direção, em vez de assumida. Routing está errado precisamente quando a tarefa encaminhada é mais barata do que a decisão de routing.
Paralelização: secções, e votação, que é self-consistency
Ligação para a secção: Paralelização: secções, e votação, que é self-consistencyA Anthropic divide este padrão em dois: sectioning — "dividir uma tarefa em subtarefas independentes executadas em paralelo" — e voting — "executar a mesma tarefa várias vezes para obter outputs diversos".1 Partilham um diagrama e quase nada mais.
Sectioning é a vitória barata, e é a linha de patterns.ts: três especialistas — faturação, fiscalidade, política — cada um com a sua própria window e tools, sobre o mesmo email, com uma chamada de síntese no fim. Trabalho idêntico, ordenado de duas formas:
| chamadas ao modelo | input | output | custo | tempo decorrido | |
|---|---|---|---|---|---|
| os três trabalhadores, um a seguir ao outro | 9 | 2,910 | 324 | $0.009708 | 3,894 ms |
os mesmos três, Promise.all | 9 | 2,910 | 324 | $0.009708 | 2,165 ms |
Mesmo token por token, 1,8 vezes mais rápido. É por isso que o padrão merece nome próprio: é o único dos cinco que melhora alguma coisa sem custar nada. O senão é que as secções têm de ser genuinamente independentes — dê à secção B um facto que a secção A produz e Promise.all corre ambas contra um estado que ainda não existe. O ciclo for escondia esse bug; a linha única expõe-no.
Voting é um animal diferente a usar a mesma imagem. Executar a mesma pergunta k vezes e escolher a maioria é self-consistency, publicado por Wang et al. em março de 2022 como estratégia de descodificação, quase três anos antes de alguém lhe chamar um padrão de orquestração. O seu resumo é preciso quanto ao mecanismo — "primeiro amostra um conjunto diverso de caminhos de raciocínio em vez de escolher apenas o greedy, e depois seleciona a resposta mais consistente marginalizando os caminhos de raciocínio amostrados" — e quanto ao ganho: +17,9 pontos no GSM8K.2
Daqui seguem duas coisas que a imagem esconde. Primeiro, voting exige a amostragem do Capítulo 17: a temperatura zero, todas as k amostras são a mesma amostra, e a maioria é uma resposta paga k vezes. Segundo, só funciona onde uma maioria tem significado — na resposta à fatura acima não há nada para contar, porque cinco rascunhos são cinco frases diferentes. Voting é para tarefas com uma resposta curta e comparável, que é exatamente o tipo de benchmark de Wang e quase nada do que um agent virado para clientes faz.
Medido aqui em 20 problemas de palavras com três passos, cujas respostas são calculadas em vez de julgadas, com o modelo local do Capítulo 23 a raciocinar passo a passo:
| chamadas ao modelo | input | output | custo dos 20 | corretas | intervalo de 95 % | |
|---|---|---|---|---|---|---|
| uma cadeia greedy | 20 | 1,330 | 2,649 | $0.034448 | 9/20 | 26–66 % |
| maioria de 5, temperatura 0.8 | 100 | 6,650 | 13,245 | $0.172240 | 9/20 | 26–66 % |
Cinco vezes as chamadas, cinco vezes os tokens, exatamente cinco vezes a conta, e nem uma resposta correta adicional. Voting é uma aposta, não uma melhoria, e esta execução perdeu-a.
Duas ressalvas, antes que alguém cite isto como refutação de Wang. Vinte ensaios não distinguem 45 % de 60 % — o intervalo tem a largura da afirmação, que é a disciplina do Capítulo 4 aplicada ao meu próprio resultado. E os ganhos publicados vêm de modelos ordens de grandeza maiores, onde os caminhos de raciocínio diversos que voting marginaliza são realmente diversos. O que se transfere não é o número: é que o multiplicador é exato e conhecido de antemão, enquanto o ganho não é nenhuma das duas coisas.
Orchestrator-workers, e o que um resumo não é
Ligação para a secção: Orchestrator-workers, e o que um resumo não éNo workflow orchestrator-workers, "um LLM central decompõe tarefas dinamicamente, delega-as a LLMs trabalhadores e sintetiza os seus resultados", e a diferença face ao sectioning é que "as subtarefas não são pré-definidas, mas determinadas pelo orquestrador".1 A ascendência aqui não vem de modelos de linguagem de todo: isto é master-worker, e a versão em que os trabalhadores escrevem conclusões num espaço partilhado que um controlador lê é a arquitetura blackboard, da investigação em compreensão de fala dos anos 1970. O que é novo em 2026 é que o controlador é um modelo e, por isso, a decomposição pode ser decidida por input — que é a flexibilidade e o custo numa só frase.
Custou 12 chamadas ao modelo contra as 5 do agent único, e chegou ao mesmo veredicto. Depois fez algo que vale a pena observar de perto:
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-4471Ambas estão certas. Só uma sabe porquê. O trabalhador fiscal tinha a fatura, a encomenda e a tabela fiscal na sua própria window, chegou à conclusão e também reparou — ninguém perguntou — que o número da ordem de compra na fatura não coincide com o da encomenda. Depois devolveu um resumo. O orquestrador consegue repetir ambas as afirmações e verificar nenhuma, porque a evidência ficou numa window que ele nunca viu. Esta é a pergunta final do Capítulo 24, respondida: o pai pode ver aquilo que o filho decidiu escrever.
A correção é uma flag, e tem um preço:
| o que o trabalhador devolve | orchestrator input tokens | custo | o que o pai pode fazer |
|---|---|---|---|
| a sua conclusão | 3,628 | $0.012512 | repeti-la |
| a sua conclusão e a sua evidência | 4,065 | $0.013554 | derivá-la de novo, e discordar |
Mais doze por cento de input tokens, mais 8,3 % de dinheiro, e a frase source=worker_unverified desaparece da resposta. Essa é a troca em todos os sistemas multi-agent e quase nunca é explicitada: vale a pena ter a window limpa do filho, vale a pena pagar pela capacidade de o pai a auditar, e não se pode ter as duas coisas grátis.
Então quando é que orchestrator-workers está errado? Aqui, nesta tarefa. Comprou uma resposta correta que um agent com as mesmas quatro tools também alcançou, por 1,66 vezes o custo e 2,3 vezes o tempo decorrido, e tornou essa resposta mais difícil de defender. A própria orientação da Anthropic diz isso antes de os padrões começarem: encontrar "a solução mais simples possível, e só aumentar a complexidade quando necessário", porque "os sistemas agentic muitas vezes trocam latência e custo por melhor desempenho na tarefa".1 As tabelas acima são essa frase com números por baixo.
Evaluator-optimiser, e o juiz que escreveu o exame
Ligação para a secção: Evaluator-optimiser, e o juiz que escreveu o exameUma chamada gera, outra avalia, e o ciclo repete-se até a avaliação passar.1 Os antepassados publicados são Self-Refine — o mesmo modelo como "generator, refiner, and feedback provider", reportando cerca de 20 pontos de melhoria absoluta em média em sete tarefas3 — e Reflexion, que guarda a crítica num buffer episódico entre tentativas e reporta 91 % pass@1 no HumanEval quando a baseline chegou a 80 %.4
O modelo de custo é o mais simples dos cinco: duas chamadas por ronda, e a contagem de rondas não é sua. Três rondas de refinement numa tarefa que demorou uma chamada são seis chamadas, por isso o piso do padrão é 6× e o teto é qualquer limite que definir — o que torna a saída por orçamento do Capítulo 23 obrigatória em vez de elegante.
O teto é mais subtil, e é mensurável. Nos mesmos 20 problemas, o modelo local respondeu corretamente a 9. Depois foram-lhe mostradas cada uma dessas respostas e foi-lhe perguntado se estava certa — sem lhe dizer que a resposta era sua, o que remove o confundidor da bajulação e deixa o da capacidade:
| a resposta do próprio modelo | disse "sim" | disse "não" |
|---|---|---|
| as 9 que estavam certas | 9 | 0 |
| as 11 que estavam erradas | 3 | 8 |
É um juiz melhor do que o título da secção implica, e dizê-lo é o objetivo de medir em vez de afirmar: não bloqueou nada correto e apanhou 8 de 11 erros. Como filtro, vale as chamadas.
Como regra de paragem, que é aquilo para que um ciclo evaluator-optimiser realmente o usa, essas três aprovações são a história toda: terminam o ciclo com uma resposta errada na mão, e nenhuma quantidade de rondas extra alguma vez chega a elas. Um ciclo de refinement não pode tornar-se mais correto do que o seu juiz. Comprar mais rondas compra tentativas sobre os erros que o juiz consegue ver, a preço inteiro, e nada contra os que não consegue.
Daí a regra: um evaluator só merece as suas chamadas quando tem algo que o generator não tem. Um compilador, uma suite de testes, um validador de schema, um modelo diferente, um humano. Os próprios resultados do Self-Refine são medidos contra preferência humana e métricas de tarefa, nunca contra a opinião do modelo sobre si próprio. Se a única vantagem do seu evaluator é um prompt diferente, está a pagar o dobro por concordância. O Capítulo 29 constrói a versão com uma vantagem real: um golden set com as respostas escritas antecipadamente.
Os ciclos não são os padrões
Ligação para a secção: Os ciclos não são os padrõesOs cinco acima são formas para o seu código. Por baixo deles existe uma segunda família que é muitas vezes listada ao lado e não devia ser: ReAct, Reflexion, plan-and-execute e tree of thoughts são ciclos de raciocínio, e o seu custo está em pedidos.
O Capítulo 12 foi sobre raciocínio dentro do modelo, pelo qual se paga em output tokens numa chamada. Este é o outro tipo. A diferença importa quando a conta chega: uma chain of thought mais longa torna uma chamada mais cara, e um ciclo de raciocínio transforma uma tarefa em muitas chamadas, cada uma reenviando tudo o que veio antes — a quadrática que o Capítulo 23 mediu na sua tabela de descontrolo.
| ciclo | chamadas, por tarefa | o que as chamadas extra compram |
|---|---|---|
| ReAct | uma por passo, até parar | o modelo reage ao que as tools devolveram5 |
| plan-and-execute | uma para planear, depois uma por passo | o plano é fixado antes do primeiro passo correr6 |
| Reflexion | tentativas × (agir + refletir) | a crítica sobrevive para a tentativa seguinte4 |
| tree of thoughts | fator de ramificação × profundidade, mais uma avaliação por nó | pesquisa, com backtracking7 |
O artigo tree-of-thoughts publica a sua própria tabela de custos, o que é mais raro do que devia ser. No Game of 24 com GPT-4: input/output prompting best-of-100 resolveu 33 % a $0.13 por caso, chain of thought best-of-100 resolveu 49 % a $0.47, e tree of thoughts resolveu 74 % a $0.74, com os autores a notar que "could require 5-100 times more generated tokens than CoT".7
Quase seis vezes o preço do método barato para pouco mais do dobro da taxa de sucesso. Se isso é um bom negócio depende do que custa um caso falhado — a pergunta a fazer antes de adotar qualquer um destes quatro.
Este curso não os reimplementa. Os quatro têm implementações de referência pelos próprios autores, em Python, e o seu valor é serem a fonte em vez de uma tradução: ysymyth/ReAct, noahshinn/reflexion, princeton-nlp/tree-of-thought-llm e AGI-Edgerunners/Plan-and-Solve-Prompting. Leia os prompts nesses repositórios; os prompts são os artigos.
Duas topologias, e uma delas não volta
Ligação para a secção: Duas topologias, e uma delas não voltaAgora o multi-agent propriamente dito, onde vive a maior parte da confusão. Há duas formas de um agent envolver outro, não são variantes, e a diferença é quem fica no comando depois.
Agent como tool. O pai chama-o, recebe uma resposta e continua. É a interface de tool do Capítulo 18 com um agent inteiro por trás, e o pai nunca perde o controlo. É isto que o orquestrador acima faz.
Transferência. O pai transfere a conversa e não a recebe de volta. O guia da OpenAI é a declaração publicada mais clara: handoffs são "uma transferência num só sentido que permite a um agent delegar noutro agent... Se um agent chama uma função de handoff, começamos imediatamente a execução nesse novo agent para o qual foi feito handoff, ao mesmo tempo que transferimos o estado mais recente da conversa."8
Um aviso de vocabulário, porque isto faz tropeçar muita gente: "handoff" é a palavra de um SDK, não uma norma. É terminologia do OpenAI Agents SDK e desse guia, que também dá às duas configurações os nomes "manager" e "decentralized" e nota que no padrão manager "edges represent tool calls whereas in the decentralized pattern, edges represent handoffs".8 Há sim uma norma aberta neste espaço — A2A, na versão 1.0.0, sob copyright da Linux Foundation, com histórico de releases versionado e uma lista documentada de breaking changes, cujo princípio declarado é opaque execution: agents "collaborate based on declared capabilities and exchanged information, without needing to share their internal thoughts, plans, or tool implementations".9 Isso não é um handoff, e a comparação pertence ao Capítulo 26. O que importa aqui é que uma das duas palavras é a API de uma biblioteca e a outra é uma especificação com governação.
A distinção é uma estrutura de dados, não um diagrama:
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;
}Vinte linhas, dois bugs que de outro modo encontraria em produção. reachable encontra o agent a que ninguém consegue chegar — configurado, pago, nunca chamado. conflicts recusa a aresta que é dos dois tipos ao mesmo tempo, o que soa pedante até ser dito em voz alta: o pai tanto mantém o controlo como o entrega. Execute-o num sistema de cinco agents com um órfão e uma aresta dupla:
reachable: lead@0 billing@1 tax@1 dunning@1
orphans: ghost
conflicts: lead->taxO que atravessa realmente a fronteira
Ligação para a secção: O que atravessa realmente a fronteiraAgora a medição para a qual esta secção existe, e a única do capítulo feita contra um modelo real em vez de um com script.
Um cliente declara uma restrição na sua primeira mensagem — a nossa conta está registada em Portugal, não em Espanha; tudo o que for fiscal tem de usar Portugal — conversa sobre outra coisa, e depois faz uma pergunta a que a faturação deve responder. O caso é transferido. Vinte e quatro ensaios, um país e uma empresa diferentes de cada vez, quatro payloads de transferência, e ao agent recetor é então feita uma pergunta: em que país está registada a conta deste cliente?
| o que foi transferido | payload médio | a restrição estava lá | o especialista lembrou-se dela | intervalo de 95 % |
|---|---|---|---|---|
| a conversa inteira | 173 tokens | 24/24 | 20/24 — 83 % | 64–93 % |
| um resumo escrito pelo agent remetente | 62 tokens | 1/24 | 0/24 — 0 % | 0–14 % |
| apenas a última mensagem do utilizador | 61 tokens | 0/24 | 0/24 — 0 % | 0–14 % |
| um registo tipado | 69 tokens | 24/24 | 24/24 — 100 % | 86–100 % |
A terceira linha é um controlo e comporta-se como tal: o facto não está lá, por isso não pode ser recordado. As outras três são o resultado.
A transcrição completa tem 173 tokens e funciona 83 % das vezes, sendo as suas quatro falhas assunto do Capítulo 24 e não deste. O registo tipado tem 69 tokens — mais sete do que o resumo — e funciona sempre, porque a restrição fica num campo nomeado em vez de numa frase.
E o resumo é a linha para encarar. Falhou 24 vezes em 24, e a razão não é que o leitor não a tenha visto. A restrição apareceu em apenas 1 dos 24 resumos. O agent recetor não foi descuidado; recebeu um texto que não continha a resposta. Um resumo é uma compactação que não escreveu, produzida por um modelo cuja window não consegue ver, otimizada para se ler como um resumo — e "o cliente diz que os nossos registos têm o país errado" é exatamente o tipo de cláusula que um resumidor deixa cair como ruído procedimental.
Um limite honesto sobre esse número: o resumidor é um modelo de meio bilião de parâmetros e um maior reteria mais. O que não melhora com o tamanho é a forma do risco — o agent remetente decide, por transferência, por formulação, de forma inobservável, que factos sobrevivem. O registo tipado não depende desse julgamento de todo, e é por isso que ganha por construção em vez de por inteligência. O que tiver de sobreviver a uma transferência deve ser um campo, não uma frase.
O mesmo raciocínio aplica-se na outra direção, à topologia agent-como-tool, e a tabela anterior já lhe pôs preço: o que volta de um trabalhador também é um resumo, e pagar mais 8,3 % para receber a evidência com ele é a mesma correção vista do lado do pai.
Quando um agent vence
Ligação para a secção: Quando um agent venceTrês factos finais, todos das tabelas acima.
Um sistema multi-agent multiplica chamadas, e as chamadas são quadráticas no context. O orquestrador fez 12 chamadas ao modelo onde um agent fez 5, e cada uma transporta a sua própria transcrição crescente — 3,628 input tokens contra 2,697, uma diferença que aumenta com a duração da tarefa.
Cada fronteira é um canal com perdas. Dois agents significam um resumo. Quatro agents numa cadeia significam três, compostos, cada um escrito por um modelo a otimizar para algo diferente da sua decisão.
O agent único encontrou algo que ninguém pediu. A discrepância da ordem de compra apareceu porque uma window continha ao mesmo tempo a fatura e a encomenda. Dividir o trabalho por especialistas também divide a capacidade de notar que dois factos discordam.
Nada disto é um argumento contra as frameworks multi-agent publicadas, que vale a pena ler como fontes primárias em vez de através de tutoriais.10 É um argumento para obrigar o segundo agent a merecer o seu lugar.
Portanto, um teste em vez de uma preferência. Acrescente um segundo agent quando pelo menos uma destas condições for verdadeira: a subtarefa precisa de uma window limpa que o pai não deve herdar (Capítulo 24); as subtarefas são genuinamente independentes e o tempo decorrido importa, que é o 1,8× acima; a subtarefa precisa de permissões diferentes ou de um modelo diferente, o que o Capítulo 30 transforma num argumento de segurança; ou a subtarefa é propriedade de outra pessoa, que é onde um protocolo real começa a importar. Se a resposta for "para que cada agent tenha um prompt mais claro", dê ao agent único um prompt mais claro. É grátis.
Para onde isto vai a seguir
Ligação para a secção: Para onde isto vai a seguirAgora consegue nomear os cinco padrões, compará-los em preço numa tarefa, distinguir um orquestrador de um sectioner e uma tool call de um handoff, e defender um agent único com uma tabela em vez de uma preferência.
Todas as configurações aqui partilharam uma conveniência que não sobreviverá ao contacto com algo real: todas as tools pertenciam-nos. Fatura, encomenda, tabela fiscal, os trabalhadores por trás do orquestrador — mesmo repositório, mesmo deploy, mesmos tipos, mesmas pessoas.
Agora ponha uma delas do outro lado de uma fronteira empresarial. A tabela fiscal pertence a um fornecedor de contabilidade, o registo da encomenda a um sistema de armazém, e nenhum leu a sua interface Tool. Precisa de uma forma de um modelo que não escreveu descobrir, descrever e chamar uma capacidade operada por outra pessoa — com autenticação (que é a metade do Capítulo 27), versionamento e a garantia de que um servidor não consegue ler o resto da sua conversa. Isso é um problema de protocolo, tem uma especificação com um schema normativo, e quase tudo o que está indexado sobre ele descreve uma revisão que já não existe.
O Capítulo 26 lê essa especificação em vez de a resumir, e começa por escrever JSON-RPC num terminal à mão.
Fontes e método
Ligação para a secção: Fontes e métodoTodos os custos e contagens de tokens acima vieram do fornecedor com script descrito na segunda secção, em Node 22 sobre uma interface loopback, contando com a codificação o200k_base e calculados aos preços que o Capítulo 16 leu em 6 de setembro de 2026 — $2.00 por milhão de input tokens e $12.00 por milhão de output. Os valores de tempo decorrido vêm das mesmas execuções com a latência do fornecedor definida para 400 ms por chamada e as tools para 50 ms, por isso medem a configuração e não qualquer fornecedor. As duas medições com modelo real — a tabela de handoff e a tabela de voting-and-judging — usaram Qwen/Qwen2.5-0.5B-Instruct em float32 no CPU por trás de um endpoint da mesma forma, greedy exceto onde uma temperatura é indicada, com intervalos calculados pelo método de Wilson do Capítulo 4. Nenhum pedido neste capítulo foi para um endpoint pago, e nenhum número nele foi estimado.
Referências
Ligação para a secção: Referências-
Anthropic, Building effective agents, 19 de dezembro de 2024,
anthropic.com/engineering/building-effective-agents, lido em 7 de setembro de 2026. Fonte dos cinco nomes de workflow usados acima e de todas as frases deles citadas — prompt chaining, routing, parallelisation com as variantes sectioning e voting, orchestrator-workers, evaluator-optimiser — bem como da recomendação de encontrar "a solução mais simples possível, e só aumentar a complexidade quando necessário" e da observação de que "os sistemas agentic muitas vezes trocam latência e custo por melhor desempenho na tarefa". Os Capítulos 22 e 23 citam a sua definição de 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 (março de 2022). A origem do padrão voting, descrito ali como uma estratégia de descodificação em vez de uma arquitetura: amostrar caminhos de raciocínio diversos, depois "selecionar a resposta mais consistente marginalizando os caminhos de raciocínio amostrados", com ganhos reportados de +17,9 no GSM8K, +11,0 no SVAMP, +12,2 no AQuA, +6,4 no StrategyQA e +3,9 no ARC-challenge. ↩
-
Madaan, A. et al. Self-Refine: Iterative Refinement with Self-Feedback. arXiv:2303.17651 (2023). O ciclo evaluator-optimiser com um modelo nos três papéis — "generator, refiner, and feedback provider" — a melhorar "by ~20% absolute on average in task performance" em sete tarefas, medido por preferência humana e métricas automáticas em vez de pelo veredicto do próprio modelo. ↩
-
Shinn, N., Cassano, F., Berman, E., Gopinath, A., Narasimhan, K. e Yao, S. Reflexion: Language Agents with Verbal Reinforcement Learning. arXiv:2303.11366 (2023). Acrescenta uma memória episódica de autocríticas entre tentativas — "reinforce language agents not by updating weights, but through linguistic feedback" — reportando 91 % pass@1 no HumanEval contra 80 % para a baseline GPT-4. Note o requisito de que os seus resultados dependem: um sinal real do ambiente, como um teste falhado, em vez da opinião do modelo sobre si próprio. ↩ ↩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). Traces de raciocínio e ações intercalados; o Capítulo 23 construiu este ciclo. Citado aqui pela sua forma de custo, não pelos resultados: uma chamada ao modelo por passo, com a transcrição inteira reenviada de cada vez. ↩
-
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). "First, devising a plan to divide the entire task into smaller subtasks, and then carrying out the subtasks according to the plan" — a forma plan-then-execute, e a fonte da troca que interessa a este capítulo: o plano é fixado antes da primeira observação chegar, que é prompt chaining com a decomposição escrita por um modelo em vez de por si. ↩
-
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). Pesquisa sobre "thoughts" intermédios com autoavaliação e backtracking; 74 % no Game of 24 contra 4 % para chain-of-thought prompting. Os números de custo citados acima são do próprio artigo, do Apêndice B.3, Tabela 7: por caso, input/output prompting best-of-100 a $0.13 para 33 %, chain of thought best-of-100 a $0.47 para 49 %, e tree of thoughts a $0.74 para 74 %, com a nota dos autores de que ToT "could require 5-100 times more generated tokens than CoT". ↩ ↩2
-
OpenAI, A practical guide to building agents (PDF), lido em 7 de setembro de 2026. A divisão manager-versus-decentralised, o enquadramento em grafo citado acima ("in the manager pattern, edges represent tool calls whereas in the decentralized pattern, edges represent handoffs"), e a definição de handoff como "a one way transfer... we immediately start execution on that new agent that was handed off to while also transferring the latest conversation state". Note o que essa última oração resolve: neste SDK, o estado da conversa viaja, o que é uma decisão de design dessa biblioteca e não uma propriedade dos handoffs em geral. ↩ ↩2
-
Agent2Agent (A2A) Protocol Specification, versão lançada mais recente 1.0.0,
a2a-protocol.org/latest/specification/, lido em 7 de setembro de 2026; copyright da Linux Foundation, Apache-2.0. Citado acima: uma "open standard designed to facilitate communication and interoperability between independent, potentially opaque AI agent systems", e o princípio de opaque execution — agents "collaborate based on declared capabilities and exchanged information, without needing to share their internal thoughts, plans, or tool implementations". A página traz um histórico de releases (0.1.0, 0.2.6, 0.3.0, 1.0.0), um apêndice de breaking changes e um apêndice sobre a sua relação com MCP. O Capítulo 26 faz essa comparação. ↩ -
As frameworks multi-agent que este capítulo não ensina, para o leitor que quer as fontes primárias em vez de um tutorial: Wu, Q. et al., AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation, arXiv:2308.08155 (2023), onde agents são "customizable, conversable" e a própria conversa é o modelo de programação; Hong, S. et al., MetaGPT: Meta Programming for a Multi-Agent Collaborative Framework, arXiv:2308.00352 (2023), que codifica procedimentos operacionais standard em role prompts e é explícito ao dizer que "solutions to more complex tasks are complicated through logic inconsistencies due to cascading hallucinations caused by naively chaining LLMs" — a cadeia confiantemente errada medida no topo deste capítulo, nomeada num resumo; e Park, J. S. et al., Generative Agents: Interactive Simulacra of Human Behavior, arXiv:2304.03442 (2023), vinte e cinco agents com memória, reflexão e planeamento, que é a maior resposta publicada a "o que acontece se continuar a acrescentar agents". ↩