Multi-Agent Systems: orchestrator-worker, swarms e handoffs
- ⬜🤖 Agent Patterns: ReAct, Reflexion e Tree of Thoughts(Engenharia AI-Native)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
Multi-agent soa maduro, vende bem em slide — e quebra mais vezes do que os artigos contam. Este módulo é o mapa dos padrões reais: orchestrator-worker, swarm com handoffs, hierarquias, panel of experts. E, mais importante, os critérios honestos para decidir se multi-agent vale a pena — ou se single-agent + tools é o certo.
A pergunta antes da topologia
| Sinal | Single-agent | Multi-agent |
|---|---|---|
| Sub-tarefas paralelizáveis | Pouco ganho | Ganho real em latência |
| Contextos distintos (research vs coding) | Contexto polui | Especialização ajuda |
| Tarefa sequencial curta | Ideal | Overhead desnecessário |
| Necessidade de auditoria por etapa | Difícil rastrear | Cada agent tem trace claro |
| Custo é crítico | Menor | Handoffs dobram/triplicam tokens |
| Debug por suporte | Simples | Rastrear handoffs vira projeto |
Orchestrator-Worker: o padrão mais comum em produção
Um agent central (orchestrator) decompõe a tarefa, delega sub-tarefas a workers em paralelo, agrega os resultados. Workers não se comunicam entre si. Topologia simples, auditável, boa para pesquisa, análise multi-fonte e geração multi-secção.
┌─────────────────┐
│ Orchestrator │
│ (plan + merge) │
└────────┬────────┘
│ delega sub-tasks em paralelo
┌──────────────┼───────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Worker 1 │ │ Worker 2 │ │ Worker 3 │
│ research │ │ research │ │ summariz │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└──────────────┼────────────────┘
│ retornos
▼
Orchestrator agrega
│
▼
Resposta final
# Orchestrator-worker — versão minimal em Python
import asyncio
from anthropic import AsyncAnthropic
client = AsyncAnthropic()
async def worker(role: str, task: str) -> str:
r = await client.messages.create(
model="claude-haiku-4-5-20251001", # workers no modelo barato
max_tokens=800,
system=f"Você é um {role}. Responda objetivo, máx 400 palavras.",
messages=[{"role": "user", "content": task}],
)
return r.content[0].text
async def orchestrate(user_query: str) -> str:
# 1) Planner decide sub-tarefas (modelo forte para planejar)
plan = await client.messages.create(
model="claude-sonnet-4-6",
max_tokens=500,
system=(
"Decomponha a pergunta em 2-4 sub-tarefas independentes em JSON: "
"[{role, task}]. Cada sub-tarefa deve ser executável em paralelo."
),
messages=[{"role": "user", "content": user_query}],
)
import json
sub_tasks = json.loads(plan.content[0].text)
# 2) Workers em paralelo
results = await asyncio.gather(*[
worker(st["role"], st["task"]) for st in sub_tasks
])
# 3) Orchestrator agrega
synthesis = await client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1200,
messages=[{
"role": "user",
"content": (
f"Pergunta original: {user_query}\n\n"
f"Resultados dos workers:\n\n" +
"\n\n---\n\n".join(results) +
"\n\nSintetize uma resposta coerente, citando resultados quando útil."
),
}],
)
return synthesis.content[0].textSwarm / Handoffs: o padrão de conversa que muda de papel
Em vez de um central delegar, cada agent pode transferir o controle para outro agent quando detecta que a próxima ação está fora do seu escopo. É o padrão de atendimento: triage → specialist → billing → escalation.
User
│
▼
┌──────────────┐ handoff:
│ Triage │──► "é billing"
│ agent │
└──────┬───────┘
│ (usuário claramente pergunta conta)
▼
┌──────────────┐ handoff:
│ Billing │──► "precisa de human"
│ agent │
└──────┬───────┘
│
▼
┌──────────────┐
│ Human │
│ agent (HITL)│
└──────────────┘
# OpenAI Agents SDK — handoffs nativos
from agents import Agent, Runner, handoff
triage_agent = Agent(
name="Triage",
instructions=(
"Identifique a intenção do usuário e transfira para o agent certo. "
"Se não tem certeza, peça esclarecimento."
),
)
billing_agent = Agent(
name="Billing",
instructions=(
"Você cuida de cobrança, fatura e plano. Tem acesso a tools "
"get_invoice, update_payment. Se o usuário precisar de refund "
"acima de US$50, transfira para Human."
),
tools=[get_invoice, update_payment],
)
human_agent = Agent(
name="Human",
instructions="Abra ticket crítico para um humano resolver.",
tools=[open_ticket],
)
# Wire handoffs
triage_agent.handoffs = [billing_agent]
billing_agent.handoffs = [human_agent]
# Run
result = await Runner.run(triage_agent, "Meu cartão não passou na renovação")
# Triage → Billing → (resolve ou) → Human📋 Chatbot de atendimento com áreas distintas (vendas, suporte, billing)
Modelo mental natural: a conversa muda de 'especialista' conforme a intenção. Cada agent tem instruções, tools e policies próprias — mais limpo que um super-prompt misturando tudo.
Alt: Single-agent com router + system prompts — mais simples, mas perde isolamento de tools e instruções
Alt: Orchestrator-worker — overkill — não há paralelismo real, é conversação sequencial
Hierarquias: orchestrator que delega a outros orchestrators
Em tarefas grandes (escrever relatório de 50 páginas, auditar codebase inteiro), uma camada só de workers não basta. Orchestrator delega a sub-orchestrators, cada um coordenando workers em seu domínio.
┌──────────────────┐
│ Top orchestrator│
│ (plano macro) │
└────────┬─────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Research │ │ Analysis │ │ Writing │
│ coord. │ │ coord. │ │ coord. │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
[W][W][W] [W][W][W] [W][W][W]
Panel of experts: agents paralelos + judge
Em decisões onde qualidade > custo (ex: resposta médica, revisão de código crítico), rode N agents independentes, cada um com persona/abordagem diferente, e um judge agrega ou escolhe.
# Panel of 3 experts + LLM judge escolhendo
import asyncio
PERSONAS = [
"Você é um engenheiro sênior focado em segurança.",
"Você é um engenheiro sênior focado em performance.",
"Você é um engenheiro sênior focado em legibilidade.",
]
async def expert_review(persona: str, code: str) -> str:
r = await client.messages.create(
model="claude-sonnet-4-6",
max_tokens=600,
system=persona,
messages=[{"role": "user", "content": f"Revise:\n\n{code}"}],
)
return r.content[0].text
async def panel_review(code: str) -> str:
reviews = await asyncio.gather(*[expert_review(p, code) for p in PERSONAS])
judge = await client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1000,
messages=[{
"role": "user",
"content": (
"Três revisões de código. Consolide em uma revisão única, "
"resolvendo conflitos e priorizando severidade:\n\n" +
"\n\n---\n\n".join(reviews)
),
}],
)
return judge.content[0].textFrameworks: quando cada um vale em 2026
| Framework | Forte em | Fraco em |
|---|---|---|
| Anthropic subagents (Task tool) | Delegação dentro do Claude Code; integração MCP | Não é lib standalone |
| OpenAI Agents SDK | Handoffs, guardrails, tracing built-in | Amarrado ao ecossistema OpenAI |
| CrewAI | Prototipagem rápida de crews com role/goal/backstory | Abstrações escondem custos; menos controle em prod |
| LangGraph | State-machine explícita, fluxos complexos e ciclos | Verboso; curva de aprendizado alta |
| AutoGen (Microsoft) | Conversational multi-agent, coding especializado | Output menos determinístico; menos usado em 2026 |
| Roll your own (SDK + asyncio) | Controle total, zero dependência | Você reimplementa retry, tracing, handoff etc. |
📋 Primeira versão de multi-agent em produto existente
Você entende exatamente o que acontece. Debugging é ler seu código. Adicione framework quando a complexidade (5+ agents, state machine com ciclos, múltiplos providers) justificar.
Alt: OpenAI Agents SDK — se já estiver 100% no ecossistema OpenAI
Alt: LangGraph — quando o fluxo vira state-machine complexa com reentrância
Reliability em multi-agent: o que realmente quebra
| Problema | Causa raiz | Mitigação |
|---|---|---|
| Contexto explodindo | Cada handoff copia histórico crescente | Compressão/summary explícito a cada handoff |
| Custo 10× do esperado | Loops de handoff (A→B→A→B) | max_handoffs, trace de topologia |
| Resposta final perde info | Worker relatou, orchestrator resumiu mal | Schemas estruturados (JSON) em vez de prosa livre |
| Deadlock (tudo aguardando) | Handoff circular sem terminal | Sempre ter agent terminal que responde ao user |
| Debug impossível | Trace de conversação em N agents | Tracing estruturado (Langfuse, LangSmith, OTel) |
| Erro de guardrail | Worker viola policy definida no orchestrator | Guardrails por agent, validação no judge |
Perguntas típicas
❓ Multi-agent é sempre pior em latência?
❓ Posso misturar modelos diferentes em um sistema multi-agent?
❓ Como faço trace/observability em multi-agent?
❓ Quando devo fugir de multi-agent e voltar para workflow?
Quiz rápido
4 perguntas · Acerte tudo e ganhe o badge 🎯 Gabarito