Prompt caching é a alavanca de custo mais subestimada: 10% do preço para tokens cacheados. Em chats com prefix grande, isso é redução de 80-90% real. Context distillation vai além: substitui contexto longo por modelo treinado. Ambos têm trade-offs concretos.
💰 Hierarquia de otimização de custo
Antes de invocar técnicas avançadas, esgote as simples. Caching é low-hanging fruit; distillation é trabalho pesado.
- •1. Reduzir tokens: prompts mais curtos, RAG bom em vez de contexto longo.
- •2. Trocar de modelo: low-cost onde frontier é desnecessário.
- •3. Prompt caching: ganha 80% sem mudar capability.
- •4. Compressão: lossy mas eficaz em casos certos.
- •5. Distillation: trabalho de ML, ganho permanente.
📊 Anthropic Prompt Caching (2024)
- ~10% do preço normal para tokens lidos do cache.
- 5 min de TTL (Anthropic) — chamadas espaçadas perdem cache.
- Hit rate típico em chats: 70-95% se prefix bem estruturado.
💰 Prompt caching (Anthropic, OpenAI)
10% do preço para hits
Tokens lidos do cache custam ~10% do preço normal de input. Em chats com prefixo grande estável (5-10k tokens de system + few-shot), o ganho real é de 80-90% no custo de input. Anthropic e OpenAI suportam; Ollama e modelos OSS locais geralmente não têm cache nativo.
| Item | Sem cache | Com cache 80% hit |
|---|---|---|
| Tokens input total | 10k × $3/M = $0.03 | 10k × $3/M (escrita 1ª vez) |
| Tokens input nas próximas chamadas | 10k × $3/M = $0.03 | 8k × $0.30/M + 2k × $3/M = $0.0084 |
| Custo médio de input em 100 chamadas | $3.00 | $0.87 (-71%) |
📑 Resumo navegável
🎯 Cache breakpoints: onde marcar
Estável vs variável
Cache breakpoint marca onde o prefixo cacheável termina. Anthropic: até 4 breakpoints, declarados em metadados. OpenAI: cache automático para prefixos >1024 tokens. Tudo após o breakpoint é tratado como variável.
system = [
{'type':'text', 'text': REGRAS_BASE},
{'type':'text', 'text': FEW_SHOTS,
'cache_control': {'type':'ephemeral'}}, # bp 1
]
user = [
{'type':'text', 'text': contexto_usuario_grande,
'cache_control': {'type':'ephemeral'}}, # bp 2
{'type':'text', 'text': pergunta_atual}, # variável
]
📑 Resumo navegável
📊 Medir hit rate: você está economizando?
Métrica explícita
Hit rate é a métrica chave. Cache que NÃO está sendo lido é cache invalidado constantemente — provavelmente prefixo está mudando. Toda chamada retorna métricas: cache_creation_input_tokens e cache_read_input_tokens. Calcule e logue.
u = resp.usage
hit = u.cache_read_input_tokens
miss = u.cache_creation_input_tokens
if hit + miss > 0:
rate = hit / (hit + miss)
log.info(f'cache_hit_rate={rate:.2%} hit={hit} miss={miss}')
if rate < 0.5 and hit + miss > 1000:
log.warning('cache hit rate baixo — verificar prefixo instável')
📑 Resumo navegável
🧪 Context distillation: substituir contexto por modelo
Treinar pequeno
Para tarefa fixada e volume alto, treinar um modelo pequeno usando outputs do modelo grande (com contexto longo) elimina o contexto em runtime. Knowledge distillation: teacher = frontier com contexto, student = modelo pequeno fine-tuned. Ganho: latência baixa, custo fixo. Custo: trabalho de ML.
quando vale distillation
- ▸Volume >100k chamadas/mês com tarefa estável.
- ▸Latência crítica (modelo grande >1s, distilled <100ms).
- ▸Privacidade exige local (modelo grande é cloud).
- ▸Equipe de ML disponível para curar dataset + treinar.
📑 Resumo navegável
📦 Compressão por sumarização
LLMLingua, sumário do contexto
Para casos onde detalhe completo não é crítico, comprimir contexto antes de mandar reduz tokens. LLMLingua (Jiang et al. 2023) usa modelo pequeno para identificar e remover tokens de baixa importância. Lossy: pode comprometer qualidade — eval obrigatório.
def comprimir_contexto(docs: list[str], target_tokens: int) -> str:
tokens_atuais = sum(count_tokens(d) for d in docs)
if tokens_atuais <= target_tokens:
return '\n\n'.join(docs)
ratio = target_tokens / tokens_atuais
return llm.generate(
f'Resuma o conteúdo abaixo preservando fatos. Comprima para ~{int(ratio*100)}%:\n'
'\n\n'.join(docs)
)
📑 Resumo navegável
⚠️ Quando caching/distillation NÃO valem
Casos onde não compensa
Cada técnica tem zona de aplicabilidade. Cache não vale com prefix instável. Distillation não vale com tarefa que muda rápido. Compressão não vale onde fidelidade é crítica. Antes de invocar, esgote técnicas mais simples: prompts mais curtos, RAG bom, modelo low-cost.
| Técnica | Quando vale | Quando NÃO vale |
|---|---|---|
| Prompt caching | prefix ≥1k tokens estável, volume alto | prefix muda a cada turn |
| Compressão | tarefa tolera perda de detalhe | extração precisa |
| Distillation | tarefa estável, >100k chamadas/mês | tarefa muda mensalmente |
| Trocar modelo | tarefa estruturada simples | raciocínio crítico |
📑 Resumo navegável
📑 Resumo navegável dos tópicos
1 💰 Prompt caching (Anthropic, OpenAI) — 10% do preço para hits
2 🎯 Cache breakpoints: onde marcar — Estável vs variável
3 📊 Medir hit rate: você está economizando? — Métrica explícita
4 🧪 Context distillation: substituir contexto por modelo — Treinar pequeno
5 📦 Compressão por sumarização — LLMLingua, sumário do contexto
6 ⚠️ Quando caching/distillation NÃO valem — Casos onde não compensa
✓ O que FAZER
- ✓Marcar cache_control após system prompt + few-shot
- ✓Medir hit rate em produção
- ✓Estabilizar system prompt antes de cachear
- ✓Distillation com eval rigoroso vs modelo grande
✗ O que NÃO fazer
- ✗Sem caching habilitado em prefixos repetidos
- ✗Assumir que cache 'está funcionando'
- ✗Mexer no prefix invalidando cache
- ✗Distillation que regrede silenciosamente
🚫 Quando NÃO usar
- •Prefix muda a cada turn: cache nunca hita.
- •Volume baixo: economia absoluta é trivial; complexidade não vale.
- •Tarefa que muda rápido: distillation envelhece, modelo grande adapta.
💻 Exemplo de código
# Anthropic prompt caching (esquemático)
import anthropic
client = anthropic.Anthropic()
system_grande = """Você é um assistente especializado...
[10k tokens de regras, exemplos, etc.]"""
# Marcar cache_control no fim do prefix estável
resp = client.messages.create(
model="claude-sonnet-4-6@2026-04",
system=[
{"type": "text", "text": system_grande,
"cache_control": {"type": "ephemeral"}}
],
messages=[{"role": "user", "content": "pergunta atual"}],
max_tokens=500,
)
# resp.usage tem: input_tokens, cache_creation_input_tokens, cache_read_input_tokens
hit_rate = resp.usage.cache_read_input_tokens / (
resp.usage.cache_read_input_tokens + resp.usage.cache_creation_input_tokens
)
🏋️ Exercício hands-on
Em chat de 20 turns com system prompt de 5k tokens, meça custo SEM cache e COM cache. Hit rate alvo: ≥80%. Em exercicios/modulo-5-2/ ou simulação por gravação.
📚 Bibliografia
- Anthropic (2024) — Prompt caching with Claude
- OpenAI (2024) — Prompt caching
- Hinton et al. (2015) — Distilling Knowledge in a Neural Network
- Jiang et al. (2023) — LLMLingua: Compressing Prompts
🎯 Resumo do Módulo
- ✓Prompt caching: 10% do preço para hits — ganho real 80%.
- ✓Hit rate precisa ser MEDIDO; pequena mudança derruba.
- ✓Distillation substitui contexto longo por modelo treinado.
- ✓Compressão é lossy — eval obrigatório.
- ✓Hierarquia de otimização: simples primeiro, complexo depois.
Próximo Módulo:
T6 — Avaliação e Produção