Phase 16 - Lesson 01

Por que Multiagentes?

Um único agente encontra um limite. A jogada inteligente não é um agente maior - são mais agentes.

Type: Learn Languages: TypeScript Prerequisites: Phase 14 (Agent Engineering) Time: ~60 minutos

Objetivos de Aprendizado

  • Identificar o teto do agente único (estouro de contexto, especialidades mistas, gargalo sequencial) e explicar quando a divisão em múltiplos agentes é a escolha certa
  • Comparar padrões de orquestração (pipeline, fan-out paralelo, supervisor, hierárquico) e selecionar o correto para uma determinada estrutura de tarefa
  • Projetar um sistema multiagente com limites claros de papéis, estado compartilhado e um contrato de comunicação
  • Analisar os prós e contras da complexidade multiagente (latência, custo, dificuldade de depuração) versus a simplicidade de um agente único

O Problema

Você construiu um único agente na Phase 14. Ele funciona. Ele pode ler arquivos, executar comandos, chamar APIs e raciocinar sobre os resultados. Então você o direciona para uma base de código real: 200 arquivos, três linguagens, testes que dependem de infraestrutura e a necessidade de pesquisar APIs externas antes de escrever o código.

O agente engasga. Não porque o LLM seja burro, mas porque a tarefa excede o que um loop de agente único pode suportar. A janela de contexto fica cheia com o conteúdo dos arquivos. O agente esquece o que leu 40 chamadas de ferramenta atrás. Ele tenta ser um pesquisador, um codificador e um revisor, tudo de uma vez, e faz as três coisas mal.

Esse é o teto do agente único. Você o atinge toda vez que uma tarefa exige:

  • Mais contexto do que cabe em uma janela - ler 50 arquivos ultrapassa os 200k tokens
  • Diferentes especialidades em diferentes etapas - a pesquisa exige um direcionamento (prompting) diferente da geração de código
  • Trabalho que pode ocorrer em paralelo - por que ler três arquivos sequencialmente quando você pode lê-los simultaneamente?

O Conceito

O Teto do Agente Único

Um único agente é um loop, uma janela de contexto, um system prompt. Imagine:

┌─────────────────────────────────────────┐
│            SINGLE AGENT                 │
│                                         │
│  ┌───────────────────────────────────┐  │
│  │         Context Window            │  │
│  │                                   │  │
│  │  research notes                   │  │
│  │  + code files                     │  │
│  │  + test output                    │  │
│  │  + review feedback                │  │
│  │  + API docs                       │  │
│  │  + ...                            │  │
│  │                                   │  │
│  │  ██████████████████████ FULL ███  │  │
│  └───────────────────────────────────┘  │
│                                         │
│  One system prompt tries to cover       │
│  research + coding + review + testing   │
│                                         │
│  Result: mediocre at everything         │
└─────────────────────────────────────────┘

Três coisas falham:

  1. Saturação de contexto - os resultados das ferramentas se acumulam. Na iteração 30, o agente já consumiu 150k tokens de conteúdo de arquivos, saídas de comandos e raciocínios anteriores. Detalhes críticos da iteração 5 se perdem.

  2. Confusão de papéis - um system prompt que diz "você é um pesquisador, codificador, revisor e testador" gera um agente que pesquisa pela metade, codifica pela metade e nunca termina a revisão.

  3. Gargalo sequencial - o agente lê o arquivo A, depois o arquivo B, depois o arquivo C. Três chamadas sequenciais de LLM. Três execuções de ferramentas em série. Sem paralelismo.

A Solução Multiagente

Divida o trabalho. Dê a cada agente uma tarefa, uma janela de contexto e um system prompt ajustado para essa tarefa:

┌──────────────────────────────────────────────────────────┐
│                    ORCHESTRATOR                          │
│                                                          │
│  "Build a REST API for user management"                  │
│                                                          │
│         ┌──────────┬──────────┬──────────┐               │
│         │          │          │          │               │
│         ▼          ▼          ▼          ▼               │
│   ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐  │
│   │RESEARCHER│ │  CODER   │ │ REVIEWER │ │  TESTER  │  │
│   │          │ │          │ │          │ │          │  │
│   │ Reads    │ │ Writes   │ │ Checks   │ │ Runs     │  │
│   │ docs,    │ │ code     │ │ code     │ │ tests,   │  │
│   │ finds    │ │ based on │ │ quality, │ │ reports  │  │
│   │ patterns │ │ research │ │ finds    │ │ results  │  │
│   │          │ │ + spec   │ │ bugs     │ │          │  │
│   └─────┬────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘  │
│         │           │            │             │         │
│         └───────────┴────────────┴─────────────┘         │
│                          │                               │
│                     Merge results                        │
└──────────────────────────────────────────────────────────┘

Cada agente tem:

  • Um system prompt focado ("Você é um revisor de código. Seu único trabalho é encontrar bugs.")
  • Sua própria janela de contexto (não poluída pelo trabalho de outros agentes)
  • Um contrato claro de entrada/saída (recebe notas de pesquisa, gera código)

Sistemas Reais que Fazem Isso

Subagentes do Claude Code - quando o Claude Code gera um subagente com Task, ele cria um agente filho com uma tarefa com escopo delimitado. O pai mantém seu contexto limpo. O filho faz o trabalho focado e retorna um resumo.

Devin - executa um agente planejador, um agente codificador e um agente de navegador. O planejador divide o trabalho em etapas. O codificador escreve o código. O navegador pesquisa a documentação. Cada um tem um contexto separado.

Equipes de desenvolvimento multiagente (SWE-bench) - os sistemas com melhor desempenho no SWE-bench usam um pesquisador que lê a base de código, um planejador que projeta a correção e um codificador que a implementa. Sistemas de agente único obtêm pontuações mais baixas.

ChatGPT Deep Research - gera múltiplos agentes de busca em paralelo, cada um explorando um ângulo diferente, e depois sintetiza os resultados.

O Espectro

Multiagentes não é algo binário. É um espectro:

SIMPLE ──────────────────────────────────────────── COMPLEX

 Single        Sub-         Pipeline      Team         Swarm
 Agent         agents

 ┌───┐       ┌───┐        ┌───┐───┐    ┌───┐───┐    ┌─┐┌─┐┌─┐
 │ A │       │ A │        │ A │ B │    │ A │ B │    │ ││ ││ │
 └───┘       └─┬─┘        └───┘─┬─┘    └─┬─┘─┬─┘    └┬┘└┬┘└┬┘
               │                │        │   │       ┌┴──┴──┴┐
             ┌─┴─┐          ┌───┘───┐    │   │       │shared │
             │ a │          │ C │ D │  ┌─┴───┴─┐    │ state │
             └───┘          └───┘───┘  │  msg   │    └───────┘
                                       │  bus   │
 1 loop      Parent +      Stage by    │       │    N peers,
 1 context   child tasks   stage       └───────┘    emergent
                                       Explicit      behavior
                                       roles

Agente único (Single agent) - um loop, um prompt. Bom para tarefas simples.

Subagentes (Subagents) - um pai cria filhos para subtarefas focadas. O pai mantém o plano. Os filhos reportam de volta. É isso que o Claude Code faz.

Pipeline - os agentes rodam em sequência. A saída do Agente A torna-se a entrada do Agente B. Bom para fluxos de trabalho em etapas: pesquisa -> código -> revisão -> teste.

Equipe (Team) - os agentes rodam em paralelo com um barramento de mensagens compartilhado. Cada um tem um papel. Um orquestrador coordena. Bom quando diferentes habilidades são necessárias simultaneamente.

Enxame (Swarm) - muitos agentes idênticos ou quase idênticos com estado compartilhado. Sem orquestrador fixo. Os agentes pegam o trabalho de uma fila. Bom para tarefas paralelas de alto rendimento.

Os Quatro Padrões Multiagentes

Padrão 1: Pipeline

Input ──▶ Agent A ──▶ Agent B ──▶ Agent C ──▶ Output
          (research)  (code)      (review)

Cada agente transforma os dados e os passa adiante. Simples de raciocinar sobre. A falha em uma etapa bloqueia o restante.

Padrão 2: Fan-out / Fan-in

                ┌──▶ Agent A ──┐
                │              │
Input ──▶ Split ├──▶ Agent B ──├──▶ Merge ──▶ Output
                │              │
                └──▶ Agent C ──┘

Divide o trabalho entre agentes paralelos e depois mescla os resultados. Bom para tarefas que se decompõem em subtarefas independentes.

Padrão 3: Orquestrador-Trabalhador (Orchestrator-Worker)

                    ┌──────────┐
                    │  Orch.   │
                    └──┬───┬───┘
                  task │   │ task
                 ┌─────┘   └─────┐
                 ▼               ▼
           ┌──────────┐   ┌──────────┐
           │ Worker A │   │ Worker B │
           └──────────┘   └──────────┘

Um orquestrador inteligente decide o que fazer, delega para os trabalhadores e sintetiza os resultados. O orquestrador é, ele próprio, um agente com ferramentas para criar trabalhadores.

Padrão 4: Enxame de Pares (Peer Swarm)

          ┌───┐ ◄──── msg ────▶ ┌───┐
          │ A │                  │ B │
          └─┬─┘                  └─┬─┘
            │                      │
       msg  │    ┌───────────┐     │ msg
            └───▶│  Shared   │◄────┘
                 │  State    │
            ┌───▶│  / Queue  │◄────┐
            │    └───────────┘     │
       msg  │                      │ msg
          ┌─┴─┐                  ┌─┴─┐
          │ C │ ◄──── msg ────▶ │ D │
          └───┘                  └───┘

Sem orquestrador central. Os agentes se comunicam de igual para igual (peer-to-peer). As decisões surgem da interação. Mais difícil de depurar, mas escala para muitos agentes.

Quando NÃO Usar Multiagentes

Múltiplos agentes adicionam complexidade. Cada mensagem entre agentes é um ponto potencial de falha. A depuração passa de "ler uma única conversa" para "rastrear mensagens em cinco agentes".

Permaneça com agente único quando:

  • A tarefa couber em uma janela de contexto (menos de ~100k tokens de dados de trabalho)
  • Você não precisar de system prompts diferentes para etapas diferentes
  • A execução sequencial for rápida o suficiente
  • A tarefa for simples o suficiente para que a divisão adicione mais sobrecarga do que valor

O custo da complexidade:

  • Cada limite de agente é uma etapa de compressão com perdas: o contexto completo do agente A é resumido em uma mensagem para o agente B
  • A lógica de coordenação (quem faz o quê, quando e em que ordem) é sua própria fonte de bugs
  • A latência aumenta: N agentes significam no mínimo N chamadas sequenciais de LLM, e mais se eles precisarem conversar de um lado para o outro
  • O custo se multiplica: cada agente consome tokens de forma independente

Regra geral: se uma tarefa leva menos de 20 chamadas de ferramenta e cabe em 100k tokens, mantenha-a como agente único.

Construa

Passo 1: O Agente Único Sobrecarregado

Aqui está um agente único tentando fazer tudo. Ele tem um system prompt massivo e uma única janela de contexto que contém pesquisa, código e revisões:

type AgentResult = {
  content: string;
  tokensUsed: number;
  toolCalls: number;
};

async function singleAgentApproach(task: string): Promise<AgentResult> {
  const systemPrompt = `You are a full-stack developer. You must:
1. Research the requirements
2. Write the code
3. Review the code for bugs
4. Write tests
Do ALL of these in a single conversation.`;

  const contextWindow: string[] = [];
  let totalTokens = 0;
  let totalToolCalls = 0;

  const research = await fakeLLMCall(systemPrompt, `Research: ${task}`);
  contextWindow.push(research.output);
  totalTokens += research.tokens;
  totalToolCalls += research.calls;

  const code = await fakeLLMCall(
    systemPrompt,
    `Given this research:\n${contextWindow.join("\n")}\n\nNow write code for: ${task}`
  );
  contextWindow.push(code.output);
  totalTokens += code.tokens;
  totalToolCalls += code.calls;

  const review = await fakeLLMCall(
    systemPrompt,
    `Given all previous context:\n${contextWindow.join("\n")}\n\nReview the code.`
  );
  contextWindow.push(review.output);
  totalTokens += review.tokens;
  totalToolCalls += review.calls;

  return {
    content: contextWindow.join("\n---\n"),
    tokensUsed: totalTokens,
    toolCalls: totalToolCalls,
  };
}

Problemas com essa abordagem:

  • A janela de contexto cresce a cada etapa. Na etapa de revisão, ela contém notas de pesquisa E código E raciocínio anterior.
  • O system prompt é genérico. Ele não pode ser ajustado para cada etapa.
  • Nada roda em paralelo.

Passo 2: Agentes Especialistas

Agora divida. Cada agente recebe uma tarefa:

type SpecialistAgent = {
  name: string;
  systemPrompt: string;
  run: (input: string) => Promise<AgentResult>;
};

function createSpecialist(name: string, systemPrompt: string): SpecialistAgent {
  return {
    name,
    systemPrompt,
    run: async (input: string) => {
      const result = await fakeLLMCall(systemPrompt, input);
      return {
        content: result.output,
        tokensUsed: result.tokens,
        toolCalls: result.calls,
      };
    },
  };
}

const researcher = createSpecialist(
  "researcher",
  "You are a technical researcher. Read documentation, find patterns, and summarize findings. Output only the facts needed for implementation."
);

const coder = createSpecialist(
  "coder",
  "You are a senior TypeScript developer. Given requirements and research notes, write clean, tested code. Nothing else."
);

const reviewer = createSpecialist(
  "reviewer",
  "You are a code reviewer. Find bugs, security issues, and logic errors. Be specific. Cite line numbers."
);

Cada especialista tem um prompt focado. Cada um recebe uma janela de contexto limpa contendo apenas a entrada de que precisa.

Passo 3: Coordenação por Mensagens

Interligue os especialistas com passagem explícita de mensagens:

type AgentMessage = {
  from: string;
  to: string;
  content: string;
  timestamp: number;
};

async function multiAgentApproach(task: string): Promise<AgentResult> {
  const messages: AgentMessage[] = [];
  let totalTokens = 0;
  let totalToolCalls = 0;

  const researchResult = await researcher.run(task);
  messages.push({
    from: "researcher",
    to: "coder",
    content: researchResult.content,
    timestamp: Date.now(),
  });
  totalTokens += researchResult.tokensUsed;
  totalToolCalls += researchResult.toolCalls;

  const coderInput = messages
    .filter((m) => m.to === "coder")
    .map((m) => `[From ${m.from}]: ${m.content}`)
    .join("\n");

  const codeResult = await coder.run(coderInput);
  messages.push({
    from: "coder",
    to: "reviewer",
    content: codeResult.content,
    timestamp: Date.now(),
  });
  totalTokens += codeResult.tokensUsed;
  totalToolCalls += codeResult.toolCalls;

  const reviewerInput = messages
    .filter((m) => m.to === "reviewer")
    .map((m) => `[From ${m.from}]: ${m.content}`)
    .join("\n");

  const reviewResult = await reviewer.run(reviewerInput);
  messages.push({
    from: "reviewer",
    to: "orchestrator",
    content: reviewResult.content,
    timestamp: Date.now(),
  });
  totalTokens += reviewResult.tokensUsed;
  totalToolCalls += reviewResult.toolCalls;

  return {
    content: messages.map((m) => `[${m.from} -> ${m.to}]: ${m.content}`).join("\n\n"),
    tokensUsed: totalTokens,
    toolCalls: totalToolCalls,
  };
}

Cada agente recebe apenas as mensagens endereçadas a ele. Sem poluição de contexto. A leitura de 50k tokens de documentação do pesquisador nunca entra no contexto do revisor.

Passo 4: Comparação

async function compare() {
  const task = "Build a rate limiter middleware for an Express.js API";

  console.log("=== Single Agent ===");
  const single = await singleAgentApproach(task);
  console.log(`Tokens: ${single.tokensUsed}`);
  console.log(`Tool calls: ${single.toolCalls}`);

  console.log("\n=== Multi-Agent ===");
  const multi = await multiAgentApproach(task);
  console.log(`Tokens: ${multi.tokensUsed}`);
  console.log(`Tool calls: ${multi.toolCalls}`);
}

A versão multiagente usa mais tokens no total (três agentes, três chamadas de LLM separadas), mas o contexto de cada agente permanece limpo. A qualidade de cada etapa melhora porque o system prompt é especializado.

Use

Esta lição produz um prompt reutilizável para decidir quando adotar múltiplos agentes. Consulte outputs/prompt-multi-agent-decision.md.

Exercícios

  1. Adicione um quarto especialista: um agente "testador" que recebe o código do codificador e o feedback de revisão do revisor, e então escreve os testes
  2. Modifique o pipeline para que o revisor possa enviar feedback de volta ao codificador para um loop de revisão (máximo de 2 rodadas)
  3. Converta o pipeline sequencial em um fan-out: execute o pesquisador e um agente "analisador de requisitos" em paralelo e, em seguida, mescle suas saídas antes de passá-las para o codificador

Termos-Chave

Termo O que as pessoas dizem O que realmente significa
Swarm "Uma mente de colmeia de agentes de IA" Um conjunto de agentes pares com estado compartilhado e sem líder fixo. O comportamento surge de interações locais.
Orchestrator "O agente chefe" Um agente cujas ferramentas incluem gerar e gerenciar outros agentes. Ele planeja e delega, mas pode não fazer o trabalho real.
Coordinator "O guarda de trânsito" Um componente não agente (geralmente apenas código, não um LLM) que roteia mensagens entre agentes com base em regras.
Consensus "Os agentes concordam" Um protocolo em que vários agentes devem chegar a um acordo antes de prosseguir. Usado quando saídas conflitantes precisam de resolução.
Emergent behavior "Os agentes descobriram sozinhos" Padrões em nível de sistema que surgem das interações dos agentes, mas não foram explicitamente programados. Podem ser úteis ou prejudiciais.
Fan-out / fan-in "Map-reduce para agentes" Divisão de uma tarefa entre agentes paralelos (fan-out) e posterior combinação de seus resultados (fan-in).
Message passing "Agentes conversando entre si" O mecanismo de comunicação entre agentes: dados estruturados enviados de um agente para outro, substituindo as janelas de contexto compartilhadas.

Leituras Adicionais

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).