~/beer-and-code
▪ próximo evento AI Engineering Lab 3ª Edição — Da Arquitetura à Produção · 19—20 Set · 19 e 20 de setembro, das 09h às 13h — ao vivo via Google Meet garantir vaga
~ / tutoriais / quanto-custa-agente-ia-producao-conta-tokens $
Tutoriais

Quanto custa um agente de IA em produção: a conta real de tokens

LS Lucas Souza · · 13 min de leitura
Quanto custa um agente de IA em produção: a conta real de tokens

Seu protótipo custou R$ 12 no primeiro dia. Em produção, com 200 usuários, ele custa quase R$ 4.000 por mês. E ninguém no time sabe explicar por quê.

Quanto custa um agente de IA não é uma pergunta de tabela de preço. A resposta está na planilha que ninguém abre: quanto cada camada do agente (system prompt, definições de tool, chunks de RAG, histórico, tool results) empurra de token para dentro de cada chamada. Você não paga por pergunta. Você paga por contexto reenviado, turno após turno.

Neste post eu abro a conta de token de um agente em produção, linha a linha, com os preços públicos de hoje. Depois aplico três alavancas (compressão de prompt, pruning de histórico e seleção de contexto) e mostro a mesma planilha com os números depois. Corte final: 73%.

TL;DR

  • O que é: a anatomia de custo de token de um agente de suporte em produção, com planilha antes e depois.
  • Stack/Modelos: Claude Sonnet 5 (US$ 2/MTok entrada, US$ 10/MTok saída), tool calling, RAG, prompt caching, context editing.
  • Cenário: 200 usuários, 18 conversas/mês cada, 6 turnos por conversa, 12 tools declaradas.
  • Resultado: de US$ 728,64/mês (R$ 3.935) para US$ 196,67/mês (R$ 1.062), sem trocar de modelo e sem cortar feature.
  • Câmbio usado: R$ 5,40 por dólar. Ajuste para o câmbio do dia.

Onde o token vai embora: anatomia de uma chamada cara

Pega o turno 6 de uma conversa de suporte. O usuário digitou uma frase de 120 tokens. Foi isso que ele fez. Agora olha o que a sua aplicação mandou junto:

Camada Tokens de entrada % da chamada
System prompt (persona, regras, formato) 1.800 8,5%
Definições das 12 tools (JSON Schema) 4.200 19,9%
Chunks de RAG (5 × 600) 3.000 14,2%
Histórico dos 5 turnos anteriores 2.500 11,8%
Tool results acumulados (4 chamadas) 9.500 45,0%
Mensagem do usuário 120 0,6%
Total de entrada 21.120 100%

A pergunta do usuário é 0,6% da conta.

E três camadas que quase ninguém revisa (tool results, definições de tool e chunks de RAG) somam 79,1%. É aí que some o dinheiro. Não no modelo, não no output, não na "IA cara". Some em payload que você montou uma vez, achou razoável, e nunca mais mediu.

Custo dessa chamada única no Claude Sonnet 5, a US$ 2 por milhão de tokens de entrada e US$ 10 por milhão de saída, com 350 tokens de resposta:

entrada:  21.120 × $2  / 1.000.000 = $0,042240
saída:       350 × $10 / 1.000.000 = $0,003500
                                     ---------
total do turno 6:                    $0,045740

Quatro centavos e meio. Parece nada. Multiplica por 6 turnos, por 18 conversas, por 200 usuários, por 12 meses, e você tem um item de linha que o financeiro vai perguntar sobre.

Essa conta (e as decisões de arquitetura que a mudam: roteamento de tools, memória, grounding, tracing) é o módulo 11 do AI Engineering Lab 3ª Edição, imersão ao vivo nos dias 19 e 20 de setembro, das 9h às 13h. É onde a gente destrincha o agente inteiro, não só a camada de custo.

Como medir isso sem chutar

Não estime com tiktoken nem com "divide por 4". Meça com o endpoint de contagem, camada por camada, por diferença:

import anthropic

client = anthropic.Anthropic()
MODELO = "claude-sonnet-5"
PING = [{"role": "user", "content": "."}]

def tokens(**kwargs) -> int:
    return client.messages.count_tokens(
        model=MODELO, messages=PING, **kwargs
    ).input_tokens

piso       = tokens()
com_system = tokens(system=SYSTEM_PROMPT)
com_tools  = tokens(system=SYSTEM_PROMPT, tools=TOOLS)

print("system:", com_system - piso)      # 1.800
print("tools :", com_tools - com_system) # 4.200

Rode isso no CI. Se alguém adicionar a décima terceira tool, o diff mostra +380 tokens em toda chamada do produto, para sempre. Isso é uma decisão de arquitetura, não um commit de rotina.

O custo escondido do histórico que ninguém poda

Aqui está a parte que quebra o modelo mental de quem veio de API REST: numa conversa, você paga o turno 1 seis vezes.

O contexto é stateless. Cada chamada reenvia tudo. A conta cresce por turno:

Turno Entrada (tokens) Acumulado
1 9.120 9.120
2 11.520 20.640
3 13.920 34.560
4 16.320 50.880
5 18.720 69.600
6 21.120 90.720

Uma conversa de 6 turnos consome 90.720 tokens de entrada para 2.100 tokens de saída. Proporção de 43:1.

entrada: 90.720 × $2  / 1.000.000 = $0,181440
saída:    2.100 × $10 / 1.000.000 = $0,021000
                                    ---------
por conversa:                       $0,202440

Agora o mês: 200 usuários × 18 conversas = 3.600 conversas.

3.600 × $0,202440 = $728,64/mês  →  R$ 3.934,66

Contra R$ 12 do dia de teste (75 conversas curtas, de 3 turnos, sem tool result gordo acumulado). O protótipo não estava errado. Ele só media outra coisa.

A primeira alavanca é gratuita: prompt caching

A base fixa (system + tools) são 6.000 tokens idênticos em toda chamada. O prompt caching cobra escrita de cache a 1,25x o preço de entrada (TTL de 5 minutos) ou 2x (TTL de 1 hora), e leitura a 0,1x. Ou seja: a partir da segunda chamada, aquele bloco custa 10% do que custava.

O detalhe que trava gente: o mínimo cacheável é de 1.024 tokens no Sonnet 5 e 512 no Opus 5. Prefixo menor que isso não cacheia, e a API não reclama. Fica silenciosamente caro.

Dois breakpoints resolvem a conversa inteira. Um estático no fim do system (congela tools + system, que é a ordem de renderização) e um móvel no fim do histórico:

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    tools=TOOLS,
    system=[{
        "type": "text",
        "text": SYSTEM_PROMPT,
        "cache_control": {"type": "ephemeral"},   # congela tools + system
    }],
    messages=historico_com_breakpoint_movel + [nova_pergunta],
)

u = response.usage
total = u.input_tokens + u.cache_creation_input_tokens + u.cache_read_input_tokens
print(f"read={u.cache_read_input_tokens} write={u.cache_creation_input_tokens}")

Se cache_read_input_tokens vier zero em requisições repetidas, tem invalidador silencioso no seu prefixo: um datetime.now() no system prompt, um JSON de tools serializado sem ordenação estável, um user_id interpolado antes do breakpoint. Qualquer byte que muda no prefixo mata tudo que vem depois. Esse mecanismo é o mesmo que faz sua sessão de assistente de código evaporar, e eu já detalhei os sete jeitos de quebrar ele em como economizar tokens em Claude Code, Codex e Cursor.

Só com cache incremental, a mesma conversa cai de US$ 0,2024 para US$ 0,0877. O mês vai para US$ 315,72 (R$ 1.704). Corte de 57% sem tocar em uma linha do prompt.

Tool results: o maior vilão do contexto

45% da chamada mais cara são tool results. Vale entender por que isso acontece com quase todo agente.

Uma tool devolve o que a API devolve. Você chama consultar_pedido e recebe 2.400 tokens de JSON: endereço completo, histórico de status, dados do transportador, campos de auditoria, três níveis de objeto aninhado que ninguém lê. O modelo precisava de duas coisas: status e data prevista.

Pior: esse JSON fica no histórico. Turno 3 chamou a tool. Turno 6 ainda está pagando por ele. Quatro tool results acumulados viram 9.500 tokens que você reenvia até a conversa acabar.

Tem duas formas de podar isso, e elas resolvem problemas diferentes.

Na aplicação, antes de mandar. Você controla o formato. Projete o retorno da tool para o modelo, não para o log:

def podar_tool_results(messages, manter=3, resumo=200):
    """Mantém os N tool results mais recentes na íntegra.
    Os antigos viram uma linha de sumário."""
    indices = [i for i, m in enumerate(messages) if eh_tool_result(m)]
    for i in indices[:-manter]:
        messages[i] = resumir(messages[i], limite=resumo)
    return messages

No servidor, com context editing. A estratégia clear_tool_uses_20250919 limpa os tool results mais antigos antes do prompt chegar no modelo, mantendo os N mais recentes:

resp = client.beta.messages.create(
    model="claude-sonnet-5",
    max_tokens=4096,
    betas=["context-management-2025-06-27"],
    context_management={"edits": [{
        "type": "clear_tool_uses_20250919",
        "trigger": {"type": "input_tokens", "value": 30000},
        "keep": {"type": "tool_uses", "value": 3},
        "clear_at_least": {"type": "input_tokens", "value": 5000},
        "exclude_tools": ["consultar_pedido"],
    }]},
    tools=TOOLS,
    messages=messages,
)
print(resp.context_management.applied_edits)
# [{'cleared_tool_uses': 8, 'cleared_input_tokens': 50000}]

Cuidado com a interação: toda limpeza invalida o prefixo cacheado. Se você limpar 800 tokens e reescrever 12.000 de cache, você perdeu dinheiro. É exatamente para isso que serve o clear_at_least: só aplica a edição se ela valer o custo da reescrita.

A justificativa nem é só financeira. A documentação da Anthropic é direta: "contexto deve ser tratado como um recurso finito com retornos marginais decrescentes". Existe o efeito de context rot: conforme o número de tokens cresce, a capacidade do modelo de recuperar informação daquele contexto cai. Você paga mais para o agente errar mais.

▪ Clã Beer and Code

Tutorial te mostra o caminho — no Clã você constrói junto. Aula ao vivo toda semana, projetos reais de Engenharia de IA, ao lado de quem já está em produção.

Entrar no Clã

Compressão e pruning na prática, com números antes e depois

Três alavancas, aplicadas na mesma chamada do turno 6.

1. Compressão de prompt. O system prompt de 1.800 tokens tinha quatro exemplos few-shot que faziam a mesma coisa. Ficaram dois: 1.650. As 12 tools eram declaradas sempre, em toda chamada, mesmo quando a conversa era só sobre rastreio. Roteamento por domínio carrega 5: de 4.200 para 1.750.

2. Pruning de histórico e tool results. Os 3 tool results mais recentes ficam íntegros, os antigos viram sumário de uma linha: de 9.500 para 4.100. Os turnos 1 a 3 do histórico viram um parágrafo de resumo: de 2.500 para 1.400.

3. Seleção de contexto. Os 5 chunks de RAG entravam em toda chamada por default. Com rerank e corte por score, entram 2, e só quando a query pede recuperação: de 3.000 para 1.200.

O turno 6 depois:

Camada Antes Depois Delta
System prompt 1.800 1.650 -8%
Definições de tools 4.200 1.750 -58%
Chunks de RAG 3.000 1.200 -60%
Histórico 2.500 1.400 -44%
Tool results 9.500 4.100 -57%
Mensagem do usuário 120 120 -
Total 21.120 10.620 -49,7%

A conversa inteira cai de 90.720 para 46.020 tokens de entrada. Com os dois breakpoints de cache por cima:

Cenário Por conversa Por mês (3.600) Em reais
Baseline, sem cache, sem pruning $0,2024 $728,64 R$ 3.934,66
Só prompt caching $0,0877 $315,72 R$ 1.704,89
Caching + compressão + pruning $0,0546 $196,67 R$ 1.062,02

Corte de 73%. Mesmo modelo, mesma feature, mesma qualidade de resposta.

E repara no que mudou de figura: no cenário otimizado, os US$ 0,021 de saída viraram 38% do custo da conversa. Enquanto o input estava obeso, o output era ruído estatístico. Depois de podar, ele vira o próximo gargalo. É aí que entram limite de verbosidade, output_config.effort mais baixo em rotas simples e structured output para cortar preâmbulo.

Se o seu caso não precisa de resposta em tempo real (classificação em lote, enriquecimento noturno, geração de relatório), a Batch API corta mais 50% por cima disso, com a maioria dos lotes terminando em menos de uma hora.

O cálculo de margem: quando o produto não fecha a conta

Agora a parte que decide se o produto existe.

Assinatura de R$ 79 por usuário. 200 usuários. MRR de R$ 15.800.

Custo de token % da receita Custo por usuário
Baseline R$ 3.934,66 24,9% R$ 19,67
Otimizado R$ 1.062,02 6,7% R$ 5,31

SaaS vive de margem bruta de 70% a 80%. Com inferência comendo 25% da receita, antes de infra, observabilidade, suporte e folha, não sobra produto. Com 6,7%, sobra.

Mas a média mente. O que mata margem é a cauda.

Perfil Conversas/mês Custo otimizado Receita Resultado
Mediana 18 R$ 5,31 R$ 79 saudável
P95 90 R$ 26,55 R$ 79 apertado
P99 300 R$ 88,50 R$ 79 prejuízo de R$ 9,50

No baseline, esse mesmo usuário P99 custava R$ 327,89 por mês para pagar R$ 79. Um único power user destruía a margem de quatro clientes medianos.

Três consequências de produto, não de engenharia:

  1. Preço plano ilimitado só funciona se o teto de custo for arquitetural. Ou você limita turnos por conversa, ou você limita conversas por ciclo, ou você cobra por consumo. Não existe quarta opção.
  2. O custo por usuário precisa estar num dashboard, não num relatório trimestral. Grave input_tokens, cache_read_input_tokens, cache_creation_input_tokens e output_tokens por requisição, com user_id e rota. Uma tabela token_ledger e um gráfico. É meio dia de trabalho e paga o ano.
  3. Token é só um dos baldes. Eval em runtime, observabilidade, vector store, fila, pessoas. Se você quer a fatura completa de um agente ao longo de seis meses, é o que eu abri em Quanto custa um agente em produção em 2026: planilha real de TCO. Este post aqui é só a linha de inferência dela, aberta em camadas.

FAQ rápido

Afinal, quanto custa um agente de IA em produção?

Depende quase inteiramente de quantos tokens você reenvia por turno, não do preço do modelo. No cenário deste post, o mesmo agente custa entre R$ 1.062 e R$ 3.935 por mês para os mesmos 200 usuários. A variável não é o vendor. É a sua arquitetura de contexto.

O preço por token não está caindo? Não é melhor esperar?

O preço por token cai, mas o consumo por tarefa sobe mais rápido, porque agente novo faz mais turnos e usa mais tool. É uma discussão de mercado que eu destrinchei em IA vai ficar mais cara?. Para a sua planilha do mês que vem, o preço de lista é a variável que você não controla. Contexto é a que você controla.

Trocar de modelo não resolve mais rápido que otimizar contexto?

Às vezes, e vale medir. Mas cache é escopado por modelo: uma cascata de dois modelos abre dois namespaces de cache e você perde reuso nos dois. Faça a higiene de contexto primeiro (que é grátis), meça de novo, e só então troque de modelo com dado na mão.

Por que meu cache_read_input_tokens vive zerado?

Alguma coisa no prefixo muda a cada chamada. Os suspeitos de sempre: timestamp no system prompt, ordenação não determinística no JSON das tools, ID de sessão interpolado antes do breakpoint, ou prefixo menor que o mínimo cacheável do modelo (1.024 tokens no Sonnet 5). Log o usage cru de duas chamadas seguidas e compare byte a byte.

Fechando a planilha: quanto custa um agente de IA no seu caso

A conta de um agente em produção não é um número que você descobre. É um número que você projeta.

Cada tool que entra, cada exemplo few-shot que alguém cola no system prompt, cada chunk de RAG a mais no top-k: tudo isso é uma decisão de custo recorrente, multiplicada por todo turno de toda conversa de todo usuário. E quase nada disso aparece em code review.

O caminho é sempre o mesmo: meça por camada, cacheie o que é estável, pode o que é velho, selecione o que é relevante. Nessa ordem. Nesse cenário deu 73% de corte sem trocar de modelo.

Depois de fechar a linha de inferência, o próximo passo é olhar os cinco baldes que sobraram (eval, observabilidade, infra, dados e gente) e decidir build vs buy com número na mão.

Você sabe quanto custa a última chamada que o seu agente fez? Se a resposta for "não", esse é o primeiro bug para corrigir.

Lucas Souza
Escrito por
Lucas Souza

{AI Engineer} — apaixonado por Laravel, arquitetura de software e construir produtos com impacto. Compartilho aqui tutoriais, descobertas e reflexões sobre o dia a dia de engenharia.

▪ Clã Beer and Code

Conteúdo é o que não falta. Falta quem desembaralhe: o que importa agora é como implementar do jeito certo. No Clã você tem isso ao vivo, toda semana, com quem já filtrou o ruído.

Entrar no Clã
Conheça o Clã Beer and Code
tocando