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 Agentic | O que faz | Equivalente em infra |
|---|---|---|
| Reflection | Agent revisa próprio output | Code review, lint automático |
| Tool use | Agent chama funções externas | Service mesh, API gateway |
| Planning | Agent decompõe tarefa em steps | CI/CD pipeline stages |
| Multi-step reasoning | Agent raciocina antes de agir | Runbook com decision tree |
| Routing | Direcionar pra agent especializado | Load balancer com content-based routing |
| Parallelization | Executar múltiplas ações em paralelo | Fan-out / fan-in |
| Orchestrator-worker | Central coordena workers | Controller + workers (Celery, K8s Jobs) |
| Evaluator-optimizer | Feedback loop pra melhorar output | Canary + metrics → rollback |
Pattern 1: Reflection
O agent gera output, depois critica o próprio output e refina.
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.
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:
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
| Pattern | Overhead de tokens | Quando vale o custo |
|---|---|---|
| Tool use (básico) | 1x (baseline) | Sempre |
| Reflection (1 iter) | 2-3x | Outputs que precisam de accuracy alta |
| Planning | 1.5x | Tasks com 4+ steps |
| Routing | +200-500 tokens | Múltiplos domínios, 10+ tools total |
| Parallelization | N × custo_individual | Tasks independentes, latência importa |
| Evaluator-optimizer | 2-4x | Outputs que vão pro cliente/produção |
| Orchestrator-worker | 3-5x | Tasks 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
- Agentic Patterns Explained (Neo Kim, System Design Newsletter)
- Building effective agents (Anthropic)
- Andrew Ng on Agentic Design Patterns