Everyone building multi-agent systems in 2026 is still writing straight lines. Step one, then step two, then step three - each one waiting on the last. Here's why that's slow, and how to fix it.

O problema que ninguém verifica
Você construiu um agente com várias etapas. Ele funciona. Também é lento.
Você presume que o modelo é o gargalo. Não é.
O gargalo é o formato que você desenhou. Uma cadeia – etapa 1 espera pela etapa 2, etapa 2 espera pela etapa 3 – força a execução sequencial, mesmo quando metade dessas etapas não tem nada a ver uma com a outra.
"Resumir este documento, depois verificar o clima" são dois trabalhos independentes vestindo um casaco só como se fosse um fluxo de trabalho. A tarefa do clima não precisa do resumo. Nunca precisou. Mas se você escreveu como uma cadeia, ela espera mesmo assim.
Essa espera desperdiçada, multiplicada por dezenas de etapas, é onde a maior parte do seu tempo de execução desaparece.
Capítulo 1 – Loops vs. Grafos
Um loop é uma unidade de autoaperfeiçoamento:
1tentar algo → verificar o resultado → ajustar → tentar novamente
Esse é o átomo. Um agente, uma métrica, ciclando até convergir.
Loops têm um modo de falha conhecido: eles otimizam exatamente o que você mede e nada mais. Um bot de suporte ajustado para fechar tickets rapidamente fechará tickets rapidamente – enquanto a satisfação cai silenciosamente. O loop não consegue enxergar além da sua própria métrica. Isso é a Lei de Goodhart aparecendo na sua arquitetura de agente.
Um grafo resolve isso por design. Em vez de um único loop perseguindo um único número, você constrói uma rede de loops que se observam e se corrigem. A saída do Nó A alimenta o Nó B. O Nó C é executado independentemente e verifica ambos. Nenhuma métrica única impulsiona o sistema inteiro – a estrutura o faz.

Para sistemas de agentes, isso significa uma mudança concreta: pare de escrever um agente que faz tudo do início ao fim. Primeiro, projete a forma do trabalho – o que precisa acontecer antes do quê, o que pode ser executado ao mesmo tempo, o que realmente precisa esperar.
Capítulo 2 – Nós, arestas e o teste que os separa
Um grafo tem exatamente dois componentes:
Nó – uma unidade de trabalho. Um agente, um trabalho, uma entrada, uma saída.
Aresta – uma dependência real. A entrada do Nó B requer a saída do Nó A.
O erro que quase todo mundo comete: tratar "e depois" como uma aresta por padrão.
1"Leia esta base de código e depois escreva o changelog"2"Busque a página de preços e depois resuma os recursos do concorrente"
Faça uma pergunta para cada "e depois" no seu fluxo de trabalho:
O próximo passo realmente lê a saída do passo anterior?
Se sim → aresta real. Mantenha a ordem sequencial. Se não → sem aresta. A espera é desperdiçada. Execute-os em paralelo.
Se nenhum dado cruza a fronteira entre duas tarefas, elas são independentes — e cada par independente que você está executando sequencialmente é tempo de execução que você está jogando fora de graça.
Aqui está o teste aplicado em código:
1from dataclasses import dataclass23@dataclass4class TaskNode:5 id: str6 prompt: str7 depends_on: list[str] # IDs dos nós que este realmente precisa89def has_real_edge(node_a: TaskNode, node_b: TaskNode) -> bool:10 """11 O teste central da engenharia de grafos:12 o prompt de node_b realmente requer a saída de node_a?13 """14 return node_a.id in node_b.depends_on1516# Exemplo: a maioria das "cadeias" se reduz a 2-3 grupos de dependência reais17nodes = [18 TaskNode("audit_routes", "Listar todos os arquivos de rota da API", []),19 TaskNode("check_auth", "Verificar cobertura de middleware de autenticação", []),20 TaskNode("fetch_weather", "Obter o clima de hoje", []),21 TaskNode("summarize", "Resumir as descobertas de rota + autenticação",22 depends_on=["audit_routes", "check_auth"]),23]2425# audit_routes, check_auth, fetch_weather NÃO têm arestas entre si26# Eles são executados em paralelo. Apenas "summarize" tem arestas reais -- ele espera.
Seu agente atual de "faça A, depois B, depois C" é tecnicamente já um grafo. É apenas o pior possível – uma única cadeia onde, se C trava, nada a jusante nunca é executado.
Capítulo 3 – Construindo seu primeiro grafo

Requisitos:
- Claude Code (versão recente com suporte a Dynamic Workflows).
- Plano Max, Team ou Enterprise – workflows ativados por padrão. No Pro, ative manualmente.
Abra um repositório real. Não um exemplo de brinquedo – o retorno só aparece em escala real.
O prompt que inicia seu primeiro grafo:
1Crie um workflow para auditar cada arquivo de rota nesta base de código.23Para cada arquivo de rota, verifique independentemente:4- middleware de autenticação presente5- validação de entrada em todos os parâmetros6- limitação de taxa configurada7- tratamento de erros não vaza stack traces89Execute estas verificações em paralelo em todos os arquivos de rota —10eles não dependem uns dos outros.1112Após todos os arquivos serem verificados, produza um relatório13consolidado agrupado por gravidade: crítico, aviso, informativo.1415A etapa de consolidação deve esperar todas as verificações serem concluídas.16Tudo antes dela não deve.
Observe a estrutura embutida no próprio prompt: trabalho paralelo explicitamente mencionado, a única dependência real (consolidação aguardando todas as verificações) explicitamente nomeada. Você não está esperando que o agente infira o grafo – você está descrevendo-o.
O que acontece nos bastidores – uma versão simplificada da orquestração:
1import asyncio2from anthropic import Anthropic34client = Anthropic()56async def audit_route_file(filepath: str) -> dict:7 """Um nó. Executa independentemente de qualquer outro arquivo de rota."""8 response = await client.messages.create(9 model="claude-sonnet-5",10 max_tokens=1000,11 messages=[{12 "role": "user",13 "content": f"""Audite este arquivo de rota para:14 - middleware de autenticação, validação de entrada,15 limitação de taxa, tratamento de erros1617 Arquivo: {filepath}1819 Retorne JSON: {{"file": "", "issues": [], "severity": ""}}"""20 }]21 )22 return {"file": filepath, "result": response.content[0].text}2324async def consolidate(results: list[dict]) -> str:25 """A única aresta real -- espera todos os nós de auditoria terminarem."""26 response = await client.messages.create(27 model="claude-opus-4-8",28 max_tokens=2000,29 messages=[{30 "role": "user",31 "content": f"""Consolide estas {len(results)} auditorias de rota32 em um relatório agrupado por gravidade:3334 {results}"""35 }]36 )37 return response.content[0].text3839async def run_graph(route_files: list[str]):40 # Dispersão -- todos os nós independentes executam concorrentemente41 audit_tasks = [audit_route_file(f) for f in route_files]42 results = await asyncio.gather(*audit_tasks)4344 # Convergência -- o único nó com uma dependência real45 report = await consolidate(results)46 return report4748# 40 arquivos de rota, um prompt, uma passagem paralela49results = asyncio.run(run_graph([50 f"routes/{f}.py" for f in ["auth", "users", "billing", "orders"]51 # ...mais 36
40 chamadas de API sequenciais a ~8 segundos cada são mais de 5 minutos. As mesmas 40 chamadas dispersas em paralelo: menos de 15 segundos, limitado pelo seu arquivo individual mais lento, não pela soma de todos eles.
Capítulo 4 – Onde os grafos realmente quebram
A engenharia de grafos falha em três lugares previsíveis. Conheça-os antes de encontrá-los.
Colapso de contexto. Dispersar 1.000 nós e tentar alimentar todas as 1.000 saídas em uma única etapa de consolidação fará você estourar qualquer janela de contexto antes mesmo da síntese começar. Correção: coloque sua convergência em camadas. Agrupe nós em lotes de 20-50, resuma cada lote, depois consolide os resumos – não as saídas brutas.
1async def layered_consolidate(results: list[dict], batch_size: int = 30):2 """Convergência em camadas -- nunca sintetize saída bruta em escala."""3 batches = [results[i:i+batch_size]4 for i in range(0, len(results), batch_size)]56 batch_summaries = await asyncio.gather(*[7 summarize_batch(batch) for batch in batches8 ])910 # Consolidação final trabalha com resumos, não com 1.000 resultados brutos11 return await consolidate(batch_summaries)
Falsa independência. Você vai presumir que dois nós são independentes porque seus prompts não se referenciam – mas ambos escrevem no mesmo arquivo, ou acessam a mesma API com limite de taxa. Isso é uma aresta oculta. Correção: audite por recursos compartilhados, não apenas dados compartilhados. Dois nós com um conflito de escrita precisam de uma aresta, mesmo com dependência de dados zero.
Falha silenciosa de nó. Em uma cadeia, uma falha para tudo – irritante, mas óbvio. Em um grafo, um nó falho entre 200 pode desaparecer em um relatório que parece completo. Correção: toda etapa de convergência verifica a contagem de nós em relação à contagem esperada antes de sintetizar, e sinaliza lacunas explicitamente em vez de trabalhar silenciosamente com dados parciais.
1async def safe_consolidate(results: list[dict], expected_count: int):2 if len(results) < expected_count:3 missing = expected_count - len(results)4 print(f"AVISO: {missing} nós falharam silenciosamente. "5 f"O relatório estará incompleto.")6 return await consolidate(results)
Capítulo 5 – Escalando para uma frota real

Depois que o padrão funciona com 40 nós, escalar para centenas é uma mudança de configuração, não um redesign – desde que você tenha construído o grafo corretamente a partir do Capítulo 2.
A forma completa de produção:
1 Orquestrador2 |3 +--------+-------+-------+--------+4 v v v v v5 Nó 1 Nó 2 Nó 3 ... Nó N6 (paralelo, sem arestas entre nenhum deles)7 | | | |8 +--------+-------+-------+-------+9 v10 Resumo em Lote <- convergência em camadas11 (grupos de 30)12 v13 Relatório Final <- a única aresta verdadeira
O único trabalho do orquestrador: decompor a tarefa em nós, identificar arestas reais e despachar. Ele mesmo não faz trabalho algum – ele desenha o grafo.
1async def orchestrate(task: str, resources: list[str]):2 """3 O nó orquestrador -- decompõe, não executa.4 """5 plan = await client.messages.create(6 model="claude-opus-4-8",7 max_tokens=2000,8 messages=[{9 "role": "user",10 "content": f"""Tarefa: {task}11 Recursos disponíveis: {resources}1213 Decomponha em um grafo:14 - Liste cada nó independente (sem arestas compartilhadas)15 - Liste quaisquer dependências reais entre nós16 - Agrupe nós em lotes de convergência se a contagem > 501718 Retorne JSON com: nodes, edges, batch_groups"""19 }]20 )2122 graph = parse_plan(plan.content[0].text)2324 # Execute nós independentes em paralelo25 node_results = await asyncio.gather(*[26 execute_node(n) for n in graph["nodes"] if not n["depends_on"]27 ])2829 # Em seguida, execute nós dependentes, respeitando apenas arestas reais30 final = await execute_dependent_chain(graph["edges"], node_results)3132 return final
Esta é a mudança real que a engenharia de grafos representa: você deixa de ser a pessoa que escreve cada etapa e se torna a pessoa que projeta a estrutura de dependências. Os agentes preenchem os nós. Você é dono das arestas.
O que muda quando você pensa em grafos em vez de linhas
Um agente linear com 40 etapas tem 40 pontos de falha sequencial e 40 vezes a latência da sua etapa individual mais lenta.
Um grafo com as mesmas 40 unidades de trabalho tem tantos pontos de falha paralela quantas dependências reais você tem – geralmente de 3 a 5 na maioria dos fluxos de trabalho – e latência limitada pela sua camada mais lenta, não pela contagem total de etapas.
Isso não é uma aceleração marginal. É a diferença entre um fluxo de trabalho que leva 5 minutos e um que leva 15 segundos, executando exatamente o mesmo trabalho subjacente.
O modelo nunca foi o gargalo. A linha que você desenhou foi.
Esta é uma análise técnica dos padrões de orquestração multiagente em julho de 2026. Os exemplos de código são ilustrativos – adapte o tratamento de erros, a limitação de taxa e a lógica de repetição ao seu ambiente de produção antes de implantar em escala.
Obrigado por ler.





