5 anti-patterns que quebram seu agente de IA em produção
Funcionava lindo na demo. O agente respondia certo, chamava as ferramentas na ordem, fechava a tarefa com aquele sorriso de "tá pronto pra produção". Aí subiu. Em três dias virou uma conta de US$ 3 mil na OpenAI e um loop infinito tentando a mesma chamada de API que nunca ia dar certo.
Se você já passou por isso, não é azar. É arquitetura. Agentes de IA em produção falham por motivos chatos, repetidos e previsíveis — os mesmos cinco erros aparecem em projeto depois de projeto. Não é o modelo que é ruim. É o redor do modelo que ninguém construiu.
Neste post eu separo os 5 anti-patterns mais caros de arquitetura de agente. Cada um com o sintoma que você vê no log (ou não vê, que é pior) e a correção que para o sangramento. Sem fórmula mágica. Engenharia.
TL;DR
- O que é: os 5 anti-patterns de arquitetura que mais quebram agente em produção — context stuffing, tools sem timeout, retry burro, zero observabilidade e ausência de guardrails.
- Pra quem: quem já tem um agente rodando (ou prestes a subir) e não quer descobrir o problema pela fatura.
- Custo/Acesso: conceitual — vale pra qualquer stack (Claude Agent SDK, Prism em Laravel, LangChain, SDK próprio).
- A regra-mãe: demo testa o caminho feliz. Produção testa o que você esqueceu.
Por que agentes de IA em produção falham (e a demo mente)
A demo roda uma vez, com um input limpo, num horário em que a API tá rápida e ninguém tá tentando quebrar nada. Produção é o oposto: milhares de inputs sujos, APIs caindo, usuário hostil, e o agente rodando sozinho às 3 da manhã sem ninguém olhando.
A diferença entre protótipo e agente de produção cabe em três palavras: confiabilidade, observabilidade e segurança. Um protótipo lida com o caminho feliz. Um agente de produção lida com falha de dependência, degrada de forma previsível e te conta o que fez. (TUTAI resume bem isso.)
Os cinco erros abaixo são justamente os buracos entre esses dois mundos. Vamos um por um.
Anti-pattern 1: Context stuffing (enfiar tudo no contexto)
O sintoma: você indexa o Salesforce inteiro, a wiki inteira, o histórico inteiro da conversa, e joga tudo na janela de contexto "por garantia". A lógica parece boa — quanto mais informação, melhor a resposta, certo?
Errado. O modelo não lê o contexto, ele presta atenção nele. E atenção é um recurso escasso. A pesquisa de campo da Arize documenta o efeito Lost in the Middle: o agente ignora documentos que foram recuperados corretamente porque eles afundaram no meio de um contexto gigante. Pior: a degradação é cumulativa. Estimativas de retenção de contexto apontam perda de ~2% por passo, com menos de 60% do contexto original acessível depois de cinco ciclos num fluxo multi-step.
Traduzindo: quanto mais coisa você empurra, menos o agente enxerga. E você ainda paga por cada token enfiado lá.
A correção é engenharia de contexto, não despejo de contexto. A própria Anthropic descreve isso como curar o conjunto ótimo de tokens durante a inferência — não o conjunto máximo. Na prática:
- Recupere em blocos relevantes, não documentos inteiros. RAG com rerank, não
SELECT * FROM tudo. - Re-injete as regras críticas perto do input novo (context pinning), porque o system prompt do começo perde peso conforme a sessão cresce.
- Resuma e descarte histórico velho em vez de carregar a conversa inteira a cada turno.
# Anti-pattern: contexto vira lixeira
context = wiki_inteira + salesforce_dump + historico_completo
resposta = agent.run(context, pergunta) # o que importa afundou no meio
# Correção: recupera só o relevante, fixa a regra crítica
trechos = retriever.search(pergunta, top_k=5, rerank=True)
regras = politica_critica() # re-injetada perto do input
resposta = agent.run([regras, *trechos, pergunta])
Anti-pattern 2: Tools sem timeout
O sintoma: o agente chama uma ferramenta — uma API externa, um scraping, uma query pesada — e ela trava. Não dá erro. Não retorna. Fica pendurada. E o agente fica esperando junto, segurando a janela de contexto, o usuário e o seu dinheiro.
Uma tool que trava silenciosamente por 30 segundos antes de dar timeout já destrói a experiência. Um loop agêntico que roda 10 minutos quase sempre está travado ou fazendo algo que você não pediu — a recomendação da TUTAI é direta: mate o processo e devolva um fallback seguro.
Toda ferramenta precisa de teto de tempo. E de um estado terminal claro: ou ela retorna SUCCESS com dados, ou retorna FAILED com motivo. Nunca um silêncio que o agente interpreta como "ainda processando".
import asyncio
async def call_tool(tool, args, timeout_s=8):
try:
result = await asyncio.wait_for(tool.run(args), timeout=timeout_s)
return {"status": "SUCCESS", "data": result}
except asyncio.TimeoutError:
# estado terminal explícito: o agente sabe que falhou e segue
return {"status": "FAILED", "reason": f"timeout após {timeout_s}s"}
Esse status: FAILED não é detalhe. É o que separa um agente que se recupera de um que entra em pânico — o que nos leva direto ao próximo erro.
Anti-pattern 3: Retry burro
O sintoma: a ferramenta falha. O agente tenta de novo. Falha de novo. Tenta de novo. Sem backoff, sem limite, sem mudar de estratégia. É o loop infinito que vira a fatura de US$ 3 mil.
A Arize chama isso de recursive loops and inefficient trajectories — o agente entra em loops de polling, checando status repetidamente em vez de esperar um webhook, e gera "centenas de chamadas de API para uma única tarefa" enquanto o backend queima tokens. O detalhe cruel: a telemetria parece saudável. As requests retornam 200. Ninguém vê o incêndio até a conta chegar.
Retry não é errado. Retry burro é. A diferença:
- Backoff exponencial + jitter. Não martele a API caída a cada 100ms.
- Limite de tentativas. Três falhas e para. Quatro é teimosia.
- Mude de estratégia. Se a mesma tool falhou três vezes com o mesmo argumento, o problema não é a sorte — é o argumento. Tentar igual de novo é definição de insanidade.
Vale o número que assusta: sem lógica de recuperação, agentes acertam menos de 50% quando uma tool falha, com taxa-base de recuperação de ~32,8%. Com tratamento de falha treinado, isso sobe pra ~89,7% (análise de failure modes). A diferença entre 33% e 90% é o código de retry que você escreveu — ou não.
for tentativa in range(3): # limite duro
r = await call_tool(tool, args)
if r["status"] == "SUCCESS":
break
if tentativa == 2:
return fallback_seguro(r["reason"]) # desiste com dignidade
await asyncio.sleep((2 ** tentativa) + random.random()) # backoff + jitter
Anti-pattern 4: Zero observabilidade
O sintoma: o agente faz algo errado e você descobre pelo cliente. Ou pela fatura. Você não tem ideia de quais tools ele chamou, quantos tokens gastou em cada passo, onde o p95 de latência mora ou por que aquela conversa específica custou 40x a média.
Esse é o anti-pattern que esconde todos os outros. O retry burro do item anterior "parece saudável" justamente porque ninguém instrumentou os passos internos. Você tem um log de "request entrou, request saiu" e um buraco preto no meio.
A correção é instrumentar o agente como sistema distribuído, porque é isso que ele é. A recomendação consolidada (Datadog, entre outras) é traços OpenTelemetry que cobrem o request do usuário, a recuperação, cada tool call e a geração — com spans curtos e aninhados. Nada de um span gigante agent.run: aninhe tool.call, retrieval, generation, pra que o outlier de p95 seja diagnosticável. Capture prompt sanitizado, tokens, custo e correlation ID em cada passo.
Eu já abri esse tema em detalhe aqui no blog — qual ferramenta usar, o setup self-hosted e as três métricas de agente que realmente mudam o jogo — em Observabilidade de agentes de IA: LangSmith vs Langfuse vs Helicone. Se você só vai consertar um item dessa lista, comece por esse: sem observabilidade, você nem sabe quais dos outros quatro você tem.
Anti-pattern 5: Ausência de guardrails
O sintoma: o agente pode fazer qualquer coisa que as tools permitem. E um dia ele faz.
O caso que virou meme não é hipotético. Em julho de 2025, um agente da Replit executou DROP TABLE num banco de produção — apesar de instruções explícitas pra não tocar em produção — e depois tentou gerar registros falsos pra encobrir. A lição cabe numa frase: prompts são sugestões; falta a eles a rigidez do código. Você não pede educadamente pro agente não apagar o banco. Você tira a permissão de apagar o banco.
Guardrail é arquitetura, não instrução no prompt. Os pilares:
- Princípio do menor privilégio. Whiteliste exatamente quais tools o agente chama e com quais parâmetros. Um modelo que só tem
search_productseget_order_statusnão tem como chamardelete_user— não importa o que o prompt diga. - Checkpoints humanos antes de ação irreversível. A própria Anthropic recomenda pausar pra revisão humana antes de aprovar transação financeira, apagar dado ou qualquer coisa que não dá pra desfazer.
- Validação de input e output. Bloqueie palavras-chave destrutivas (
DROP,DELETE,rm,truncate) na borda, antes de chegar na execução.
TOOLS_PERMITIDAS = {"search_products", "get_order_status"}
def autorizar(tool_name, args):
if tool_name not in TOOLS_PERMITIDAS:
raise PermissionError(f"tool {tool_name} fora do whitelist")
if tool_name in ACOES_IRREVERSIVEIS:
exigir_aprovacao_humana(tool_name, args) # checkpoint
return True
FAQ rápido
"Preciso dos cinco desde o dia 1?" Não. Mas observabilidade e timeout são inegociáveis até num MVP — são o que te deixa enxergar e estancar os outros problemas. Guardrails entram no momento em que o agente tem qualquer tool que escreve ou apaga.
"Backoff não vai deixar meu agente lento?" Vai adicionar segundos num caso de falha. O retry burro adiciona centenas de chamadas e dólares no mesmo caso. Lento e barato ganha de rápido e falido.
"Isso vale pra agente em Laravel/PHP também?" Vale pra qualquer stack. Timeout, retry com limite, instrumentação e whitelist de tools são conceitos de arquitetura — Prism, Claude Agent SDK, LangChain ou SDK próprio, a regra é a mesma.
"Como sei qual anti-pattern está me pegando?" Você não sabe — até instrumentar. Por isso o item 4 é a base. Sem traço por passo, todo diagnóstico vira chute.
Conclusão
Os cinco não são bugs aleatórios. São o que acontece quando você arquiteta pro caminho feliz e deixa produção descobrir o resto. Context stuffing cega o modelo. Tool sem timeout pendura o agente. Retry burro queima a fatura. Zero observabilidade esconde tudo. E ausência de guardrail é o DROP TABLE esperando a vez.
A boa notícia: todos os cinco são corrigíveis com engenharia comum — teto de tempo, limite de tentativa, span por passo, whitelist de tool. Nada de exótico. Só a disciplina de tratar o agente como o sistema de produção que ele é, não como a demo que ele foi.
Esse trabalho de desenhar o redor do modelo — onde colocar o limite, o checkpoint, o fallback — é exatamente o que a gente coloca na mesa, com código rodando, no Workshop Arquitetando Soluções de IA: arquitetar solução de software com agents de verdade, não montar mais uma demo bonita. Porque o próximo salto do dev não é usar IA. É construir produto real com IA — e produto real não cai na primeira falha de tool.
{AI Engineer} — apaixonado por Laravel, arquitetura de software e construir produtos com impacto. Compartilho aqui tutoriais, descobertas e reflexões sobre o dia a dia de engenharia.
Você também pode gostar
O que é um agente de IA (e o que é só um wrapper de prompt)
90% dos "agents" que você vê no LinkedIn são um if com esteroides. A definição honesta de o que é um agente de IA: o loop percepção→decisão→ação→observação e os quatro blocos mínimos — modelo, ferramentas, memória e orquestração. Falte um e o sistema vira burro depois da terceira mensagem.
Anatomia de um Agent Harness: state, tool execution, feedback loops e guardrails
Harness é o software que envolve o LLM e separa um demo bonito de um agente que aguenta produção. Quebro a anatomia em cinco peças obrigatórias: estado persistente, roteador de ferramentas, validação de I/O, loop de raciocínio e limites de segurança. É o mapa mental que abre a série de posts sobre engenharia de agentes.
Tool calling na prática: como o agente decide chamar uma ferramenta
Anatomia do loop ReAct e do tool calling: quando o agente decide buscar/agir vs. responder direto, com design de tools (contratos, schemas, idempotência) e um exemplo de tool de busca em banco no Laravel via Claude API.
Os 4 níveis de autonomia em Agentic Code: do autocompletar ao agente que faz deploy sozinho
Quem roda agentes em código de verdade já entendeu que a régua não é se o agente faz, mas quem aprova, quem reverte e quem audita cada ação. Mapa prático de quatro níveis de autonomia em agentic code, do tab completion ao agente que abre PR sozinho em CI, com os gates de engenharia que sustentam cada degrau.