Se você já colocou uma aplicação de IA generativa em produção, conhece a sensação: a solução funciona lindamente na POC e, quando o volume cresce, a fatura de tokens vira o assunto da reunião. A boa notícia é que grande parte desse custo é desperdício evitável — você está pagando, repetidamente, para o modelo “reler” o mesmo contexto a cada chamada.
O prompt caching resolve exatamente isso. Neste artigo eu explico o que é, como funciona por baixo do capô, mostro a arquitetura, dou exemplos reais nas três plataformas que mais uso (Anthropic, Azure OpenAI e GitHub Models) e fecho com a matemática de custo e as boas práticas que separam quem economiza de quem só acha que economiza.
O problema: LLMs não têm memória entre chamadas
Modelos de linguagem são stateless. Cada requisição à API é independente: o modelo não “lembra” da chamada anterior. Para dar continuidade a uma conversa ou fornecer contexto (um documento, instruções de sistema, exemplos few-shot), você precisa reenviar tudo a cada requisição.
Na prática, um prompt típico de produção é composto assim:
[ System prompt + instruções ] <- grande, estável, repetido sempre [ Documentos / base de conhecimento ] <- grande, muda pouco [ Histórico da conversa ] <- cresce a cada turno [ Pergunta atual do usuário ] <- pequeno, sempre diferente
O problema fica evidente com números. Imagine um assistente com 30.000 tokens de contexto fixo (instruções + documentação) e uma pergunta de 200 tokens. A cada mensagem você paga por 30.200 tokens de entrada — sendo que 30.000 são exatamente iguais à chamada anterior. Multiplique por milhares de requisições e você entende de onde vem a conta.
Numa das minhas análises reais de consumo, uma ferramenta de IA acumulou ~195 milhões de tokens de entrada em 638 chamadas — cerca de 305 mil tokens por chamada. Isso só é possível quando o mesmo contexto enorme é reenviado a cada interação. É o cenário perfeito para caching.
O que é prompt caching
Prompt caching é a capacidade do provedor de armazenar o estado interno de processamento de um trecho do prompt (o prefixo) e reutilizá-lo em chamadas seguintes, em vez de reprocessá-lo do zero.
Tecnicamente, o que fica em cache não é o texto — é o resultado da computação do modelo sobre aquele texto: os estados de atenção (KV cache) das camadas do transformer para aqueles tokens. Quando você reenvia o mesmo prefixo, o provedor reconhece o hash e “pula” o trabalho pesado de recomputar essas ativações.
O efeito é duplo:
- Custo menor — tokens lidos do cache custam uma fração do preço normal (tipicamente ~10%).
- Latência menor — pular o pré-preenchimento (prefill) de dezenas de milhares de tokens acelera o time-to-first-token de forma perceptível.
A regra de ouro: o cache é por prefixo exato
Esta é a parte que mais gente erra. O cache funciona sobre o prefixo do prompt, da esquerda para a direita, e exige correspondência byte a byte. Se o primeiro caractere mudar, todo o cache a partir dali é invalidado.
Chamada 1: [A][B][C][pergunta_1] -> processa tudo, grava cache de [A][B][C] Chamada 2: [A][B][C][pergunta_2] -> cache HIT em [A][B][C], processa só a pergunta OK Chamada 3: [X][A][B][C][pergunta_3] -> prefixo mudou no início, cache MISS total
Corolário prático: coloque o conteúdo estável no começo e o variável no fim.
Arquitetura
O diagrama abaixo mostra o caminho de uma requisição com caching e onde o ganho acontece.
Usuário / App
|
(prefixo estável + entrada variável)
v
Gateway / SDK
|
v
API do provedor LLM
|
Prefixo já está em cache?
/ \
HIT MISS
| |
Lê KV-cache Processa do zero
~10% do input grava no cache
latência menor ~125% do input
\ /
\ /
v v
Geração da resposta (saída = preço normal)
|
v
Resposta -> Usuário
Anatomia de um prompt otimizado para cache:
|============ PREFIXO CACHEÁVEL (não muda) ============|== SUFIXO DINÂMICO ==|
[ System prompt ] [ Documentos / RAG ] [ Few-shot ] || [ Histórico ] [ Pergunta ]
^
cache breakpoint (cache_control)
A ideia central: você marca um ponto de corte (breakpoint) logo depois do bloco estável. Tudo à esquerda vira candidato a cache; tudo à direita é sempre recomputado.
Exemplos práticos
1. Anthropic (Claude) — controle explícito
Na API da Anthropic o caching é explícito: você marca os blocos com cache_control. É o modelo mais transparente e o que dá mais controle.
import anthropic
client = anthropic.Anthropic()
DOC_GRANDE = open("manual_produto.md").read() # ex.: 30k tokens
response = client.messages.create(
model="claude-opus-4-20250514",
max_tokens=1024,
system=[
{
"type": "text",
"text": "Você é um especialista de suporte técnico. Cite a seção do manual.",
},
{
"type": "text",
"text": DOC_GRANDE,
# tudo ATÉ AQUI vira um bloco cacheável
"cache_control": {"type": "ephemeral"},
},
],
messages=[
{"role": "user", "content": "Como faço o rollback de uma release?"}
],
)
print(response.usage)
# cache_creation_input_tokens : tokens gravados no cache (1a vez, ~1,25x)
# cache_read_input_tokens : tokens lidos do cache (~0,1x)
# input_tokens : tokens novos processados normalmente
Pontos-chave da Anthropic:
- Você pode ter até 4 breakpoints de cache.
- TTL padrão de 5 minutos (há opção estendida de 1 hora com preço diferente).
- A primeira escrita custa ~1,25× o input normal; leituras subsequentes custam ~0,1×.
- Requer um mínimo de tokens para ativar (ex.: ~1024 para Opus/Sonnet).
2. Azure OpenAI — caching automático
No Azure OpenAI (e OpenAI direto), o caching é automático e transparente para prompts acima de ~1.024 tokens. Você não marca nada; o serviço detecta prefixos repetidos.
from openai import AzureOpenAI
client = AzureOpenAI(
api_version="2024-10-21",
azure_endpoint="https://SEU-RECURSO.openai.azure.com",
)
SYSTEM = "Instruções longas e estáveis... (>1024 tokens para ativar o cache)"
resp = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": SYSTEM}, # prefixo estável primeiro
{"role": "user", "content": "Pergunta variável do usuário"},
],
)
# O ganho aparece em usage.prompt_tokens_details.cached_tokens
print(resp.usage.prompt_tokens_details.cached_tokens)
Pontos-chave do Azure OpenAI:
- Automático — ativa a partir de 1.024 tokens de prompt, em blocos de 128.
- Tokens em cache costumam ter desconto significativo sobre o input.
- Você não controla o breakpoint: por isso a disciplina de “estável primeiro, variável depois” é ainda mais importante.
- Métrica em
usage.prompt_tokens_details.cached_tokens.
3. GitHub Models — prototipagem e produção leve
O GitHub Models expõe modelos (incluindo família OpenAI e outros) por uma API compatível com OpenAI, ótimo para prototipar. O caching segue o comportamento do provedor subjacente (automático nos modelos OpenAI).
from openai import OpenAI
client = OpenAI(
base_url="https://models.github.ai/inference",
api_key="SEU_GITHUB_TOKEN", # PAT com escopo de models
)
resp = client.chat.completions.create(
model="openai/gpt-4o",
messages=[
{"role": "system", "content": "Contexto estável e longo aqui..."},
{"role": "user", "content": "Pergunta do usuário"},
],
)
print(resp.choices[0].message.content)
Atenção ao modelo de cobrança do GitHub Models: o plano gratuito é por rate limit (ótimo para experimentar), e o uso pago é medido em requisições/tokens. Para produção com alto volume, o caminho natural é migrar para Azure OpenAI mantendo o mesmo código (API compatível).
A matemática do custo
Vamos aos números com um exemplo concreto. Suponha o modelo Opus com preços de referência de $15 por milhão de tokens de entrada e $75 por milhão de saída, e um workload de 638 chamadas, ~195M tokens de entrada (dominados por contexto repetido) e ~1,12M tokens de saída.
Cenário A — sem caching
| Item | Tokens | Preço | Custo |
|---|---|---|---|
| Entrada | 195M | $15/M | $2.925,00 |
| Saída | 1,12M | $75/M | $84,00 |
| Total | ≈ $3.009 |
Cenário B — com 90% de cache hit
Cache read a ~$1,50/M (10% do input). 90% da entrada vira leitura de cache, 10% é processada normalmente:
| Item | Tokens | Preço | Custo |
|---|---|---|---|
| Entrada — cache read (90%) | 175,4M | $1,50/M | $263,10 |
| Entrada — normal (10%) | 19,5M | $15/M | $292,50 |
| Saída | 1,12M | $75/M | $84,00 |
| Total | ≈ $640 |
Resultado: de ~$3.009 para ~$640 — uma redução de ~79% na fatura, sem mudar uma linha da lógica de negócio. Em workloads com contexto muito grande e estável, a economia real frequentemente passa dos 80%.
Fórmula geral
custo_input = tokens_normais * preço_input
+ tokens_cache_write * (preço_input * 1.25)
+ tokens_cache_read * (preço_input * 0.10)
custo_total = custo_input + tokens_saída * preço_saída
O ponto de equilíbrio: como a escrita custa 1,25× e a leitura 0,10×, o cache “se paga” a partir de ~2 leituras do mesmo prefixo. Ou seja, qualquer contexto reutilizado mais de uma vez em poucos minutos já vale a pena.
Boas práticas de produção
- Estável primeiro, variável por último. System prompt, instruções, documentos e few-shots no começo; histórico e pergunta no fim. É o requisito nº 1 para qualquer caching funcionar.
- Não injete conteúdo volátil no prefixo. Timestamps, IDs de sessão, “hora atual”, nomes de usuário no meio do system prompt — tudo isso quebra o cache. Mova para o fim ou remova.
- Padronize o prefixo entre chamadas. Whitespace, ordem de campos, serialização de JSON — qualquer diferença byte a byte causa miss. Gere o prefixo de forma determinística.
- Respeite o TTL. O cache é efêmero (~5 min). Requisições esparsas não se beneficiam. Se o tráfego for intermitente, considere o TTL estendido (onde disponível) ou “aquecer” o cache com um ping periódico.
- Meça de verdade. Instrumente
cache_read_input_tokens/cached_tokense acompanhe a taxa de cache hit como um KPI de FinOps. Sem medir, você está adivinhando. - Segmente por versão. Ao mudar o system prompt, você invalida todo o cache. Faça deploys de prompt de forma consciente e agrupe requisições pela mesma versão.
- Combine com outras técnicas. Caching reduz o custo do input, mas não substitui RAG bem feito, truncamento de histórico e escolha adequada de modelo (nem tudo precisa de Opus).
- Cuidado com dados sensíveis. O cache é isolado por conta/organização, mas trate contexto com PII com as mesmas políticas de governança do resto do pipeline.
Onde o caching NÃO ajuda
- Prompts curtos e sempre diferentes. Sem prefixo estável significativo, não há o que cachear.
- Prefixos abaixo do mínimo (ex.: menos de 1024 tokens): o caching nem ativa.
- Tráfego muito esparso, com intervalos maiores que o TTL entre chamadas semelhantes.
- Redução de tokens de saída: caching age no input; a geração continua no preço cheio.
Checklist de implementação
- O bloco estável (system + docs + few-shot) está no início do prompt?
- Todo conteúdo volátil (timestamps, IDs) foi movido para o fim?
- O prefixo é gerado de forma determinística (mesmo byte a byte)?
- O prefixo estável tem mais de ~1.024 tokens?
- Você está medindo a taxa de cache hit em produção?
- As chamadas semelhantes acontecem dentro do TTL (~5 min)?
- (Anthropic) Os
cache_controlestão nos pontos certos? - (Azure/OpenAI) Você confia no caching automático e organizou o prompt para ele?
Conclusão
Prompt caching é uma das poucas otimizações de IA generativa que entrega ganho grande com esforço pequeno: você reorganiza o prompt, marca (ou confia no) breakpoint e passa a pagar uma fração pelo contexto repetido. No exemplo real deste artigo, foi a diferença entre uma fatura de ~$3.000 e ~$640 para o mesmo trabalho.
O segredo não é mágico — é disciplina de arquitetura: contexto estável primeiro, conteúdo variável por último, e medição constante. Faça isso, e o caching deixa de ser um detalhe técnico para virar uma alavanca real de FinOps na sua plataforma de IA.
