Armazenamento exato em cache com Redis
Armazene respostas do LLM em cache calculando o hash do prompt completo e guardando o resultado no Redis com um TTL, atendendo instantaneamente a solicitações idênticas sem nenhuma chamada à API.
Armazenamento exato em cache com Redis é uma aula grátis de AI Engineering Academy 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 Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.
Por que armazenar respostas de LLM em cache?
As chamadas à API de LLM são caras: uma única solicitação ao GPT-4o pode custar de US$ 0,005 a US$ 0,15, dependendo da quantidade de tokens. Em muitas aplicações, uma parcela significativa das consultas recebidas é idêntica ou quase idêntica às anteriores — pense em robôs de FAQ, sistemas de suporte ao cliente ou ferramentas de revisão de código, nos quais os usuários fazem repetidamente as mesmas perguntas. O armazenamento em cache pode eliminar de 20% a 50% das chamadas à API nesses casos de uso, reduzindo diretamente os custos e a latência.
Cache exato: criação da chave do cache
Um cache exato armazena respostas de LLM usando como chave um hash determinístico da entrada. A chave do cache deve capturar todas as entradas que afetam a saída: a matriz de mensagens, o nome do modelo, a temperatura e quaisquer outros parâmetros que alterem a resposta. Omitir qualquer um desses elementos da chave causa colisões de cache, nas quais uma resposta armazenada é fornecida para uma solicitação efetiva diferente.
import hashlib
import json
def make_cache_key(messages: list[dict], model: str, temperature: float) -> str:
# Create a canonical, order-stable representation
key_data = {
'model': model,
'temperature': temperature,
'messages': messages, # list order matters
}
# Serialize to JSON with sorted keys for determinism
serialized = json.dumps(key_data, sort_keys=True, ensure_ascii=False)
# Hash to a fixed-length key safe for Redis
return 'llm_cache:' + hashlib.sha256(serialized.encode()).hexdigest()Conectando-se ao Redis
O Redis é a escolha padrão para armazenar respostas de LLM em cache devido à sua latência de leitura inferior a um milissegundo e ao suporte integrado a TTL. Use a biblioteca redis-py para acesso síncrono ou aioredis (agora incorporada ao redis-py como redis.asyncio) para acesso assíncrono em aplicações FastAPI. Armazene a conexão com o Redis como um singleton para evitar o esgotamento do pool de conexões.
import redis
import redis.asyncio as aioredis
# Synchronous Redis client
r = redis.Redis(
host='localhost',
port=6379,
db=0,
decode_responses=True, # return str instead of bytes
)
# Async Redis client (for FastAPI)
async_r = aioredis.Redis(
host='localhost',
port=6379,
db=0,
decode_responses=True,
)
# Test connection
print(r.ping()) # True if Redis is runningImplementação do padrão cache-aside
O padrão cache-aside é a estratégia padrão de armazenamento em cache para APIs de LLM. A cada solicitação: (1) calcule a chave do cache; (2) verifique no Redis se há uma resposta armazenada; (3) se houver (acerto de cache), retorne-a imediatamente; (4) se não houver (falha de cache), chame a API de LLM; (5) armazene a resposta no Redis com um TTL; (6) retorne a resposta. Esse padrão mantém a lógica de cache externa à própria chamada de LLM.
import json
from openai import OpenAI
client = OpenAI()
def cached_completion(
messages: list[dict],
model: str = 'gpt-4o-mini',
temperature: float = 0.7,
ttl_seconds: int = 3600,
) -> str:
cache_key = make_cache_key(messages, model, temperature)
# Cache hit?
cached = r.get(cache_key)
if cached is not None:
print('[CACHE HIT]')
return json.loads(cached)
# Cache miss: call API
print('[CACHE MISS]')
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature,
)
result = response.choices[0].message.content
# Store in cache with TTL
r.setex(cache_key, ttl_seconds, json.dumps(result))
return resultCache-aside assíncrono para FastAPI
Em uma aplicação FastAPI assíncrona, use o cliente assíncrono do Redis para que as consultas ao cache não bloqueiem o ciclo de eventos. O padrão é idêntico à versão síncrona, mas usa await em todas as operações do Redis. Assim, a camada de cache permanece totalmente não bloqueante e compatível com o cliente assíncrono de LLM.
from openai import AsyncOpenAI
import redis.asyncio as aioredis
import json
async_client = AsyncOpenAI()
async_r = aioredis.Redis(host='localhost', port=6379, decode_responses=True)
async def async_cached_completion(
messages: list[dict],
model: str = 'gpt-4o-mini',
temperature: float = 0.0,
ttl: int = 86400,
) -> str:
key = make_cache_key(messages, model, temperature)
cached = await async_r.get(key)
if cached:
return json.loads(cached)
response = await async_client.chat.completions.create(
model=model, messages=messages, temperature=temperature
)
result = response.choices[0].message.content
await async_r.setex(key, ttl, json.dumps(result))
return resultEscolhendo o TTL adequado
O TTL (tempo de vida) controla por quanto tempo as respostas armazenadas em cache permanecem válidas. Para perguntas e respostas factuais com bases de conhecimento estáveis, TTLs longos (de 24 a 72 horas) maximizam as taxas de acerto do cache. Para respostas que devem refletir os dados mais recentes (resumos de notícias, preços em tempo real), TTLs curtos (de 5 a 15 minutos) ou a ausência total de cache são adequados. Para tarefas criativas com temperatura diferente de zero, o cache pode produzir respostas desatualizadas — considere armazenar em cache somente quando temperature=0.
# TTL strategy by use case
TTL_STRATEGY = {
'faq_answering': 86400 * 7, # 7 days — stable facts
'code_explanation': 86400, # 1 day — code rarely changes
'document_summarization': 3600 * 6, # 6 hours
'news_analysis': 300, # 5 minutes — stale quickly
'creative_writing': 0, # 0 = don't cache (non-deterministic)
}
def get_ttl_for_use_case(use_case: str) -> int:
return TTL_STRATEGY.get(use_case, 3600) # default 1 hourMétricas e monitoramento do cache
Acompanhe a taxa de acerto do cache como uma métrica principal de redução de custos. Uma taxa de acerto de 30% significa que 30% das chamadas à API são evitadas. Armazene as contagens de acertos e falhas no próprio Redis usando comandos INCR em contadores separados. Exponha um endpoint /metrics na sua aplicação FastAPI que informe a taxa de acerto atual, o total de solicitações e a economia estimada para quantificar o ROI do armazenamento em cache.
CACHE_HITS_KEY = 'llm_cache_metrics:hits'
CACHE_MISSES_KEY = 'llm_cache_metrics:misses'
async def async_cached_completion_instrumented(messages, model, temperature=0.0):
key = make_cache_key(messages, model, temperature)
cached = await async_r.get(key)
if cached:
await async_r.incr(CACHE_HITS_KEY)
return json.loads(cached)
await async_r.incr(CACHE_MISSES_KEY)
response = await async_client.chat.completions.create(
model=model, messages=messages, temperature=temperature
)
result = response.choices[0].message.content
await async_r.setex(key, 3600, json.dumps(result))
return result
async def get_cache_stats():
hits = int(await async_r.get(CACHE_HITS_KEY) or 0)
misses = int(await async_r.get(CACHE_MISSES_KEY) or 0)
total = hits + misses
return {'hit_rate': hits / total if total > 0 else 0, 'total': total}Estratégias de invalidação do cache
A invalidação de um cache exato é simples porque as chaves são determinísticas. Para invalidar uma entrada específica, recalcule a chave e chame r.delete(key). Para invalidar todas as entradas de um padrão de prompt específico, use prefixos de chaves do Redis com uma varredura por caractere curinga. Para invalidar todo o cache após uma atualização importante da base de conhecimento, chame r.flushdb() (use com cuidado — isso exclui todas as chaves do banco de dados).
async def invalidate_cache_entry(messages, model, temperature):
key = make_cache_key(messages, model, temperature)
deleted = await async_r.delete(key)
print(f'Deleted {deleted} cache entries')
async def invalidate_all_llm_cache():
# Scan for all keys with prefix 'llm_cache:'
keys_to_delete = []
async for key in async_r.scan_iter(match='llm_cache:*'):
keys_to_delete.append(key)
if keys_to_delete:
await async_r.delete(*keys_to_delete)
print(f'Invalidated {len(keys_to_delete)} cache entries')Serializando respostas complexas
Se sua aplicação armazena em cache objetos completos de resposta da API (e não apenas o conteúdo de texto), serialize-os cuidadosamente. O objeto ChatCompletion completo inclui o uso de tokens, a versão do modelo e o motivo de finalização — informações úteis para logging e acompanhamento de custos. Use o método .model_dump_json() do SDK para serializar objetos de resposta do Pydantic em strings JSON e reconstrua-os com ChatCompletion.model_validate_json() ao recuperar os dados do cache.
from openai.types.chat import ChatCompletion
async def cached_completion_full_response(
messages, model='gpt-4o-mini', temperature=0.0
):
key = make_cache_key(messages, model, temperature) + ':full'
cached = await async_r.get(key)
if cached:
return ChatCompletion.model_validate_json(cached) # reconstruct object
response = await async_client.chat.completions.create(
model=model, messages=messages, temperature=temperature
)
# Serialize Pydantic model to JSON
await async_r.setex(key, 3600, response.model_dump_json())
return responseArmazenamento em cache e não determinismo
O armazenamento em cache exato só faz sentido para solicitações determinísticas ou quase determinísticas. Com temperature=0 e top_p=1.0, a maioria dos LLMs produz a mesma saída para a mesma entrada (embora isso não seja garantido devido ao não determinismo de ponto flutuante). Em temperaturas mais altas, as respostas armazenadas em cache ficam desatualizadas, pois o modelo teria produzido saídas diferentes. Sempre armazene em cache com temperature=0 ou documente claramente na chave do cache que as respostas podem variar.
Cluster Redis e configuração para produção
Para implantações em produção com grandes volumes de cache, use o Redis Cluster para particionamento horizontal entre vários nós ou um serviço Redis gerenciado, como AWS ElastiCache ou Redis Cloud. Defina uma política de maxmemory (normalmente allkeys-lru, para remover as entradas usadas menos recentemente quando a memória estiver cheia) a fim de evitar que o Redis fique sem memória e gerenciar automaticamente o tamanho do cache.
# Redis configuration for production LLM caching
# In redis.conf:
# maxmemory 2gb
# maxmemory-policy allkeys-lru
# Connection with retry and connection pool
import redis
from redis.retry import Retry
from redis.backoff import ExponentialBackoff
retry = Retry(ExponentialBackoff(base=0.1), 3)
production_redis = redis.Redis(
host='your-redis-host.cache.amazonaws.com',
port=6379,
ssl=True,
decode_responses=True,
max_connections=50,
retry=retry,
retry_on_error=[redis.ConnectionError, redis.TimeoutError],
)Verificação rápida
Teste sua compreensão do armazenamento em cache exato de respostas de LLM com Redis nesta lição.
Resumo da lição
Nesta lição, você aprendeu que o armazenamento em cache exato gera um hash de todas as entradas do LLM para produzir uma chave de cache determinística; que o padrão cache-aside verifica o Redis antes de chamar a API e armazena os resultados após uma falha; e que a escolha do TTL deve refletir a frequência com que seu conteúdo muda — mais longo para conhecimento estável e mais curto para dados dinâmicos. Monitore a taxa de acerto do cache como uma métrica principal de redução de custos. A seguir, criaremos um cache semântico para consultas semelhantes, mas não idênticas.
Perguntas Frequentes
A aula “Armazenamento exato em cache com Redis” é grátis?
Sim — o texto completo de “Armazenamento exato em cache com Redis” é 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 Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.
O que vou aprender em “Armazenamento exato em cache com Redis”?
Armazene respostas do LLM em cache calculando o hash do prompt completo e guardando o resultado no Redis com um TTL, atendendo instantaneamente a solicitações idênticas sem nenhuma chamada à API. Você pratica AI Engineering Academy 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 Engineering Academy?
Nenhuma experiência prévia é necessária. AI Engineering Academy 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 “Armazenamento exato em cache com Redis”?
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 Engineering Academy?
Sim. Cada aula de AI Engineering Academy 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
- Armazenamento exato em cache com Redis
- Armazenamento semântico em cache com embeddings
- Armazenamento em cache de prefixos de prompts da OpenAI
- Lotes, roteamento de modelos e painéis de custos