Quantizar o cache KV: economizar VRAM (longo contexte)
Você tem VRAM suficiente para carregar o modelo, mas, assim que aumenta o contexto para 16k ou 32k tokens, a capacidade da VRAM é excedida. O culpado é o KV cache: uma memória oculta que cresce linearmente com o contexto e que, em prompts longos, pode ocupar tanto espaço quanto o próprio modelo. A quantização do KV cache o compacta em Q8 ou Q4 para dobrar o contexto que cabe na mesma placa. Veja como ativá-la no Ollama e no llama.cpp, os ganhos quantificados e o impacto real na qualidade.
#Por que o cache KV consome sua VRAM
Quando um LLM gera texto, ele não recalcula a atenção sobre todo o prompt a cada novo token: ele mantém em memória os vetores de chave (K) e valores (V) de cada token já visto. Isso é o KV cache, e é o que torna a geração rápida. O problema: essa memória cresce linearmente com o comprimento do contexto. Dobre o contexto, você dobra o KV cache.
Com um prompt curto de algumas centenas de tokens, é insignificante. Mas assim que se passa a usar RAG com grandes documentos, resumos de transcrições ou agentes com memória longa, o contexto explode — e o KV cache também. Em um modelo de 70B com 32k de contexto, ele pode ultrapassar 10 GB sozinho, além dos ~40 GB do modelo. Muitas vezes é ele, e não o modelo, que causa a falta de memória em prompts longos.
#Quanto pesa seu cache KV
Seu ChatGPT privado e gratuito na sua máquina em 1 hora — LM Studio, Ollama, Open WebUI, seus documentos, sem nuvem.
- Espaço online vitalício
- PDF + arquivos
- Atualizações vitalícias
O tamanho do cache KV depende de quatro fatores: o número de camadas do modelo, a dimensão de atenção, o comprimento do contexto e a precisão de armazenamento. Em FP16 (padrão), a fórmula aproximada é: 2 (K e V) × camadas × dim_kv × contexto × 2 bytes. Na prática, tenha em mente estas ordens de grandeza em FP16 com um contexto de 32k tokens:
- 7-9B (ex. Qwen 3.5 9B, Granite 4.2 8B)
- Aproximadamente 2 a 4 GB de cache KV com 32k, dependendo da arquitetura (GQA ajuda muito).
- 14B
- ≈ 4 a 6 GB em 32k tokens.
- 32B
- ≈ 8 a 10 GB com 32k tokens.
- 70B
- ≈ 10 a 16 GB para 32k tokens — geralmente o fator limitante.
#O que a quantização do cache KV muda
A ideia é a mesma dos pesos do modelo: ao invés de armazenar cada valor do cache em 16 bits (FP16), armazena-se em 8 bits (Q8_0) ou 4 bits (Q4_0). Divide-se mecanicamente a memória do cache por 2 (Q8) ou por 4 (Q4). Como o KV cache pode representar uma grande parte da VRAM em contextos longos, o ganho é direto: com VRAM constante, é possível dobrar aproximadamente a extensão do contexto em Q8.
- FP16
- Precisão de referência, sem perda, mas é a que mais consome memória. É a opção padrão.
- Q8_0
- Metade da memória, perda de qualidade quase indetectável na maioria dos modelos. O melhor equilíbrio.
- Q4_0
- Quatro vezes menos memória, mas perda de qualidade mensurável, variável conforme o modelo. Reservado para casos em que a VRAM realmente é o fator limitante.
#Ativar a quantização KV no Ollama
Ollama expõe a quantização do cache KV através de duas variáveis de ambiente do daemon. É necessário ativar o Flash Attention, depois escolher o tipo de cache. Essas variáveis são definidas no serviço Ollama, não no momento do ollama run.
- 01Ativar Flash AttentionDefina OLLAMA_FLASH_ATTENTION=1 no ambiente do daemon. É o pré-requisito para qualquer cache não-FP16.
- 02Escolher o tipo de cacheDefina OLLAMA_KV_CACHE_TYPE com o valor desejado: f16 (padrão), q8_0 (recomendado) ou q4_0 (agressivo).
- 03Reiniciar o daemonAs variáveis de ambiente são lidas apenas na inicialização do serviço. Reinicie o Ollama para que elas sejam aplicadas.
- 04Verificar o ganhoCarregue um modelo com um contexto grande e monitore a VRAM com nvidia-smi ou ollama ps. Você deve conseguir usar um valor de num_ctx maior do que antes.
#Ativar no llama.cpp
Na linha de comando com llama.cpp, a quantização do cache KV é controlada por duas flags distintas para as chaves (K) e os valores (V), além da flag de Flash Attention. É possível quantizar K e V de forma independente, mas, na prática, ambos são configurados no mesmo nível.
- -fa
- Ative o Flash Attention. Sem essa opção, -ctk/-ctv com precisão inferior a f16 falha.
- -ctk q8_0
- Quantiza o cache das chaves em 8 bits. Valores possíveis: f16, q8_0, q4_0, q4_1, q5_0, q5_1.
- -ctv q8_0
- Quantiza o cache dos valores. Mesmo conjunto de valores que -ctk.
- -c 32768
- O tamanho de contexto que você pretende usar. É esse tamanho que a quantização permite aumentar sem exceder a memória disponível.
#Quanto contexto ganhamos: números reais
O ganho concreto depende da parcela da sua capacidade de VRAM ocupada pelo cache KV. Quando o modelo cabe com folga, quantizar o cache libera apenas um pouco de espaço. Quando o modelo já ocupa toda a VRAM disponível, isso pode fazer a diferença entre 8k e 24k de contexto. Aqui estão ordens de grandeza observadas, mantendo a mesma quantidade de VRAM:
- FP16 → Q8_0
- Cache dividido por 2. Na prática, o tamanho do contexto que cabe na memória aproximadamente dobra quando o cache era o principal consumidor da memória disponível.
- FP16 → Q4_0
- Cache dividido por 4. É possível manter um contexto até cerca de 3 a 4 vezes mais longo, ao custo de uma perda de qualidade mensurável.
- Exemplo de 14B na RTX 4080 de 16GB
- De ~16k de contexto em FP16 a ~32k+ em Q8_0, com o modelo e o restante cabendo nos mesmos 16 GB.
- Exemplo de 32B em RTX 4090 24GB
- Passar o cache para Q8_0 muitas vezes permite superar a barreira dos documentos longos de RAG sem offload para a CPU.
#O impacto na qualidade conforme o modelo
Essa é a verdadeira pergunta. Quantizar o cache introduz ruído na atenção, e nem todos os modelos reagem da mesma forma. A regra empírica que emerge dos testes comunitários:
- Q8_0 no cache
- Diferença quase indetectável na grande maioria dos modelos. Perplexidade e qualidade percebida quase idênticas às obtidas com FP16. É o ajuste a ser ativado por padrão, quase sem pensar.
- Q4_0 no cache
- Perda visível e variável. Alguns modelos lidam muito bem com isso; outros começam a divagar em contextos muito longos, a perder o fio ou a alucinar mais. Testar no SEU caso.
- Modelos com GQA
- Geralmente mais robustos à quantização do cache, pois seu cache já é compacto e bem estruturado.
- Tarefas sensíveis (código, cálculo, extração estrita)
- Mais suscetíveis à degradação Q4. Mantenha Q8 para tudo que exige precisão factual.
#Solução de problemas
- « flash attention required » ou cache ignorado
- Você esqueceu -fa (llama.cpp) ou OLLAMA_FLASH_ATTENTION=1 (Ollama). O cache quantizado volta silenciosamente para FP16, ou um erro é gerado.
- Nenhum ganho de VRAM visível
- Seu contexto é curto demais para que o cache ocupe uma quantidade significativa de memória. O ganho só aparece em prompts longos. Aumente num_ctx / -c para constatá-lo.
- Qualidade que piora em prompts longos
- Você provavelmente está em Q4 em um modelo que não suporta bem. Volte para K em q8_0 (ou até mesmo totalmente em q8_0) e teste novamente.
- Variáveis Ollama sem efeito
- Elas só são lidas na inicialização do daemon. Reinicie o serviço depois de defini-las e verifique se estão de fato visíveis para o processo ollama.
- Ainda ocorre OOM apesar da quantização
- É o próprio modelo que excede a memória disponível, não o cache. Quantize também os pesos (Q4_K_M) ou escolha um modelo de tamanho menor.
#Para se aprofundar
A quantização do cache KV é um dos recursos para acomodar grandes contextos localmente. Estes guias completam o panorama:
- Flash Attention 2 em LLM local: ativar e medir o ganho de desempenho
- O pré-requisito da quantização KV, que também proporciona ganhos de memória e velocidade por si só. Leia primeiro se o Flash Attention ainda não estiver ativo na sua instalação.
- Escolher sua quantização (Q4, Q5, Q8, FP16)
- Para quantizar os pesos do modelo — o outro grande consumidor de VRAM —, em complemento à quantização do cache.
- Instalar o Ollama: Windows, macOS e Linux
- Se sua stack ainda não estiver montada, com os pré-requisitos de GPU para dimensionamento adequado.
Um comentário, um erro ou uma observação? Avise-nos; isso ajuda a melhorar o guia para todos.