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 ilusao do tempo de resposta
Voce faz uma pergunta ao ChatGPT. Ele leva um segundo para comecar a responder. Depois as palavras saem quase instantaneamente, na velocidade de uma leitura rapida.
Essa assimetria nao e um capricho de interface. E a marca de uma otimizacao 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 geracao, o Transformer precisa produzir um novo token. Para isso, ele calcula a atencao do ultimo token sobre todos os tokens anteriores. E assim que ele leva em conta o contexto inteiro.
Mas a atencao precisa, para cada token do contexto, de dois vetores: uma chave (K) e um valor (V). Sem otimizacao, a cada novo token gerado, o modelo recalcula K e V para toda a sequencia — incluindo os tokens ja processados no passo anterior. E um trabalho O(n²) no comprimento da sequencia: dobrar o numero de tokens quadruplica o custo.
E inutil: esses vetores nao mudaram. O token n°3 tem a mesma chave K₃ que tinha no passo anterior.
O KV cache: nunca recalcular o que ja temos
A ideia e trivial e decisiva. Mantemos na memoria (no GPU) os K e V de todos os tokens ja processados. A cada novo passo de geracao, calculamos apenas o K e o V do novo token, e o adicionamos ao cache.
A atencao olha entao o cache completo, mas o calculo a fazer nesse passo e O(1) em tamanho — nao O(n).
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).
A esquerda, sem cache: cada passo redesenha todas as linhas. A direita, com cache: simplesmente acrescentamos uma linha. Depois de alguns tokens, o gap em operacoes acumuladas se torna consideravel.
Prefill vs decode: duas fases bem distintas
A geracao com um LLM se divide em duas fases que os engenheiros de inferencia distinguem cuidadosamente.
Prefill. O modelo recebe o prompt completo e calcula K e V para todos os seus tokens em paralelo. E rapido em termos de throughput — o GPU fica saturado — mas leva tempo se o prompt for longo. E isso que determina o TTFT (Time To First Token), o atraso ate a primeira palavra aparecer.
Decode. O modelo gera o resto, um token por vez, reutilizando o cache. Cada passo e rapido individualmente, mas sequencial: nao da para paralelizar os tokens futuros, ja que cada um depende do anterior. E isso que determina a ITL (Inter-Token Latency).
Essas duas fases tem perfis completamente diferentes:
| Prefill | Decode | |
|---|---|---|
| Paralelizavel? | Sim (todos os tokens de uma vez) | Nao (sequencial) |
| Limite de hardware | Compute (FLOPs) | Memoria (leitura do cache) |
| Efeito do comprimento | Linear em N | Linear em N por token |
| Metrica chave | TTFT | ITL |
Em um prompt longo, o prefill pode levar alguns segundos. Em uma saida longa, e o decode que domina — e ele e limitado pela velocidade com que o KV cache pode ser lido da memoria HBM do GPU.
Por que os providers cobram os "input tokens" de forma diferente
Se voce olhar os precos da OpenAI, da Anthropic ou do Google, os input tokens sao sistematicamente mais baratos que os output tokens — frequentemente 4× a 5× mais baratos. Isso nao e arbitrario. O prefill, que processa os input tokens, e 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 varias requisicoes comecam com o mesmo system prompt, o KV cache desse prefixo e calculado uma unica vez e reutilizado. E isso que torna agentes e chatbots multi-turno economicamente viaveis: sem prefix caching, cada turno custaria reprocessar a conversa inteira.
O custo escondido: a memoria do GPU
O KV cache nao e gratis em memoria. Ele ocupa:
memoria = 2 × n_layers × n_heads × d_head × seq_len × batch_size × 2 bytes (FP16)
Para um modelo de 70 bilhoes de parametros com contexto de 128.000 tokens e batch de 1, estamos falando de dezenas de GB. Isso e frequentemente o que limita o comprimento de contexto pratico, mais do que a capacidade do proprio modelo de raciocinar sobre a sequencia.
Para ir alem, existem varias tecnicas:
- Cache quantization: armazenar K e V em INT8 ou INT4 em vez de FP16, dividindo a memoria por 2 ou 4.
- MQA / GQA (Multi-Query / Grouped-Query Attention): compartilhar os K/V entre varios 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 paginas de memoria virtual, para gerenciar melhor o batching dinamico.
Quantization, em duas palavras
A palavra aparece em todo lugar nesta parte: QLoRA em 4 bits (capitulo 14), cache quantization logo acima, modelos GGUF que voce baixa do Hugging Face. E hora de explicar o que isso significa.
Quantizar e representar cada parametro do modelo com menos bits. Um numero de ponto flutuante de 32 bits (FP32) ocupa 4 bytes. Em FP16, 2 bytes. Em INT8, 1 byte. Em INT4, meio byte — a memoria ocupada pelos pesos e dividida por 8 em comparacao com o FP32 original.
| Precisao | Bytes / parametro | 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 nao se torna exatamente 0,237 em INT4 (que tem apenas 16 valores possiveis), mas o valor mais proximo em uma grade discreta. A perda de qualidade depende do modelo e do metodo, mas e tipicamente pequena ate INT8, modesta em INT4 (alguns % de degradacao nos benchmarks), significativa abaixo disso.
As tecnicas modernas (GPTQ, AWQ, GGUF) nao quantizam todos os pesos da mesma forma — elas preservam a precisao das camadas sensiveis e comprimem mais agressivamente as outras. E a quantization do KV cache, mencionada acima, aplica exatamente a mesma ideia as ativacoes armazenadas em memoria durante a geracao.
E essa tecnica que permite rodar Llama 70B em um MacBook com 64 GB de RAM, onde a versao FP16 exige um cluster.
A licao
Sem o KV cache, os LLMs em producao seriam impraticaveis. Uma conversa longa, um agente que pensa, um chatbot que lembra do que voce disse cinco mensagens atras — nada disso seria economicamente viavel.
Mas esse cache tambem e o que limita o comprimento do contexto. Quando se fala em "janela de 1 milhao de tokens", isso e em grande parte um problema de memoria de cache, nao um problema de calculo de atencao.
O KV cache nao e uma otimizacao entre outras. E o que transforma a atencao de um mecanismo teorico em uma infraestrutura de producao.
Atualizado em