Neste artigo
Cache semântico é uma camada que guarda respostas de LLM e as reaproveita quando uma nova pergunta é parecida o suficiente com uma já respondida, mesmo que as palavras sejam diferentes. Ele funciona comparando o embedding da pergunta nova com embeddings de perguntas anteriores, e se a similaridade passa de um limiar definido, devolve a resposta salva sem chamar o modelo de novo. Na prática isso corta custo e latência em aplicações com muita repetição semântica, tipo suporte, FAQ e busca interna.
Eu comecei a usar cache semântico depois de ver a fatura de API de um projeto de atendimento crescer todo mês sem o volume de usuários crescer na mesma proporção. Analisando os logs, dava para ver claramente: um monte de pergunta diferente na forma, mas idêntica no conteúdo. "Como cancelo minha assinatura" e "quero cancelar o plano" iam parar em chamadas separadas para o modelo, gastando token e tempo à toa.
Cache tradicional, por chave exata, não resolve isso. Ele só bate quando a string é igual. Cache semântico resolve porque compara significado, não texto literal. E é aqui que a coisa fica interessante, porque a implementação não é complicada, mas tem detalhe que decide se o resultado vai ser bom ou vai virar dor de cabeça.
Cache semântico x prompt caching: são coisas diferentes
Esse é o ponto que mais confunde gente que está começando. Cache semântico não é a mesma coisa que prompt caching, que ataca o problema do lado do provedor.
Prompt caching guarda um prefixo fixo de contexto (um system prompt grande, um documento anexado) para não reprocessar aquilo em cada chamada. Ele reduz custo de tokens de entrada, mas o modelo continua sendo chamado toda vez.
Cache semântico é outra camada, geralmente fora do provedor, que evita a chamada inteira quando a pergunta já foi respondida antes de forma equivalente. Os dois não competem, eles se complementam. Dá para ter prompt caching no provedor e cache semântico na sua própria infraestrutura ao mesmo tempo.
Quando faz sentido implementar
Cache semântico não serve para tudo. Ele brilha quando existe repetição de intenção, não necessariamente repetição de texto.
Sinais de que vale a pena:
- Volume alto de perguntas parecidas (suporte, FAQ, busca em base de conhecimento)
- Respostas que não mudam com frequência (política de troca, horário de funcionamento, dúvida técnica recorrente)
- Latência é um problema visível para o usuário
- Custo de API já é uma linha relevante no orçamento
Sinais de que não vale a pena, pelo menos por enquanto:
- Cada interação é praticamente única (geração criativa, análise de dado específico do usuário)
- A resposta precisa refletir informação que muda a cada minuto
- O volume de chamadas ainda é baixo o suficiente para o ganho não compensar a complexidade
Na minha visão, se você já colocou esforço em estimar e controlar o custo de LLMs em produção e viu que uma fatia grande do gasto vem de perguntas repetidas, esse é o sinal mais claro de todos.
Como funciona na prática
O fluxo básico tem três etapas. Nenhuma delas é mágica, mas cada uma tem uma pegadinha.
Gerar o embedding da pergunta
Toda pergunta nova passa por um modelo de embedding antes de chegar no LLM principal. Isso transforma o texto em um vetor numérico que representa o significado dela. Esse passo adiciona uma chamada extra, mas modelos de embedding são muito mais baratos e rápidos que um LLM completo, então o custo extra costuma ser irrisório perto do que se economiza.
Buscar similaridade no Redis (ou em outro armazenamento vetorial)
Com o vetor da pergunta em mãos, você busca no seu armazenamento por vetores próximos que já foram cacheados. Redis com o módulo de busca vetorial é uma opção comum para isso, porque já é rápido, já está presente em muita stack e resolve o caso sem precisar subir um banco vetorial dedicado só para essa função. Se o volume de vetores crescer muito ou a necessidade for mais ampla que só cache, aí sim vale olhar para escolher entre pgvector, Qdrant ou Weaviate.
Definir o limiar de similaridade
Esse é o ponto que mais quebra implementação de cache semântico mal calibrada. Um limiar muito baixo (permissivo demais) devolve resposta errada para pergunta diferente. Um limiar muito alto (restritivo demais) nunca bate cache e você perde todo o ganho.
Eu costumo começar com um limiar conservador, testar com perguntas reais do domínio, e só afrouxar aos poucos observando os casos que erraram. Não tem fórmula mágica aqui, é calibração empírica mesmo.
Para subir um Redis com suporte a busca vetorial rapidinho em um container de teste:
- docker run -d –name redis-cache -p 6379:6379 redis/redis-stack-server:latest instala o Redis Stack com busca vetorial já habilitada
- docker exec -it redis-cache redis-cli abre o cliente de linha de comando dentro do container
- ping confirma que o serviço respondeu com PONG

Redis ou banco de dados vetorial dedicado?
Para cache semântico puro, Redis costuma ganhar. Ele é rápido, tem TTL nativo (importante para expirar cache antigo), e você provavelmente já usa Redis para outra coisa no projeto, então não adiciona mais uma peça de infraestrutura.
Um banco vetorial dedicado faz mais sentido quando o cache é só uma parte de um sistema maior de busca semântica, tipo um pipeline de RAG que já precisa de armazenamento vetorial robusto de qualquer jeito. Se esse é o seu caso, dá uma olhada em quando montar um pipeline de recuperação antes de decidir a peça de infraestrutura.
Os riscos que ninguém conta
Cache semântico tem um efeito colateral que a documentação de nenhuma ferramenta destaca o suficiente: resposta desatualizada servida com confiança total.
Se a informação por trás de uma resposta cacheada muda (um preço, uma política, um status), o cache continua devolvendo a versão antiga até expirar ou ser invalidado manualmente. Isso é pior que simplesmente não ter cache, porque o usuário recebe uma resposta errada com a mesma cara de resposta certa.
Defina TTL curto para conteúdo que muda com frequência, e invalide o cache de forma ativa quando você souber que a fonte de verdade mudou. Não confie só no tempo de expiração.
Outro risco é o falso positivo de similaridade: duas perguntas com vetores próximos, mas com intenção diferente. "Como cancelo o plano" e "como faço para trocar de plano" podem ficar perto demais dependendo do modelo de embedding usado. Testar com casos reais do seu domínio antes de colocar em produção evita boa parte disso.
O custo de não implementar
Sem cache semântico, cada variação textual de uma mesma pergunta vira uma chamada nova, com custo de token cheio e a latência inteira do modelo. Em volume baixo isso não aparece na conta. Em volume alto, é dinheiro saindo pela porta dos fundos.
Combinado com o problema de latência, o efeito é duplo: você paga mais e ainda entrega resposta mais lenta para uma pergunta que já tinha sido respondida minutos antes. Se latência é dor no seu produto, vale revisar onde medir e otimizar a latência de LLMs e ver onde o cache semântico entraria no funil.
Perguntas frequentes
O que é cache semântico em LLMs?
É uma camada que reutiliza respostas de LLM para perguntas com significado parecido, mesmo que o texto seja diferente. A comparação é feita por embeddings, não por igualdade literal de string.
Cache semântico substitui o prompt caching?
Não, eles resolvem problemas diferentes. Prompt caching reduz o custo de reprocessar um contexto fixo no provedor, enquanto cache semântico evita a chamada inteira ao modelo quando a pergunta já tem resposta equivalente salva.
Qual o limiar de similaridade ideal para cache semântico?
Não existe número universal, depende do modelo de embedding e do domínio. O caminho prático é começar conservador, testar com perguntas reais e ajustar aos poucos observando os erros.
Cache semântico funciona bem para respostas que mudam com frequência?
Funciona mal se não houver invalidação ativa. Para conteúdo dinâmico, use TTL curto e invalide o cache manualmente quando a fonte de verdade mudar, senão o risco é servir resposta desatualizada.
Vale a pena usar cache semântico em aplicações pequenas?
Geralmente não compensa a complexidade se o volume de chamadas ainda é baixo. O ganho aparece quando existe repetição real de intenção em escala, não em projetos com poucas requisições por dia.
Cache semântico não é bala de prata, mas para aplicação com volume real e repetição de intenção, o ganho de custo e latência costuma justificar a implementação. Comece pequeno, calibre o limiar com dados reais e trate a invalidação como parte do design, não como detalhe.
Se você já sabe que tem repetição de pergunta na sua aplicação, o próximo passo é medir quanto disso está custando hoje antes de implementar qualquer camada nova. Depois, avalie se Redis resolve sozinho ou se o volume pede um banco vetorial dedicado.


