Guia de Cache de Inferência
Este artigo irá explicar como funciona o cache de inferência em modelos de linguagem grandes e como usá-lo para reduzir custos e latência em sistemas de produção. Abordaremos tópicos como o funcionamento do cache de inferência, os diferentes tipos de cache e como escolher a estratégia certa para sua aplicação. Ao final deste artigo, você estará equipado com as ferramentas necessárias para otimizar seu sistema de produção com cache de inferência.
Chamar uma API de modelo de linguagem grande em escala é caro e lento. Uma grande parte desse custo vem da computação repetida: o mesmo texto processado do zero a cada solicitação, e as mesmas consultas comuns respondidas como se o modelo nunca as tivesse visto antes. O cache de inferência resolve isso armazenando os resultados de computações caras de modelos de linguagem grandes e reutilizando-os quando uma solicitação equivalente chega. Dependendo da camada de cache que você aplica, você pode saltar computações de atenção redundantes no meio da solicitação, evitar reprocessar prefixos compartilhados de prompt entre solicitações ou atender consultas comuns a partir de uma busca sem invocar o modelo. Em sistemas de produção, isso pode reduzir significativamente o gasto de tokens com quase nenhuma alteração na lógica da aplicação.
Quando você envia um prompt para um modelo de linguagem grande, o modelo realiza uma quantidade significativa de computação para processar a entrada e gerar cada token de saída. Essa computação leva tempo e custa dinheiro. O cache de inferência é a prática de armazenar os resultados dessa computação — em vários níveis de granularidade — e reutilizá-los quando uma solicitação semelhante ou idêntica chega. Existem três tipos distintos para entender, cada um operando em uma camada diferente da pilha: cache de chave-valor (KV), cache de prefixo e cache semântico. Esses não são alternativas intercambiáveis; são camadas complementares. O cache de chave-valor é sempre executado. O cache de prefixo é a otimização de maior valor que você pode adicionar à maioria das aplicações de produção. O cache semântico é uma melhoria adicional quando o volume e a semelhança da consulta são suficientemente altos para justificá-lo.
O cache de chave-valor é a base sobre a qual tudo o mais é construído. Para entender isso, você precisa de um olhar breve sobre como funciona a atenção do transformador durante a inferência. Os modelos de linguagem grandes modernos usam a arquitetura de transformador com autoatenção. Para cada token na entrada, o modelo computa três vetores: consulta, chave e valor. As pontuações de atenção são computadas comparando cada token de consulta com as chaves de todos os tokens anteriores, e então usando essas pontuações para ponderar os valores. Isso permite que o modelo entenda o contexto em toda a sequência. Os modelos de linguagem grandes geram saída de forma autoregressiva — um token de cada vez. Sem cache, gerar o token N exigiria recomputar K e V para todos os N-1 tokens anteriores do zero. Para sequências longas, esse custo se acumula com cada passo de decodificação.
Durante uma passagem para frente, uma vez que o modelo computa os vetores K e V para um token, esses valores são salvos na memória da GPU. Para cada passo de decodificação subsequente, o modelo procura os pares K e V armazenados para os tokens existentes em vez de recomputá-los. Apenas o token recém-gerado exige computação fresca. Aqui está um exemplo simples: o cache de chave-valor em seu sentido original é uma otimização dentro de uma única solicitação. É automático e universal; todos os frameworks de inferência de modelos de linguagem grandes o habilitam por padrão. Você não precisa configurá-lo. No entanto, entendê-lo é essencial para entender o cache de prefixo, que estende esse mecanismo entre solicitações.
O cache de prefixo — também chamado de cache de prompt ou cache de contexto, dependendo do provedor — leva o conceito de cache de chave-valor um passo adiante. Em vez de armazenar estados de atenção apenas dentro de uma solicitação, ele os armazena entre múltiplas solicitações — especificamente para qualquer prefixo compartilhado que essas solicitações tenham em comum. Considere uma aplicação típica de modelo de linguagem grande em produção. Você tem um longo texto — instruções, um documento de referência e alguns exemplos — que é idêntico em todas as solicitações. Apenas a mensagem do usuário no final muda. Sem o cache de prefixo, o modelo recomputa os estados de chave-valor para todo esse texto em cada chamada. Com o cache de prefixo, ele os computa uma vez, armazena e toda solicitação subsequente que compartilha esse prefixo salta diretamente para processar a mensagem do usuário.
O cache de prefixo só funciona quando a porção armazenada do prompt é idêntica byte-a-byte. Uma única diferença de caractere — um espaço final, um ponto de pontuação alterado ou uma data reformatada — invalida o cache e força uma recomputação completa. Isso tem implicações diretas sobre como você estrutura seus prompts. Coloque o conteúdo estático primeiro e o conteúdo dinâmico por último. Instruções do sistema, documentos de referência e exemplos de poucos tiros devem liderar cada prompt. Variáveis por solicitação — a mensagem do usuário, um ID de sessão ou a data atual — devem aparecer no final. Da mesma forma, evite serialização não determinística, pois isso pode levar a prefixos inconsistentes e invalidar o cache. Para uma explicação mais aprofundada, consulte o Guia de Cache de Chave-Valor em Modelos de Linguagem Grandes para Desenvolvedores.
Em resumo, o cache de inferência é uma ferramenta poderosa para otimizar sistemas de produção que utilizam modelos de linguagem grandes. Compreender como funciona o cache de chave-valor e como estendê-lo para