12k
All articles

Como Contar Tokens e Estimar Custos de APIs de LLM

Conte tokens de LLM com precisão e estime custos de API com os tokenizers de OpenAI, Claude, Gemini e Llama, além de contexto e cobrança.

OpenReplay Team
OpenReplay Team
Como Contar Tokens e Estimar Custos de APIs de LLM

Para contar tokens com precisão, execute o corpo completo da requisição pelo tokenizador do modelo que você está realmente chamando e, em seguida, estime o custo como (input_tokens ÷ 1.000.000) × input_rate + (output_tokens ÷ 1.000.000) × output_rate, usando as taxas atuais obtidas na página de preços do provedor.

Ninguém calcula isso com antecedência. O assunto surge na manhã em que a fatura chega, ou na tarde em que uma conversa longa começa a lançar erros de janela de contexto para usuários reais, e de repente “quantos tokens tem isso?” passa a ser a única pergunta que importa. A parte incômoda é que um token não é uma palavra, a contagem depende do modelo, e metade do que é cobrado nunca aparece na string do seu prompt.

Este artigo apresenta o método repetível: quando uma estimativa aproximada é suficiente, como obter uma contagem exata em cada provedor, o que realmente é cobrado e como transformar contagens em uma projeção de custo que sobreviva a uma mudança de preços.

Principais Conclusões

  • Conte tokens com o tokenizador do modelo que você está chamando: tiktoken para OpenAI, messages.countTokens para Claude, countTokens para Gemini e o próprio tokenizador do modelo no Hugging Face para Llama.
  • Heurísticas como caracteres ÷ 4 são aceitáveis para planejamento de capacidade, mas nunca para faturamento; elas falham com código, JSON, textos em idiomas diferentes do inglês e emojis.
  • O prompt cobrado é o corpo completo da requisição, incluindo system prompt, estruturação de roles, schemas de ferramentas e histórico de conversa reenviado — não apenas a mensagem do usuário.
  • As contagens de tokens de entrada são determinísticas, as de saída não: colete amostras de 50 a 200 requisições reais, planeje o custo a partir do comprimento médio da saída e defina max_tokens com base no p95.
  • O custo estimado por requisição é (input_tokens ÷ 1M) × input_rate + (output_tokens ÷ 1M) × output_rate, com as taxas lidas ao vivo na página de preços do provedor.

Por Que um Token Não É uma Palavra?

Um token é uma unidade de texto específica de cada modelo, produzida por um tokenizador de subpalavras, e não corresponde nem a palavras nem a caracteres. Tokenizadores baseados em byte pair encoding, como o tiktoken da OpenAI, mesclam sequências de caracteres vistas com frequência em tokens únicos e dividem palavras raras em vários pedaços. A palavra “idempotency” é codificada em quatro tokens (“id”, “emp”, “ot”, “ency”) no cl100k_base, o encoding da era GPT-4, e em três (“id”, “empot”, “ency”) no o200k_base, o encoding usado pelos modelos atuais da OpenAI.

Esse último ponto é o que importa para o faturamento: a divisão é específica do modelo. A mesma frase produz contagens diferentes nos tokenizadores de GPT, Claude, Gemini e Llama, porque cada um foi treinado com dados distintos e um vocabulário distinto. Qualquer contagem feita com o tokenizador errado é um palpite.

Quando uma Estimativa Aproximada É Suficiente?

Para prosa em inglês, caracteres ÷ 4 ou palavras × 1,33 chega perto o bastante para dimensionar uma coluna de banco de dados ou esboçar um plano de capacidade. Use heurísticas para planejamento de capacidade, nunca para faturamento ou decisões sobre janela de contexto.

As heurísticas falham exatamente onde vive o tráfego de produção: código, JSON, textos em idiomas diferentes do inglês e emojis. Payloads estruturados são tokenizados com base em padrões de pontuação e espaçamento que a contagem de caracteres ignora, e um único emoji pode se expandir em vários tokens, de modo que caracteres ÷ 4 subestima gravemente strings com muitos emojis. Diferenças entre tokenizadores que permanecem modestas em prosa em inglês crescem de forma significativa em código e dados estruturados, que são precisamente o tipo de conteúdo que um sumarizador ou agente envia.

Qual Contador de Tokens de LLM Fornece uma Contagem Exata?

O princípio cabe em uma linha: conte com o tokenizador que pertence ao modelo que você está chamando. Os caminhos por provedor:

ProvedorRota para contagem exata
OpenAItiktoken, ou js-tiktoken em Node e edge runtimes
Anthropico endpoint count-tokens, client.messages.countTokens() no SDK TypeScript
Geminiai.models.countTokens() no SDK @google/genai
Llama e outros modelos abertoso próprio tokenizador do modelo publicado no Hugging Face

Em JavaScript, o js-tiktoken é um port em JS puro, então não há binário WASM para carregar nem memória para liberar manualmente, e você pode importar apenas um encoding em vez do conjunto completo, o que mantém o bundle pequeno:

import { Tiktoken } from "js-tiktoken/lite";
import o200k_base from "js-tiktoken/ranks/o200k_base";

const enc = new Tiktoken(o200k_base);
const count = enc.encode("Summarise this ticket thread for support.").length;

O endpoint da Anthropic é gratuito para chamar, sujeito apenas aos seus próprios limites de taxa, portanto não há desculpa de custo para aproximar contagens do Claude com o tokenizador de outro provedor. Trate o resultado como a contagem pré-voo autoritativa, não como uma contagem exata: a Anthropic a documenta como uma estimativa, e o valor cobrado vem dos campos de usage da resposta. Os tokenizadores também mudam entre gerações de modelos dentro de um mesmo provedor. A documentação de contagem de tokens da Anthropic coloca o Claude 4.7 e versões posteriores em um tokenizador mais novo que transforma o mesmo texto em aproximadamente 30% mais tokens do que nos modelos Claude anteriores, e a diferença exata depende do seu conteúdo. Uma contagem antiga não é transferível; faça uma nova contagem no modelo que você está realmente chamando. E quando você só quer o número sem integrar um SDK, cole o prompt em um contador de tokens de LLM que cobre GPT, Claude, Gemini e Llama.

Por Que Minha Contagem Não Corresponde à Fatura?

O prompt cobrado é o corpo completo da requisição, não a string que você escreveu. A estruturação de roles, o system prompt, os schemas de ferramentas e funções e os separadores por mensagem todos adicionam tokens, e é por isso que contar apenas a mensagem do usuário sempre subestima. Uma única definição de ferramenta pode adicionar centenas de tokens de entrada a cada requisição que a carrega.

O histórico da conversa é o multiplicador. Um recurso de chat reenvia todo o histórico em cada turno, então a entrada de cada turno inclui todos os turnos anteriores, e o custo por conversa cresce de forma superlinear com o comprimento da conversa. A solução para a contagem é simples: monte exatamente o array de messages, o system prompt e as tools que você vai enviar, e conte isso. O endpoint count-tokens da Anthropic recebe o mesmo payload que você teria enviado para criar a mensagem, definições de ferramentas incluídas, então você pode passar a requisição montada diretamente para ele.

Como Transformo Contagens de Tokens em uma Estimativa de Custo?

O custo estimado por requisição é uma linha de aritmética, mantida em termos simbólicos:

cost = (input_tokens / 1_000_000) * input_rate + (output_tokens / 1_000_000) * output_rate

Quando os provedores suportam prompt caching, os tokens de entrada em cache são cobrados a uma cached_input_rate separada e mais baixa. Os preços por modelo mudam em questão de semanas, então nenhuma taxa é impressa aqui. Trate as taxas como configuração injetada no seu código, leia os valores atuais na página de preços do provedor e use uma calculadora de custos de LLM para comparar os números atuais entre modelos.

Dois fatos moldam toda estimativa. Primeiro, os tokens de saída geralmente têm uma taxa significativamente mais alta do que os de entrada nos principais provedores, então o comprimento da resposta muitas vezes domina o custo. Segundo, as contagens de entrada são determinísticas enquanto as de saída não são: a mesma requisição sempre conta o mesmo na entrada, mas o que volta varia conforme a amostragem. Meça a saída empiricamente. Execute de 50 a 200 requisições representativas, planeje o custo a partir do comprimento médio da saída e defina max_tokens com base no percentil 95, para que respostas legítimas não sejam truncadas enquanto gerações descontroladas permanecem limitadas.

Como Sei Se um Prompt Cabe na Janela de Contexto?

Os tokens de entrada mais os tokens de saída esperados devem caber dentro da janela de contexto do modelo, ou a chamada falha por completo ou a resposta é truncada. A verificação pré-voo pertence ao seu wrapper de requisição: distribua o orçamento da janela entre contexto de sistema, histórico da conversa e margem para a saída, conte a requisição montada e reduza o histórico antes de enviar, em vez de depois de um erro. Um verificador de janela de contexto diz se um determinado prompt cabe em um determinado modelo sem que você precise memorizar tamanhos de janela que mudam a cada lançamento.

A localização do wrapper importa porque um estouro é visível para o usuário: uma resposta truncada ou um erro no meio do streaming, e o reflexo do usuário é tentar novamente, então um bug de orçamento de tokens é cobrado duas vezes. Session replays de funcionalidades baseadas em LLM revelam exatamente esse loop de retentativas, muito antes de ele aparecer em uma fatura revisada mensalmente.

O Que Registrar em Produção

O método é estável, mesmo que os preços não sejam: conte a requisição montada com o próprio tokenizador do modelo chamado, colete amostras de tráfego real para conhecer sua distribuição de saída e mantenha as taxas como configuração que você atualiza a partir das páginas de preços. Depois, feche o ciclo em produção. Todos os principais provedores retornam as contagens reais de tokens nos campos de usage da resposta, como usage.input_tokens da Anthropic e usageMetadata do Gemini, embora a nova Interactions API do Gemini, ainda em Beta, retorne usage com total_input_tokens e total_output_tokens. Registre-os por requisição desde o primeiro dia; gravá-los é trivial, reconstruí-los depois que a fatura surpreendente chega não é.

Perguntas Frequentes

Posso usar o tiktoken para contar tokens de modelos Claude ou Gemini?

Não. O tokenizador de cada provedor tem seu próprio vocabulário, então uma contagem com tiktoken só é válida para modelos da OpenAI e pode divergir substancialmente para a mesma entrada no Claude ou no Gemini. Use o endpoint count-tokens da Anthropic, que é gratuito, para o Claude; o método countTokens no SDK @google/genai para o Gemini; e o tokenizador publicado no Hugging Face para modelos abertos como o Llama.

Qual é a diferença entre os pacotes npm tiktoken e js-tiktoken?

tiktoken é um binding WASM: ele carrega um binário compilado e exige chamar free() para liberar a memória do encoder quando você terminar. js-tiktoken é um port em JavaScript puro com métodos em camelCase (getEncoding, encodingForModel), sem binário WASM e sem gerenciamento manual de memória, o que o torna a escolha mais segura para runtimes edge e serverless. Importar um único arquivo de ranks de encoding mantém o tamanho do bundle pequeno.

Respostas em streaming também informam o uso de tokens?

Sim, mas não por padrão em todos os casos. Para o Chat Completions da OpenAI, defina stream_options com include_usage igual a true e a API envia um chunk final extra cujo campo usage cobre toda a requisição e cujo array choices está vazio. A Anthropic envia o usage automaticamente: o evento message_start carrega input_tokens e os eventos message_delta carregam output_tokens cumulativos. Registre esses campos em vez de contar você mesmo os chunks transmitidos.

Qual encoding do tiktoken devo usar para cada modelo da OpenAI?

Use o200k_base para os modelos atuais da OpenAI, como gpt-4o e posteriores, e cl100k_base apenas para modelos da era GPT-4. Os dois encodings dividem o texto de formas diferentes, então uma contagem feita com um não se transfere para o outro. Dado um ID de modelo, encodingForModel no js-tiktoken seleciona o encoding correspondente para você, o que evita fixar o encoding errado conforme os modelos mudam.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.