Construindo uma Calculadora de Custo Pré-Requisição com a API de Contagem de Tokens
Um pipeline que descobre o custo de uma requisição apenas após a resposta chegar não pode impor um orçamento; ele só pode relatar uma violação depois que o dinheiro já foi gasto.
messages.count_tokens fecha essa lacuna: ele retorna uma contagem exata de tokens de entrada sem executar o modelo, para que você possa precificar uma requisição antes que ela chegue ao endpoint de completude.
Esta página constrói uma calculadora de custo reutilizável em torno dessa chamada e, em seguida, a integra a um portão que pode rejeitar ou rebaixar uma requisição excessivamente grande antes que ela seja enviada.
Receita
Cartão de receita de referência rápida, pronto para copiar e colar.
import anthropic
client = anthropic.Anthropic()
RATES = {
"claude-sonnet-5": {"input": 2.00, "output": 10.00},
"claude-opus-4-8": {"input": 5.00, "output": 25.00},
"claude-haiku-4-5": {"input": 1.00, "output": 5.00},
}
def estimate_cost(client, model: str, max_tokens: int, **kwargs) -> float:
count = client.messages.count_tokens(model=model, **kwargs)
rate = RATES[model]
input_cost = (count.input_tokens / 1_000_000) * rate["input"]
worst_case_output_cost = (max_tokens / 1_000_000) * rate["output"]
return input_cost + worst_case_output_cost
cost = estimate_cost(
client,
model="claude-sonnet-5",
max_tokens=500,
messages=[{"role": "user", "content": "Rascunhe uma nota de lançamento para a v2.4."}],
)
print(f"${cost:.6f}")Quando usar isso:
- Você está construindo um pipeline onde uma única requisição incorreta ou excessivamente grande (por exemplo, um documento de 50 páginas colado por um usuário) pode estourar um orçamento por requisição ou por inquilino.
- Você deseja registrar um custo estimado junto com uma requisição antes que ela seja enviada, para fluxos de trabalho de observabilidade ou aprovação.
- Você está comparando o custo de rotear a mesma requisição para duas ou três camadas de modelos antes de escolher uma.
- Você precisa de um limite rígido para o custo em um pipeline automatizado, não apenas um aviso suave após o fato.
Exemplo de Trabalho
import anthropic
client = anthropic.Anthropic()
RATES = {
"claude-sonnet-5": {"input": 2.00, "output": 10.00},
"claude-opus-4-8": {"input": 5.00, "output": 25.00},
"claude-haiku-4-5": {"input": 1.00, "output": 5.00},
}
class BudgetExceeded(Exception):
pass
def estimate_cost(client, model: str, max_tokens: int, **request_kwargs) -> dict:
"""Retorna um detalhamento do custo de entrada estimado, custo de saída no pior caso e total."""
count = client.messages.count_tokens(model=model, **request_kwargs)
rate = RATES[model]
input_cost = (count.input_tokens / 1_000_000) * rate["input"]
worst_case_output_cost = (max_tokens / 1_000_000) * rate["output"]
return {
"input_tokens": count.input_tokens,
"input_cost": input_cost,
"worst_case_output_cost": worst_case_output_cost,
"worst_case_total": input_cost + worst_case_output_cost,
}
def send_with_budget(client, max_cost_usd: float, model: str, max_tokens: int, **request_kwargs):
"""Estima o custo, impõe um orçamento e, em seguida, envia a requisição apenas se ela couber."""
breakdown = estimate_cost(client, model, max_tokens, **request_kwargs)
if breakdown["worst_case_total"] > max_cost_usd:
raise BudgetExceeded(
f"Custo no pior caso ${breakdown['worst_case_total']:.4f} excede "
f"orçamento ${max_cost_usd:.4f} para o modelo {model}"
)
response = client.messages.create(model=model, max_tokens=max_tokens, **request_kwargs)
return response, breakdown
try:
response, breakdown = send_with_budget(
client,
max_cost_usd=0.02,
model="claude-sonnet-5",
max_tokens=500,
messages=[{"role": "user", "content": "Rascunhe uma nota de lançamento para a v2.4."}],
)
print(response.content[0].text)
print(f"Estimado: ${breakdown['worst_case_total']:.6f}")
except BudgetExceeded as e:
print(f"Rejeitado: {e}")O que isso demonstra:
estimate_costisola a matemática de precificação da requisição em si, para que possa ser reutilizada para registro, controle ou comparação sem duplicar a tabela de taxas.- A estimativa de saída no pior caso assume que todo o orçamento
max_tokensfoi consumido, fornecendo um limite superior conservador em vez de uma suposição otimista. send_with_budgetsó chamamessages.createapós a estimativa passar na verificação do orçamento, para que uma requisição rejeitada nunca chegue à API e nunca seja cobrada.- Levantar uma exceção dedicada
BudgetExceededpermite que o código de chamada distinga "muito caro" de um erro real da API e lide com cada um de forma diferente.
Mergulho Profundo
Como Funciona
messages.count_tokensaceita os mesmos parâmetrosmodel,system,toolsemessagesquemessages.create, portanto, ele conta exatamente os tokens de entrada que sua chamada real produziria.- Ele não aceita nem precisa de
max_tokens, pois nunca gera saída, apenas mede o lado de entrada. - A chamada em si não consome tokens faturáveis; é uma operação de medição, não uma operação de geração, portanto, chamá-la liberalmente em uma verificação pré-voo não adiciona custo significativo.
- O custo de saída só pode ser estimado, nunca contado exatamente, antes da chamada, porque o modelo ainda não gerou nada. Usar
max_tokenscomo o comprimento de saída assumido fornece um pior caso real, pois a API nunca gerará mais do que esse limite. - Para uma estimativa de saída mais precisa (mas não garantida), você pode rastrear uma média móvel de
output_tokensreais de chamadas semelhantes anteriores em vez de sempre assumir o tetomax_tokenscompleto.
Construindo uma Estimativa Mais Precisa com Médias Históricas
class RollingOutputEstimator:
"""Rastreia o uso real de tokens de saída por modelo para refinar a suposição do pior caso."""
def __init__(self):
self._history: dict[str, list[int]] = {}
def record(self, model: str, output_tokens: int) -> None:
self._history.setdefault(model, []).append(output_tokens)
def typical(self, model: str, fallback: int) -> int:
samples = self._history.get(model)
if not samples:
return fallback
return sum(samples) // len(samples)
estimator = RollingOutputEstimator()
def estimate_cost_v2(client, model: str, max_tokens: int, **request_kwargs) -> dict:
count = client.messages.count_tokens(model=model, **request_kwargs)
rate = RATES[model]
input_cost = (count.input_tokens / 1_000_000) * rate["input"]
typical_output = estimator.typical(model, fallback=max_tokens)
typical_output_cost = (typical_output / 1_000_000) * rate["output"]
return {"input_cost": input_cost, "typical_output_cost": typical_output_cost}Este padrão troca um limite superior garantido por uma estimativa mais realista assim que você tiver dados de uso reais, útil para painéis onde você deseja um número representativo em vez de um pior caso.
Parâmetros e Valores de Retorno
| Parâmetro | Tipo | Descrição |
|---|---|---|
model | str | Obrigatório, o mesmo identificador de modelo usado para messages.create. |
system | str | list | None | Opcional, espelha o system que você enviaria na requisição real. |
tools | list | None | Opcional, espelha as tools que você enviaria; grandes catálogos de ferramentas contam para input_tokens. |
messages | list | Obrigatório, a mesma lista de mensagens que você enviaria para messages.create. |
count.input_tokens | int | O valor de retorno: contagem exata de tokens de entrada para a forma da requisição dada. |
Armadilhas
- Esquecer de passar
systemetoolsparacount_tokens. Se sua requisição real incluir um prompt de sistema ou ferramentas, omiti-los da chamadacount_tokenssubcontará significativamente. Correção: sempre chamecount_tokenscom osystem/tools/messagesidêntico que você está prestes a enviar. - Assumir que
count_tokensestima a saída. Ele apenas retornainput_tokens; não há campo de saída, porque a saída não existe até que a geração aconteça. Correção: usemax_tokens(pior caso) ou uma média móvel (caso típico) para o lado da saída. - Tratar o total do pior caso como o custo esperado. Um portão de orçamento construído com
max_tokensfrequentemente rejeitará requisições que, na prática, teriam ficado bem abaixo do orçamento. Correção: use o portão do pior caso para aplicação rígida de orçamento, mas rastreie os custos reais separadamente para relatórios realistas. - Codificar taxas embutidas em vez de em uma tabela compartilhada. Espalhar literais
2.00e10.00pelo código torna uma atualização de precificação propensa a erros. Correção: mantenhaRATEScomo uma única fonte de verdade, idealmente carregada da configuração em vez de um literal Python, para que possa ser atualizada sem um deploy de código. - Não verificar novamente o orçamento após uma fallback de modelo. Se seu pipeline tentar novamente uma requisição rejeitada em um modelo mais barato, pular uma segunda chamada
estimate_costsignifica que você está confiando que a fallback se encaixa sem verificar. Correção: reexecute a estimativa para o modelo de fallback, não apenas assuma que "modelo mais barato" sempre significa "abaixo do orçamento". - Ignorar que as próprias taxas de precificação de
count_tokenspodem mudar. Uma tabela de taxas embutida no momento da criação ficará silenciosamente desatualizada da realidade após uma atualização de precificação. Correção: revise a tabela de taxas em uma programação, ou melhor ainda, carregue-a de uma fonte de configuração que você controla independentemente dos deploys de código.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
Portão count_tokens pré-requisição (esta página) | Você precisa rejeitar ou redirecionar antes de pagar por uma chamada | A latência para a própria verificação do portão é mais importante do que a precisão do orçamento |
Registro usage pós-requisição apenas | Você quer visibilidade de custo sem bloquear nenhuma requisição | Você precisa de um limite rígido de orçamento que nunca pode ser excedido |
| Estimativa aproximada de tokens por contagem de caracteres | Você precisa de uma estimativa rápida e aproximada sem ida e volta à API | Você precisa de números exatos para uma decisão de orçamento rígida |
| Limites de gastos no lado do servidor (nível de plataforma) | Você quer um backup para toda a conta, independente do código do aplicativo | Você precisa de granularidade por requisição ou por inquilino |
FAQs
Chamar count_tokens custa alguma coisa?
Não, é uma operação de medição que não executa o modelo nem gera saída, portanto, não consome tokens de entrada ou saída faturáveis.
count_tokens pode me dizer quantos tokens de saída uma requisição usará?
Não, os tokens de saída não existem até que a geração aconteça. O melhor que você pode fazer antes da chamada é uma estimativa do pior caso usando max_tokens, ou uma estimativa típica a partir de médias históricas.
Por que minha estimativa de custo do pior caso parece muito mais alta do que o que realmente foi cobrado?
Porque assume que o teto max_tokens completo foi usado como saída, o que é um limite superior real, não uma previsão de uso real. A maioria das completudes termina bem abaixo de seu limite max_tokens.
Cada requisição em meu pipeline deve passar por este portão?
É mais valioso para requisições de tamanho imprevisível, como documentos fornecidos pelo usuário, e menos necessário para chamadas internas de formato fixo onde você já sabe que a contagem de tokens é pequena e estável.
O que acontece se eu omitir system ou tools da chamada count_tokens?
Os input_tokens retornados subcontarão, pois refletem apenas o que você realmente passou. Sempre espelhe a forma exata da requisição que você pretende enviar.
Um estimador de média móvel é seguro para usar em um limite de orçamento rígido?
Não sozinho, pois pode subestimar em uma resposta incomumente longa. Use-o para relatórios ou avisos suaves e mantenha o pior caso de max_tokens para qualquer aplicação rígida.
Com que frequência devo atualizar a tabela RATES?
Sempre que as mudanças de preço forem anunciadas, e especialmente em torno de datas de transição conhecidas, como expirações de preços introdutórios. Armazenar taxas em configuração externa em vez de código torna isso uma atualização de dados, não um deploy.
Posso usar este mesmo padrão para comparar custos entre modelos antes de escolher um?
Sim, chame estimate_cost uma vez para cada modelo candidato com a mesma forma de requisição e compare os totais; isso é uma extensão direta deste padrão.
Este calculador leva em conta os descontos de cache de prompt?
Não como está escrito, ele assume tokens de entrada com preço integral. Uma versão ciente de cache precisaria saber qual parte do prefixo deve atingir o cache, o que count_tokens sozinho não pode informar.
Relacionado
- Noções Básicas de Economia de Tokens - os padrões subjacentes de
count_tokense uso nos quais esta calculadora se baseia. - Como Funciona Realmente a Precificação de Tokens do Claude - por que a tabela de taxas tem preços de entrada e saída separados por modelo.
- Tiering de Modelos: Roteando Tarefas Simples para Haiku, Tarefas Difíceis para Opus - usando uma estimativa de custo como uma entrada para uma decisão de roteamento.
- Economia da API em Lote: Quando 50% de Desconto Supera Chamadas em Tempo Real - estendendo este tipo de calculadora para comparar preços síncronos vs. em lote.
Versões da Stack: Escrito contra a linha de modelos Claude atual em ~junho de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (o padrão) e Claude Haiku 4.5 - e o SDK oficial
anthropicpara Python (última versão 0.x). Nomes de modelos, preços e versões de SDK mudam rapidamente - verifique os detalhes atuais em platform.claude.com/docs antes de confiar neles.