Cache de prompts explicado: quando economiza dinheiro e quando não
Às 9:12 da manhã de uma segunda-feira, um dos nossos agentes de suporte começou a custar 4x a mais do que o esperado.
O modelo não estava alucinando, o gráfico de tráfego não estava errado e ninguém havia trocado acidentalmente de Haiku para Opus. O problema era mais simples: cada requisição incluía o mesmo manual de políticas de 42,000 tokens, mas nossa taxa de acertos no cache de prompts era praticamente zero porque estávamos inserindo um novo registro de data e hora e metadados específicos do usuário antes do manual.
Mesmo conteúdo. Mesmo modelo. Mesma aplicação. Nenhuma economia com cache.
O cache de prompts é um daqueles recursos que parecem automáticos até você tentar reduzir a conta. Na prática, ele favorece uma estrutura de prompt muito específica: um prefixo grande e estável, reutilizado em muitas requisições. Se você entender essa frase, geralmente conseguirá prever se o cache vai economizar dinheiro ou, silenciosamente, não fazer diferença.
O que o cache de prompts realmente armazena
O cache de prompts não é memória semântica. O provedor não está dizendo: “Isso parece semelhante a algo que você enviou antes.” É mais próximo de:
“O início desta requisição corresponde suficientemente a uma sequência anterior de tokens, considerando este modelo e esta política de cache, então podemos reutilizar o processamento interno desse prefixo.”
Essa distinção importa.
O cache de prompts geralmente ajuda quando você envia repetidamente o mesmo prefixo longo:
- Instruções de sistema
- Esquemas de ferramentas
- Conjuntos extensos de documentação
- Catálogos de produtos
- Contexto da base de código
- Manuais jurídicos ou de políticas
- Exemplos de few-shot
- Resultados estáticos de recuperação reutilizados em muitas requisições
Geralmente, ele não ajuda muito quando cada requisição começa de forma diferente:
- Registros dinâmicos de data e hora no início
- Dados específicos do usuário antes do conteúdo compartilhado
- Ordem aleatória dos exemplos
- UUIDs por requisição dentro da seção que pode ser armazenada em cache
- Trechos recuperados cuja ordem ou formatação muda
- Histórico de conversa colocado antes das instruções estáveis
A principal medida de engenharia é colocar primeiro o contexto estável e de alto custo, deixando o contexto variável para depois.
Anthropic vs OpenAI: objetivo semelhante, controles diferentes
Anthropic e OpenAI oferecem suporte a cache de prompts, mas a experiência de desenvolvimento é diferente.
A Anthropic disponibiliza o cache de prompts de forma mais explícita. Você pode marcar blocos de conteúdo com controles de cache e depois inspecionar campos de uso como cache_creation_input_tokens e cache_read_input_tokens. Isso facilita entender se você está criando entradas de cache ou lendo delas.
O cache de prompts da OpenAI é mais automático nos modelos compatíveis. Quando um prefixo de prompt é reutilizado, os tokens de entrada em cache podem ser cobrados de forma diferente e aparecer nos metadados de uso. Normalmente, você não define pontos de delimitação explícitos de cache da mesma maneira; em vez disso, estrutura as requisições para que o prefixo reutilizável seja estável em bytes e tokens.
A diferença prática é controle versus conveniência.
| Dimensão | Cache explícito no estilo da Anthropic | Cache automático no estilo da OpenAI |
|---|---|---|
| Controle do desenvolvedor | Maior; você pode marcar blocos que podem ser armazenados em cache | Menor; o provedor detecta prefixos reutilizáveis |
| Facilidade de depuração | Geralmente mais clara por meio de contadores de criação e leitura de cache | Depende dos metadados de uso disponibilizados pelo modelo ou pela API |
| Importância da estrutura do prompt | Muito alta | Muito alta |
| Mais indicado para | Grandes blocos estáticos, ferramentas, documentação e exemplos | Prefixos longos reutilizados em chamadas repetidas |
| Falha comum | Ponto de delimitação de cache colocado após conteúdo dinâmico | O prefixo muda antes que o cache possa encontrar uma correspondência |
| Modelo mental | “Estou gravando e lendo um prefixo com uma espécie de nome” | “O provedor reconhece este prefixo repetido” |
Os detalhes de implementação variam conforme o modelo e o provedor, e continuam evoluindo. Mas a regra arquitetural é estável: o cache depende de prefixos repetidos, não de prompts semelhantes.
O modelo de preços: criação vs leitura
Uma forma útil de pensar no cache de prompts é dividir os tokens de entrada em três categorias:
- Tokens de entrada normais: cobrados pelo preço usual de entrada.
- Tokens de criação de cache: tokens usados para criar uma entrada de cache, frequentemente cobrados com um acréscimo ou uma tarifa especial de gravação.
- Tokens de leitura de cache: tokens lidos de uma entrada de cache existente, geralmente cobrados com desconto.
A Anthropic disponibiliza essa distinção diretamente em campos de uso como:
{
"usage": {
"input_tokens": 812,
"cache_creation_input_tokens": 42000,
"cache_read_input_tokens": 0,
"output_tokens": 684
}
}
Em uma requisição posterior, se houver um acerto de cache para o prefixo, você deve esperar algo mais próximo de:
{
"usage": {
"input_tokens": 936,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 42000,
"output_tokens": 711
}
}
A primeira chamada cria o cache. As chamadas seguintes leem dele.
A viabilidade econômica depende dos preços atuais do provedor, do TTL do cache e do modelo. Como os preços mudam, prefiro modelar isso com variáveis no código em vez de fixar valores em documentos de projeto.
Aqui está uma pequena função em Python que uso para decidir se vale a pena implementar cache em uma rota:
def cache_savings(
cached_tokens: int,
normal_input_per_mtok: float,
cache_write_per_mtok: float,
cache_read_per_mtok: float,
requests: int,
) -> dict:
mtok = cached_tokens / 1_000_000
no_cache = requests * mtok * normal_input_per_mtok
with_cache = (
mtok * cache_write_per_mtok +
(requests - 1) * mtok * cache_read_per_mtok
)
return {
"no_cache": round(no_cache, 6),
"with_cache": round(with_cache, 6),
"savings": round(no_cache - with_cache, 6),
"savings_pct": round((1 - with_cache / no_cache) * 100, 2),
}
print(cache_savings(
cached_tokens=42_000,
normal_input_per_mtok=3.00,
cache_write_per_mtok=3.75,
cache_read_per_mtok=0.30,
requests=100,
))
Este exemplo usa apenas preços ilustrativos. O que importa é a estrutura.
Com um prefixo reutilizável de 42,000 tokens e 100 requisições, o cache geralmente é excelente. Com o mesmo prefixo e apenas uma requisição, o cache pode sair mais caro se o preço de gravação for maior que o preço normal de entrada.
Essa é a primeira grande armadilha: o cache de prompts é uma forma de amortização. Se você não reutilizar o prefixo em cache, não terá o benefício.
A fórmula do ponto de equilíbrio
Você pode estimar o ponto de equilíbrio com:
no_cache_cost = N * T * normal_price
cache_cost = T * write_price + (N - 1) * T * read_price
Onde:
Né o número de requisições que usam o mesmo prefixoTé a quantidade de tokens que podem ser armazenados em cachenormal_priceé o preço normal dos tokens de entradawrite_priceé o preço de criação do cacheread_priceé o preço de leitura do cache
O cache economiza dinheiro quando:
T * write_price + (N - 1) * T * read_price
<
N * T * normal_price
O T se cancela no cálculo do ponto de equilíbrio puramente financeiro, o que significa que o número de reutilizações e os preços relativos determinam a decisão. Mas a quantidade de tokens ainda importa operacionalmente: economizar 80% em 500 tokens é insignificante; economizar essa mesma porcentagem em 80,000 tokens é um valor que merece uma linha no orçamento.
Uma versão útil para um cálculo aproximado:
break_even_requests =
(write_price - read_price) / (normal_price - read_price)
Se as gravações em cache forem apenas um pouco mais caras que a entrada normal e as leituras forem muito mais baratas, o ponto de equilíbrio pode ser muito baixo. Se as gravações em cache forem caras ou seu prefixo raramente se repetir, a economia com cache será frágil.
Como estruturar prompts para ter prefixos estáveis
A melhor otimização para cache de prompts não é uma opção da API. É a organização do prompt.
Organização ruim:
Request ID: req_8f19a
Current time: 2026-02-14T09:12:33Z
User: customer_4812
Locale: en-US
SYSTEM INSTRUCTIONS:
...
POLICY MANUAL:
[42,000 tokens of stable text]
USER QUESTION:
Can I get a refund after 45 days?
Isso impede o cache de prefixos porque o prompt diverge logo no início.
Organização melhor:
SYSTEM INSTRUCTIONS:
...
POLICY MANUAL:
[42,000 tokens of stable text]
DYNAMIC REQUEST METADATA:
Request ID: req_8f19a
Current time: 2026-02-14T09:12:33Z
User: customer_4812
Locale: en-US
USER QUESTION:
Can I get a refund after 45 days?
O bloco estável vem primeiro. O bloco dinâmico vem depois.
Para cache explícito no estilo da Anthropic, a estrutura conceitual pode ser assim:
{
"model": "claude-sonnet-4-6",
"max_tokens": 800,
"system": [
{
"type": "text",
"text": "You are a support policy assistant..."
},
{
"type": "text",
"text": "Refund policy manual v2026-02-01:\n\n...",
"cache_control": {
"type": "ephemeral"
}
}
],
"messages": [
{
"role": "user",
"content": "Can I get a refund after 45 days?"
}
]
}
O esquema exato da requisição varia conforme a versão da API e o SDK, então trate isso como uma estrutura, e não como código pronto para copiar e colar. O importante é que o grande bloco estável seja explicitamente elegível para cache e permaneça inalterado entre as chamadas.
Para cache automático no estilo da OpenAI, a estrutura do prompt importa tanto quanto, mesmo que você não marque um bloco manualmente:
{
"model": "gpt-5.5",
"messages": [
{
"role": "system",
"content": "You are a support policy assistant...\n\nRefund policy manual v2026-02-01:\n\n..."
},
{
"role": "user",
"content": "Can I get a refund after 45 days?"
}
]
}
Se a mensagem de sistema mudar a cada requisição, você não deve esperar leituras consistentes do cache.
Um padrão prático de arquitetura
Para sistemas em produção, gosto de tornar os prefixos de prompt em cache explícitos no código da aplicação.
Um padrão simples:
prompt_prefix/
support_policy_v17.txt
tool_schema_v4.json
examples_v9.md
runtime_request/
user_question
user_profile
retrieved_recent_orders
Depois, componha as requisições assim:
from pathlib import Path
POLICY_PREFIX = Path("prompt_prefix/support_policy_v17.txt").read_text()
TOOL_SCHEMA = Path("prompt_prefix/tool_schema_v4.json").read_text()
EXAMPLES = Path("prompt_prefix/examples_v9.md").read_text()
def build_prompt(user_question: str, user_profile: dict) -> str:
stable_prefix = f"""
You are a support policy assistant.
TOOLS:
{TOOL_SCHEMA}
POLICY:
{POLICY_PREFIX}
EXAMPLES:
{EXAMPLES}
""".strip()
dynamic_suffix = f"""
USER PROFILE:
{user_profile}
USER QUESTION:
{user_question}
""".strip()
return stable_prefix + "\n\n--- DYNAMIC REQUEST ---\n\n" + dynamic_suffix
Na prática, também versiono o prefixo. Se o manual de políticas mudar, quero que isso seja um evento deliberado de invalidação do cache:
sha256sum prompt_prefix/support_policy_v17.txt
Esse hash aparece nos logs junto com o nome do modelo, os tokens de criação de cache, os tokens de leitura de cache e a rota da requisição. Sem essa observabilidade, os problemas de cache são difíceis de diagnosticar porque a resposta continua funcionando; ela só custa mais.
Uma linha de log útil se parece com:
{
"route": "support.answer",
"model": "claude-sonnet-4-6",
"prefix_hash": "9d3a4a...",
"input_tokens": 932,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 42000,
"output_tokens": 688,
"latency_ms": 1840
}
Não otimize apenas com base na cobrança. Registre o comportamento do cache por rota.
Latência: geralmente melhora, mas não faz mágica
O cache de prompts pode reduzir a latência porque o provedor do modelo pode reutilizar o processamento do prefixo em cache. Mas eu não definiria um SLA supondo uma redução fixa de latência sem antes medi-la na minha própria carga de trabalho.
O que realmente acontece em produção é mais complicado:
- Prompts curtos podem não apresentar mudanças significativas na latência.
- Prefixos longos em cache costumam melhorar o tempo até o primeiro token.
- O comprimento da saída ainda é o fator dominante em muitas requisições.
- Chamadas de ferramentas, latência de rede e filas podem ocultar os benefícios do cache.
- Falhas de cache geram picos na latência de cauda se as gravações forem mais lentas que as leituras.
Uma configuração realista de benchmark é simples:
# warm cache
python run_eval.py --case support_refund --repeat 1
# measure cache reads
python run_eval.py --case support_refund --repeat 50 --jsonl out.jsonl
# inspect p50/p95 by cache_read_input_tokens > 0
python analyze_latency.py out.jsonl
Meça separadamente as requisições com acerto e com falha de cache. Misturá-las produz um número que não explica nenhuma das duas.
Armadilhas que vejo em sistemas reais
1. Conteúdo dinâmico antes do conteúdo estável
Esta é a falha mais comum. Um registro de data e hora, ID de requisição, lista de flags de funcionalidades, configuração regional do usuário ou atribuição a um experimento é colocado no início do prompt de sistema.
Mova isso para baixo.
2. JSON “equivalente” não é equivalente
Estes dois trechos são semanticamente idênticos, mas não necessariamente idênticos para o cache:
{"name":"refund_lookup","timeout":3,"strict":true}
{
"strict": true,
"timeout": 3,
"name": "refund_lookup"
}
Se você incluir esquemas de ferramentas ou configurações no prefixo em cache, serialize-os de forma determinística:
import json
def stable_json(data: dict) -> str:
return json.dumps(data, sort_keys=True, separators=(",", ":"))
Isso evita falhas de cache acidentais causadas por mudanças na ordem das chaves ou nos espaços em branco.
3. A recuperação pode inviabilizar o uso de cache
Sistemas RAG costumam montar prompts assim:
Retrieved documents:
[doc A]
[doc B]
[doc C]
Instructions:
...
Se os resultados da recuperação variarem por consulta, o prefixo também variará. Isso é aceitável se o contexto recuperado for de fato dinâmico, mas não coloque suas instruções estáveis depois dele.
Melhor:
Instructions:
...
Long-lived product documentation:
[stable docs]
Query-specific retrieved documents:
[doc A]
[doc B]
[doc C]
Para sistemas de alto volume, considere dividir o contexto em:
- Instruções globalmente estáveis
- Documentação estável por tenant
- Recuperação específica do usuário ou da consulta
Cada camada tem um comportamento de cache diferente.
4. Os TTLs do cache importam
Algumas entradas de cache expiram. Se seu tráfego ocorre em rajadas, um prefixo pode ser muito reutilizado por dez minutos e depois deixar de ser acessado. Tempos de vida mais longos para o cache podem ajudar, mas podem ter preços ou disponibilidade diferentes dependendo do provedor e do modelo.
É aqui que a distribuição das requisições importa. “Recebemos 10,000 requisições por dia” é menos útil do que “recebemos 200 requisições por minuto para este prefixo exato entre 9 e 10 da manhã”.
5. Mudanças de modelo invalidam premissas
Não se deve presumir que um prefixo armazenado em cache para um modelo possa ser reutilizado em outro. Se você rotear entre Claude Opus 4.8, Sonnet 4.6, GPT-5.5, Gemini 3 ou modelos abertos como Llama, Qwen, DeepSeek, MiniMax ou Kimi, acompanhe o comportamento do cache por modelo.
O roteamento entre vários modelos é útil, mas complica a amortização. Se o tráfego for dividido de cinco formas, cada modelo poderá receber menos prefixos repetidos.
6. A personalização de prompts pode ter o efeito contrário
As equipes costumam personalizar prompts de sistema:
You are helping {{customer_name}}, who is on plan {{plan_name}}.
Isso parece inofensivo, mas, se aparecer antes do conteúdo em cache, cada cliente receberá um prefixo diferente. Coloque a personalização mais adiante, a menos que ela realmente altere a interpretação do bloco estável pelo modelo.
Quando o cache de prompts economiza dinheiro
O cache costuma ser uma boa opção quando:
- O prefixo que pode ser armazenado em cache é grande, muitas vezes com milhares ou dezenas de milhares de tokens.
- Exatamente o mesmo prefixo é reutilizado muitas vezes.
- O prefixo permanece estável entre as requisições.
- O tráfego chega dentro do tempo de vida do cache.
- Você consegue observar os tokens de criação e de leitura do cache.
- A rota tem uma composição de prompt previsível.
Exemplos concretos:
- Um assistente de programação inclui repetidamente o mesmo mapa do repositório e guia de estilo.
- Um bot de suporte inclui o mesmo manual de políticas em todas as perguntas sobre reembolso.
- Um agente usa um grande esquema estático de ferramentas em todas as requisições.
- Um assistente interno de pesquisa inclui a mesma visão geral do corpus para uma equipe.
Para essas cargas de trabalho, o cache de prompts pode ser uma das otimizações de custo de maior impacto, pois não exige reduzir a qualidade do contexto. Você mantém o prompt longo; apenas deixa de pagar o preço integral de entrada a cada vez.
Quando o cache de prompts não ajuda
O cache oferece pouco benefício ou tem impacto negativo quando:
- O prompt é curto.
- Os prefixos raramente são reutilizados.
- A maior parte do contexto é obtida por recuperação específica da consulta.
- Dados dinâmicos aparecem antes dos dados estáveis.
- Você modifica constantemente as instruções durante os experimentos.
- O tráfego fica muito disperso entre diversos modelos, tenants ou variantes de prompt.
- As gravações no cache custam mais e as leituras são raras demais para amortizá-las.
Uma armadilha comum durante a avaliação: o cache de prompts parece ruim em um notebook porque você executa cada caso uma única vez. Depois, ele parece excelente em produção porque milhares de usuários compartilham o mesmo prefixo estável. O inverso também acontece: uma demonstração repete o mesmo prompt 100 vezes e mostra uma grande economia, mas a produção tem personalização por tenant que impede a reutilização.
Teste com a distribuição real das requisições.
Uma lista simples para verificar a prontidão para o cache
Antes de habilitar o cache de prompts ou depender dele, verifico:
- Existe pelo menos um prefixo estável com mais de alguns milhares de tokens?
- Ele aparece antes de todo o conteúdo dinâmico?
- A serialização é determinística?
- O prefixo tem versionamento e um hash calculado?
- Consigo registrar os tokens de criação e de leitura do cache?
- Sei o número esperado de reutilizações dentro do tempo de vida do cache?
- Medi a latência separadamente para acertos e falhas de cache?
Se a resposta a três ou mais perguntas for “não”, o cache ainda pode funcionar, mas você está apenas supondo.
Recomendações Práticas
O cache de prompts não é uma compressão mágica. É a reutilização de um prefixo estável de tokens, e a economia vem de pagar um custo de criação uma vez e um custo de leitura menor muitas vezes.
O roteiro de engenharia é simples:
- Coloque primeiro o conteúdo grande e estável: instruções, ferramentas, documentação e exemplos.
- Mova registros de data e hora, metadados do usuário, resultados de recuperação e IDs de requisição para depois do prefixo que pode ser armazenado em cache.
- Acompanhe
cache_creationversuscache_readtokens por rota e modelo. - Use serialização determinística para esquemas de ferramentas e configurações em JSON.
- Modele o ponto de equilíbrio com os preços reais do seu provedor e a distribuição do tráfego.
- Tenha cuidado com o roteamento entre vários modelos, a personalização por tenant e os prompts curtos.
- Meça a latência de acertos e falhas separadamente em vez de confiar nas médias.
A melhor otimização de cache de prompts que já vi não tinha nada de engenhoso: movemos 42,000 tokens estáveis para antes de 12 tokens dinâmicos. O comportamento do modelo não mudou. A conta mudou.
Uma única chave de API para Claude Opus 5.5, Sonnet 5, Haiku 4.5 e Fable 5.1, além de GPT-6 modelos. Pague conforme o uso, sem assinatura.
Obtenha Sua Chave de API →