0Pricing
AI Engineering Academy · Aula

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 running

Implementaçã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 result

Cache-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 result

Escolhendo 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 hour

Mé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 response

Armazenamento 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

  1. Armazenamento exato em cache com Redis
  2. Armazenamento semântico em cache com embeddings
  3. Armazenamento em cache de prefixos de prompts da OpenAI
  4. Lotes, roteamento de modelos e painéis de custos
← Voltar para AI Engineering Academy