Orquestração multi-agent: cinco padrões e quando um vence
A mesma fatura resolvida de quatro formas e precificada em uma tabela: o orquestrador custou 1,66x o agent único e chegou ao mesmo veredito.
Nesta página
Capítulo 24 terminou com uma pergunta que mereceu fazer: quando um sub-agent está errado, o que exatamente o pai consegue examinar?
Este capítulo responde com uma conta. Uma tarefa — um cliente contesta uma fatura e quer uma resposta — resolvida de quatro formas, todas executando o harness do Capítulo 23 contra o mesmo provedor roteirizado, todas contando os mesmos tokens com o mesmo encoder, todas precificadas nas tarifas que o Capítulo 16 leu em 6 de setembro de 2026.
| arranjo | chamadas ao modelo | input tokens | output | custo | tempo de parede | veredito |
|---|---|---|---|---|---|---|
| prompt chaining | 4 | 900 | 165 | $0.003780 | 1.648 ms | errado |
| um agent, quatro ferramentas | 5 | 2.697 | 179 | $0.007542 | 2.224 ms | certo |
| seções paralelas | 9 | 2.910 | 324 | $0.009708 | 2.165 ms | certo |
| orquestrador-workers | 12 | 3.628 | 438 | $0.012512 | 5.090 ms | certo, e não consegue provar |
Leia a primeira e a última linha juntas: entre elas está toda a discussão que este setor está tendo agora. O arranjo mais barato também foi o mais rápido e produziu uma resposta enviável, confiante e errada. O mais caro acertou, levou 3,3 vezes mais dinheiro e 3,1 vezes mais tempo, e terminou citando a conclusão de um worker que ele não tem como verificar.
A linha que ninguém coloca nessas tabelas é a segunda: um agent com as quatro ferramentas chegou ao mesmo veredito do orquestrador por 60 % do dinheiro e 44 % do tempo de parede. Isso não é uma preferência por 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 para o contrato da ferramenta: um schema que o modelo vê, um endpoint que ele nunca vê. Um agent inteiro cabe por trás dessa interface, que é todo o multi-agent.
- Capítulo 22 para as duas definições publicadas de "agent" que discordam, e para a aritmética de que uma cadeia de prompts é N chamadas.
- Capítulo 23 para o loop, as cinco saídas, o estado da execução e o trace. Todo arranjo abaixo é aquele arquivo, chamado de um jeito diferente.
- Capítulo 24 para quanto custa uma janela e o que cai para fora dela. Um sub-agent é a quarta de suas quatro estratégias, e a única que é um segundo agent, não 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
Link para a seção: A tarefa e a armadilha dentro delaUma empresa portuguesa escreve sobre a fatura FT-2026-0918. O e-mail diz que o IVA parece errado e anexa a fatura: líquido EUR 248,00, IVA cobrado a 21 %, EUR 52,08, total EUR 300,08.
Os fatos necessários para responder estão em três lugares, e só um deles está no e-mail:
| onde | o que diz |
|---|---|
| a fatura anexada | vendedor na Espanha, IVA aplicado a 21 %, EUR 52,08 |
| o registro do pedido | o comprador está registrado em Portugal, com um identificador de IVA válido, business-to-business |
| a tabela tributária | alíquota doméstica espanhola 21 %; intra-UE business-to-business com identificador válido, reverse charge, 0 % |
Junte os três e a fatura está errada: com reverse charge aplicado, o IVA deveria ter sido zero, e é devida uma nota de crédito de EUR 52,08. Olhe só para a fatura e ela está aritmeticamente perfeita — 248,00 mais 52,08 é 300,08 — e você dirá isso.
O e-mail de fato afirma "somos uma empresa portuguesa". Isso é uma alegação, não um registro, e nenhum sistema de faturamento emite uma nota de crédito com base em uma alegação. A armadilha não é um truque: é o formato comum do trabalho de negócios, em que a decisão precisa de um fato que ninguém pensou em buscar.
Tudo acima roda contra um provedor roteirizado no estilo do Capítulo 23, com exatamente uma regra:
Uma resposta só pode usar um fato que esteja em seu prompt.
O "modelo" pede cada ferramenta que tem, uma vez, na ordem do catálogo, e então aplica uma regra fixa ao texto que consegue ver. Nada é roteirizado por arranjo, então as diferenças naquela tabela de abertura não são afirmações sobre inteligência do modelo: são roteamento de informação, medido. Um modelo real acrescenta suas próprias falhas por cima; ele não remove estas.
Os cinco padrões, em cerca de quarenta linhas
Link para a seção: Os cinco padrões, em cerca de quarenta linhasOs cinco nomes abaixo são da Anthropic, de Building effective agents, que foi onde esse vocabulário se estabilizou.1 Nenhuma das cinco ideias é nova, e dizer qual casa deu nome a quê — e qual ideia é mais antiga — é metade do valor de conhecê-las.
/* 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 };
}Esse é o kit inteiro: cinco funções, nenhum framework, e a paralela é uma única linha — esse é justamente o motivo de escrevê-la em vez de desenhá-la. Agora, uma por uma, com sua ancestralidade, seu preço e o caso em que está errada.
Chaining e a decisão que ele toma por você
Link para a seção: Chaining e a decisão que ele toma por vocêPrompt chaining "decompõe uma tarefa em uma sequência de etapas, em que cada chamada ao LLM processa o output da anterior".1 A ideia é anterior aos modelos de linguagem: é um pipeline, com a troca do pipeline — clareza em troca de um fluxo de controle fixado antes de os dados chegarem.
Quatro etapas para nossa tarefa: extrair os campos da fatura, verificar a aritmética, decidir o que é devido, escrever a resposta. Aqui ele 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 repasse custou $0.001940 e perdeu os campos da fatura entre as etapas dois e três, porque a etapa três recebeu uma frase sobre aritmética e nada mais. Produziu uma mensagem de espera: inútil, e visivelmente inútil.
A cadeia acumuladora — a linha da tabela de abertura — custou $0.003780, o que é 95 % a mais para quatro chamadas idênticas, porque cada etapa agora carrega tudo que veio antes. Ela produziu o output perigoso. Fluente, citando sua aritmética, correto em todos os números que menciona e dizendo a um cliente que nada é devido quando EUR 52,08 é devido.
A diferença entre as duas é um ternário. Uma cadeia que carrega menos produz respostas obviamente incompletas; uma cadeia que carrega tudo produz respostas confiantemente erradas — e só o segundo tipo é enviado.
Nenhuma das duas é a falha real. A falha real é que o pipeline decidiu, antes de ler qualquer coisa, que essa tarefa tem quatro etapas sobre o conteúdo de um e-mail. Em nenhum lugar dessa estrutura há um espaço para dizer "o país de registro não está neste e-mail; vá buscá-lo". Chaining é correto quando a decomposição é conhecida de antemão e estável. Aqui ela era um palpite, e o palpite foi para produção.
Routing, o mais antigo, e o plano B que ninguém escreve
Link para a seção: Routing, o mais antigo, e o plano B que ninguém escreveRouting "classifica um input e o direciona para uma tarefa de acompanhamento especializada".1 O nome é novo; o mecanismo é o dispatcher, mais antigo do que quase todo o resto deste livro. A novidade é 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 erro; é o padrão. Um router baseado em modelo tem um modo de falha que um dispatcher não tem: ele pode retornar um rótulo que não existe, dar timeout ou — o caro — retornar um rótulo plausível e errado sem nenhum sinal de que está errado. Os três precisam aterrissar em algum lugar, e esse lugar não pode ser outra chamada ao modelo, porque você já está no ramo em que chamadas ao modelo falharam.
A segunda coisa é que o prompt do próprio router não é gratuito. Para escolher um modelo, um router precisa de um catálogo de modelos para escolher, e cada entrada nele é input que o router paga antes de ter lido a pergunta do usuário. Na tarifa de input com que este curso precifica, um catálogo de cerca de 3.800 tokens já custa tanto quanto a execução inteira do agent de cinco chamadas na tabela de abertura. Na prática, a chamada de roteamento roda em um modelo barato, e essa é justamente a razão pela qual o roteamento se paga; mas vale a pena fazer a aritmética nessa direção em vez de presumir. O roteamento está errado exatamente quando a tarefa roteada é mais barata do que a decisão de roteamento.
Paralelização: seções e votação, que é self-consistency
Link para a seção: Paralelização: seções e votação, que é self-consistencyA Anthropic divide isto 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 Eles compartilham um diagrama e quase nada mais.
Sectioning é o ganho barato, e é a linha de patterns.ts: três especialistas — billing, fiscal, políticas — cada um com sua própria janela e ferramentas, sobre o mesmo e-mail, uma chamada de síntese no fim. Trabalho idêntico, ordenado de duas formas:
| chamadas ao modelo | input | output | custo | tempo de parede | |
|---|---|---|---|---|---|
| os três workers, um depois do 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 vez mais rápido. É por isso que o padrão ganha nome próprio: é o único dos cinco que melhora algo sem custar nada. O detalhe é que as seções precisam ser genuinamente independentes — dê à seção B um fato que a seção A produz e Promise.all executa as duas contra um estado que ainda não existe. O loop for escondia esse bug; a linha única o expõe.
Voting é outro bicho usando a mesma imagem. Rodar a mesma pergunta k vezes e pegar a maioria é self-consistency, publicado por Wang et al. em março de 2022 como uma estratégia de decoding, quase três anos antes de alguém chamá-lo de padrão de orquestração. Seu resumo é preciso sobre o mecanismo — "primeiro amostra um conjunto diverso de caminhos de raciocínio em vez de tomar apenas o greedy, e então seleciona a resposta mais consistente marginalizando os caminhos de raciocínio amostrados" — e sobre o ganho: +17,9 pontos no GSM8K.2
Duas coisas decorrem disso que a imagem esconde. Primeiro, voting exige o sampling do Capítulo 17: com temperature zero, todas as k amostras são a mesma amostra, e a maioria é uma resposta paga k vezes. Segundo, ele só funciona onde uma maioria faz sentido — na resposta da 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, exatamente os benchmarks de Wang e quase nada que um agent voltado ao cliente faz.
Medido aqui em 20 problemas de enunciado em três etapas cujas respostas são computadas, não julgadas, com o modelo local do Capítulo 23 raciocinando passo a passo:
| chamadas ao modelo | input | output | custo para os 20 | correto | intervalo de 95 % | |
|---|---|---|---|---|---|---|
| uma cadeia greedy | 20 | 1.330 | 2.649 | $0.034448 | 9/20 | 26–66 % |
| maioria de 5, temperature 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 a mais. Voting é uma aposta, não uma melhoria, e esta execução perdeu.
Duas ressalvas, antes que alguém cite isso como refutação de Wang. Vinte testes 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 magnitude maiores, nos quais os caminhos de raciocínio diversos que o voting marginaliza são de fato diversos. O que se transfere não é o número: é que o multiplicador é exato e conhecido de antemão, enquanto o ganho não é.
Orquestrador-workers e o que um resumo não é
Link para a seção: Orquestrador-workers e o que um resumo não éNo workflow orquestrador-workers, "um LLM central divide tarefas dinamicamente, delega-as a LLMs workers e sintetiza seus resultados", e a diferença em relação ao sectioning é que "as subtarefas não são predefinidas, mas determinadas pelo orquestrador".1 A ancestralidade aqui não vem de modelos de linguagem: isso é master-worker, e a versão em que workers escrevem descobertas em um espaço compartilhado que um controlador lê é a arquitetura blackboard, da pesquisa de compreensão de fala nos anos 1970. O que é novo em 2026 é que o controlador é um modelo e, portanto, a decomposição pode ser decidida por input — que é a flexibilidade e o custo em uma frase.
Custou 12 chamadas ao modelo contra 5 do agent único, e chegou ao mesmo veredito. Então fez algo que vale 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-4471Ambos estão certos. Só um sabe por quê. O worker fiscal tinha a fatura, o pedido e a tabela tributária em sua própria janela, chegou à conclusão e também percebeu — ninguém perguntou — que o número do pedido de compra na fatura não corresponde ao do pedido. Então retornou um resumo. O orquestrador consegue repetir as duas afirmações e não consegue verificar nenhuma, porque a evidência ficou em uma janela que ele nunca viu. A pergunta final do Capítulo 24, respondida: o pai consegue examinar o que quer que o filho tenha escolhido escrever.
A correção é uma flag, e ela tem um preço:
| o que o worker retorna | input tokens do orquestrador | custo | o que o pai consegue fazer |
|---|---|---|---|
| sua conclusão | 3.628 | $0.012512 | repeti-la |
| sua conclusão e sua evidência | 4.065 | $0.013554 | derivá-la de novo e discordar |
Doze por cento mais input tokens, 8,3 % mais dinheiro, e a frase source=worker_unverified desaparece da resposta. Essa é a troca em todo sistema multi-agent e ela quase nunca é declarada: vale a pena ter a janela limpa do filho, vale a pena pagar pela capacidade do pai de auditá-la, e você não pode ter as duas de graça.
Então quando orquestrador-workers está errado? Aqui, nesta tarefa. Ele comprou uma resposta correta que um agent com as mesmas quatro ferramentas também alcançou, por 1,66 vez o custo e 2,3 vezes o tempo de parede, 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 "agentic systems frequentemente trocam latência e custo por melhor desempenho na tarefa".1 As tabelas acima são essa frase com números embaixo.
Evaluator-optimiser e o juiz que escreveu a prova
Link para a seção: Evaluator-optimiser e o juiz que escreveu a provaUma chamada gera, outra avalia, e o loop se repete até a avaliação passar.1 Os ancestrais publicados são Self-Refine — o mesmo modelo como "gerador, refinador e provedor de feedback", relatando cerca de 20 pontos de melhoria absoluta em média sobre sete tarefas3 — e Reflexion, que armazena a crítica em um buffer episódico entre tentativas e relata 91 % pass@1 no HumanEval, onde o baseline chegou a 80 %.4
O modelo de custo é o mais simples dos cinco: duas chamadas por rodada, e a contagem de rodadas não é sua. Três rodadas de refinamento em uma tarefa que levou uma chamada são seis chamadas, então o piso do padrão é 6× e o teto é qualquer limite que você definir — o que torna a saída por orçamento do Capítulo 23 obrigatória, não apenas elegante.
O teto é mais sutil, e é mensurável. Nos mesmos 20 problemas, o modelo local respondeu 9 corretamente. Então mostramos cada uma dessas respostas a ele e perguntamos se estava certa — sem dizer que a resposta era dele, o que remove o confundidor da bajulação e deixa o da capacidade:
| a própria resposta do modelo | ele disse "sim" | ele 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 seção sugere, e dizer isso é o objetivo de medir em vez de afirmar: ele não bloqueou nada correto e capturou 8 de 11 erros. Como filtro, vale suas chamadas.
Como regra de parada, que é para o que um loop evaluator-optimiser realmente o usa, essas três aprovações são a história inteira: elas encerram o loop com uma resposta errada em mãos, e nenhuma quantidade de rodadas extras jamais chega nelas. Um loop de refinamento não pode ficar mais correto do que seu juiz. Comprar mais rodadas compra tentativas nos erros que o juiz consegue ver, a preço cheio, e absolutamente nada contra os que ele não consegue.
Daí a regra: um evaluator só merece suas chamadas quando tem algo que o gerador não tem. Um compilador, uma suíte de testes, um schema validator, 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 mesmo. Se a única vantagem do seu evaluator é um prompt diferente, você está pagando 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 de antemão.
Os loops não são os padrões
Link para a seção: Os loops não são os padrõesOs cinco acima são formatos para o seu código. Abaixo deles fica uma segunda família que muitas vezes é listada junto e não deveria ser: ReAct, Reflexion, plan-and-execute e tree of thoughts são loops de raciocínio, e seu custo está em requisições.
O Capítulo 12 tratou de raciocínio dentro do modelo, que você paga em output tokens em uma chamada. Este é o outro tipo. A diferença importa quando a conta chega: uma cadeia de pensamento mais longa torna uma chamada mais cara, e um loop de raciocínio transforma uma tarefa em muitas chamadas, cada uma reenviando tudo que veio antes — o quadrático que o Capítulo 23 mediu em sua tabela de runaway.
| loop | chamadas, por tarefa | o que as chamadas extras compram |
|---|---|---|
| ReAct | uma por etapa, até parar | o modelo reage ao que as ferramentas retornaram5 |
| plan-and-execute | uma para planejar, depois uma por etapa | o plano é fixado antes da primeira etapa rodar6 |
| Reflexion | tentativas × (agir + refletir) | a crítica sobrevive para a próxima tentativa4 |
| tree of thoughts | branching factor × profundidade, mais uma avaliação por nó | busca, com backtracking7 |
O artigo de tree-of-thoughts publica sua própria tabela de custos, o que é mais raro do que deveria. 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 observando que ele "poderia exigir 5–100 vezes mais tokens gerados do que CoT".7
Quase seis vezes o preço do método barato para um pouco mais que o dobro da taxa de sucesso. Se isso é uma barganha depende de quanto custa para você um caso fracassado — a pergunta a fazer antes de adotar qualquer um desses quatro.
Este curso não os reimplementa. Todos os quatro têm implementações de referência pelos próprios autores, em Python, e seu valor é serem a fonte, não 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
Link para a seção: Duas topologias, e uma delas não voltaAgora o multi-agent propriamente dito, onde mora a maior parte da confusão. Há duas formas de um agent envolver outro, elas não são variantes, e a diferença é quem fica no comando depois.
Agent como ferramenta. O pai o chama, recebe uma resposta e continua. É a interface de ferramenta do Capítulo 18 com um agent inteiro por trás, e o pai nunca perde o controle. É isso que o orquestrador acima faz.
Handoff. 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 unidirecional que permite a um agent delegar a outro agent... Se um agent chama uma função de handoff, imediatamente iniciamos a execução naquele novo agent ao qual foi feito o handoff, enquanto também transferimos o estado mais recente da conversa".8
Um alerta de vocabulário, porque isso confunde as pessoas o tempo todo: "handoff" é a palavra de um SDK, não um padrão. É terminologia do OpenAI Agents SDK e daquele guia, que também chama os dois arranjos de "manager" e "decentralized" e observa que, no padrão manager, "as arestas representam chamadas de ferramenta, enquanto no padrão decentralized, as arestas representam handoffs".8 Há sim um padrão aberto nesse espaço — A2A, na versão 1.0.0, sob copyright da Linux Foundation, com histórico de versões e uma lista documentada de breaking changes, cujo princípio declarado é execução opaca: agents "colaboram com base em capacidades declaradas e informações trocadas, sem precisar compartilhar seus pensamentos internos, planos ou implementações de ferramentas".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 governança.
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 você só encontraria em produção. reachable encontra o agent que ninguém consegue alcançar — configurado, pago, nunca chamado. conflicts recusa a aresta que é dos dois tipos ao mesmo tempo, o que soa pedante até você ler em voz alta: o pai tanto mantém o controle quanto o entrega. Rode isso em um 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 realmente atravessa a fronteira
Link para a seção: O que realmente atravessa a fronteiraAgora a medição para a qual esta seção existe, e a única do capítulo feita contra um modelo real em vez de um roteirizado.
Um cliente declara uma restrição em sua primeira mensagem — nossa conta está registrada em Portugal, não na Espanha; tudo relacionado a impostos precisa usar Portugal — conversa sobre outra coisa, depois faz uma pergunta que billing precisa responder. O caso é transferido. Vinte e quatro testes, um país e uma empresa diferentes a cada vez, quatro payloads de transferência, e o agent receptor então recebe uma pergunta: em que país a conta deste cliente está registrada?
| o que foi transferido | payload médio | a restrição estava nele | o especialista a lembrou | 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 % |
| só a última mensagem do usuário | 61 tokens | 0/24 | 0/24 — 0 % | 0–14 % |
| um registro tipado | 69 tokens | 24/24 | 24/24 — 100 % | 86–100 % |
A terceira linha é um controle e se comporta como tal: o fato não está ali, então não pode ser lembrado. As outras três são o achado.
A transcrição completa tem 173 tokens e funciona 83 % das vezes, com suas quatro falhas sendo assunto do Capítulo 24, não deste. O registro tipado tem 69 tokens — sete a mais que o resumo — e funciona todas as vezes, porque a restrição fica em um campo nomeado, não em uma frase.
E o resumo é a linha para encarar. Ele falhou 24 vezes em 24, e o motivo não é que o leitor não a viu. A restrição apareceu em apenas 1 dos 24 resumos. O agent receptor não foi descuidado; recebeu um texto que não continha a resposta. Um resumo é uma compactação que você não escreveu, produzida por um modelo cuja janela você não consegue ver, otimizada para soar como um resumo — e "o cliente diz que nossos registros têm o país errado" é exatamente o tipo de oração que um sumarizador descarta como ruído procedural.
Um limite honesto desse número: o sumarizador é um modelo de meio bilhão de parâmetros, e um maior manteria mais. O que não melhora com tamanho é o formato do risco — o agent remetente decide, a cada handoff, a cada formulação, de forma inobservável, quais fatos sobrevivem. O registro tipado não depende desse julgamento, e é por isso que vence por construção, não por inteligência. Tudo que precisa sobreviver a uma transferência deve ser um campo, não uma frase.
O mesmo raciocínio se aplica na outra direção, à topologia de agent-como-ferramenta, e a tabela anterior já colocou preço nisso: o que volta de um worker também é um resumo, e pagar 8,3 % a mais para receber a evidência junto é a mesma correção vista do lado do pai.
Quando um agent vence
Link para a seção: Quando um agent venceTrês fatos finais, todos das tabelas acima.
Um sistema multi-agent multiplica chamadas, e chamadas são quadráticas em context. O orquestrador fez 12 chamadas ao modelo onde um agent fez 5, e cada uma carrega sua própria transcrição crescente — 3.628 input tokens contra 2.697, uma diferença que aumenta com a duração da tarefa.
Toda fronteira é um canal com perdas. Dois agents significam um resumo. Quatro agents em cadeia significam três, compostos, cada um escrito por um modelo que otimiza para algo diferente da sua decisão.
O agent único encontrou algo que ninguém pediu. A divergência do pedido de compra veio à tona porque uma janela continha a fatura e o pedido ao mesmo tempo. Dividir trabalho entre especialistas também divide a capacidade de notar que dois fatos discordam.
Nada disso argumenta contra os frameworks multi-agent publicados, que vale ler como fontes primárias em vez de por tutoriais.10 Argumenta a favor de fazer o segundo agent merecer seu lugar.
Então, um teste em vez de uma preferência. Adicione um segundo agent quando pelo menos uma destas coisas for verdadeira: a subtarefa precisa de uma janela limpa que o pai não deve herdar (Capítulo 24); as subtarefas são genuinamente independentes e o tempo de parede 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 em argumento de segurança; ou a subtarefa é de outra pessoa, que é onde um protocolo real começa a importar. Se a resposta for "para cada agent ter um prompt mais claro", dê ao agent único um prompt mais claro. É de graça.
Para onde isso vai agora
Link para a seção: Para onde isso vai agoraAgora você sabe nomear os cinco padrões, precificá-los uns contra os outros em uma tarefa, diferenciar um orquestrador de um sectioner e uma chamada de ferramenta de um handoff, e defender um agent único com uma tabela em vez de uma preferência.
Todo arranjo aqui compartilhou uma conveniência que não sobreviverá ao contato com nada real: todas as ferramentas pertenciam a nós. Fatura, pedido, tabela tributária, os workers por trás do orquestrador — mesmo repositório, mesmo deploy, mesmos tipos, mesmas pessoas.
Agora coloque uma delas do outro lado de uma fronteira de empresa. A tabela tributária pertence a um fornecedor contábil, o registro do pedido a um sistema de armazém, e nenhum dos dois leu sua interface Tool. Você precisa de uma forma para um modelo que você não escreveu descobrir, descrever e chamar uma capacidade que outra pessoa opera — 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 schema normativo, e quase tudo indexado sobre ele descreve uma revisão que já não existe.
O Capítulo 26 lê essa especificação em vez de resumi-la, e começa digitando JSON-RPC em um terminal à mão.
Fontes e método
Link para a seção: Fontes e métodoTodo custo e contagem de tokens acima veio do provedor roteirizado descrito na segunda seção, em Node 22 sobre uma interface loopback, contando com a codificação o200k_base e precificado nas tarifas 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 números de tempo de parede vêm das mesmas execuções com a latência do provedor definida em 400 ms por chamada e as ferramentas em 50 ms, então medem o arranjo, não qualquer provedor. As duas medições com modelo real — a tabela de handoff e a tabela de voting e julgamento — usaram Qwen/Qwen2.5-0.5B-Instruct em float32 na CPU atrás de um endpoint do mesmo formato, greedy exceto onde uma temperature é declarada, com intervalos computados pelo método de Wilson do Capítulo 4. Nenhuma requisição neste capítulo foi para um endpoint pago, e nenhum número nele foi estimado.
Referências
Link para a seçã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 toda frase citada deles — prompt chaining, routing, parallelisation com suas 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 "agentic systems frequentemente trocam latência e custo por melhor desempenho na tarefa". Os Capítulos 22 e 23 citam 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 decoding, não uma arquitetura: amostrar caminhos de raciocínio diversos e então "selecionar a resposta mais consistente marginalizando os caminhos de raciocínio amostrados", com ganhos relatados 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 loop evaluator-optimiser com um modelo nos três papéis — "gerador, refinador e provedor de feedback" — melhorando "em ~20% absoluto em média no desempenho de tarefas" em sete tarefas, medido por preferência humana e métricas automáticas, não pelo veredito 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). Adiciona uma memória episódica de autocríticas entre tentativas — "reforçar language agents não atualizando pesos, mas por meio de feedback linguístico" — relatando 91 % pass@1 no HumanEval contra 80 % para o baseline GPT-4. Note o requisito de que seus resultados dependem: um sinal real do ambiente, como um teste falhando, e não a opinião do modelo sobre si mesmo. ↩ ↩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 esse loop. Citado aqui por seu formato de custo, não por seus resultados: uma chamada ao modelo por etapa, com a transcrição inteira reenviada a 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). "Primeiro, conceber um plano para dividir toda a tarefa em subtarefas menores, e então executar as subtarefas de acordo com o plano" — o formato planejar-e-executar, e a fonte da troca com que este capítulo se importa: o plano é fixado antes de a primeira observação chegar, que é prompt chaining com a decomposição escrita por um modelo em vez de por você. ↩
-
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). Busca sobre "thoughts" intermediários 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 "poderia exigir 5–100 vezes mais tokens gerados do que CoT". ↩ ↩2
-
OpenAI, A practical guide to building agents (PDF), lido em 7 de setembro de 2026. A divisão manager versus decentralized, o enquadramento em grafo citado acima ("no padrão manager, as arestas representam chamadas de ferramenta, enquanto no padrão decentralized, as arestas representam handoffs") e a definição de handoff como "uma transferência unidirecional... imediatamente iniciamos a execução naquele novo agent ao qual foi feito o handoff, enquanto também transferimos o estado mais recente da conversa". Note o que essa última cláusula resolve: neste SDK, o estado da conversa viaja, o que é uma decisão de design dessa biblioteca e não uma propriedade de handoffs em geral. ↩ ↩2
-
Agent2Agent (A2A) Protocol Specification, versão lançada mais recente 1.0.0,
a2a-protocol.org/latest/specification/, lida em 7 de setembro de 2026; copyright da Linux Foundation, Apache-2.0. Citado acima: um "padrão aberto projetado para facilitar a comunicação e a interoperabilidade entre sistemas de AI agent independentes e potencialmente opacos", e o princípio de execução opaca — agents "colaboram com base em capacidades declaradas e informações trocadas, sem precisar compartilhar seus pensamentos internos, planos ou implementações de ferramentas". 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 sua relação com MCP. O Capítulo 26 faz essa comparação. ↩ -
Os 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), em que agents são "customizáveis, conversáveis" 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 padrão em role prompts e explicita que "soluções para tarefas mais complexas se complicam por inconsistências lógicas devido a alucinações em cascata causadas por encadear LLMs ingenuamente" — a cadeia confiantemente errada medida no topo deste capítulo, nomeada em um 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 planejamento, que é a maior resposta publicada para "o que acontece se você continuar adicionando agents". ↩