Todo mundo construindo sistemas multi-agente em 2026 ainda está escrevendo linhas retas. Passo um, depois passo dois, depois passo três - cada um esperando o anterior. Aqui está o porquê isso é lento e como consertar.

O problema que ninguém verifica
Você construiu um agente multi-etapas. Funciona. Também é lento.
Você assume que o modelo é o gargalo. Não é.
O gargalo é a forma que você desenhou. Uma cadeia - passo 1 espera o passo 2, passo 2 espera o passo 3 - força a execução sequencial mesmo quando metade desses passos não tem nada a ver um com o outro.
"Resuma este documento, depois verifique o clima" são duas tarefas independentes vestindo um casado como se fossem um fluxo de trabalho. A tarefa do clima não precisa do resumo. Nunca precisou. Mas se você escreveu como uma cadeia, ela espera de qualquer jeito.
Essa espera desperdiçada, multiplicada por dezenas de passos, é onde a maior parte do seu tempo de execução desaparece.
Capítulo 1 - Loops vs. grafos
Um loop é uma unidade de auto-aperfeiç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 vai fechar tickets rapidamente - enquanto a satisfação cai silenciosamente. O loop não consegue ver 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 loop perseguindo um 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 roda independentemente e verifica ambos. Nenhuma métrica única dirige o sistema inteiro - a estrutura o faz.

Para sistemas de agente, isso significa uma mudança concreta: pare de escrever um agente que faz tudo do início ao fim. Projete a forma do trabalho primeiro - o que tem que acontecer antes do quê, o que pode rodar 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, uma tarefa, 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 então" como uma aresta por padrão.
1"Leia este código-fonte e então escreva o changelog"2"Acesse a página de preços e então resuma os recursos dos concorrentes"
Faça uma pergunta para cada "e então" 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 → não há 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 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 rodam 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 jamais é 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 neste código-fonte.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 aguardar a conclusão de todas as verificações.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ê o está descrevendo.
O que acontece internamente - uma versão simplificada da orquestração:
1import asyncio2from anthropic import Anthropic34client = Anthropic()56async def audit_route_file(filepath: str) -> dict:7 """Um nó. Roda 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 que todos os nós de auditoria terminem."""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 # Fan-out -- todos os nós independentes rodam concorrentemente41 audit_tasks = [audit_route_file(f) for f in route_files]42 results = await asyncio.gather(*audit_tasks)4344 # Fan-in -- 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 distribuídas em paralelo: menos de 15 segundos, limitado pelo seu arquivo único 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 enfrentá-los.
Colapso de contexto. Distribua 1.000 nós e tente alimentar todas as 1.000 saídas em uma única etapa de consolidação, e você estourará qualquer janela de contexto antes mesmo da síntese começar. Correção: coloque seu fan-in 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 """Fan-in 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 # A consolidação final trabalha com resumos, não com 1.000 resultados brutos11 return await consolidate(batch_summaries)
Falsa independência. Você assumirá 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ó com falha entre 200 pode desaparecer em um relatório que parece completo. Correção: todo passo de fan-in 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

Uma vez que o padrão funciona com 40 nós, escalar para centenas é uma mudança de configuração, não um redesenho - 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 <- fan-in 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 fan-in 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 passo e se torna a pessoa que projeta a estrutura de dependência. 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 passos tem 40 pontos de falha sequencial e 40x a latência do seu passo único mais lento.
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 passos.
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 o mesmo trabalho subjacente exato.
O modelo nunca foi o gargalo. A linha que você desenhou foi.
Esta é uma análise técnica dos padrões de orquestração multi-agente a partir de 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 pela leitura.





