Capítulo 18 · Inferência · 8 min
Por que o 2º token é mais rápido que o 1º
O KV cache e a geração autorregressiva. Prefill vs decode, TTFT, e por que o cache muda tudo.
A ilusão do tempo de resposta
Você faz uma pergunta ao ChatGPT. Ele leva um segundo para começar a responder. Depois as palavras saem quase instantaneamente, na velocidade de uma leitura rápida.
Essa assimetria não é um capricho de interface. É a marca de uma otimização fundamental, sem a qual gerar texto com um LLM custaria cem vezes mais caro: o KV cache.
Como um Transformer gera um token
A cada passo de geração, o Transformer precisa produzir um novo token. Para isso, ele calcula a atenção do último token sobre todos os tokens anteriores. É assim que ele leva em conta o contexto inteiro.
Mas a atenção precisa, para cada token do contexto, de dois vetores: uma chave (K) e um valor (V). Sem otimização, a cada novo token gerado, o modelo recalcula K e V para toda a sequência — incluindo os tokens já processados no passo anterior. É um trabalho O(n²) no comprimento da sequência: dobrar o número de tokens quadruplica o custo.
É inútil: esses vetores não mudaram. O token n°3 tem a mesma chave K₃ que tinha no passo anterior.
O KV cache: nunca recalcular o que já temos
A ideia é trivial e decisiva. Mantemos na memória (no GPU) os K e V de todos os tokens já processados. A cada novo passo de geração, calculamos apenas o K e o V do novo token, e o adicionamos ao cache.
Cuidado para não superestimar o ganho: o que fica constante é o cálculo dos K e V do novo token. A atenção, essa, ainda precisa comparar esse token com cada uma das chaves do cache — continua proporcional a n. O que se economiza é o recálculo de todo o prefixo: cada passo passa de O(n²) para O(n).
Rode a geração nas duas colunas abaixo e olhe o contador de operações em vez da animação. Pergunte-se a cada passo: o que está sendo realmente recalculado, e o que só é calculado uma vez?
Sem cache, cada novo token recalcula toda a attention sobre o prefixo — custo em O(n²). Com cache, calcula-se apenas a nova linha. É isso que separa o primeiro token (lento, prefill) do segundo (rápido, decode).
À esquerda, sem cache: cada passo redesenha todas as linhas. À direita, com cache: simplesmente acrescentamos uma linha. Depois de alguns tokens, o gap em operações acumuladas se torna considerável.
Prefill vs decode: duas fases bem distintas
A geração com um LLM se divide em duas fases que os engenheiros de inferência distinguem cuidadosamente.
Prefill. O modelo recebe o prompt completo e calcula K e V para todos os seus tokens em paralelo. É rápido em termos de throughput — o GPU fica saturado — mas leva tempo se o prompt for longo. É isso que determina o TTFT (Time To First Token), o atraso até a primeira palavra aparecer.
Decode. O modelo gera o resto, um token por vez, reutilizando o cache. Cada passo é rápido individualmente, mas sequencial: não dá para paralelizar os tokens futuros, já que cada um depende do anterior. É isso que determina a ITL (Inter-Token Latency).
Essas duas fases têm perfis completamente diferentes:
| Prefill | Decode | |
|---|---|---|
| Paralelizável? | Sim (todos os tokens de uma vez) | Não (sequencial) |
| Limite de hardware | Compute (FLOPs) | Memória (leitura do cache) |
| Efeito do comprimento | Linear em N | Linear em N por token |
| Métrica chave | TTFT | ITL |
Em um prompt longo, o prefill pode levar alguns segundos. Em uma saída longa, é o decode que domina — e ele é limitado pela velocidade com que o KV cache pode ser lido da memória HBM do GPU.
Por que os providers cobram os "input tokens" de forma diferente
Se você olhar os preços da OpenAI, da Anthropic ou do Google, os input tokens são sistematicamente mais baratos que os output tokens — frequentemente 4× a 8× mais baratos. Isso não é arbitrário. O prefill, que processa os input tokens, é massivamente paralelo e usa o GPU de forma eficiente. O decode, por sua vez, gera os output tokens um por um e aproveita mal o hardware.
De forma mais sutil: Anthropic, OpenAI e outros agora oferecem o prefix caching. Se várias requisições começam com o mesmo system prompt, o KV cache desse prefixo é calculado uma única vez e reutilizado. É isso que torna agentes e chatbots multi-turno economicamente viáveis: sem prefix caching, cada turno custaria reprocessar a conversa inteira.
O custo escondido: a memória do GPU
O KV cache não é grátis em memória. Ele ocupa:
memória = 2 × n_layers × n_kv_heads × d_head × seq_len × batch_size × 2 bytes (FP16)
n_kv_heads é o número de heads que realmente possuem seus próprios K e V. Em um Transformer multi-head clássico, ele vale simplesmente n_heads. Nos modelos recentes ele é bem menor — veremos por que logo abaixo.
Para um modelo de 70 bilhões de parâmetros com contexto de 128.000 tokens e batch de 1, estamos falando de dezenas de GB. Isso é frequentemente o que limita o comprimento de contexto prático, mais do que a capacidade do próprio modelo de raciocinar sobre a sequência.
Para ir além, existem várias técnicas:
- Cache quantization: armazenar K e V em INT8 ou INT4 em vez de FP16, dividindo a memória por 2 ou 4.
- MQA / GQA (Multi-Query / Grouped-Query Attention): compartilhar os K/V entre vários heads. Llama 2 70B e Llama 3 usam GQA, o que reduz drasticamente o tamanho do cache.
- Sliding window attention: manter apenas uma janela recente do cache (Mistral, Gemma).
- PagedAttention (vLLM): tratar o cache como páginas de memória virtual, para gerenciar melhor o batching dinâmico.
Quantization, em duas palavras
A palavra aparece em todo lugar nesta parte: QLoRA em 4 bits (capítulo 14), cache quantization logo acima, modelos GGUF que você baixa do Hugging Face. É hora de explicar o que isso significa.
Quantizar é representar cada parâmetro do modelo com menos bits. Um número de ponto flutuante de 32 bits (FP32) ocupa 4 bytes. Em FP16, 2 bytes. Em INT8, 1 byte. Em INT4, meio byte — a memória ocupada pelos pesos é dividida por 8 em comparação com o FP32 original.
| Precisão | Bytes / parâmetro | Modelo 70B ocupa |
|---|---|---|
| FP32 | 4 | 280 GB |
| FP16 / BF16 | 2 | 140 GB |
| INT8 | 1 | 70 GB |
| INT4 | 0,5 | 35 GB |
| INT2 (extremo) | 0,25 | 17,5 GB |
O truque: um peso de 0,237 não se torna exatamente 0,237 em INT4 (que tem apenas 16 valores possíveis), mas o valor mais próximo em uma grade discreta. A perda de qualidade depende do modelo e do método, mas é tipicamente pequena até INT8, modesta em INT4 (alguns % de degradação nos benchmarks), significativa abaixo disso.
As técnicas modernas (GPTQ, AWQ, GGUF) não quantizam todos os pesos da mesma forma — elas preservam a precisão das camadas sensíveis e comprimem mais agressivamente as outras. E a quantization do KV cache, mencionada acima, aplica exatamente a mesma ideia às ativações armazenadas em memória durante a geração.
É essa técnica que permite rodar Llama 70B em um MacBook com 64 GB de RAM, onde a versão FP16 exige um cluster.
A lição
Sem o KV cache, os LLMs em produção seriam impraticáveis. Uma conversa longa, um agente que pensa, um chatbot que lembra do que você disse cinco mensagens atrás — nada disso seria economicamente viável.
Mas esse cache também é o que limita o comprimento do contexto. Quando se fala em "janela de 1 milhão de tokens", isso é em grande parte um problema de memória de cache, não um problema de cálculo de atenção.
O KV cache não é uma otimização entre outras. É o que transforma a atenção de um mecanismo teórico em uma infraestrutura de produção.
O que desloca a questão do tamanho. Um modelo não custa apenas o que se pagou para treiná-lo uma vez: ele custa memória e cálculo a cada token, em cada requisição, para sempre. Então, se um modelo menor pode ser servido bilhões de vezes por uma fração do preço, "maior" ainda quer dizer "melhor"? O próximo capítulo mostra que a pesquisa já decidiu — e não no sentido que se imagina.
Atualizado em