Pular para o conteúdo
IAAvançado

Agentes de IA em produção: arquiteturas que funcionam

Aprenda a montar agentes de IA em produção: loop com ferramentas, limites de passos e custo, detecção de repetição, tratamento de falhas e rastreio.

Por Equipe IAUAI Estudos · 10 de julho de 2026 · 9 min de leitura

Nesta página

Ao final deste artigo você vai saber escrever o loop de um agente de IA com ferramentas, colocar limites que seguram custo e repetição, tratar falhas de ferramenta e decidir quando um agente nem deveria existir.

O problema real

Seu assistente responde bem a perguntas simples. Aí chega: "quanto eu gastei com backups neste mês?". Para responder, ele precisa consultar uma API, somar os valores, talvez consultar outra API e só então redigir a resposta. Um agente é isso: um modelo de linguagem que decide qual ferramenta chamar, recebe o resultado e repete até concluir.

Na primeira versão, quase todo mundo deixa o loop rodar até o modelo "achar" a resposta. Em algum dia ele fica preso repetindo a mesma chamada e a conta do mês vai junto. Aí vem o limite de 5 passos, que segura o custo mas às vezes corta tarefas legítimas no meio. A solução está em desenhar o loop com limites explícitos e saídas de emergência.

O loop agêntico

O ciclo é curto:

  1. O modelo recebe a tarefa, as ferramentas disponíveis e o histórico.
  2. Ele responde com texto final ou com um pedido de ferramenta.
  3. Seu código executa a ferramenta (o modelo nunca executa nada).
  4. O resultado volta ao histórico como mensagem.
  5. Repete até haver resposta final ou até um limite ser atingido.

O que torna isso confiável em produção é o código ao redor do modelo: limites, validação e registro de tudo.

Um agente simples e completo

O exemplo abaixo usa o SDK da Anthropic, mas a estrutura é a mesma em qualquer provedor com tool use. O nome do modelo vem de uma variável de ambiente para você escolher o que fizer sentido (um modelo pequeno costuma bastar para agentes com poucas ferramentas).

import json
import os
import anthropic

client = anthropic.Anthropic()
MODEL = os.environ["AGENT_MODEL"]  # defina o modelo que você usa

# Ferramentas de mentira, só para o exemplo rodar
def consultar_discos(mes: str) -> list[dict]:
    return [
        {"disco": "backup_01", "tamanho_gb": 250},
        {"disco": "backup_02", "tamanho_gb": 180},
    ]

def custo_armazenamento(tamanho_gb: float, preco_por_gb: float) -> float:
    return round(tamanho_gb * preco_por_gb, 2)

FERRAMENTAS = {
    "consultar_discos": consultar_discos,
    "custo_armazenamento": custo_armazenamento,
}

SCHEMAS = [
    {
        "name": "consultar_discos",
        "description": "Lista os discos de backup usados em um mês (formato AAAA-MM).",
        "input_schema": {
            "type": "object",
            "properties": {"mes": {"type": "string"}},
            "required": ["mes"],
        },
    },
    {
        "name": "custo_armazenamento",
        "description": "Calcula o custo de armazenar tamanho_gb a um preço por GB.",
        "input_schema": {
            "type": "object",
            "properties": {
                "tamanho_gb": {"type": "number"},
                "preco_por_gb": {"type": "number"},
            },
            "required": ["tamanho_gb", "preco_por_gb"],
        },
    },
]

def executar_ferramenta(nome: str, args: dict) -> str:
    funcao = FERRAMENTAS.get(nome)
    if funcao is None:
        return f"Erro: a ferramenta '{nome}' não existe."
    try:
        return json.dumps(funcao(**args), ensure_ascii=False)
    except Exception as e:  # o erro volta ao modelo, que pode se corrigir
        return f"Erro ao executar {nome}: {e}"

def rodar_agente(tarefa: str, max_passos: int = 6, max_tokens_total: int = 20_000) -> str:
    mensagens = [{"role": "user", "content": tarefa}]
    tokens_gastos = 0
    chamadas_vistas = []

    for passo in range(1, max_passos + 1):
        resposta = client.messages.create(
            model=MODEL,
            max_tokens=1024,
            system="Você é um assistente de FinOps. Use as ferramentas quando precisar de dados.",
            tools=SCHEMAS,
            messages=mensagens,
        )
        tokens_gastos += resposta.usage.input_tokens + resposta.usage.output_tokens
        mensagens.append({"role": "assistant", "content": resposta.content})

        if resposta.stop_reason != "tool_use":
            return "".join(b.text for b in resposta.content if b.type == "text")

        resultados = []
        for bloco in resposta.content:
            if bloco.type != "tool_use":
                continue
            assinatura = (bloco.name, json.dumps(bloco.input, sort_keys=True))
            if chamadas_vistas.count(assinatura) >= 2:
                return "Parei: o agente repetiu a mesma chamada várias vezes."
            chamadas_vistas.append(assinatura)
            resultados.append({
                "type": "tool_result",
                "tool_use_id": bloco.id,
                "content": executar_ferramenta(bloco.name, bloco.input),
            })
        mensagens.append({"role": "user", "content": resultados})

        if tokens_gastos > max_tokens_total:
            return "Parei: orçamento de tokens da tarefa esgotado."

    return "Parei: limite de passos atingido sem resposta final."

print(rodar_agente("Quanto gastei com discos de backup em 2026-09? Considere 0,05 por GB."))

Repare nos detalhes que fazem diferença: o erro da ferramenta volta como texto para o modelo tentar de novo, o histórico guarda o tool_use_id de cada chamada, e o loop tem três saídas de emergência (passos, tokens e repetição). Orçamento em tokens é mais estável que em dinheiro, porque preço muda; converta para valor no seu painel de custos.

Três arquiteturas, quando usar cada uma

Agente único com ferramentas

Um modelo, poucas ferramentas bem descritas. É o ponto de partida e resolve a maioria dos casos de até uns dez passos. Fica fácil de depurar porque existe um único histórico para ler.

O risco é o contexto inchar e o modelo se confundir quando as ferramentas passam de umas quinze. Quando isso acontecer, divida.

Roteador com especialistas

Uma primeira chamada, barata, só classifica o pedido (cobrança, infraestrutura, suporte) e entrega a um agente especializado, cada um com poucas ferramentas e um prompt curto.

def rotear(pedido: str) -> str:
    r = client.messages.create(
        model=MODEL,
        max_tokens=10,
        system="Classifique o pedido em uma palavra: cobranca, infra ou suporte.",
        messages=[{"role": "user", "content": pedido}],
    )
    area = r.content[0].text.strip().lower()
    return area if area in {"cobranca", "infra", "suporte"} else "suporte"

O fallback para "suporte" evita que uma resposta inesperada do classificador derrube o fluxo. O custo é ter mais prompts para manter e testar.

Pipeline em etapas

Quando a tarefa tem fases fixas (coletar, analisar, redigir), encadeie chamadas com código determinístico entre elas. Aqui o agente nem decide o fluxo: você decide. Isso costuma ser mais barato e previsível que um agente livre, e é a primeira coisa a considerar antes de soltar um modelo no comando.

Falhas de ferramenta e repetição de chamadas

Ferramentas falham: timeout, 500, argumento inválido. Três regras ajudam.

  • Devolva o erro ao modelo em texto claro, como no exemplo. Muitas vezes ele corrige o argumento sozinho.
  • Faça retry com espera crescente só para erros transitórios (rede, 429, 503), dentro da própria ferramenta. Erro de validação não melhora tentando de novo.
  • Ferramentas que alteram o mundo (enviar e-mail, pagar, apagar) precisam de confirmação humana ou de idempotência, para que uma repetição não duplique o efeito.

A detecção de repetição do exemplo compara nome e argumentos das chamadas. É simples e pega o caso clássico do agente que pergunta a mesma coisa em círculo.

Rastreie cada execução

Sem registro, você descobre que o agente falhou pelo cliente reclamando. Grave por execução um identificador, a tarefa, cada passo (ferramenta, argumentos, resultado resumido, tokens, duração) e o motivo de parada. O artigo sobre observabilidade de LLM mostra como transformar isso em traces. Cuidado com dados pessoais nesses registros: mascare antes de gravar.

Armadilhas comuns

  • Achar que mais passos dão resposta melhor. Depois de alguns passos sem progresso, o mais provável é loop. Meça a distribuição de passos reais e ajuste o limite com base nela.
  • Descrever mal as ferramentas. A descrição é o prompt da ferramenta. Nome vago e parâmetros sem explicação geram chamadas erradas.
  • Dar ferramentas demais. Cada ferramenta extra aumenta a chance de escolha errada. Comece com o mínimo.
  • Não ter caminho manual. Nenhum agente resolve tudo. Defina o que acontece quando ele desiste, por exemplo abrir um ticket com o histórico anexado.
  • Esquecer segurança. Texto vindo de ferramentas e documentos pode conter instruções maliciosas. Veja segurança em aplicações com LLM.

Quando não usar um agente

  • A tarefa tem um ou dois passos conhecidos: um prompt estruturado ou function calling direto resolve.
  • Você precisa de latência baixa e previsível: cada volta do loop soma uma chamada ao modelo.
  • O fluxo é fixo: um pipeline em código é mais barato e mais fácil de testar.

Checklist de produção

  • Limite de passos e de tokens por tarefa
  • Detecção de chamadas repetidas
  • Erro de ferramenta devolvido ao modelo em texto
  • Ações destrutivas com confirmação ou idempotência
  • Trace completo de cada execução, sem dados pessoais
  • Testes com falha de API, timeout e entrada hostil (veja avaliação de LLM com evals)
  • Caminho manual quando o agente desiste

Para acompanhar os gastos, siga com FinOps para IA. Quer aplicar isso na sua empresa? Marque uma conversa de 45 minutos em https://iauaicloud.com.br/consultoria

Teste seu conhecimento

Teste o que você aprendeu sobre agentes de IA

Pergunta 1 de 5

Qual é o papel do seu código no loop de um agente com ferramentas?

Um conteúdo prático por quinzena

Deixe o seu e-mail para receber um conteúdo prático de IA e cloud a cada quinzena. Sem spam, e você pede a exclusão quando quiser.

Continue lendo