Estratégias de cache para prompts
Cache semântico, cache por correspondência exata e cache de prompts da Anthropic.
Estratégias de cache para prompts é uma aula grátis de AI Prompt Engineering no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Prompt Engineering, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Prompt Engineering inclui 4 aulas no total.
Por que armazenar os resultados das instruções em cache?
As chamadas à API de LLM são caras e lentas. Muitas aplicações em produção enviam as mesmas instruções, ou instruções muito semelhantes, repetidamente. O armazenamento em cache retorna resultados armazenados para consultas repetidas, eliminando chamadas redundantes à API e reduzindo drasticamente tanto o custo quanto a latência.
Armazenamento em cache por correspondência exata com chaves de hash
O cache mais simples: gere o hash da string exata da instrução e armazene o resultado. Se a mesma string de instrução aparecer novamente, retorne o resultado armazenado em cache sem chamar a API.
import hashlib
import json
from functools import lru_cache
class ExactMatchCache:
def __init__(self, backend=None):
# backend: a dict (in-memory) or Redis client
self.store = backend or {}
def _key(self, messages, model, max_tokens):
content = json.dumps({'messages': messages, 'model': model,
'max_tokens': max_tokens}, sort_keys=True)
return 'llm:' + hashlib.sha256(content.encode()).hexdigest()
def get(self, messages, model, max_tokens):
key = self._key(messages, model, max_tokens)
return self.store.get(key)
def set(self, messages, model, max_tokens, result, ttl_seconds=3600):
key = self._key(messages, model, max_tokens)
self.store[key] = result
# In Redis: self.store.setex(key, ttl_seconds, json.dumps(result))
cache = ExactMatchCache()
# Usage
messages = [{'role': 'user', 'content': 'What is the capital of France?'}]
cached = cache.get(messages, 'gpt-4o-mini', 100)
if cached:
print('Cache HIT:', cached[:50])
else:
print('Cache MISS — calling API...')Cliente LLM com cache integrado
Envolva a chamada à API de LLM com um decorador de cache para que todos os chamadores obtenham o armazenamento em cache de forma transparente, sem alterar o próprio código.
import openai
from typing import Optional
client = openai.OpenAI(api_key='YOUR_API_KEY')
cache = ExactMatchCache()
def cached_completion(messages, model='gpt-4o-mini', max_tokens=500,
temperature=0.0, use_cache=True) -> str:
if use_cache and temperature == 0.0:
# Only cache deterministic requests (temperature=0)
cached = cache.get(messages, model, max_tokens)
if cached:
return cached
response = client.chat.completions.create(
model=model,
messages=messages,
max_tokens=max_tokens,
temperature=temperature
)
result = response.choices[0].message.content
if use_cache and temperature == 0.0:
cache.set(messages, model, max_tokens, result)
return result
# Important: only cache temperature=0 responses
# Non-deterministic responses (temp>0) may return stale results
print('Cache wrapping: only deterministic (temp=0) calls are cached.')Armazenamento em cache semântico com incorporações
O armazenamento em cache semântico retorna resultados armazenados para consultas semelhantes em significado, não apenas para strings idênticas. Ele usa vetores de incorporação e similaridade de cosseno para encontrar consultas quase duplicadas.
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
class SemanticCache:
def __init__(self, similarity_threshold=0.95):
self.entries = [] # [(embedding, query, result)]
self.threshold = similarity_threshold
def embed(self, text):
'''Get embedding for text using OpenAI embeddings API.'''
response = client.embeddings.create(
model='text-embedding-3-small',
input=text
)
return np.array(response.data[0].embedding)
def get(self, query):
if not self.entries:
return None
query_emb = self.embed(query)
for emb, stored_query, result in self.entries:
sim = cosine_similarity([query_emb], [emb])[0][0]
if sim >= self.threshold:
print(f'Semantic cache HIT (similarity={sim:.3f}): {stored_query[:40]}...')
return result
return None
def set(self, query, result):
emb = self.embed(query)
self.entries.append((emb, query, result))
sem_cache = SemanticCache(similarity_threshold=0.95)
print('Semantic cache ready. Threshold: 0.95 cosine similarity.')Biblioteca GPTCache
O GPTCache é uma biblioteca de código aberto para armazenamento em cache semântico que oferece suporte a vários modelos de incorporação, mecanismos de similaridade (FAISS, Redis) e estratégias de remoção. Ela se integra diretamente a clientes OpenAI e LangChain.
# pip install gptcache
# GPTCache integration example
# from gptcache import cache
# from gptcache.adapter import openai
# from gptcache.embedding import Onnx
# from gptcache.manager import CacheBase, VectorBase, get_data_manager
# from gptcache.similarity_evaluation.distance import SearchDistanceEvaluation
# Initialize GPTCache
# onnx = Onnx()
# data_manager = get_data_manager(
# CacheBase('sqlite'),
# VectorBase('faiss', dimension=onnx.dimension)
# )
# cache.init(
# embedding_func=onnx.to_embeddings,
# data_manager=data_manager,
# similarity_evaluation=SearchDistanceEvaluation(),
# )
# After init, use openai from gptcache.adapter instead of standard openai
# response = openai.ChatCompletion.create(
# model='gpt-4o-mini',
# messages=[{'role': 'user', 'content': 'What is Python?'}]
# )
# Same API, but cache is checked first
print('GPTCache: drop-in semantic cache for OpenAI API calls.')
print('Supports: FAISS, Redis, SQLite, Milvus as vector backends.')Armazenamento nativo de instruções em cache da Anthropic
A Anthropic oferece armazenamento nativo de instruções em cache, que armazena o processamento da instrução do sistema nos próprios servidores. Quando há um acerto no cache, você paga apenas 10% do preço normal dos tokens de entrada. Isso é separado do armazenamento de respostas em cache no nível da aplicação.
import anthropic
client = anthropic.Anthropic(api_key='YOUR_API_KEY')
LONG_SYSTEM_PROMPT = '''You are an expert financial analyst with 20 years of experience.
''' + 'Domain knowledge: ' + 'analysis context...' * 500 # large system prompt
# Enable prompt caching with cache_control
response = client.messages.create(
model='claude-opus-4-5',
max_tokens=1024,
system=[
{
'type': 'text',
'text': LONG_SYSTEM_PROMPT,
'cache_control': {'type': 'ephemeral'} # cache this prefix
}
],
messages=[{'role': 'user', 'content': 'Analyze Q3 2024 earnings.'}]
)
print('Cache write tokens:', response.usage.cache_creation_input_tokens)
print('Cache read tokens: ', response.usage.cache_read_input_tokens)
print('Regular input tokens:', response.usage.input_tokens)
# On cache HIT: cache_read_input_tokens shows the cached tokens
# Cost: cached tokens charged at 10% of normal rateTTL do cache e estratégias de remoção
Os resultados armazenados em cache ficam obsoletos quando o conhecimento subjacente muda ou o modelo é atualizado. O TTL (tempo de vida) e as estratégias de remoção gerenciam a atualidade dos dados.
import time
from collections import OrderedDict
class TTLCache:
def __init__(self, max_size=1000, default_ttl=3600):
self.store = OrderedDict() # key: (value, expire_at)
self.max_size = max_size
self.default_ttl = default_ttl
def set(self, key, value, ttl=None):
ttl = ttl or self.default_ttl
expire_at = time.time() + ttl
if key in self.store:
del self.store[key]
self.store[key] = (value, expire_at)
# LRU eviction: remove oldest if over capacity
if len(self.store) > self.max_size:
self.store.popitem(last=False)
def get(self, key):
if key not in self.store:
return None
value, expire_at = self.store[key]
if time.time() > expire_at:
del self.store[key]
return None # expired
# Move to end (LRU update)
self.store.move_to_end(key)
return value
# TTL strategy guidelines
ttl_guidelines = {
'Static knowledge': 86400, # 24h (facts, definitions)
'Semi-static': 3600, # 1h (product info, FAQs)
'Dynamic content': 300, # 5min (news, prices)
'Personalized': 0 # no cache (user-specific)
}
for k, v in ttl_guidelines.items():
print(f'{k}: {v}s TTL')Padrões de invalidação de cache
A invalidação de cache — saber quando limpar dados obsoletos — é um dos problemas mais difíceis da computação. Para caches de LLM, estes padrões tratam das necessidades de invalidação mais comuns.
class InvalidationAwareCache(TTLCache):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tags = {} # key: set of tags
self.tag_index = {} # tag: set of keys
def set_with_tags(self, key, value, tags, ttl=None):
self.set(key, value, ttl)
self.tags[key] = set(tags)
for tag in tags:
self.tag_index.setdefault(tag, set()).add(key)
def invalidate_by_tag(self, tag):
keys_to_delete = self.tag_index.pop(tag, set())
for key in keys_to_delete:
self.store.pop(key, None)
self.tags.pop(key, None)
print(f'Invalidated {len(keys_to_delete)} entries with tag={tag}')
# Usage: tag cache entries by data source
cache = InvalidationAwareCache()
cache.set_with_tags('product_faq_123', 'Product FAQs...', tags=['product:123', 'faqs'])
cache.set_with_tags('product_spec_123', 'Spec sheet...', tags=['product:123', 'specs'])
# When product 123 is updated, invalidate all its cache entries
cache.invalidate_by_tag('product:123') # Invalidated 2 entriesMedição do desempenho do cache
Acompanhe as métricas de desempenho do cache para entender o impacto do armazenamento em cache sobre o custo e a latência. Um cache bem ajustado deve atingir uma taxa de acertos >50% na maioria dos casos de uso em produção.
class CacheMetrics:
def __init__(self):
self.hits = 0
self.misses = 0
self.total_latency_saved_ms = 0
self.total_cost_saved_usd = 0
self.avg_api_latency_ms = 1500 # typical LLM call latency
self.avg_api_cost_usd = 0.002 # typical cost per call
def record_hit(self):
self.hits += 1
self.total_latency_saved_ms += self.avg_api_latency_ms
self.total_cost_saved_usd += self.avg_api_cost_usd
def record_miss(self):
self.misses += 1
def report(self):
total = self.hits + self.misses
hit_rate = self.hits / total if total else 0
return {
'hit_rate': f'{hit_rate:.1%}',
'total_requests': total,
'cache_hits': self.hits,
'latency_saved_sec': round(self.total_latency_saved_ms / 1000, 1),
'cost_saved_usd': round(self.total_cost_saved_usd, 2)
}
metrics = CacheMetrics()
for i in range(100):
if i % 3 == 0: # simulate 33% hit rate
metrics.record_hit()
else:
metrics.record_miss()
print(metrics.report())Cache com Redis para produção
Os caches em memória são perdidos após uma reinicialização e não podem ser compartilhados entre instâncias do servidor. O Redis fornece um cache persistente e compartilhado, que funciona em vários servidores de API em uma implantação de produção.
import redis
import json
import hashlib
class RedisLLMCache:
def __init__(self, host='localhost', port=6379, db=0, default_ttl=3600):
self.client = redis.Redis(host=host, port=port, db=db,
decode_responses=True)
self.default_ttl = default_ttl
def _key(self, messages, model):
content = json.dumps({'messages': messages, 'model': model},
sort_keys=True)
return 'llmcache:' + hashlib.sha256(content.encode()).hexdigest()
def get(self, messages, model):
key = self._key(messages, model)
value = self.client.get(key)
if value:
self.client.expire(key, self.default_ttl) # refresh TTL on hit
return json.loads(value)
return None
def set(self, messages, model, result, ttl=None):
key = self._key(messages, model)
self.client.setex(key, ttl or self.default_ttl, json.dumps(result))
def stats(self):
keys = self.client.keys('llmcache:*')
return {'cached_entries': len(keys),
'memory_bytes': self.client.memory_usage('llmcache:') or 0}
# Usage: drop-in replacement for in-memory cache
# cache = RedisLLMCache(host='redis.internal', port=6379)
print('RedisLLMCache: shared across all server instances, survives restarts.')Quando não usar cache
O armazenamento em cache não é adequado para todas as chamadas a LLM. Entender quando ignorar o cache evita o fornecimento de resultados desatualizados ou incorretos.
DONT_CACHE_WHEN = {
'High temperature': (
'temperature > 0 produces different outputs for the same input. '
'Caching would always return the first generation, defeating the purpose.'
),
'Real-time data required': (
'Queries about current prices, live news, or real-time status '
'must always hit the API and live data source.'
),
'Personalized responses': (
'Responses that depend on user_id, session context, or personal data '
'should not be shared across users.'
),
'Safety-critical': (
'Medical, legal, or financial responses where staleness could cause harm '
'require fresh responses with the most current model version.'
),
'Non-deterministic tools': (
'If the prompt includes a current timestamp or random seed, '
'the response is by design non-repeatable.'
)
}
for condition, reason in DONT_CACHE_WHEN.items():
print(f'Skip cache: {condition}')
print(f' Reason: {reason[:60]}...')
print()Verificação rápida
Qual é a principal diferença entre o armazenamento em cache por correspondência exata e o armazenamento em cache semântico para respostas de LLM?
Resumo das estratégias de cache
Um armazenamento eficaz de instruções em cache combina várias estratégias:
- Correspondência exata: baseado em hash, sem sobrecarga quando há correspondência e com baixa taxa de correspondência para formulações variadas
- Cache semântico: a similaridade entre representações vetoriais encontra correspondências de paráfrases, proporcionando uma taxa de correspondência maior
- GPTCache: biblioteca de código aberto que combina as duas estratégias com sistemas de retaguarda FAISS/Redis
- Cache nativo da Anthropic: armazenamento no servidor das instruções do sistema em cache, a 10% do custo dos tokens
- Expiração TTL + LRU: atualização baseada em tempo + gerenciamento de capacidade
- Invalidação baseada em tags: invalida entradas relacionadas quando os dados de origem mudam
- Quando não usar cache: temperatura diferente de zero, dados em tempo real, dados personalizados ou situações críticas para a segurança
Perguntas Frequentes
A aula “Estratégias de cache para prompts” é grátis?
Sim — o texto completo de “Estratégias de cache para prompts” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Prompt Engineering, atualize para CoddyKit PRO. O curso de AI Prompt Engineering inclui 4 aulas no total.
O que vou aprender em “Estratégias de cache para prompts”?
Cache semântico, cache por correspondência exata e cache de prompts da Anthropic. Você pratica AI Prompt Engineering com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Prompt Engineering?
Nenhuma experiência prévia é necessária. AI Prompt Engineering no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “Estratégias de cache para prompts”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Prompt Engineering?
Sim. Cada aula de AI Prompt Engineering inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Estratégias de cache para prompts
- Processamento em lote e execução assíncrona
- Balanceamento de carga entre modelos
- Monitoramento e alertas para pipelines de prompts