· 6 min · Agentes

Como evitar que ciclos de agentes consumam seu orçamento de API

Como evitar que ciclos de agentes consumam seu orçamento de API

Vou redigir o artigo diretamente, com táticas concretas de engenharia, uma tabela comparativa e exemplos práticos. Vou me basear no comportamento real dos loops e em controles de custos, e garantir que ele termine com recomendações práticas.## A maneira mais rápida de consumir um orçamento de API

Uma vez, vi um agente de programação “simples” transformar uma solicitação de usuário de 400 tokens em um item de 28,000 tokens na fatura em menos de dois minutos.

O padrão era dolorosamente familiar: o agente chamou uma ferramenta de busca, resumiu os resultados, releu seu próprio resumo, consultou a mesma ferramenta novamente com uma formulação ligeiramente diferente e, então, expandiu o contexto até que cada turno carregasse toda a conversa, metade do repositório e um rastro de planos fracassados. Não havia nada de errado com o modelo. O projeto do loop estava errado.

Esse é o problema central dos sistemas agênticos: o custo não cresce com os prompts dos usuários, mas com o comportamento do loop. Um único loop mal projetado pode multiplicar:

  • os tokens de entrada devido a um contexto que não para de crescer,
  • os tokens de saída devido a um “raciocínio” prolixo,
  • os gastos com ferramentas devido a chamadas repetidas,
  • e a latência devido a novas tentativas em série.

Se você está desenvolvendo agentes em produção, o verdadeiro trabalho não é “tornar o modelo mais inteligente”. É “tornar o loop mais barato, mais curto e menos propenso a sair do controle”.

Por que loops de agentes fazem os custos dispararem

Um turno de chat normal tem uma entrada e uma saída. Um loop de agente tem uma sequência como esta:

  1. o usuário faz uma pergunta,
  2. o modelo planeja,
  3. o modelo chama uma ferramenta,
  4. a ferramenta retorna dados,
  5. o modelo lê os dados,
  6. o modelo decide o próximo passo,
  7. o ciclo se repete.

Cada iteração acrescenta novos tokens ao prompt da próxima iteração. Se você continuar anexando as saídas completas das ferramentas e os raciocínios anteriores, o prompt crescerá mais ou menos como uma escada.

Na prática, isso produz três multiplicadores de custo:

  • Acúmulo de contexto: cada etapa carrega as etapas anteriores.
  • Excesso de chamadas a ferramentas: a mesma ferramenta é chamada com argumentos ligeiramente diferentes.
  • Novas tentativas sem controle: o modelo continua “tentando mais uma coisa” quando já fez o suficiente.

Uma armadilha comum é que o desperdício de tokens geralmente fica invisível até você examinar os rastros de cada execução. A resposta final pode ser concisa, mas a cadeia oculta pode ser 10x maior que a saída visível para o usuário.

Um modelo simples de custo

Se um loop executa N etapas, cada uma com:

  • C tokens de contexto carregado,
  • I tokens de saída de ferramentas reinseridos,
  • O tokens de saída do modelo,

então uma estimativa do total é:

total_tokens ≈ N * (C + I + O)

Essa estimativa é otimista, porque C geralmente cresce à medida que o loop continua. Em um agente real, os turnos posteriores costumam ser os mais caros.

Os mecanismos de controle que realmente importam

Há alguns pontos em que você pode intervir. O segredo é combiná-los.

ControleO que reduzMelhor caso de usoContrapartida
Limites de etapasLoops sem controleQualquer agente com ferramentasPode parar cedo demais em tarefas difíceis
Redução de contextoTokens de entradaTarefas de longa duraçãoRisco de perder histórico útil
Subagentes mais baratosGastos com trabalho rotineiroBusca, extração, classificaçãoSobrecarga de coordenação
Cache de resultados de ferramentasGastos com chamadas repetidas a ferramentasFontes estáveis, consultas repetidasDesatualização e invalidação
Observabilidade de gastosFaturas inesperadasSistemas em produçãoExige trabalho de instrumentação
Condições de parada do loopLoops infinitos ou quase infinitosAgentes pouco confiáveisÉ preciso definir o que é “bom o suficiente”

As configurações mais eficazes em produção usam todos esses mecanismos.

1) Limite rigorosamente o número de etapas

Esta é a correção mais simples e mais subestimada: se você não definir um limite máximo rígido, estará confiando que o modelo pare por conta própria.

Eu geralmente começo com:

  • 3–5 etapas para tarefas de escopo restrito,
  • 6–8 etapas para tarefas de complexidade moderada,
  • mais etapas apenas quando há um motivo forte.

Um bom limite não é apenas uma válvula de segurança. Ele força uma decomposição melhor. Se o agente só dispõe de quatro ações, tende a:

  • solicitar a ferramenta certa mais cedo,
  • evitar desvios exploratórios,
  • e convergir mais rapidamente para uma resposta utilizável.

Exemplo de controlador de loop

MAX_STEPS = 5

for step in range(MAX_STEPS):
    action = model.next_action(state)

    if action.type == "final":
        return action.final_answer

    observation = run_tool(action.tool_name, action.arguments)
    state = update_state(state, action, observation)

raise RuntimeError("Agent stopped after step cap")

Uma armadilha comum: os limites de etapas devem se aplicar ao plano inteiro, não a cada sub-rotina de forma independente. Caso contrário, você transfere a explosão de custos do agente principal para os auxiliares aninhados.

2) Reduza o contexto a cada turno

A maioria dos agentes carrega histórico demais. Eles não precisam de todas as respostas anteriores das ferramentas, especialmente quando a resposta era grande e apenas um detalhe importava.

Na prática, obtive os melhores resultados com uma política de memória em camadas:

  • Manter na íntegra: solicitação do usuário, objetivo atual, decisões finais, restrições ainda não resolvidas.
  • Resumir: raciocínio anterior, tentativas de caminhos alternativos, saídas longas de ferramentas.
  • Descartar: hipóteses sem saída, resultados duplicados de ferramentas, rascunhos intermediários antigos.

O que manter

Um objeto de estado compacto funciona melhor do que reenviar a transcrição bruta:

{
  "goal": "Find the failing endpoint and propose a fix",
  "constraints": [
    "No schema changes",
    "Must preserve backward compatibility"
  ],
  "known_facts": [
    "500s started after deploy 1842",
    "Only /v1/search is affected"
  ],
  "open_questions": [
    "Is the new cache layer returning stale payloads?"
  ],
  "step": 3
}

Isso é muito mais barato do que fornecer ao modelo 20 turnos de “raciocínio em voz alta”.

Padrão prático de redução de contexto

Use três buffers:

  • working_set: turno atual, saídas das ferramentas, plano ativo.
  • summary_memory: histórico compactado.
  • archive: tudo o que você possa precisar para auditorias, mas não para o contexto do prompt.

O agente só vê working_set + summary_memory. Quando working_set crescer demais, resuma seu conteúdo em summary_memory.

A armadilha aqui é a distorção gradual dos resumos. Se o seu sumarizador perder informações, ele pode apagar restrições e fazer o agente repetir erros. Gosto de preservar fatos estruturados separadamente dos resumos em texto livre, para que o modelo não precise inferi-los a partir da prosa.

3) Use subagentes mais baratos para tarefas simples

Nem toda etapa merece seu melhor modelo.

Se a tarefa for:

  • extrair campos de JSON,
  • classificar um chamado,
  • verificar se um arquivo foi alterado,
  • ou gerar uma consulta de busca curta,

então um modelo menor e mais barato costuma ser suficiente. Reserve o modelo caro para planejamento, síntese e situações ambíguas.

Divisão comum

  • Agente principal: raciocina sobre a tarefa e decide quando parar.
  • Subagente: executa tarefas específicas, como busca, extração ou normalização.
  • Verificador: verifica o formato, a completude ou erros evidentes nas saídas.

Uma arquitetura prática:

User
  -> Orchestrator (strong model)
      -> Search agent (cheap model)
      -> Extract agent (cheap model)
      -> Final synthesis (strong model)

Por que isso funciona

O modelo principal mantém o foco no fluxo de controle, em vez de fazer tudo sozinho. O subagente pode ter seu escopo restringido pelo prompt e um limite rígido de tokens.

Exemplo de prompt para um subagente de busca:

Return only:
1. the best search query,
2. 3 likely source categories,
3. no explanation.

Esse tipo de contrato restrito mantém as saídas curtas e previsíveis.

Se a sua plataforma oferece acesso a vários modelos a um preço acessível, é aqui que isso compensa: um modelo robusto para orquestração, um modelo mais barato para subtarefas repetitivas e nenhum motivo para gastar tokens premium na análise sintática de rotina.

4) Leve o cache de resultados de ferramentas a sério

Os loops de agentes costumam pagar várias vezes pela mesma informação:

  • leituras repetidas de arquivos,
  • consultas repetidas ao banco de dados,
  • buscas repetidas na web,
  • chamadas repetidas de embedding ou recuperação.

Armazenar as saídas das ferramentas em cache é uma das mudanças com maior retorno sobre o investimento que você pode fazer.

Use chaves semânticas no cache, em vez de texto bruto

Um cache baseado no texto bruto do prompt não encontra uma correspondência se a redação mudar ligeiramente. Chaves melhores se baseiam na intenção normalizada:

def cache_key(tool_name, args):
    normalized = normalize_args(args)
    return f"{tool_name}:{hash(normalized)}"

Exemplo de entrada de cache:

{
  "tool": "repo_search",
  "query": "auth middleware rate limit bug",
  "result": {
    "files": ["src/middleware/auth.py", "src/api/routes.py"],
    "ts": 1710001123
  }
}

Quando o cache mais ajuda

  • Agentes de inspeção de repositórios,
  • busca de documentos,
  • bases de conhecimento estáveis,
  • transformações determinísticas,
  • recuperação repetida em fluxos de trabalho com vários turnos.

Onde o cache pode atrapalhar

  • dados que mudam rapidamente,
  • resultados específicos de cada usuário,
  • qualquer informação com requisitos de atualização sensíveis ao tempo.

Uma armadilha comum é armazenar as saídas das ferramentas em cache sem informar ao agente o quanto estão atualizadas. Se o modelo acreditar que recebeu dados em tempo real quando recebeu dados em cache, poderá tomar decisões ruins. Inclua registros de data e hora ou janelas de validade nos metadados da ferramenta.

5) Coloque os gastos no painel

Se você acompanhar apenas a latência e a taxa de sucesso, deixará passar o verdadeiro modo de falha: o sucesso caro.

Você precisa de observabilidade por execução para:

  • tokens de entrada,
  • tokens de saída,
  • chamadas de ferramentas,
  • latência das ferramentas,
  • gasto total,
  • contagem de etapas,
  • motivo da parada.

Esquema mínimo de eventos

{
  "run_id": "r_8f2c",
  "step": 4,
  "model": "gpt-5.5",
  "input_tokens": 1842,
  "output_tokens": 221,
  "tool_name": "repo_search",
  "tool_latency_ms": 312,
  "estimated_cost_usd": 0.087,
  "stop_reason": "step_cap"
}

O que observar na prática

  • Tokens por tarefa concluída com sucesso: o indicador de custo mais claro.
  • Tokens por etapa: detecta o inchaço do prompt.
  • Chamadas repetidas de ferramentas: geralmente indicam um erro de planejamento.
  • Distribuição dos motivos de parada: se muitas execuções terminam ao atingir o limite, seu agente está planejando de forma insuficiente.

Um dos gráficos mais úteis é o de custo por tipo de tarefa. Algumas categorias serão naturalmente caras. Tudo bem. O que você quer detectar é a tarefa que deveria ser barata, mas não é.

6) Interrompa cedo os loops descontrolados

Um loop deve parar por mais motivos do que “atingi o limite de etapas”.

Entre as condições úteis de parada estão:

  • o modelo produziu uma resposta final,
  • a mesma chamada de ferramenta se repete sem novas informações,
  • a variação de confiança ou utilidade está abaixo do limiar,
  • a tarefa está resolvida segundo um verificador,
  • o plano estagnou.

Exemplo de mecanismo de interrupção de loop

seen_calls = set()

for step in range(MAX_STEPS):
    action = model.next_action(state)
    signature = (action.tool_name, canonicalize(action.arguments))

    if signature in seen_calls:
        return fail("repeated tool call with no new information")
    seen_calls.add(signature)

    observation = run_tool(action.tool_name, action.arguments)
    state = update_state(state, action, observation)

    if verifier_says_done(state):
        return finalize(state)

Isso detecta um modo de falha muito comum: o modelo “quer ajudar” e apenas reformula a mesma consulta.

Outra proteção útil: condicionar a continuidade à utilidade

Se uma etapa não alterar o estado o suficiente, não continue. Isso pode se resumir a condições como:

  • nenhum novo arquivo encontrado,
  • nenhuma nova entidade extraída,
  • nenhuma melhora na confiança da resposta,
  • nenhuma evidência inédita adicionada.

A métrica exata depende da tarefa, mas alguma noção de ganho marginal é essencial.

O que realmente acontece quando você ajusta isso bem

Quando você torna o loop mais eficiente, o agente geralmente melhora de maneiras que podem passar despercebidas no início:

  • Ele fica menos prolixo e mais decidido.
  • Ele solicita a ferramenta certa mais cedo.
  • Ele produz menos ciclos de “ainda estou investigando”.
  • Ele fica mais barato e mais rápido, porque menos turnos significam menos contexto e menos latência.

A contrapartida importante é que limites rígidos e uma redução agressiva de contexto podem tornar o sistema frágil em tarefas realmente difíceis. Portanto, não finja que o agente está “resolvendo” problemas quando, na verdade, apenas está esgotando o tempo disponível. Deixe isso claro nos logs e nas mensagens exibidas ao usuário.

Minha regra prática: priorize a competência com limites em vez de exploração sem fim.

Uma Configuração Prática para Produção

Se eu fosse lançar um agente amanhã, começaria com:

  • MAX_STEPS = 5
  • estado estruturado, em vez de reprocessar toda a transcrição
  • memória resumida após cada turno
  • subagentes de baixo custo para busca e extração
  • cache de resultados de ferramentas com metadados de atualização
  • registro de tokens e custos por execução
  • detector de chamadas repetidas
  • motivos explícitos de parada

Essa configuração não é glamourosa, mas é o que impede a conta de crescer mais rápido que o produto.

Recomendações Práticas

  • Limite primeiro o número de etapas; é a proteção mais barata contra loops descontrolados.
  • Reduza o contexto de forma rigorosa e mantenha o estado estruturado separado dos resumos.
  • Use subagentes mais baratos para tarefas específicas, em vez de gastar tokens premium em tudo.
  • Armazene em cache as saídas reutilizáveis das ferramentas, mas indique seu grau de atualização para que o modelo não confie cegamente em dados desatualizados.
  • Registre os gastos por execução, por etapa e por chamada de ferramenta para que regressões de custo fiquem visíveis imediatamente.
  • Interrompa os loops quando houver repetição, estagnação ou conclusão verificada — não apenas quando os recursos se esgotarem.
  • Projete para uma competência com limites: ser bom o suficiente, rápido e previsível sempre supera ser engenhoso, mas caro.
A

A AI Prime Tech publica este blog. Os artigos são redigidos com assistência de IA; confira detalhes específicos de cada versão, como IDs de modelos, preços e limites, na documentação oficial antes de se basear neles.

Obtenha acesso mais barato à API do Claude

Uma única chave de API para Claude Opus 5.5, Sonnet 5, Haiku 4.5 e Fable 5.1, além de GPT-6 modelos. Pague conforme o uso, sem assinatura.

Obtenha Sua Chave de API →
A AI Prime Tech é um gateway de API independente de terceiros. Claude™ e Anthropic® são marcas comerciais da Anthropic, PBC. Não há afiliação nem endosso implícitos.