Pular para o conteúdo
iauaiiauai — portal de tecnologia, IA e Cloud
IAAvançado

Agentes de IA: arquiteturas que funcionam

Implemente loops agênticos: pensar → ferramenta → observar. Controle custo, falhas e loops infinitos.

Por Equipe iauai · 10 de julho de 2026 · 14 min de leitura

Nesta página

O problema real

Você montou um LLM que responde perguntas bem. Mas aí chega uma pergunta que ele não consegue responder sozinho: "quanto de disk eu gastei no mês com backups?". Isso exige chamar uma API, processar resultado, reformular, chamar outra API. Um agente faz isso: pensa, chama ferramenta, observa, repete até resolver.

A primeira tentativa, você deixa o agente rodar até achar a resposta. Roda 50 vezes. Custo explosivo. Aí você coloca limite de 5 iterações. Funciona, mas às vezes não completa a tarefa. Bem-vindo ao caos dos agentes em produção. Este artigo mostra as arquiteturas que funcionam de verdade.

O loop agêntico

Um agente é um loop simples:

1. PENSAR: LLM recebe a tarefa e histórico
2. PLANEJAR: LLM decide: "Preciso chamar a ferramenta X com parâmetro Y"
3. AGIR: Seu código executa a ferramenta
4. OBSERVAR: Resultado retorna pro LLM
5. LOOP: Se resolveu, termina. Se não, volta ao passo 1

Controlar esse loop é a arte.

Três padrões de arquitetura

Padrão 1: Agente simples com ferramentas

Um LLM, várias ferramentas. Melhor para tarefas bem-definidas.

import json
from openai import OpenAI
from typing import Callable, Any

class SimplifiedAgent:
    def __init__(self, model: str = "gpt-4o-mini"):
        self.client = OpenAI()
        self.model = model
        self.tools = {}
        self.iterations = 0
        self.max_iterations = 5
        self.cost = 0.0
        
    def register_tool(self, name: str, func: Callable, description: str):
        """Registra uma ferramenta disponível para o agente."""
        self.tools[name] = {
            "func": func,
            "description": description
        }
    
    def _execute_tool(self, tool_name: str, params: dict) -> Any:
        """Executa uma ferramenta e retorna resultado."""
        if tool_name not in self.tools:
            return f"Erro: ferramenta '{tool_name}' não existe"
        
        try:
            result = self.tools[tool_name]["func"](**params)
            return result
        except Exception as e:
            return f"Erro ao executar {tool_name}: {str(e)}"
    
    def _build_system_prompt(self) -> str:
        """Constrói prompt com lista de ferramentas disponíveis."""
        tools_description = "\n".join([
            f"- {name}: {info['description']}"
            for name, info in self.tools.items()
        ])
        
        return f"""Você é um assistente que pode executar ações.
Quando precisar chamar uma ferramenta, responda com JSON no formato:
{{"action": "ferramenta_name", "params": {{"param1": "valor1"}}}}

Ferramentas disponíveis:
{tools_description}

Se conseguir responder sem ferramentas, faça isso.
Se não conseguir, use as ferramentas.
Seja conciso."""
        
    def run(self, task: str) -> str:
        """Executa a tarefa usando o loop agêntico."""
        self.iterations = 0
        self.cost = 0.0
        conversation = []
        
        print(f"\n[AGENTE] Tarefa: {task}")
        
        while self.iterations < self.max_iterations:
            self.iterations += 1
            
            # Cria mensagem pro LLM
            system_prompt = self._build_system_prompt()
            conversation.append({"role": "user", "content": task})
            
            # Chama LLM
            response = self.client.chat.completions.create(
                model=self.model,
                system=system_prompt,
                messages=conversation,
                temperature=0  # Determinístico
            )
            
            assistant_message = response.choices[0].message.content
            conversation.append({"role": "assistant", "content": assistant_message})
            
            # Estima custo (simplificado)
            input_tokens = response.usage.prompt_tokens
            output_tokens = response.usage.completion_tokens
            self.cost += (input_tokens * 0.00015 + output_tokens * 0.0006) / 1000
            
            print(f"[Iteração {self.iterations}] {assistant_message[:100]}...")
            
            # Verifica se é uma ação ou resposta final
            try:
                action = json.loads(assistant_message)
                if "action" in action:
                    tool_name = action["action"]
                    params = action.get("params", {})
                    
                    # Executa ferramenta
                    result = self._execute_tool(tool_name, params)
                    print(f"[Ferramenta {tool_name}] {str(result)[:100]}...")
                    
                    # Retorna resultado pro agente
                    task = f"Resultado da ferramenta {tool_name}: {result}"
                else:
                    # Resposta final
                    print(f"[RESPOSTA] {assistant_message}")
                    return assistant_message
            except json.JSONDecodeError:
                # Não é JSON, é resposta final
                print(f"[RESPOSTA] {assistant_message}")
                return assistant_message
        
        # Limite de iterações atingido
        return f"Atingido limite de iterações ({self.max_iterations})"


# Exemplo prático
def query_database(table: str, where: str = "") -> list:
    """Simula uma query em banco de dados."""
    if table == "disks" and "month" in where:
        return [
            {"disk": "backup_01", "size_gb": 250},
            {"disk": "backup_02", "size_gb": 180}
        ]
    return []

def calculate_cost(size_gb: int, price_per_gb: float = 0.05) -> float:
    """Calcula custo de armazenamento."""
    return size_gb * price_per_gb

# Configura agente
agent = SimplifiedAgent()
agent.register_tool(
    "query_db",
    query_database,
    "Query banco de dados. Parâmetros: table, where"
)
agent.register_tool(
    "calc_cost",
    calculate_cost,
    "Calcula custo. Parâmetros: size_gb, price_per_gb"
)

# Executa
result = agent.run("Quanto de disk gastei em backup esse mês? Considera USD 0.05 por GB")
print(f"\nCusto de execução: USD {agent.cost:.4f}")
print(f"Iterações: {agent.iterations}")

Vantagens:

  • Simples de implementar
  • Fácil debugar
  • Adequado para tarefas < 10 passos

Desvantagens:

  • Uma ferramenta quebra, tudo quebra
  • Sem priorização

Padrão 2: Roteador (agente supervisor)

Um agente decide qual tarefa delegar para qual suboagente. Melhor para tarefas complexas com ramificações.

class RouterAgent:
    """Agente supervisor que roteia para subagenges especializados."""
    
    def __init__(self):
        self.client = OpenAI()
        self.subagentos = {}
    
    def register_subagenote(self, name: str, agent):
        """Registra um subagenote especializado."""
        self.subagentos[name] = agent
    
    def route(self, task: str) -> str:
        """Decide qual subagenote executa a tarefa."""
        
        routing_prompt = f"""Dado esta tarefa, qual especialista deve resolver?
        
Especialistas:
- billing: consulta custos, faturas, orçamentos
- infrastructure: consulta servidores, disks, CPUs
- security: consulta logs de acesso, permissões
- support: consulta tickets de clientes

Responda com APENAS o nome do especialista:"""
        
        response = self.client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": routing_prompt + task}],
            temperature=0
        )
        
        specialist = response.choices[0].message.content.strip().lower()
        
        if specialist not in self.subagentos:
            specialist = "support"  # fallback
        
        print(f"[ROTEADOR] Tarefa delegada para: {specialist}")
        return self.subagentos[specialist].run(task)

Vantagens:

  • Cada subagenote é especialista em seu domínio
  • Falha de um não afeta outros
  • Escalável

Desvantagens:

  • Mais complexo de debugar
  • Necessário treinar roteador bem

Padrão 3: Agentes em cascata (multi-etapa)

Um agente chama outro. Útil para tarefas que precisam de contexto progressivo.

class CascadeAgent:
    """Executa agentes em sequência, passando contexto."""
    
    def run_cascade(self, task: str, agents: list) -> str:
        """Executa lista de agentes em ordem."""
        context = task
        
        for i, agent in enumerate(agents):
            print(f"\n[Etapa {i+1}] Executando {agent.__class__.__name__}")
            result = agent.run(context)
            
            # Próximo agente recebe resultado do anterior
            context = f"Contexto anterior: {result}\n\nProxima tarefa: {task}"
        
        return result

Controlando custo e loops infinitos

Limite de iterações

Sempre tenha:

max_iterations = 5  # Maioria dos casos resolve em 2-3

Limite de custo

def run(self, task: str, max_cost: float = 0.5) -> str:  # USD 0.50 max
    self.cost = 0.0
    
    while self.iterations < self.max_iterations:
        # ... executa LLM ...
        
        if self.cost > max_cost:
            print(f"Limite de custo atingido: USD {self.cost}")
            break

Detecção de loop infinito

def detect_loop(self, last_n_messages: int = 3) -> bool:
    """Detecta se agente está repetindo."""
    if len(self.conversation) < last_n_messages * 2:
        return False
    
    # Compara últimas N ações
    recent = self.conversation[-last_n_messages:]
    if len(set(recent)) == 1:
        # Todas iguais
        return True
    
    return False

Tratamento de falha de ferramenta

Ferramentas falham. Prepare-se:

def execute_with_retry(self, tool_name: str, params: dict, max_retries: int = 2):
    """Tenta executar ferramenta com retry."""
    for attempt in range(max_retries):
        try:
            return self.tools[tool_name]["func"](**params)
        except Exception as e:
            if attempt == max_retries - 1:
                return f"Ferramenta falhou após {max_retries} tentativas: {str(e)}"
            # Avisa o LLM que falhou
            return f"Tentativa {attempt + 1} falhou: {str(e)}. Tentando novamente..."

Observabilidade: rastreando a execução

Em produção, você quer saber por que o agente falhou. Trace cada chamada:

import uuid
from datetime import datetime

class TracedAgent:
    def run(self, task: str):
        trace_id = str(uuid.uuid4())[:8]
        
        log = {
            "trace_id": trace_id,
            "task": task,
            "start_time": datetime.now().isoformat(),
            "iterations": [],
            "total_cost": 0.0,
            "status": "running"
        }
        
        # Para cada iteração:
        iteration_log = {
            "number": self.iterations,
            "llm_input": "...",
            "llm_output": "...",
            "tool_called": "query_db",
            "tool_params": {"table": "disks"},
            "tool_result": "[...]",
            "timestamp": datetime.now().isoformat()
        }
        log["iterations"].append(iteration_log)
        
        # Salva em JSON, CloudWatch, ou banco
        print(json.dumps(log, indent=2))
        return log

Armadilhas comuns

"Agenetes sempre precisam ferramentas"

Falso. Um agente que só chama LLM e pensa melhor pode ser mais barato.

"Mais iterações = melhor resultado"

Falso. Após 5-10 iterações, começam loops. Diminua o limite se resolver em menos.

"Agente resolve 100% dos casos"

Falso. Agentes falham ~5-10% do tempo. Tenha fallback manual.

"Rastrear tudo é grátis"

Logging excessivo custa tokens (LLM precisa processar logs grandes). Trace essencial apenas.

Quando NOT usar agentes

  • Tarefa é simples (< 2 passos) → prompt estruturado é melhor
  • Latência < 200ms é obrigatória → agentes adicionam 500ms+
  • Você não tem ferramentas bem-definidas → agente fica confuso
  • Custo é crítico e tarefa é simples → desnecessário

Próximos passos

  1. Estruture seus prompts de agente com Engenharia de prompt em produção.
  2. Monitore custos com FinOps para IA.
  3. Implemente observabilidade com Observabilidade em aplicações com LLM.
  4. Garanta segurança das ferramentas com Segurança em aplicações com LLM.

Resumo: checklist de produção para agentes

  • Defini limite de iterações (máx. 10)
  • Defini limite de custo em dólares
  • Cada ferramenta tem tratamento de erro
  • Ferramenta sempre retorna JSON ou texto estruturado
  • Testei com cases que quebram (falha de API, timeout)
  • Tenho fallback se agente não resolve
  • Trace completo de cada execução
  • Latência testada em produção
  • Detecta loops infinitos

Agentes são poderosos mas exigem disciplina. Sem ela, explodem custo.

Teste seu conhecimento

Teste o que você aprendeu sobre agentes de IA

Pergunta 1 de 5

Seu retriever devolve um trecho que corta no meio de uma frase importante, perdendo contexto. Qual é a causa mais provável?

Continue lendo