One Door to the Models, Parte 6: Semantic Caching e Seus Modos de Falha
Um semantic cache é uma superfície de correção, não só uma alavanca de custo. A Parte 6 ajusta o threshold, isola tenants e trata o dia em que o cache some.

A própria documentação de policy da Microsoft diz que um score threshold acima de 0.2 pode levar a cache mismatch, o que é uma forma educada de dizer que o gateway vai responder uma pergunta que o chamador não fez. Todos os outros mecanismos desta série falharam fazendo barulho: um 429, um 503, um batch job expirado. Um semantic cache falha devolvendo uma resposta fluente, bem formada e confiante que pertence ao prompt de outra pessoa. A Parte 5 tornou o gasto atribuível. Esta parte o torna menor, e trata o mecanismo que faz isso como uma superfície de correção, não como uma alavanca de custo.
O que o cache realmente precisa antes de funcionar
Semantic caching no API Management tem uma lista de pré-requisitos que decide uma escolha de infraestrutura impossível de revisitar depois, então ela vem antes da policy, não depois.
- Um segundo model deployment, para embeddings. O deployment de chat completion atende as chamadas dos consumidores; um deployment separado de embeddings é o que o cache usa para transformar um prompt em um vetor. Isso é uma segunda linha de capacidade, uma segunda quota e uma segunda coisa para monitorar.
- Autenticação por managed identity do API Management para as APIs de modelo, que a policy exige:
embeddings-backend-authdeve ser definido comosystem-assigned. Não existe opção baseada em key aqui, o que é uma boa restrição. - Azure Managed Redis com o módulo RediSearch habilitado, configurado como external cache na instância de API Management.
Esse último item carrega a armadilha. O RediSearch só pode ser habilitado quando o cache é criado, e não pode ser adicionado a um cache existente. Uma plataforma que já roda uma instância Redis para sessões ou estado de rate-limit não pode simplesmente ligar o semantic caching: ela precisa de um cache novo, provisionado com o módulo, e o Terraform da Parte 2 é o lugar onde essa decisão fica registrada. Descobrir isso no meio de um sprint que orçou uma tarde para "habilitar caching" é o desfecho comum.
O par de policies
O lookup vai no inbound, o store vai no outbound, e cada um do par só pode aparecer uma vez por seção de policy. Ambos estão disponíveis nos escopos global, de product, de API e de operation, e nos gateways classic, v2, consumption e self-hosted.
<inbound>
<base />
<llm-semantic-cache-lookup
score-threshold="0.05"
embeddings-backend-id="embeddings-backend"
embeddings-backend-auth="system-assigned"
ignore-system-messages="true"
max-message-count="6">
<vary-by>@(context.Subscription.Id)</vary-by>
</llm-semantic-cache-lookup>
<rate-limit calls="10" renewal-period="60" />
</inbound>
<outbound>
<llm-semantic-cache-store duration="60" />
<base />
</outbound>
Quatro desses atributos são decisões, não boilerplate.
score-threshold define quão próximo um prompt de entrada precisa estar de um prompt em cache, em uma escala de 0.0 a 1.0, onde valores mais baixos exigem similaridade semântica mais alta. Isso inverte o que a maioria assume na primeira leitura, e errar a direção transforma um cache conservador em um promíscuo. A orientação da Microsoft é começar baixo, por volta de 0.05, e ajustar em direção à razão de hit para miss que você quer, com o aviso explícito de que acima de 0.2 os mismatches se tornam prováveis e de que casos de uso sensíveis devem ficar mais baixo.
ignore-system-messages="true" remove as system messages antes de a similaridade ser avaliada, e é recomendado. Importa mais do que parece: duas aplicações com perguntas de usuário idênticas e system prompts diferentes pareceriam diferentes para o cache, e uma única aplicação cujo system prompt fosse editado invalidaria o cache inteiro sem nenhuma razão semântica.
max-message-count pula o caching quando um diálogo passa do número especificado de mensagens restantes. Conversas longas são exatamente onde um match semântico é menos confiável, porque o significado da última mensagem depende de turnos que o embedding nunca viu.
vary-by é a fronteira de isolamento, e a próxima seção explica por que ele é um controle de segurança.
vary-by não é um capricho de particionamento
Sem vary-by, um único cache é compartilhado entre todos os chamadores da API. Um prompt do assistente de atendimento contendo os dados de um cliente pode ser respondido a partir de uma completion em cache, e um prompt semanticamente similar vindo de outro tenant pode ser respondido a partir dessa mesma entrada. A documentação diz sem rodeios: controle o acesso entre usuários às entradas do cache especificando vary-by com identificadores específicos de usuário ou de grupo de usuários.
Para esta plataforma o mínimo é o subscription ID, que alinha a fronteira do cache exatamente com a fronteira de tenancy que a Parte 5 construiu. Onde uma aplicação atende usuários finais cujos dados não podem se misturar, o valor correto é um claim do token validado, não algo que o chamador possa definir em um header, e é por isso que o validate-jwt da Parte 5 escreve seu token em output-token-variable-name. Um vary-by que lê um header não validado é um vazamento de dados entre tenants com um arquivo de configuração como causa raiz.
O custo do particionamento estreito é um hit rate mais baixo, e essa troca é real. Ela também é o default correto: um cache que nunca vaza e economiza 20 por cento vence um que economiza 45 por cento e um dia devolve a resposta do cliente errado.
A dependência que você acabou de adicionar
O cache fica no caminho de requisição de toda chamada, o que significa que o Redis agora está no caminho crítico do gateway. A recomendação da Microsoft é específica e vale seguir à risca: coloque uma policy rate-limit ou rate-limit-by-key imediatamente depois do cache lookup, para impedir que o backend seja sobrecarregado se o cache não estiver disponível.
Pense nessa falha até o fim. Em um dia normal, uma parcela significativa do tráfego nunca chega a um modelo. Se o Redis ficar indisponível, cada uma dessas requisições vira uma chamada real de completion, instantaneamente, contra uma quota dimensionada para o estado estável com cache. A queda do cache não degrada a plataforma, ela multiplica a carga, e o rate limit é o que converte isso de uma indisponibilidade em throttling. É a mesma lição de qualquer cache na frente de um banco de dados, e é mais fácil esquecer aqui porque o cache foi introduzido como otimização de custo, não como dependência de capacidade.
O deployment de embeddings merece o mesmo raciocínio. Todo lookup gera o embedding do prompt de entrada, então o modelo de embeddings precisa de capacidade suficiente e de tamanho de contexto suficiente para o volume e os comprimentos de prompt em produção. Um deployment de embeddings dimensionado para uma prova de conceito vira o gargalo de todo o tráfego, com cache ou sem, porque o lookup acontece antes de se saber se é hit ou miss.
O que um cache hit faz com os números da Parte 5
Um hit não é gratuito e não é uma completion. Ele custa uma chamada de embeddings, algum tempo de Redis e nenhum token de completion, o que significa que o modelo de chargeback da Parte 5 precisa de três pequenas mudanças, não de uma reescrita.
- O gasto com embeddings vira uma linha de custo da plataforma. Ele é incorrido em toda requisição, incluindo os misses, e não é atribuível a uma completion. Ou é cobrado dos tenants pro rata pela contagem de requisições, ou é absorvido pela plataforma. Escolha uma opção e documente; não a deixe fora da reconciliação.
- Hit rate é uma dimensão de métrica legítima. É de baixa cardinalidade e pertence ao dashboard ao lado do gasto, porque um hit rate que cai costuma ser uma mudança de prompt template que ninguém anunciou.
- A economia deve ser reportada como custo evitado, não como gasto. Um tenant cuja fatura caiu 30 por cento por causa do caching vai assumir que o número menor é a nova baseline. Mostrar tokens evitados ao lado de tokens faturados mantém essa conversa honesta, e sustenta o argumento pela instância Redis que a plataforma está pagando.
Quando não usar cache nenhum
Semantic caching serve a prompts de alto volume, baixa variância e não personalizados. A busca de conhecimento de varejo da empresa sobre documentação de produto está perto do ideal. Os outros casos não estão, e a policy deve ter escopo por API em vez de ser aplicada globalmente, que é exatamente o motivo de ela suportar escopo de product e de API.
Pule o cache onde a resposta depende da hora atual ou de estado vivo, porque um duration de 60 segundos é uma janela de correção, não só uma preferência de frescor. Pule em fluxos de tool-calling, onde a saída do modelo é uma instrução para agir, não um texto para ler, e uma instrução obsoleta é uma ação errada. Pule em qualquer coisa personalizada além do que o vary-by consegue particionar. E trate diálogos longos de múltiplos turnos como fora de escopo definindo max-message-count, em vez de torcer para o score de similaridade perceber.
Modos de falha para observar
- O threshold definido ao contrário. Mais alto é mais frouxo. Um time otimizando o hit rate o sobe para 0.4, a razão melhora, e os mismatches ficam invisíveis até um usuário reportar uma resposta que não tem nada a ver com a pergunta dele.
- Um
vary-byausente. Sem erro, sem aviso, e um cache compartilhado entre todos os tenants da API. - RediSearch descoberto tarde demais. O módulo não pode ser adicionado a um cache existente, então a resposta é um cache novo e uma migração, no meio de um trabalho que assumia uma mudança de configuração.
- Redis fora do ar, backend inundado. Sem o rate limit logo depois do lookup, uma queda do cache chega ao modelo como um pico de tráfego.
- Um deployment de embeddings subdimensionado. Ele é chamado em toda requisição, então estrangula hits e misses igualmente, e o sintoma parece o cache deixando tudo mais lento.
- Uma mudança de prompt template que esvazia o cache em silêncio. Vale alertar sobre o hit rate em vez de descobrir na fatura.
O que a Parte 7 herda
O cache responde repetições. Ele não faz nada pelo caso muito mais comum em que o modelo precisa de informação com a qual nunca foi treinado, que é o problema de retrieval, e a busca de conhecimento de varejo da empresa já está esperando por ele. A seguir: Azure AI Search contra um vector database dedicado, comparados nos termos que realmente decidem a escolha.
Leia isso a seguir
- Parte 7, Azure AI Search ou um Vector Database, onde a camada de retrieval é decidida por limites de serviço, não por features.
- Parte 5, Identidade, Quota e Chargeback, o modelo de contabilidade que os cache hits desta parte mudam em silêncio.
- Cache Semântico: Duas Perguntas Diferentes, Uma Resposta, o mecanismo em seus próprios termos, incluindo de onde vem o threshold de similaridade.
Para o lado de infraestrutura e plataforma de rodar isso em escala, as notas de campo estão em ercan.cloud, e o hub fica em ercanermis.com.
Referências
Mais de Ercan
Mais dois sites, mesmo autor, terreno diferente.
Cloud, AWS, EKS, Terraform, engenharia de plataforma.
Notas de campo de sistemas em produção. EKS, IAM, Terraform em escala organizacional, observabilidade, otimização de custos.
Visitar ercan.cloud →O hub. Sobre, consultoria, contato.
Hub pessoal para as duas trilhas de escrita. Quem sou eu, como funciona a consultoria, como me contatar.
Visitar ercanermis.com →