Objetivo da Aula
Ao concluir esta aula, você será capaz de:
Comparar Sequential, Parallel, Supervisor e Handoff patterns
Implementar supervisorPattern() — Supervisor decide qual agente delegar e quando parar
Implementar handoffPattern() — Agente passa controle quando está fora do domínio
Completar os 2 TODOs do starter TypeScript
Escolher o padrão certo para cada tipo de problema
Por que isso importa
Sequential e Parallel (já implementados) são simples mas inflexíveis. Supervisor adiciona tomada de decisão dinâmica: o sistema decide em runtime qual agente chamar, não na hora do design. Handoff resolve o problema de um agente generalista saber que precisa de um especialista — como um médico clínico geral encaminhando para um cardiologista.
Conceitos Fundamentais
TODO 1: Supervisor Pattern
O Supervisor usa tool_use para delegar para sub-agentes especializados:
async function supervisorPattern(tarefa: string): Promise<string> {
const SUPERVISOR_TOOLS: Anthropic.Tool[] = [
{
name: 'delegar_para_pesquisador',
description: 'Coleta fatos e dados sobre o tópico.',
input_schema: { type: 'object' as const, properties: { topico: { type: 'string' } }, required: ['topico'] },
},
{
name: 'delegar_para_analista',
description: 'Analisa dados e identifica padrões.',
input_schema: { type: 'object' as const, properties: { dados: { type: 'string' } }, required: ['dados'] },
},
{
name: 'delegar_para_redator',
description: 'Escreve relatório final com os insights.',
input_schema: { type: 'object' as const, properties: { analise: { type: 'string' } }, required: ['analise'] },
},
{
name: 'finalizar',
description: 'Encerra o processo quando o resultado final está pronto.',
input_schema: { type: 'object' as const, properties: { resultado: { type: 'string' } }, required: ['resultado'] },
},
]
const mensagens: Anthropic.MessageParam[] = [{
role: 'user',
content: `Coordene os agentes para completar esta tarefa: ${tarefa}`,
}]
while (true) {
const response = await client.messages.create({
model: 'claude-haiku-4-5-20251001',
max_tokens: 500,
system: 'Você é um supervisor de agentes. Delegue para os agentes especializados na ordem certa e finalize quando tiver o resultado completo.',
tools: SUPERVISOR_TOOLS,
messages: mensagens,
})
mensagens.push({ role: 'assistant', content: response.content })
if (response.stop_reason === 'end_turn') break
const resultados: Anthropic.ToolResultBlockParam[] = []
for (const bloco of response.content) {
if (bloco.type !== 'tool_use') continue
const args = bloco.input as Record<string, string>
let resultado: string
if (bloco.name === 'finalizar') {
resultados.push({ type: 'tool_result', tool_use_id: bloco.id, content: 'Finalizado.' })
mensagens.push({ role: 'user', content: resultados })
return args.resultado
}
// Chamar sub-agente especializado
const subAgentSystem = bloco.name === 'delegar_para_pesquisador'
? 'Você é um pesquisador. Colete fatos relevantes de forma concisa.'
: bloco.name === 'delegar_para_analista'
? 'Você é um analista. Identifique padrões e insights dos dados.'
: 'Você é um redator executivo. Escreva de forma clara e concisa.'
const subInput = Object.values(args)[0]
const subResponse = await chamarLLM(subInput, subAgentSystem)
console.log(` [${bloco.name}] concluído`)
resultados.push({ type: 'tool_result', tool_use_id: bloco.id, content: subResponse })
}
mensagens.push({ role: 'user', content: resultados })
}
return 'Supervisor encerrou sem resultado'
}TODO 2: Handoff Pattern
async function handoffPattern(tarefa: string): Promise<string> {
const estado: EstadoHandoff = {
historico: [],
contexto: { tarefa_original: tarefa },
agenteAtual: 'generalista',
}
const AGENTES: Record<string, string> = {
generalista: 'Você é um assistente geral. Se a tarefa exigir expertise em direito, finanças ou tecnologia, use a tag [HANDOFF:juridico|financeiro|tecnico] no início da resposta.',
juridico: 'Você é um especialista jurídico. Analise aspectos legais e regulatórios.',
financeiro: 'Você é um especialista financeiro. Analise métricas, ROI e impacto financeiro.',
tecnico: 'Você é um especialista técnico. Analise aspectos de arquitetura e implementação.',
}
for (let i = 0; i < 5; i++) { // max 5 handoffs
const agente = estado.agenteAtual
const historico_str = estado.historico.join('\n')
const prompt = i === 0
? tarefa
: `Contexto acumulado:\n${historico_str}\n\nContinue a análise de ${agente}.`
const resposta = await chamarLLM(prompt, AGENTES[agente])
estado.historico.push(`[${agente}]: ${resposta}`)
// Detectar handoff request
const handoffMatch = resposta.match(/\[HANDOFF:(juridico|financeiro|tecnico)\]/)
if (handoffMatch) {
const proximo = handoffMatch[1]
console.log(` [HANDOFF] ${agente} → ${proximo}`)
estado.agenteAtual = proximo
estado.contexto.handoff_de = agente
continue
}
// Sem handoff = resultado final
return resposta
}
return estado.historico[estado.historico.length - 1]
}Aprofundamento Técnico
Supervisor vs Parallel: Quando Usar
Critério | Parallel | Supervisor |
Ordem de execução conhecida | Sim → Parallel | Não → Supervisor |
Sub-tarefa B depende de A | Não funciona | Funciona |
Quantidade de agentes | Fixo | Dinâmico |
Debugging | Simples | Complexo |
Supervisor tem overhead de latência (mais LLM calls). Use somente quando a ordem de execução depende do output de agentes anteriores.
Handoff vs Supervisor: Diferença Chave
Supervisor: coordenador externo decide quem age
Handoff: o próprio agente decide passar o controle
Handoff é mais autônomo. Supervisor tem mais controle.
Exemplos Anotados
Exemplo 1: Supervisor Flow
Tarefa: "Adotar IA para atendimento ao cliente"
Supervisor → delegar_para_pesquisador("IA atendimento cliente")
Pesquisador → "Casos de uso: chatbot FAQ, triagem de tickets..."
Supervisor → delegar_para_analista("Casos de uso: chatbot FAQ...")
Analista → "Oportunidades: -40% custo operacional. Riscos: qualidade..."
Supervisor → delegar_para_redator("Oportunidades: -40%...")
Redator → "Recomendação: implementar IA em fases..."
Supervisor → finalizar("Recomendação: implementar IA...")
→ Resultado final entreguePadrões e Armadilhas
Padrões
Padrão 1: Sub-agentes com system prompts focados Cada sub-agente tem um system prompt que o confina ao seu domínio. Agente de pesquisa que começa a analisar está fora do papel.
Padrão 2: Estado compartilhado via EstadoHandoff
estado.contexto[chave] = valor // persiste entre handoffsArmadilhas
⚠️ Armadilha 1: Supervisor recursivo infinito Se o Supervisor chamar delegar_para_pesquisador indefinidamente, coloque limite de iterações.
⚠️ Armadilha 2: Handoff sem contexto
Agente Jurídico recebe apenas "continue" sem o contexto anterior
→ repete análise do zeroSempre passe historico_str no prompt do agente receptor.
⚠️ Armadilha 3: Perda de tool_use_id
// Para cada bloco de tool_use, criar tool_result correspondente com MESMO id
resultados.push({ type: 'tool_result', tool_use_id: bloco.id, content: resultado })Se não for realizar o laboratório, pule para o próximo capítulo.
Ponte para o Lab
TODO 1 — supervisorPattern(tarefa): crie 4 tools para o Supervisor (delegar_para_pesquisador, delegar_para_analista, delegar_para_redator, finalizar). Loop agent com sub-agentes especializados via chamarLLM.
TODO 2 — handoffPattern(tarefa): generalista detecta [HANDOFF:tipo] em sua resposta, atualiza estado.agenteAtual, passa histórico acumulado para o próximo agente.
Agora você está pronto para o lab.