Controle de custos em agentes de IA: roteamento de modelos, orçamento de ferramentas, cache e retries

"OpenAI API Pricing"
Às 3 da manhã, um report Agent em segundo plano retorna uma resposta vazia. O status HTTP é 200, mas o body vem vazio. A lógica de retry só confere o status, então continua tentando. Cada request envia 500 tokens de entrada. Depois de 1.500 retries, foram gastos 750 mil tokens. A conta na manhã seguinte vira o alerta de verdade.
A causa raiz não é “o modelo era caro”. Faltavam três proteções: circuit breaker, checagem de orçamento e classificação de erro. O custo de um Agent costuma sair do controle de três formas:
Retries sem limite. Os modos de falha não são classificados, então uma resposta vazia vira erro recuperável. Sem circuit breaker, nem 1.500 falhas consecutivas param a execução. Cada retry reenvia todo o contexto e multiplica o custo por 2-5x.
Contexto inchado. Uma tarefa longa roda por 6 horas e o histórico da conversa cresce para 80K tokens. Sem checkpoint, uma falha reinicia tudo do zero e cada etapa é paga de novo.
Uso excessivo de modelo. Todas as tarefas usam um frontier model porque não há estratégia de roteamento. Até uma classificação simples passa pelo caminho mais caro e desperdiça 70% dos tokens.
Controle de custos em Agents não é uma otimização isolada. É um desenho em camadas: objetos de orçamento, estratégia de roteamento, cache hits, circuit breakers de retry, logs de custo e limites de alerta. O caminho prático é transformar esses seis objetos de engenharia em tabelas de decisão ou checks executáveis.
Design do objeto de orçamento: o que registrar, onde guardar e quando cortar
Controle de custo começa com um objeto de orçamento, não com um total único. Sem camadas, um pico na conta não mostra qual usuário, tarefa ou ferramenta queimou o orçamento.
Sete camadas de orçamento
Os objetos de orçamento vão do mais amplo ao mais fino:
| Camada de orçamento | Objeto de orçamento | Limite sugerido | Gatilho de alerta |
|---|---|---|---|
| Layer 1 | user | Limite diário/mensal por usuário | Alerta quando restante < 20% |
| Layer 2 | tenant | Pool de orçamento por tenant | Alerta quando restante < 30% |
| Layer 3 | workflow | Orçamento por tipo de workflow | Alerta quando restante < 40% |
| Layer 4 | task | Orçamento por tipo de tarefa | Alerta quando restante < 50% |
| Layer 5 | tool | Orçamento por chamada de ferramenta | Pular ferramenta se passar do limite |
| Layer 6 | retry | Limite de retry + circuit breaker | Desativar ferramenta após N falhas seguidas |
| Layer 7 | cache | Monitoramento de cache hit rate | Alerta se hit rate ficar abaixo do esperado |
Os limites exatos dependem do modelo de negócio e são configuração mutável. A estrutura em camadas é mais estável. O campo de orçamento restante precisa entrar nos logs de custo para alimentar alertas e circuit breakers.
Campos que cada camada deve registrar
Cada camada de orçamento deve registrar estes campos:
| Nome do campo | Uso | Tipo | Por que registrar |
|---|---|---|---|
model | Identificar o modelo | string | Ver se o roteamento de modelos faz sentido |
inputTokens | Número de tokens de entrada | integer | Calcular custo de entrada |
outputTokens | Número de tokens de saída | integer | Custo de saída deve ser acompanhado separadamente |
cachedTokens | Tokens atendidos por cache | integer | Medir economia de cache |
costEstimate | Estimativa de custo desta chamada | float | Acumular custo em tempo real |
budgetRemaining | Orçamento restante | float | Base para decisão de circuit breaker |
O ponto do objeto de orçamento é contabilidade por dimensão, não “guardar só total_cost”. Em multi-tenant, o custo precisa ser separado por tenantId. Em sistemas com muitas ferramentas, toolName revela a caixa-preta.
Lógica de circuit breaker
Quando o orçamento restante cair abaixo do limite, acione o circuit breaker:
def check_budget_before_retry(budget_remaining, retry_cost_estimate):
if budget_remaining < retry_cost_estimate:
return "skip_retry" # Pular retry porque ele passaria do orçamento
if budget_remaining < threshold: # threshold como 20%
return "wait_approval" # Orçamento baixo, esperar aprovação
return "continue"
O circuit breaker confere o orçamento antes do retry, não depois. Estime o custo antes de cada tentativa e pare se a próxima passar do orçamento. É assim que você evita a “resposta vazia repetida 1.500 vezes”.
O artigo de context engineering da mesma série vai tratar quais partes do contexto entram no prefix estável e quais ficam como variáveis de execução.
Estratégia de roteamento de modelos: nem toda tarefa precisa do modelo mais caro
Um ticket triage Agent costuma ter uma distribuição assim: 70% das tarefas são classificação simples, 20% precisam rascunhar uma resposta e só 10% devem subir para um frontier model antes de enviar um email ao cliente. Uma estratégia de roteamento pode economizar 40-85% do custo.
Roteamento por camada de modelo
O roteamento por modelo segue a complexidade da tarefa:
| Nível da tarefa | Tarefas típicas | Nível de modelo recomendado | Proporção | Perfil de custo |
|---|---|---|---|---|
| 70% - nível S | Classificação, extração, filtro, Q&A simples | nano/flash (mais barato) | 70% | Saída curta, poucos turnos, poucas chamadas de ferramentas |
| 20% - nível M | Rascunho, resumo, geração de código, raciocínio médio | mid-tier (preço médio) | 20% | Saída média, pode chamar ferramentas |
| 10% - nível L | Revisão, arquitetura, raciocínio complexo, coordenação multi-ferramenta | frontier (mais caro) | 10% | Saída longa, muitos turnos, chamadas frequentes de ferramentas |
A estratégia tem três passos:
Primeiro passo: classificar a tarefa. Defina critérios S/M/L para cada workflow, incluindo tamanho da saída, número de chamadas de ferramentas, profundidade de raciocínio e risco.
Segundo passo: usar S como padrão. Só suba para M ou L quando houver sinais claros de complexidade.
Terceiro passo: roteamento em cascata. Se S falhar, suba para M. Se M falhar, suba para L. Se L falhar, entre em intervenção humana. Antes de cada subida, cheque orçamento restante; se não houver orçamento, pule a subida.
Roteamento por camada de serviço
O mesmo modelo também pode ser separado por latency priority. Descontos e janelas de conclusão mudam; confira preços oficiais antes de publicar.
| Camada de serviço | Desconto de custo | Tempo de conclusão | Uso indicado |
|---|---|---|---|
| Realtime API | Sem desconto | Resposta imediata | Conversa interativa com Agent, tarefas de alta prioridade |
| Batch API | 50% cost discount (verificar antes de publicar) | 24-hour turnaround (verificar antes de publicar) | evals batch, classificação, embeddings, processamento de repositório de conteúdo |
| Flex Processing | Custo menor (verificar antes de publicar) | Resposta mais lenta, indisponibilidade ocasional | Tarefas assíncronas de baixa prioridade, model evaluations, data enrichment |
Checklist para roteamento offline:
- Precisa de resposta imediata? Sim -> Realtime API, com roteamento de modelo.
- Pode esperar 24 horas? Sim -> Batch API.
- É baixa prioridade e tolera falhas ocasionais? Sim -> Flex Processing.
- É processamento batch, como eval, classificação ou embedding? Sim -> Batch API.
Classificação de risco
As tarefas também devem ser classificadas por risco:
| Nível de risco | Operação típica | Estratégia de roteamento | Ramificação de orçamento |
|---|---|---|---|
| Baixo risco | Classificação, extração, resumo interno | Modelo S + caminho automático | Sem aprovação, limite de orçamento mais folgado |
| Risco médio | Rascunho de resposta ao cliente, sugestão de mudança de código | Modelo M + aprovação opcional | Ao passar do orçamento, pedir aprovação |
| Alto risco | Enviar email ao cliente, cobrar, mudar arquitetura | Modelo L + aprovação obrigatória | Espera, rejeição e timeout viram ramificações de orçamento |
O artigo Human-in-the-Loop da mesma série explica como espera, rejeição e timeout de aprovação afetam o orçamento.
Restrições principais
O roteamento precisa de restrições claras:
- Não hardcodear preços: preços mudam. Registre model + pricingVersion, em vez de fixar uma fórmula de custo na lógica de negócio.
- Checar orçamento restante: antes de subir de nível, confira budgetRemaining. Se não houver orçamento, pule a subida ou peça aprovação.
- Classificar erros: separe falhas recuperáveis de capacidade do modelo de erros não recuperáveis, como parâmetro inválido ou permissão negada.
Orçamento de chamadas de ferramentas: per-tool budget, timeout e limite de retries
Chamadas de ferramentas têm custo de schema e de API. Cada chamada envia schema, parâmetros e contexto de parsing de resposta; além disso, a API externa pode rate-limitar ou dar timeout. Esses custos são separados da chamada ao modelo.
Controle de orçamento de ferramentas
Cada ferramenta deve ter controles próprios:
| Controle | Configuração sugerida | Campo de monitoramento | Ação |
|---|---|---|---|
| Per-tool budget | Limite por chamada | tool_cost_estimate | Pular ferramenta ou degradar |
| Tool timeout | Timeout da API externa | tool_duration | Marcar timeout como erro recuperável |
| Retry limit per tool | Limite de retries por ferramenta | tool_retry_count | Desistir da ferramenta, sem loop de retries |
Ferramentas que chamam APIs externas, como busca, banco de dados e serviços de terceiros, precisam de contabilidade própria. Caso contrário, tool calling vira uma caixa-preta de custo.
Classificação de falhas de ferramentas
Falhas de ferramentas se dividem em recuperáveis e não recuperáveis:
| Tipo de falha | Erros típicos | Estratégia | Impacto de custo |
|---|---|---|---|
| Falha recuperável | Timeout de rede, 503 Service Unavailable, 429 Rate Limit | Retry automático com exponential backoff e retry-after | Cada retry envia todo o contexto |
| Falha não recuperável | 403 Permission Denied, 400 Bad Request, ferramenta inexistente | Não repetir; injetar o erro para o modelo decidir | Sem retry, sem gasto repetido |
A regra é simples: repita apenas falhas temporárias causadas por condições externas. Não repita erros de configuração interna.
Circuit breaker
Depois de N falhas consecutivas, desative a ferramenta:
def circuit_breaker_tool(tool_name, consecutive_failures, threshold=5):
if consecutive_failures >= threshold:
return "disable_tool" # Desativar ferramenta
return "continue"
O estado do circuit breaker deve entrar nos logs para explicar por que a ferramenta foi desativada. Depois do disparo, espere intervenção humana ou uma checagem de recuperação automática, em vez de chamar uma ferramenta instável repetidamente.
As bases de tool calling estão em Tool Calling. Este artigo amplia com per-tool budget, timeout e limite de retries.
Design de Prompt Caching: prefix estável, variáveis e limite de 1024 tokens
Prompt Caching otimiza o custo de tokens de entrada para um prompt prefix estável. Não é cache de resultado de negócio. Ele roteia requests com o mesmo prompt prefix para um servidor que processou esse prefix recentemente, reduzindo latência e custo de entrada.
Prompt Caching não é cache de resultado
Prompt Caching guarda um prompt prefix estável, não um resultado de negócio. A diferença importa:
- Prompt Caching: guarda um prompt prefix estável, como system prompt ou tool schema. Um hit economiza tokens de entrada, mas a inferência ainda roda.
- Cache de resultado de negócio: guarda uma saída completa, como resultado de ferramenta ou consulta ao banco de dados. Um hit retorna direto, sem chamar o modelo.
Os objetivos são diferentes. Prompt Caching reduz custo de tokens de entrada; cache de negócio reduz o custo da chamada inteira. Dá para usar ambos: prefixos estáveis no Prompt Caching, resultados frequentes de ferramentas no cache de negócio.
Requisitos de estrutura
A chave é separar prefix estável de variáveis de execução:
| Tipo de conteúdo | Posição | Chance de cache hit | Exemplos |
|---|---|---|---|
| Prefix estável (entra no cache) | Início do prompt | Alta | System prompt, Tool schema, documentos Policy, exemplos Few-shot |
| Variáveis de execução (não entram no cache) | Mais tarde no prompt | Baixa | User input, File fragments, Runtime state (turno atual, variáveis temporárias) |
Passos de design:
- Coloque System prompt, Tool schema e Policy no início: eles são estáveis entre chamadas e tendem a acertar o cache.
- Coloque User input, File fragments e Runtime state depois: esses conteúdos mudam a cada chamada e não devem entrar no prefix estável.
- Monitore Cache hit rate: registre cachedTokens e total de tokens de entrada, depois calcule a taxa. Acima de 40% é saudável; abaixo de 20%, revise a estrutura do prompt.
Limite e efeito
O limite automático e o efeito de Prompt Caching são fatos mutáveis; confira a documentação oficial antes de publicar:
- Limite: ativação automática a partir de 1024 tokens (verificar antes de publicar).
- Efeito: hits podem reduzir custo e latência (verificar proporções exatas).
- Como verificar hits: campo
usage.prompt_tokens_details.cached_tokens.
Modelos suportados, limites e descontos de Prompt Caching podem mudar. Verifique na página oficial de pricing antes de publicar. O princípio durável é simples: conteúdo estático antes, conteúdo variável depois.
Circuit breakers de retry: idempotência, checkpoints e orçamento restante
Retries são uma das maiores fontes de custo descontrolado. Um report Agent preso em uma ferramenta instável pode reenviar todo o contexto a cada falha; depois de 1.500 retries, o custo sai muito do caminho normal.
Checar orçamento antes do retry
Confira o orçamento restante antes de tentar de novo, não depois:
def should_retry(error_type, budget_remaining, retry_cost_estimate):
# Classificação de erro
if error_type in ["403", "400", "tool_not_exist"]:
return False # Erro não recuperável, não repetir
# Checagem de orçamento
if budget_remaining < retry_cost_estimate:
return False # Fora do orçamento, não repetir
return True # Retry permitido
A checagem de orçamento deve vir antes da lógica de retry. Assim você evita gastar o orçamento diário com uma resposta vazia repetida 1.500 vezes.
Idempotência
Um retry não pode repetir efeitos colaterais, como enviar email ou cobrar:
- Use um ID de idempotência, como requestId, nas chamadas de ferramentas. Se a API externa receber o mesmo ID, deve devolver o resultado em cache, não processar a operação de novo.
- Escreva o ID de idempotência nos logs de custo para diagnosticar chamadas repetidas.
A ideia da idempotência é que a mesma operação não consuma duas vezes. Sem isso, retries amplificam custo e efeitos colaterais.
Salvamento de estado (Checkpoint)
Tarefas longas devem se recuperar sem repetir todo o workflow:
- Salve um checkpoint em nós importantes, com etapas concluídas, estado atual e resumo de contexto.
- Depois de uma falha, continue a partir do checkpoint, não do começo.
- Persista o checkpoint. Deixar só em memória não basta.
O design de checkpoint e thread state está em Arquitetura de Agent com LangGraph.
Estratégia de retry
Cada tipo de erro pede uma estratégia:
| Tipo de erro | Erro típico | Estratégia de retry | Impacto de custo |
|---|---|---|---|
| Timeout de rede | Sem resposta em 10 segundos | Exponential backoff + retry-after, no máximo 3 retries | Cada retry envia todo o contexto |
| 503/429 | Service Unavailable, Rate Limit | Esperar janela de rate limit + retry-after, no máximo 3 retries | Esperar não consome tokens, mas o retry consome |
| 403/400 | Permission Denied, Bad Request | Não repetir; injetar o erro para o modelo decidir | Sem retry, evita gasto inválido |
A regra é: só repita erros recuperáveis. Não envie requests inválidos ao modelo de novo e de novo.
Circuit breaker
Depois de N falhas consecutivas, pare os retries e espere intervenção:
def circuit_breaker(consecutive_failures, threshold=5):
if consecutive_failures >= threshold:
return "stop_retry" # Parar retries
return "continue"
A decisão do circuit breaker deve entrar nos logs para explicar por que os retries pararam. Depois disso, espere intervenção humana ou recuperação de orçamento, em vez de chamar novamente um modelo ou ferramenta instável.
Logs de custo e alertas: campos e limites
Observabilidade de custos é pré-requisito para controle de custos. Se os campos de log são incompletos, você não encontra o problema.
OpenTelemetry trace span attributes
Projete logs de custo em três níveis de span:
Agent run span (nível superior):
| Nome do campo | Uso | Tipo | Por que registrar |
|---|---|---|---|
runId | Identificar execução específica | string | Distingue runs repetidos do mesmo workflow |
tenantId | Identificar tenant | string | Distribui custos em sistemas multi-tenant |
userId | Identificar usuário | string | Acompanha tendência de custo por usuário |
workflowName | Identificar workflow | string | Acompanha custos por tipo de workflow |
totalCost | Custo total estimado | float | Acumula custos em tempo real |
budgetRemaining | Orçamento restante | float | Base para decisão de circuit breaker |
totalRetries | Total de retries | integer | Mostra amplificação por retries |
Model call span (span filho):
| Nome do campo | Uso | Tipo | Por que registrar |
|---|---|---|---|
model | Identificar modelo | string | Ver se o roteamento faz sentido |
pricingVersion | Versão de preços | string | Evita fórmula de custo hardcodeada |
inputTokens | Tokens de entrada | integer | Calcula custo de entrada |
outputTokens | Tokens de saída | integer | Acompanha custo de saída separadamente |
cachedTokens | Tokens em cache | integer | Calcula economia de cache |
costEstimate | Estimativa desta chamada | float | Acumula custos em tempo real |
latencyMs | Latência da chamada | integer | Ajuda a decidir se Batch/Flex encaixa |
Tool call span (span filho):
| Nome do campo | Uso | Tipo | Por que registrar |
|---|---|---|---|
toolName | Identificar ferramenta | string | Localiza overhead de tool calls |
toolBudget | Limite de orçamento da ferramenta | float | Base para circuit breaker |
toolTimeout | Timeout da ferramenta | integer | Classifica falhas de timeout |
retryCount | Número de retries | integer | Mede amplificação por retries |
errorType | Tipo de erro | string | Separa recuperável de não recuperável |
Não registre só total_cost. Separe por dimensão. Sem esses campos, um pico na conta só diz “passou do orçamento”; não mostra qual usuário, ferramenta ou retry causou.
O design completo de logs, alertas e recuperação está em Monitoramento e recuperação de Agents. Este artigo adiciona campos de custo e objetos de orçamento.
Limites de alerta
Defina alertas por dimensão:
| Dimensão de alerta | Limite | Canal | Ação |
|---|---|---|---|
| Consumo global de orçamento | 70%, 90%, 100% | Slack/email | 70% avisar, 90% degradar, 100% cortar |
| Consumo de um user/tenant | Mais de 3x a média | Slack/email | Verificar chamadas anormais |
| Taxa de falha de um modelo | > 5% | Dashboard | Verificar roteamento ou estado do serviço |
| Retries de uma ferramenta | > limite | Dashboard | Verificar estabilidade da ferramenta |
| Cache hit rate | < esperado | Dashboard | Verificar estrutura do prompt |
Os limites devem ficar na lógica de custo para disparar alertas e circuit breakers automaticamente.
Estratégia de degradação
Depois de um alerta, a degradação pode seguir estes caminhos:
| Caminho de degradação | Método | Caso indicado | Impacto de custo |
|---|---|---|---|
| Degradação de modelo | Modelo grande -> modelo pequeno | Um modelo tem alta taxa de falha | Reduz custo, pode reduzir qualidade |
| Degradação de caminho | Realtime API -> Batch API -> Flex Processing | Orçamento global sendo consumido rápido demais | Aumenta latência, reduz custo |
| Degradação de função | Desativar ferramentas não essenciais | Uma ferramenta tem retries demais | Reduz overhead de ferramentas |
| Degradação de usuário | Rate limit, fila, mensagem “tente mais tarde” | Consumo anormal de um usuário | Evita que um usuário queime o orçamento |
A degradação deve morar na lógica de orçamento. Quando um alerta dispara, o sistema deve degradar automaticamente, não esperar intervenção manual.
Próximos passos
Controle de custos de Agents depende também de monitoramento, tool calling e context engineering:
- Publicado: Monitoramento e recuperação de Agents: campos de log, alertas e recuperação de falhas. Este artigo adiciona campos de custo e objetos de orçamento.
- Publicado: Arquitetura de Agent com LangGraph: checkpoints, thread state e recuperação para tarefas longas.
- Publicado: Tool Calling: fundamentos de chamadas de ferramentas. Este artigo adiciona per-tool budget, timeout e limite de retries.
- Mesma série: context engineering: prefixos estáveis, cache hits e que contexto vai no prefix estável versus variáveis de execução.
- Mesma série: Human-in-the-Loop: espera, rejeição, timeout de aprovação e como isso muda custos e retries.
Comece pela defesa em nível de sessão: configure um per-session cost limit e encerre automaticamente a sessão quando ela passar do orçamento. Essa é a primeira proteção mais rápida contra uma tarefa descontrolada que queima o orçamento do dia. Depois, expanda para camadas de orçamento, roteamento de modelos, orçamento de ferramentas, Prompt Caching, circuit breakers de retry e logs de custo.
Projetar orçamento de custo e circuit breaker para Agents
Use objetos de orçamento, roteamento de modelos, roteamento de serviço, cache, orçamento de ferramentas e circuit breakers de retry para antecipar o controle de custos antes de cada run.
⏱️ Estimated time: 45 min
- 1
Step 1: Listar todos os caminhos de custo
Liste chamadas de modelos, chamadas de ferramentas, leitura de arquivos, APIs externas, processamento batch, caches e caminhos de retry do Agent. - 2
Step 2: Definir o objeto de orçamento
Registre orçamento por tenant, user, run, workflow, model, tool, retry, cache e time window. - 3
Step 3: Configurar a estratégia de roteamento
Defina roteamento de modelo e roteamento de serviço para tipos diferentes de tarefa: online, batch, flex e queue. - 4
Step 4: Projetar cache hits
Coloque contexto estável no prompt prefix, conteúdo variável depois, e separe prompt caching, cache de resultado de negócio e cache de resposta de ferramenta. - 5
Step 5: Limitar ferramentas e retries
Dê a cada ferramenta timeout, max retries, idempotency key, per-tool budget e fallback. - 6
Step 6: Registrar spans de custo
Em cada run/span, registre token, cached token, tool, retry, latency, estimated cost, budget remaining e traceId. - 7
Step 7: Configurar degradação e circuit breaker
Defina limites de degradação, pausa, circuit breaker e alertas, e teste tudo com casos reais de falha.
FAQ
O custo de um Agent deve ser medido por usuário, sessão, tarefa ou ferramenta?
Roteamento de modelos é só usar um modelo pequeno em tarefas simples?
Qual é a diferença entre Prompt Caching e cache de negócio comum?
Quantas vezes devo tentar de novo uma chamada de ferramenta com falha?
O que fazer quando uma tarefa longa de Agent está quase sem orçamento?
Quais campos um log de custo deve registrar?
15 min de leitura · Publicado em: 17 set 2026
Guia de engenharia de AI Agents
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Design de agentes human-in-the-loop: quais etapas precisam de aprovação humana
Guia prático para definir pontos de aprovação em agentes de IA: ações automáticas, pausas obrigatórias, approve/reject/resume, timeouts, compensação e logs de auditoria.
Parte 10 de 13
Próximo
Modelo de permissões para agentes de IA: identidade do usuário, permissões de ferramentas, auditoria e isolamento de secrets
Antes de conectar um agente de IA a ferramentas reais, desenhe o modelo de permissões: mapeamento de identidade, service accounts, per-tool permission, scopes, secret vault, rotação de chaves, approval policy, data boundary e audit log.
Parte 12 de 13



Comentários
Entre com GitHub para comentar