O que são Tokens
Tokens são as unidades básicas que os LLMs usam para processar texto. Não são palavras, nem caracteres — são fragmentos subpalavra definidos pelo tokenizador do modelo (geralmente BPE — Byte Pair Encoding).
~4 chars por token (EN)
Regra de bolso para textos em inglês.
~3 chars por token (PT)
Português consome mais tokens que inglês — acentos e palavras compostas.
0.75 palavras por token
Aproximação média — útil para estimar custo de um corpus.
750 palavras ≈ 1.000 tokens
Uma página A4 tem cerca de 500 palavras, logo ~660 tokens.
Exemplos de Tokenização
"Hello world" -> ["Hello", " world"] = 2 tokens
"Tokenizacao" -> ["Token", "iza", "cao"] = 3 tokens
"def fibonacci(n):" -> ["def", " fibonacci", "(n):", ""] = 4 tokens
"rocket" -> [" rocket", " emoji", ...] = 3-5 tokens
# Emojis e caracteres especiais custam mais tokens!Input vs Output Tokens
- Input tokens: Tudo que você envia — system prompt + histórico + nova mensagem + contexto RAG.
- Output tokens: A resposta gerada. Geralmente 2-3x mais caros que input.
- Cache tokens: Anthropic e OpenAI oferecem preços reduzidos para partes do prompt em cache.
Como Contar Tokens
Contar tokens antes de enviar requisições permite estimar custo, respeitar limites e truncar contexto quando necessário.
Python — tiktoken (OpenAI/GPT)
import tiktoken
enc = tiktoken.encoding_for_model("gpt-4o")
text = "Ola mundo! Isso e um teste de tokenizacao."
tokens = enc.encode(text)
print(f"Tokens: {len(tokens)}") # -> 12
print(f"Custo estimado input: ${len(tokens) * 0.0000025:.6f}")
# Para mensagens formatadas (inclui overhead de roles)
def count_chat_tokens(messages, model="gpt-4o"):
enc = tiktoken.encoding_for_model(model)
total = 0
for msg in messages:
total += 4 # overhead por mensagem
total += len(enc.encode(msg["content"]))
return total + 2 # overhead inicialJavaScript — js-tiktoken
import { encodingForModel } from 'js-tiktoken';
const enc = encodingForModel('gpt-4o');
const tokens = enc.encode('Hello, world!');
console.log('Token count:', tokens.length);
// Para Anthropic - usar API de contagem
const { input_tokens } = await anthropic.messages.countTokens({
model: 'claude-sonnet-4-6',
system: systemPrompt,
messages: messages
});Estimativa Rápida Sem Biblioteca
// Regra de bolso: chars / 4 para ingles, chars / 3 para portugues
function estimateTokens(text: string, lang = 'pt'): number {
const divisor = lang === 'en' ? 4 : 3;
return Math.ceil(text.length / divisor);
}
// +/-20% de precisao - bom para estimativas rapidasCustos por Plataforma
Os preços abaixo são referência (por 1M tokens). Consulte sempre a página oficial do provedor, pois mudam frequentemente.
| Modelo | Input ($/1M) | Output ($/1M) | Cache Read |
|---|---|---|---|
| Claude Opus 4.7 | $15 | $75 | $1.50 |
| Claude Sonnet 4.6 | $3 | $15 | $0.30 |
| Claude Haiku 4.5 | $0.80 | $4 | $0.08 |
| GPT-4o | $2.50 | $10 | $1.25 |
| GPT-4o mini | $0.15 | $0.60 | $0.075 |
| o3 | $10 | $40 | $2.50 |
| Gemini 2.5 Pro | $1.25 | $10 | — |
| Gemini 2.5 Flash | $0.15 | $0.60 | — |
Calculando Custo Mensal
// Calculadora simples de custo
interface Usage { inputTokens: number; outputTokens: number }
interface Pricing { input: number; output: number } // por 1M tokens
function calcCost(usage: Usage, pricing: Pricing): number {
return (usage.inputTokens / 1_000_000) * pricing.input
+ (usage.outputTokens / 1_000_000) * pricing.output;
}
// Exemplo: 1000 requisicoes/dia de 2k input + 500 output com Sonnet
const daily = calcCost(
{ inputTokens: 1000 * 2000, outputTokens: 1000 * 500 },
{ input: 3, output: 15 }
);
console.log(`Custo diario: $${daily.toFixed(2)}`); // -> $13.50
console.log(`Custo mensal: $${(daily * 30).toFixed(2)}`); // -> $405Estratégias de Otimização
Reduzir tokens sem sacrificar qualidade é uma habilidade crítica em sistemas de IA de produção.
1. Prompt Compression
// Verboso (150 tokens)
"Por favor, analise cuidadosamente o seguinte codigo JavaScript que
foi enviado pelo usuario e forneca uma explicacao detalhada sobre o
que ele faz, incluindo possiveis problemas ou melhorias que possam
ser feitas para torna-lo mais eficiente e legivel."
// Conciso (45 tokens) - mesma instrucao
"Analise este codigo JS: explique o que faz, identifique problemas
e sugira melhorias de performance e legibilidade."2. Prompt Caching
// Anthropic: marque partes estaticas do prompt para cache
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-6',
system: [
{
type: 'text',
text: longStaticSystemPrompt, // 10.000 tokens
cache_control: { type: 'ephemeral' } // cacheia!
}
],
messages: userMessages
});
// Primeira req: cobra full. Seguintes: 90% desconto no system prompt.3. Gerenciar Contexto em Chat
// Estrategia: sliding window com resumo
class ContextManager {
private messages: Message[] = [];
private maxTokens = 50_000;
async add(msg: Message) {
this.messages.push(msg);
if (await this.countTokens() > this.maxTokens) {
await this.compress();
}
}
private async compress() {
// Resumir as mensagens mais antigas em um bloco
const oldest = this.messages.splice(0, 10);
const summary = await summarize(oldest);
this.messages.unshift({ role: 'system', content: '(Resumo: ' + summary + ')' });
}
}4. Structured Output
// Pedir JSON em vez de prosa reduz tokens da resposta
"Responda APENAS com JSON valido, sem explicacao:
{\"sentiment\": \"positive|negative|neutral\", \"confidence\": 0.0-1.0}"
// vs. pedir uma resposta em paragrafo que depois precisa ser parseadaFerramentas de Observabilidade
Observabilidade em IA vai além de logs — inclui tracing de chamadas, análise de qualidade e alertas de custo.
LangSmith
Da LangChain. Tracing completo, avaliação automática, dataset management. Melhor para projetos LangChain/LangGraph.
Helicone
Proxy transparente. Não muda código — só troca a base URL. Analytics, rate limiting, cache, retry automático.
Langfuse
Open-source. Auto-hostável. Tracing, feedback, scores, prompts versionados. Ótima alternativa a LangSmith.
Braintrust
Focado em avaliação e evals. Compara versões de prompts com dados reais. Excelente para prompt engineering.
OpenTelemetry + OTLP
Padrão aberto. Integra com Grafana, Datadog, etc. Bom se já tem stack de observabilidade.
Portkey
Gateway de IA com observabilidade, rate limiting, fallbacks e cache semântico.
Exemplo: Integração com Langfuse
import Anthropic from '@anthropic-ai/sdk';
import { Langfuse } from 'langfuse';
const langfuse = new Langfuse({
publicKey: process.env.LANGFUSE_PUBLIC_KEY,
secretKey: process.env.LANGFUSE_SECRET_KEY
});
async function chat(userMessage: string) {
const trace = langfuse.trace({ name: 'chat', userId: 'user-123' });
const span = trace.span({ name: 'llm-call' });
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-6',
max_tokens: 1024,
messages: [{ role: 'user', content: userMessage }]
});
span.end({
output: response.content[0].text,
usage: {
input: response.usage.input_tokens,
output: response.usage.output_tokens
}
});
await langfuse.flushAsync();
return response.content[0].text;
}Exemplo: Helicone (zero código)
// Apenas mude a base URL!
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
baseURL: 'https://anthropic.helicone.ai',
defaultHeaders: {
'Helicone-Auth': `Bearer ${process.env.HELICONE_API_KEY}`
}
});
// Pronto - 100% das chamadas sao monitoradas automaticamenteRate Limits e Quotas
Todos os provedores impõem limites de requisições e tokens por minuto/dia. Gerenciar bem esses limites é essencial para aplicações de produção.
Limites Comuns (Anthropic — Tier 1)
RPM
Requests per minute. Geralmente 50-1000 dependendo do tier e modelo.
TPM
Tokens per minute. Input + output. Ex: 40k TPM para Sonnet no tier 1.
TPD
Tokens per day. Limite diário acumulado. Reset a meia-noite UTC.
Retry com Exponential Backoff
async function callWithRetry<T>(
fn: () => Promise<T>,
maxRetries = 5
): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (e: any) {
if (e.status === 429) { // Rate limit
const delay = Math.min(1000 * 2 ** i + Math.random() * 1000, 60000);
console.log(`Rate limited. Aguardando ${delay}ms...`);
await new Promise(r => setTimeout(r, delay));
continue;
}
throw e; // Outros erros: nao retenta
}
}
throw new Error('Max retries exceeded');
}maxRetries na instanciação do cliente.Cache Semântico
Cache semântico armazena respostas de queries similares (não apenas idênticas) e as reutiliza, reduzindo drasticamente custos e latência.
import { Redis } from 'ioredis';
import { cosineSimilarity } from './utils';
class SemanticCache {
private redis: Redis;
private threshold = 0.95; // similaridade minima
async get(query: string): Promise<string | null> {
const queryEmbedding = await embed(query);
const keys = await this.redis.keys('cache:*');
for (const key of keys) {
const cached = JSON.parse(await this.redis.get(key)!);
const sim = cosineSimilarity(queryEmbedding, cached.embedding);
if (sim >= this.threshold) {
console.log(`Cache hit! Similaridade: ${sim.toFixed(3)}`);
return cached.response;
}
}
return null;
}
async set(query: string, response: string, ttl = 3600) {
const embedding = await embed(query);
const key = `cache:${Date.now()}`;
await this.redis.setex(key, ttl, JSON.stringify({ embedding, response }));
}
}Ferramentas de Cache Semântico Prontas
- GPTCache: Biblioteca Python com múltiplos backends (Redis, Milvus, FAISS).
- Portkey AI: Cache semântico como serviço, transparente na API.
- Prompt Cache (Anthropic/OpenAI): Cache nativo para system prompts longos.
Alertas e Dashboards
Configure alertas proativos antes que custos ou erros surpreendam em produção.
// Middleware de tracking de tokens por usuario/feature
import { EventEmitter } from 'events';
const tokenTracker = new EventEmitter();
interface TokenEvent {
userId: string;
feature: string;
model: string;
inputTokens: number;
outputTokens: number;
cost: number;
}
async function trackUsage(event: TokenEvent) {
// Persiste no banco
await db.tokenUsage.create({ data: event });
// Acumula por usuario no Redis (janela de 30 dias)
const key = `usage:${event.userId}:${new Date().toISOString().slice(0,7)}`;
await redis.incrbyfloat(key, event.cost);
await redis.expire(key, 60 * 60 * 24 * 35);
// Alerta se usuario passou de $10 no mes
const monthCost = await redis.get(key);
if (parseFloat(monthCost!) > 10) {
await sendAlert(`Usuario ${event.userId} passou $10 este mes`);
}
}Métricas Importantes para Monitorar
- Cost per request: Média e p95 de custo por chamada.
- Tokens per feature: Qual feature consome mais tokens.
- Cache hit rate: Percentual de chamadas servidas do cache.
- Error rate 429: Frequência de rate limit errors.
- Latency p50/p95/p99: Latência de ponta a ponta.
- Daily/monthly spend: Gasto total com alertas de threshold.