Back

7 Padrões Que Impedem Seu Agente AI de Sair do Controle em Produção

Seu agente AI funciona perfeitamente em desenvolvimento. Passa em todos os testes, lida com os cenários de demo sem problemas e impressiona os stakeholders na sprint review. Aí você faz o deploy. Em 48 horas, ele queima $400 em custos de API processando um loop recursivo, manda pra um cliente os dados pessoais do vizinho dele, e gera com toda confiança uma query SQL que derruba um índice do banco de produção.

Isso não é hipotético. É um padrão que tá acontecendo em toda a indústria em 2026. A distância entre "pronto pra demo" e "pronto pra produção" em agentes AI é maior do que a maioria dos times imagina, e os modos de falha são fundamentalmente diferentes do software tradicional. Sua API REST não decide responder uma pergunta diferente da que foi feita. Seu driver de banco não alucina o nome de uma tabela. Mas seu agente AI faz as duas coisas, e faz com total confiança.

Esse guia cobre sete padrões testados em batalha pra manter agentes AI confiáveis em produção. Não são frameworks teóricos — são extraídos de post-mortems reais, incidentes de produção e lições aprendidas na marra por times que operam agentes em escala.


Padrão 1: O Circuit Breaker

Software tradicional usa circuit breakers pra prevenir falhas em cascata quando serviços downstream caem. Agentes AI também precisam, mas com uma diferença: você não tá protegendo só contra HTTP 500s. Tá protegendo contra um modelo que começa a devolver lixo.

Por Que Agentes Precisam de Circuit Breakers

Um agente AI que chama uma ferramenta com falha não crasha. Ele retenta. E retenta. E como é "inteligente", pode tentar abordagens levemente diferentes cada vez — todas falham, todas custam tokens. Sem um circuit breaker, uma única ferramenta quebrada pode queimar todo seu orçamento diário de API em minutos.

Implementação

class AgentCircuitBreaker { private failures: Map<string, { count: number; lastFailure: number }> = new Map(); private readonly threshold = 5; private readonly resetTimeout = 60000; async callTool(toolName: string, fn: () => Promise<any>): Promise<any> { const state = this.failures.get(toolName) || { count: 0, lastFailure: 0 }; if (state.count >= this.threshold) { const elapsed = Date.now() - state.lastFailure; if (elapsed < this.resetTimeout) { throw new CircuitOpenError( `Ferramenta "${toolName}" desabilitada temporariamente. ` + `${Math.ceil((this.resetTimeout - elapsed) / 1000)}s até retry.` ); } state.count = this.threshold - 1; } try { const result = await fn(); this.failures.set(toolName, { count: 0, lastFailure: 0 }); return result; } catch (error) { state.count++; state.lastFailure = Date.now(); this.failures.set(toolName, state); throw error; } } }

O Ponto-Chave

Quando o circuito abre, devolva o erro pro agente como contexto. Não lance só uma exceção — diga pro modelo que a ferramenta tá indisponível e sugira alternativas:

if (error instanceof CircuitOpenError) { return { role: 'tool', content: `O serviço ${toolName} tá temporariamente indisponível (circuit breaker aberto). ` + `Informe o usuário que essa feature tá temporariamente fora, ` + `ou tente uma abordagem alternativa que não precise dessa ferramenta.` }; }

Isso transforma uma falha dura em degradação elegante.


Padrão 2: Retry-Classify (Não Retente às Cegas)

O padrão ingênuo de retry — "se falhou, tenta de novo a mesma coisa" — é ativamente prejudicial com agentes AI. Se o modelo gerou uma chamada de API malformada, retentar o mesmo prompt provavelmente gera a mesma chamada malformada. Você tá pagando dobrado pelo mesmo erro.

O Padrão Retry-Classify

Em vez de retries cegos, classifique o erro primeiro e direcione pra estratégia de recuperação adequada:

class RetryClassifier: def classify(self, error: Exception, tool_name: str) -> RetryStrategy: if isinstance(error, RateLimitError): return RetryStrategy.BACKOFF if isinstance(error, ValidationError): return RetryStrategy.REPAIR if isinstance(error, AuthenticationError): return RetryStrategy.FAIL_FAST if isinstance(error, TimeoutError): return RetryStrategy.BACKOFF if isinstance(error, ToolNotFoundError): return RetryStrategy.FALLBACK return RetryStrategy.FAIL_FAST async def execute_with_retry(agent, action, max_retries=3): classifier = RetryClassifier() for attempt in range(max_retries): try: return await agent.execute(action) except Exception as e: strategy = classifier.classify(e, action.tool_name) if strategy == RetryStrategy.FAIL_FAST: raise if strategy == RetryStrategy.BACKOFF: wait = (2 ** attempt) + random.uniform(0, 1) await asyncio.sleep(wait) continue if strategy == RetryStrategy.REPAIR: action = await agent.repair_action(action, error=str(e)) continue if strategy == RetryStrategy.FALLBACK: action = agent.get_fallback_action(action) continue raise MaxRetriesExceeded(f"Falhou depois de {max_retries} tentativas")

A Estratégia de Reparo em Detalhe

A estratégia REPAIR é onde fica interessante. Em vez de retentar o mesmo prompt, você passa a mensagem de erro pro modelo como contexto adicional:

async def repair_action(self, failed_action, error: str): repair_prompt = f"""Sua chamada anterior à ferramenta falhou com este erro: Ferramenta: {failed_action.tool_name} Input: {json.dumps(failed_action.input)} Erro: {error} Analise o erro e gere uma chamada corrigida. NÃO repita o mesmo input que causou a falha.""" corrected = await self.llm.generate(repair_prompt) return corrected

Esse padrão resolve uma parcela significativa dos erros de validação na primeira tentativa de reparo. Formatos de data errados, campos obrigatórios faltando, valores fora de faixa — são exatamente o tipo de erros estruturados que os modelos conseguem auto-corrigir quando recebem a mensagem de erro específica. Na prática, times reportam taxas de reparo bem acima de 50% pra falhas no nível de schema.


Padrão 3: Governadores de Orçamento

A falha mais assustadora de um agente AI não é um crash — é uma espiral de custos descontrolada. Um agente preso num loop de raciocínio pode queimar centenas de dólares em custos de API antes de qualquer um perceber. Governadores de orçamento são limites rígidos que previnem isso.

Três Camadas de Controle de Orçamento

interface BudgetConfig { maxTokensPerRequest: number; maxTokensPerSession: number; maxToolCallsPerSession: number; maxCostPerSession: number; maxDurationSeconds: number; } class BudgetGovernor { private usage = { tokens: 0, toolCalls: 0, cost: 0, startTime: Date.now() }; check(config: BudgetConfig): void { if (this.usage.tokens > config.maxTokensPerSession) throw new BudgetExceededError('Orçamento de tokens excedido'); if (this.usage.toolCalls > config.maxToolCallsPerSession) throw new BudgetExceededError('Limite de chamadas — possível loop infinito'); if (this.usage.cost > config.maxCostPerSession) throw new BudgetExceededError(`Teto de custo atingido: $${this.usage.cost.toFixed(2)}`); const elapsed = (Date.now() - this.usage.startTime) / 1000; if (elapsed > config.maxDurationSeconds) throw new BudgetExceededError(`Timeout de sessão: ${elapsed.toFixed(0)}s`); } recordUsage(tokens: number, cost: number, isToolCall: boolean): void { this.usage.tokens += tokens; this.usage.cost += cost; if (isToolCall) this.usage.toolCalls++; } }

Calibrando os Limites

Tipo de OrçamentoDesenvolvimentoStagingProdução
Tokens por sessão50,00030,00020,000
Chamadas a ferramentas por sessão502515
Custo por sessão$5.00$2.00$0.50
Timeout5 min3 min2 min

Comece restritivo em produção e afrouxe com base em dados reais de uso. É muito mais fácil subir limites do que explicar uma fatura surpresa de $2,000.

O Padrão "Detecção de Agente Travado"

def detect_stuck_agent(tool_call_history: list[str], window: int = 5) -> bool: if len(tool_call_history) < window: return False recent = tool_call_history[-window:] most_common = max(set(recent), key=recent.count) return recent.count(most_common) / len(recent) >= 0.8

Padrão 4: Guardrails de Saída

O modelo eventualmente vai gerar algo que não deveria. PII numa resposta pro cliente. Um statement SQL num payload de webhook. Uma URL alucinada que leva pra um site de phishing. Guardrails de saída são sua última linha de defesa.

O Pipeline de Guardrails

class GuardrailPipeline { private guardrails: Guardrail[] = []; async validate(output: string, context: AgentContext): Promise<string> { for (const guardrail of this.guardrails) { const result = guardrail.check(output, context); if (result.action === 'BLOCK') throw new GuardrailViolation(guardrail.name, result.reason); if (result.action === 'REDACT') output = result.redactedOutput; if (result.action === 'FLAG') await this.alertOncall(guardrail.name, output, result.reason); } return output; } }

Guardrails Essenciais

1. Detecção de PII — Regex patterns pra SSN, emails, telefones, cartões de crédito com ação REDACT.

2. Prevenção de Injeção de Código — Bloquear DROP TABLE, <script>, eval(), rm -rf em respostas user-facing.

3. Âncora de Groundedness — Verificar que URLs referenciadas na saída existam no contexto fonte.


Padrão 5: O Kill Switch

Todo agente AI em produção precisa de um mecanismo de parada de emergência. Não "degradar gradualmente nos próximos minutos" — uma parada dura e imediata que freia toda atividade do agente em todas as instâncias.

Por Que Você Precisa

Kill switches não são pra error handling normal. São pra cenários como: o agente começa a mandar conteúdo inapropriado pra clientes, um ataque de prompt injection tá sendo explorado ativamente, o agente tá fazendo alterações não autorizadas em dados de produção, ou os custos tão espirando e os governadores de orçamento não tão pegando.

Implementação: Feature Flag + Remote Config

class AgentKillSwitch { async checkBeforeAction(agentId: string): Promise<void> { const config = await this.getRemoteConfig(); if (config.globalKillSwitch) throw new AgentHaltedError('Todos os agentes parados pelo kill switch global'); if (config.disabledAgents.includes(agentId)) throw new AgentHaltedError(`Agente ${agentId} parado pelo kill switch direcionado`); if (await this.abuseDetector.isCompromised(agentId)) { await this.activateKillSwitch(agentId, 'Automático: abuso detectado'); throw new AgentHaltedError('Agente parado: padrão de abuso detectado'); } } }

A Regra Crítica

O check do kill switch deve acontecer antes de cada chamada LLM e cada execução de ferramenta — não só no início da sessão.

while (hasMoreSteps) { await killSwitch.checkBeforeAction(this.agentId); // ← Cada iteração const response = await llm.chat(messages); await killSwitch.checkBeforeAction(this.agentId); // ← Depois do LLM, antes da ferramenta if (response.toolCalls) { for (const call of response.toolCalls) { await killSwitch.checkBeforeAction(this.agentId); // ← Antes de cada ferramenta await executeTool(call); } } }

Padrão 6: Observabilidade e Tracing

Você não consegue arrumar o que não consegue ver. E agentes AI são notoriamente opacos — o mesmo input pode produzir cadeias de raciocínio diferentes, sequências de tool calls diferentes, e outputs diferentes. Monitoramento tradicional (tempos de resposta, taxas de erro) te diz quase nada sobre por que um agente falhou.

O Que Tracear

Cada execução de agente deve produzir um trace estruturado com: traceId, sessionId, a cadeia completa de passos (cada LLM call, tool call e guardrail check), métricas agregadas (tokens, custo, duração, quantidade de tool calls, retries, guardrails triggered), e o outcome final.

Os Três Dashboards Que Você Precisa

1. Dashboard de Operações em Tempo Real

MétricaO Que Te Diz
Sessões ativasQuantos agentes tão rodando agora
Taxa de erro (janela 5 min)Se algo acabou de quebrar
Latência P95Degradação de experiência do usuário
Custo por minutoVelocidade de consumo do orçamento
Status dos circuit breakersQuais ferramentas tão falhando

2. Dashboard de Qualidade (Diário)

MétricaO Que Te Diz
Taxa de completude de tarefasSe os agentes realmente resolvem problemas
Taxa de triggers de guardrailsQuão frequente o modelo se comporta mal
Taxa de retry por ferramentaQuais integrações são instáveis
Passos médios por tarefaSe os prompts precisam de otimização
Satisfação do usuário (se disponível)A única métrica que realmente importa

3. Visão de Investigação de Incidentes

Quando algo dá errado, você precisa conseguir reproduzir a sequência exata: cada mensagem, cada resposta do LLM, cada input/output de tool call, cada verificação de guardrail. Armazene os traces por pelo menos 30 dias. Quando um incidente acontece, esse trace é sua evidência forense.

Dica Prática: Logue o Prompt, Não Só a Resposta

A maioria dos times loga as respostas do LLM mas não o prompt completo que foi enviado. Isso torna o debugging impossível. Logue o prompt completo (mensagem de sistema + histórico + definições de ferramentas) pra cada chamada. Sim, é verboso. Sim, custa storage. Vai te economizar horas de debugging quando as coisas derem errado.


Padrão 7: Gates de Aprovação Human-in-the-Loop

Autonomia total é um objetivo, não um ponto de partida. Os agentes mais confiáveis em produção usam autorização por camadas — o agente faz coisas de baixo risco de forma autônoma, mas ações de alto risco precisam de aprovação humana.

Definindo Níveis de Risco

enum RiskTier { LOW = 'low', // Autônomo: ler dados, buscar, gerar texto MEDIUM = 'medium', // Notificar: enviar emails, atualizar registros HIGH = 'high', // Aprovar: deletar dados, transações financeiras CRITICAL = 'critical', // Multi-aprovar: mudanças de schema, controle de acesso }

O Fluxo de Aprovação

async function executeWithApproval( agent: Agent, toolCall: ToolCall, context: AgentContext ): Promise<ToolResult> { const risk = toolRiskMap[toolCall.name] || RiskTier.HIGH; switch (risk) { case RiskTier.LOW: return await executeTool(toolCall); case RiskTier.MEDIUM: const result = await executeTool(toolCall); await notifyTeam(toolCall, result, context); return result; case RiskTier.HIGH: const approval = await requestApproval({ toolCall, context, timeout: 300_000 }); if (approval.approved) return await executeTool(toolCall); else return { role: 'tool', content: `Ação negada: ${approval.reason}` }; case RiskTier.CRITICAL: const approvals = await requestMultiApproval({ toolCall, context, requiredApprovals: 2, timeout: 600_000 }); if (approvals.every(a => a.approved)) return await executeTool(toolCall); else return { role: 'tool', content: 'Aprovação adicional necessária.' }; } }

A Realidade Prática

Human-in-the-loop cria latência. Mitigue isso com: pré-aprovação de padrões frequentes, batching de aprovações, workflows assíncronos pra tarefas não urgentes, e confiança progressiva (comece com HITL pra tudo e diminua o nível de risco conforme ganha confiança).


Juntando Tudo: O Stack de Confiabilidade

┌─────────────────────────────────────────┐
│          Human-in-the-Loop              │  ← Ações de alto risco gateadas
├─────────────────────────────────────────┤
│          Guardrails de Saída            │  ← PII, injeção, alucinação
├─────────────────────────────────────────┤
│          Governadores de Orçamento      │  ← Custo, tokens, tempo
├─────────────────────────────────────────┤
│          Kill Switch                    │  ← Parada de emergência
├─────────────────────────────────────────┤
│          Circuit Breakers               │  ← Isolamento de falhas
├─────────────────────────────────────────┤
│          Retry-Classify                 │  ← Recuperação inteligente
├─────────────────────────────────────────┤
│          Observabilidade                │  ← Trace completo de cada decisão
└─────────────────────────────────────────┘

Ordem de Implementação

  1. Governadores de Orçamento (Dia 1) — Previne dano financeiro imediatamente
  2. Kill Switch (Dia 1) — Seu freio de emergência
  3. Observabilidade (Semana 1) — Não dá pra melhorar o que não dá pra medir
  4. Guardrails de Saída (Semana 1-2) — Barrar conteúdo ruim antes de chegar ao usuário
  5. Circuit Breakers (Semana 2) — Isolar falhas de ferramentas
  6. Retry-Classify (Semana 2-3) — Melhorar taxas de sucesso
  7. Human-in-the-Loop (Semana 3-4) — Adicionar confiança pra ações críticas

A Realidade de 2026

O ecossistema de agentes AI tá amadurecendo rápido. Frameworks como LangGraph, CrewAI, e os SDKs de agentes da OpenAI e Google tão adicionando mais primitivas de confiabilidade built-in. Mas não são suficientes sozinhos. Os defaults dos frameworks são permissivos — foram feitos pra facilitar demos, não pra manter sistemas de produção seguros.

Seu agente eventualmente vai fazer algo inesperado. A questão não é "se" mas "quando", e se seu stack de confiabilidade pega antes de chegar a um usuário, um banco de dados ou um sistema de faturamento.

Os melhores agentes AI não são os mais inteligentes. São os que falham com elegância.

AILLMAI AgentsProductionReliabilityEngineering

Explore ferramentas relacionadas

Experimente estas ferramentas gratuitas do Pockit