Se agents são controllers (LLM + tools + loop), padrões agentic são os design patterns que esses controllers usam. Assim como em software tradicional você tem Observer, Strategy e Chain of Responsibility, em AI agents também existem padrões que aparecem o tempo todo.

Saber reconhecer esses patterns encurta bastante o caminho. Em vez de desenhar tudo do zero a cada caso, você monta a solução com blocos que já provaram valor.

O mapa pro profissional de infra

Padrão AgenticO que fazEquivalente em infra
ReflectionAgent revisa próprio outputCode review, lint automático
Tool useAgent chama funções externasService mesh, API gateway
PlanningAgent decompõe tarefa em stepsCI/CD pipeline stages
Multi-step reasoningAgent raciocina antes de agirRunbook com decision tree
RoutingDirecionar pra agent especializadoLoad balancer com content-based routing
ParallelizationExecutar múltiplas ações em paraleloFan-out / fan-in
Orchestrator-workerCentral coordena workersController + workers (Celery, K8s Jobs)
Evaluator-optimizerFeedback loop pra melhorar outputCanary + metrics → rollback

Pattern 1: Reflection

O agent gera output, depois critica o próprio output e refina.

Pattern de reflectionFluxo linear com Generate, Critic, Refine e Output.Generate(draft)Critic(review)Refine(improve)Output(final)

Implementação

def reflection_pattern(task, max_reflections=2):
    # Step 1: gerar draft
    draft = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": "Gere uma resposta completa."},
            {"role": "user", "content": task}
        ]
    ).choices[0].message.content
    
    # Step 2: criticar
    for i in range(max_reflections):
        critique = client.chat.completions.create(
            model="gpt-4o",
            messages=[
                {"role": "system", "content": 
                 "Analise esta resposta criticamente. "
                 "Identifique erros factuais, gaps, e pontos que podem melhorar. "
                 "Se está boa, responda apenas 'APPROVED'."},
                {"role": "user", "content": f"Tarefa: {task}\n\nResposta:\n{draft}"}
            ]
        ).choices[0].message.content
        
        if "APPROVED" in critique:
            break
        
        # Step 3: refinar com base na crítica
        draft = client.chat.completions.create(
            model="gpt-4o",
            messages=[
                {"role": "system", "content": "Melhore a resposta com base no feedback."},
                {"role": "user", "content": f"Resposta original:\n{draft}\n\nFeedback:\n{critique}"}
            ]
        ).choices[0].message.content
    
    return draft

Quando usar: code generation, respostas longas, análise técnica. Sempre que o custo de um erro é alto o suficiente pra justificar 2-3x mais tokens.

Cuidado: reflection pode entrar em loop. O critic pode ser mais exigente que necessário e nunca aprovar. Limite as iterações.

Pattern 2: Tool use (já cobrimos em posts anteriores)

Agent decide quais tools chamar e em que ordem. É o pattern mais fundamental e já exploramos em detalhes nos posts 8 e 9.

Resumo rápido do que importa:

  • Cada tool é uma função com input/output definidos
  • O LLM decide quando e qual tool chamar
  • Resultado da tool volta pro LLM como observação
  • Loop até tarefa completa ou limite atingido

Pattern 3: Planning

Agent cria um plano antes de executar. Diferente de ReAct (decide step by step), planning cria overview primeiro.

def planning_pattern(task, tools):
    # Step 1: criar plano
    plan = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": f"""
Crie um plano pra resolver a tarefa. Formato:
1. [AÇÃO] descrição - usando tool X
2. [AÇÃO] descrição - usando tool Y
3. [VERIFICAÇÃO] confirmar resultado
4. [RESPOSTA] consolidar e responder

Tools disponíveis: {[t['function']['name'] for t in tools]}
"""},
            {"role": "user", "content": task}
        ]
    ).choices[0].message.content
    
    # Step 2: executar cada step do plano
    results = []
    for step in parse_plan_steps(plan):
        if step["type"] == "AÇÃO":
            result = execute_tool(step["tool"], step["args"])
            results.append(result)
            
            # Replanejar se step falhou
            if not result.get("success", True):
                plan = replan(task, plan, step, result)
        
        elif step["type"] == "VERIFICAÇÃO":
            if not verify(step["condition"], results):
                # Voltar e tentar abordagem diferente
                plan = replan(task, plan, step, "verification_failed")
    
    # Step 3: consolidar
    return summarize(task, plan, results)

Vantagem sobre ReAct: fica mais previsível e mais fácil de auditar. Você consegue olhar o plano e entender a linha de raciocínio antes da execução.

Desvantagem: o plano envelhece rápido se o passo 2 muda o contexto de forma inesperada. Aí não tem milagre, precisa replanejar.

Pattern 4: Routing

Nem toda tarefa vai pro mesmo agent/modelo. Routing classifica a tarefa e direciona pro handler certo.

Pattern de routingRouter Agent classifica a tarefa e direciona para Agent DB, Agent Net ou Agent K8s.Router Agent(classifica)Agent DB(database)Agent Net(network)Agent K8s(cluster)
def routing_pattern(task):
    # Classificar com modelo leve (barato e rápido)
    classification = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": """
Classifique a tarefa em uma categoria:
- database: problemas com SQL, replicação, backup, performance de queries
- network: conectividade, DNS, firewall, VPN, load balancer
- kubernetes: pods, deployments, services, ingress, node issues
- general: outros

Responda APENAS com a categoria."""},
            {"role": "user", "content": task}
        ]
    ).choices[0].message.content.strip().lower()
    
    # Rotear pra agent especializado
    agents = {
        "database": DatabaseAgent(tools=DB_TOOLS),
        "network": NetworkAgent(tools=NET_TOOLS),
        "kubernetes": K8sAgent(tools=K8S_TOOLS),
        "general": GeneralAgent(tools=ALL_TOOLS),
    }
    
    agent = agents.get(classification, agents["general"])
    return agent.run(task)

Quando usar: quando você tem domínios distintos com tools diferentes. Menos tools por agent costuma melhorar a chance de o modelo escolher a ação certa.

Pattern 5: Parallelization

Executar múltiplas ações independentes ao mesmo tempo. Fan-out e fan-in.

import asyncio
import json

async def parallelization_pattern(task, servers):
    """Verificar múltiplos servidores em paralelo."""
    
    # Fan-out: lançar verificações em paralelo
    tasks = [check_server(server) for server in servers]
    raw_results = await asyncio.gather(*tasks, return_exceptions=True)
    
    results = []
    for server, result in zip(servers, raw_results):
        if isinstance(result, Exception):
            results.append({
                "server": server,
                "success": False,
                "error": str(result),
            })
        else:
            results.append(result)
    
    # Fan-in: consolidar resultados
    summary = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": "Analise os resultados e identifique problemas."},
            {"role": "user", "content": f"Resultados de {len(servers)} servidores:\n{json.dumps(results, indent=2, default=str)}"},
        ],
    ).choices[0].message.content
    
    return summary

Quando usar: tasks onde múltiplas verificações são independentes. Verificar N servidores, buscar em múltiplas fontes, validar múltiplas condições.

Cuidado: rate limits. Se cada check chama Azure OpenAI, você pode bater no TPM limit com fan-out agressivo.

Pattern 6: Evaluator-optimizer loop

O output é avaliado e, se não atender critérios, volta pro agent melhorar. Diferente de Reflection (auto-crítica), aqui o evaluator pode ser um sistema separado.

def evaluator_optimizer(task, quality_threshold=0.8):
    for attempt in range(3):
        # Gerar
        output = agent.run(task)
        
        # Avaliar (pode ser outro modelo, regras, ou humano)
        score = evaluate(output, criteria={
            "correctness": "informação factual correta?",
            "completeness": "respondeu tudo que foi perguntado?",
            "actionable": "inclui steps concretos?"
        })
        
        if score >= quality_threshold:
            return output
        
        # Otimizar: dar feedback pro agent e tentar de novo
        feedback = generate_feedback(output, score)
        task = f"{task}\n\nFeedback da tentativa anterior: {feedback}"
    
    # Se não atingiu qualidade em 3 tentativas, entrega o melhor
    return output

Pattern 7: Orchestrator-worker

Um agent central (orchestrator) coordena múltiplos workers especializados. O orchestrator não executa, ele delega e consolida.

class Orchestrator:
    def __init__(self):
        self.workers = {
            "researcher": ResearchWorker(),
            "executor": ExecutorWorker(),
            "validator": ValidatorWorker(),
        }
    
    def run(self, task):
        # Orquestrador decompõe a tarefa
        plan = self.decompose(task)
        
        results = {}
        for step in plan:
            worker = self.workers[step["worker"]]
            result = worker.execute(step["sub_task"])
            results[step["id"]] = result
            
            # Orquestrador decide próximo passo baseado no resultado
            if not result["success"]:
                # Pode re-assignar, escalar, ou adaptar
                recovery = self.decide_recovery(step, result)
                if recovery == "retry_different_worker":
                    result = self.workers["executor"].execute(step["sub_task"])
                elif recovery == "escalate":
                    return self.escalate(task, results)
        
        return self.consolidate(results)

Combinando patterns

Na prática, agents sofisticados combinam múltiplos patterns:

Combinação de patterns agenticFluxo em cascata com Routing, Planning, Tool use, Reflection e Evaluator.Routingseleciona agentespecializadoPlanningcria planoTool useexecuta cada stepReflectionvalida outputde cada stepEvaluatorverifica qualidadefinal

Mas eu começaria simples. Um agent com Tool Use + Planning já resolve a maioria dos casos. Adicione Reflection quando o erro custar caro. Adicione Routing quando os domínios realmente se separarem.

Custo comparativo dos patterns

PatternOverhead de tokensQuando vale o custo
Tool use (básico)1x (baseline)Sempre
Reflection (1 iter)2-3xOutputs que precisam de accuracy alta
Planning1.5xTasks com 4+ steps
Routing+200-500 tokensMúltiplos domínios, 10+ tools total
ParallelizationN × custo_individualTasks independentes, latência importa
Evaluator-optimizer2-4xOutputs que vão pro cliente/produção
Orchestrator-worker3-5xTasks complexas, multi-domínio

O que levar pra segunda-feira

  • Patterns são blocos de construção. Não precisa inventar arquitetura do zero toda vez.
  • Comece com Tool Use + Planning. Complexidade entra depois, quando houver motivo.
  • Reflection costuma ter ótimo custo-benefício quando você precisa subir a qualidade sem mexer no resto da infra.
  • Routing reduz confusão porque cada agent trabalha com menos tools e menos contexto inútil.
  • Parallelization vale muito a pena quando as tarefas são independentes, mas continue respeitando rate limits.
  • Cada pattern multiplica o custo. Reflection pode triplicar tokens. Orchestrator pode multiplicar várias chamadas. Faça a conta antes.

No próximo post, vamos escalar: arquitetura multi-agent, onde múltiplos agents colaboram em sistemas complexos.

Leitura complementar