Padrões de Orquestração Multiagente: Filas, Estado e Handoffs
Sistemas multiagente confiáveis não dependem de prompts engenhosos — dependem da chata disciplina de sistemas distribuídos: filas duráveis entre agentes, estado mantido fora do modelo e handoffs idempotentes que sobrevivem às retentativas. O modelo é o trabalhador; a fila é a espinha dorsal.
Toda quarta-feira. 28.400+ operadores. Zero enrolação.
✓ Verifique sua caixa de entrada — clique no link de confirmação para concluir o cadastro.
✓ Inscrição concluída!
✓ Você já está na lista.
Índice
Atualizado junho de 2026.
TL;DR: Sistemas multiagente confiáveis não se ganham com prompts engenhosos — ganham-se com a chata disciplina de sistemas distribuídos. Coloque uma fila durável entre os agentes, mantenha o estado fora do modelo e torne cada handoff idempotente para que uma retentativa não possa agir duas vezes. O modelo é o trabalhador; a fila é a espinha dorsal. Acerte nesses três pontos e a orquestração deixa de ser assustadora.
Leitura do operador: A maioria dos meus mais de 100 agentes é de etapa única. Os que não são — os pipelines que classificam, depois enriquecem, depois agem — só se tornaram confiáveis quando parei de pensar em “cadeia de prompts” e comecei a pensar em “fila de jobs com trabalhadores LLM”. Isto é arquitetura, não engenharia de prompts.
“Multiagente” soa como se os agentes conversassem entre si. Na prática, a versão confiável é o oposto: os agentes não se comunicam diretamente de jeito nenhum. Eles deixam mensagens numa fila e pegam trabalho de uma fila, e a orquestração vive no encanamento entre eles. Aqui estão os padrões que se sustentam em produção.
Padrão 1: Coloque uma fila durável entre cada agente
O primeiro instinto é chamar o agente B diretamente de dentro do agente A. Não faça isso. Chamadas diretas acoplam os dois: se B é lento, A bloqueia; se B falha, o trabalho de A é perdido; se você precisa escalar B, não consegue sem mexer em A.
Em vez disso, A termina seu trabalho e enfileira uma mensagem para B. B é um trabalhador separado que esvazia a fila no próprio ritmo.
// O agente A termina e faz o handoff via fila — sem chamada direta a B
await env.ENRICH_QUEUE.send({
traceId,
type: "enrich",
payload: classifierResult,
});
// O trabalho de A está concluído. B vai pegá-lo de forma independente.No Cloudflare uso Workers Queues exatamente para isso — as mesmas primitivas por trás da stack de agentes que eu uso. A fila te dá quatro coisas de graça: buffering (B pode estar fora do ar sem perder trabalho), retentativas (mensagens com falha são reentregues), contrapressão (um pico se enfileira em vez de derrubar) e desacoplamento (escale ou reimplante B sem mexer em A). Cada uma dessas é algo que, de outra forma, você teria que construir na mão e errar.
Padrão 2: Mantenha o estado fora do modelo, sempre
O bug multiagente mais comum é supor que o modelo lembra de qualquer coisa entre as etapas. Ele não lembra. Cada chamada ao modelo é stateless; a única memória é o que você coloca no prompt. Então a fonte da verdade para “onde está este job no pipeline” precisa viver num banco de dados, não numa conversa.
Mantenho um único registro de job que cada agente lê e atualiza:
interface JobState {
traceId: string;
stage: "classified" | "enriched" | "acted" | "done" | "failed";
data: Record<string, unknown>;
attempts: number;
updatedAt: number;
}Cada agente faz o mesmo loop: ler o estado do job, fazer seu trabalho, escrever o novo estado, enfileirar a próxima etapa. O modelo nunca mantém o estado — ele recebe a fatia relevante como entrada e devolve um resultado. É isso que torna o sistema reiniciável: se um trabalhador morre no meio de um job, o registro de estado ainda diz exatamente onde as coisas estavam, e a mensagem de fila reentregue retoma a partir dali. Também torna a depuração tratável, porque a tabela de estado é um registro consultável da jornada de cada job — a mesma mentalidade de instrumentação de como meço se um agente está funcionando.
Padrão 3: Torne cada handoff idempotente
Filas garantem entrega pelo menos uma vez, não exatamente uma vez. Isso significa que uma mensagem pode ser entregue duas vezes — quedas de rede, retentativas, reimplantações. Se a ação do seu agente não é idempotente, uma entrega dupla age duas vezes: dois e-mails de confirmação, duas reservas, duas cobranças. Essa é a classe mais traiçoeira de bug de orquestração, e é a que as equipes descobrem em produção.
A correção é tornar as ações idempotentes com uma chave:
async function handleEnrich(msg: QueueMessage, env: Env) {
const job = await getJob(env, msg.traceId);
if (job.stage !== "classified") {
// Já processado além desta etapa — é uma entrega duplicada. Pular.
return;
}
const result = await enrich(job.data);
await advanceJob(env, msg.traceId, "enriched", result);
await env.ACT_QUEUE.send({ traceId: msg.traceId, type: "act" });
}A verificação de etapa torna a operação segura para executar duas vezes: a segunda entrega vê que o job já avançou e não faz nada. Para efeitos colaterais externos (enviar um e-mail, cobrar um cartão), passe uma chave de idempotência para a API a jusante para que ela também deduplique. Suponha que cada mensagem será entregue duas vezes e projete de modo que isso seja inofensivo — porque, mais cedo ou mais tarde, vai acontecer.
Padrão 4: Orquestrador vs coreografia — escolha deliberadamente
Há duas maneiras de conectar o fluxo, e a escolha certa depende da complexidade.
Coreografia (o que uso por padrão): cada agente conhece apenas a próxima etapa e a enfileira. O fluxo emerge da cadeia. Simples, descentralizada, fácil de estender — adicione uma etapa inserindo uma fila. A desvantagem é que nenhum lugar único descreve o fluxo inteiro, então um pipeline complexo pode ficar difícil de raciocinar.
Orquestração (um coordenador central): um orquestrador é dono do fluxo, chama cada agente por vez e decide o que vem em seguida com base nos resultados. O fluxo inteiro vive em um único lugar legível e a lógica de ramificação é explícita. O custo é um componente central que precisa ser, ele próprio, durável — se o estado próprio do orquestrador não for externalizado (Padrão 2), ele se torna o ponto único de falha.
Minha regra: coreografia até a ramificação ficar complexa, depois um orquestrador durável. Um pipeline linear de três etapas é coreografia. Um fluxo com roteamento condicional, fan-out paralelo e joins quer um orquestrador cujo estado vive no banco de dados para que possa retomar após uma queda.
Padrão 5: Fan-out, fan-in sem perder pedaços
Quando um job gera N subtarefas paralelas (enriquecer 50 registros, resumir 20 documentos) e você precisa esperar por todas antes de continuar, você precisa de um join. O truque é um contador no estado do job:
- O pai enfileira N mensagens filhas e escreve
expected: N, completed: 0no registro do job. - Cada filho faz seu trabalho e incrementa atomicamente
completed. - O filho que leva
completeda igualarexpectedenfileira a próxima etapa.
O incremento atômico é essencial — sem ele, dois filhos terminando simultaneamente podem ambos achar que não são o último, e o join nunca dispara. Use um contador que o datastore possa incrementar atomicamente, ou uma transação. Esse padrão permite paralelizar o caro miolo de um pipeline (muitas vezes trabalho barato para Haiku — veja a matemática de custo Haiku vs Sonnet) mantendo um join limpo no final.
O que eu pularia
Você não precisa de um framework de agentes pesado para fazer nada disso. Filas, uma tabela de estado e chaves de idempotência são primitivas que toda plataforma já tem. Já vi equipes recorrerem a elaborados frameworks multiagente para obter recursos que uma fila dá de graça, e herdarem uma caixa-preta mais difícil de depurar do que o encanamento que substituiu. Comece com as chatas primitivas. Recorra a um framework só quando tiver sentido uma dor específica que ele resolve.
O resumo: agentes são trabalhadores stateless, filas são a espinha dorsal durável, o estado vive num banco de dados e cada handoff é seguro para executar duas vezes. Esse é o jogo todo.
Perguntas frequentes
Os agentes devem chamar uns aos outros diretamente ou passar por uma fila?
Por uma fila. Chamadas diretas acoplam os agentes — a falha ou lentidão de um se propaga para o outro, e você não consegue escalar nem reimplantar de forma independente. Uma fila durável te dá buffering, retentativas, contrapressão e desacoplamento de graça.
Onde o estado multiagente deve viver?
Fora do modelo, num banco de dados, como um registro de job que cada agente lê e atualiza. Chamadas ao modelo são stateless, então a fonte da verdade para o progresso do pipeline precisa ser externa — é isso que torna o sistema reiniciável após uma queda.
Como impeço um agente de agir duas vezes no mesmo job?
Torne os handoffs idempotentes. Verifique a etapa do job antes de agir e não faça nada se ele já avançou, e passe chaves de idempotência para as APIs externas. Filas entregam pelo menos uma vez, então suponha que cada mensagem pode chegar duas vezes e projete de modo que duplicatas sejam inofensivas.
Preciso de um framework multiagente?
Geralmente não. Filas duráveis, uma tabela de estado e chaves de idempotência cobrem a maioria das necessidades de produção com primitivas que sua plataforma já fornece. Adote um framework só quando esbarrar num problema concreto que ele resolve de forma única, não por padrão.
Toda quarta-feira. 28.400+ operadores. Zero enrolação.
✓ Verifique sua caixa de entrada — clique no link de confirmação para concluir o cadastro.
✓ Inscrição concluída!
✓ Você já está na lista.
Receba o manual de IA na sua caixa de entrada
Toda quarta-feira. 28.400+ operadores. Zero enrolação.
Verifique sua caixa de entrada.
Enviamos um e-mail de confirmação — clique no link para concluir sua inscrição. Verifique o spam se não o vir em um minuto.
Você está inscrito.
Bem-vindo — a próxima edição chega em breve à sua caixa de entrada.
Você já está na lista — fique de olho toda quarta-feira.