Capítulo 7 — Estratégias Avançadas de Batching

Publicado em: 2026-04-29 Última atualização em: 2026-07-07 Versão: 1
Capítulo 7 — Estratégias Avançadas de Batching

Capítulo 7 — Estratégias Avançadas de Batching

Sétimo post do passeio capítulo a capítulo pelo LLM Primer VI: Escalando Sistemas de IA. O capítulo que mostra por que o batching não é uma otimização, mas o movimento estrutural que torna a decodificação limitada por largura de banda tratável — e por que "lote" (batch) é um verbo, não um substantivo.


Por que este capítulo existe

Um único passo de decodificação lê dezenas de gigabytes de pesos da HBM para produzir um token. Se a GPU está transmitindo esses pesos de qualquer jeito, ela pode produzir um token para muitas requisições no mesmo passo, a custo marginal quase zero. Batching, portanto, não é uma otimização no sentido comum — é a única maneira de tornar a decodificação economicamente tratável em hardware limitado por largura de banda de memória. Mas a maneira óbvia de fazer batching colapsa ao contato com o mundo real, porque as requisições têm comprimentos diferentes e terminam em momentos diferentes. O Capítulo 7 percorre o caminho do esquema ingênuo que quase funciona até o escalonador em nível de iteração que os motores de produção de fato rodam, e nomeia a dívida que esse escalonador cria para o Capítulo 8 pagar.

Em uma linha: O batching contínuo transforma o "lote" de substantivo em verbo — sequências entram e saem a cada iteração — e ao fazer isso expõe o KV cache como a nova restrição vinculante.

7.1 O batching estático é derrotado pelo problema do que termina primeiro

O batching estático é o que todo mundo escreve primeiro: acumular requisições até atingir o batch B ou um timeout, rodar prefill em todo o lote no comprimento S_max, e rodar um loop de decodificação até que toda sequência do lote emita EOS. Os dois custos são catastróficos em combinação. O padding — o prompt de 50 tokens no mesmo lote que o prompt de 4.000 tokens paga 80 vezes o trabalho de prefill de que precisa. O que termina primeiro — o loop de decodificação roda até que todas as sequências terminem, então um lote com uma requisição de 20 tokens e outra de 2.000 tokens passa 99% do tempo com 31 slots produzindo tokens que serão descartados. A vazão média parece aceitável e a latência de cauda é dominada por qualquer requisição longa que por acaso caiu naquele lote. O batching dinâmico (timeout variável, admitir chegadas atrasadas no lote pendente) suaviza a espera mas não muda o esquema fundamental; ele herda o mesmo problema do que termina primeiro assim que a decodificação começa.

7.2 O batching contínuo escalona por iteração, não por requisição

O batching contínuo — o escalonamento em nível de iteração do Orca, o in-flight batching da NVIDIA, "o truque central" do vLLM e do TGI — é a mudança de variável. Em vez de comprometer um lote pela duração da geração, o escalonador revisita a composição do lote a cada passo de decodificação. Após cada passo: sequências terminadas deixam seus slots e liberam o KV; novas sequências da fila entram nos slots liberados; o passo conjunto de decodificação roda sobre o novo conjunto ativo. Duas propriedades da decodificação em LLM tornam isso possível. Cada passo de decodificação é estruturalmente a mesma operação — o kernel não se importa qual sequência está no slot 7 versus no slot 11. E cada sequência carrega seu próprio KV cache de forma independente, então sua memória simplesmente fica disponível quando ela sai. A unidade de justiça vira a iteração, não a requisição: uma requisição de 20 tokens termina em cerca de 20 iterações independentemente de quem mais está no lote, e uma de 2.000 tokens ocupa um slot pelo tempo que precisar sem manter as outras reféns. Em tráfego real de cauda longa — misturas de turnos curtos de chat e completions longas de RAG — a utilização da GPU em um modelo de 70B sobe da faixa de 10 a 20% típica do batching estático para 60 a 80%, e a latência p99 aperta drasticamente.

7.3 O chunked prefill unifica prefill e decodificação no mesmo chip

O batching contínuo ainda deixa uma tensão. Novas chegadas precisam de prefill, que é limitado por compute e prefere sequências longas por passo. Sequências em voo precisam de decodificação, que é limitada por largura de banda de memória e prefere lotes largos. Rodar um prefill completo de um prompt novo de 4.000 tokens no mesmo forward pass que o passo de decodificação de trinta sequências em andamento ou atrasa as decodificações em andamento (TTFT ruim para os usuários existentes) ou atrasa o prefill da nova chegada (TTFT ruim para o novo usuário). O chunked prefill divide o prefill em pedaços — digamos, 512 tokens por vez — e intercala esses pedaços com os passos de decodificação das sequências ativas. O forward pass único agora carrega ao mesmo tempo algum trabalho de prefill de novo prompt e algum trabalho de decodificação em andamento, e as duas fases compartilham o mesmo streaming de pesos. O caráter compute-bound do prefill absorve a aritmética; a demanda de largura de banda da decodificação é amortizada em mais trabalho útil por byte. As duas fases deixam de ser antagônicas em um único chip. O caso restante — tráfego suficiente para elas ainda brigarem — é o setup para o serving desagregado no Capítulo 12.

Vale a pena guardar: O ganho de throughput do batching contínuo é real, e ele reformula o problema de memória. Sequências entram e saem a cada passo, então o motor não pode pré-alocar uma laje fixa por slot. Qualquer esquema de memória que substitua a laje precisa sobreviver a admissões e evicções constantes — e é por isso que paginação.

O que o Capítulo 7 prepara

O batching contínuo faz seu trabalho e, ao fazê-lo, expõe o KV cache como a restrição vinculante da concorrência. Cada sequência ativa carrega seu próprio KV, dimensionado em proporção ao seu comprimento atual; sequências entram e saem a cada passo; o motor não pode saber de antemão quão longa qualquer uma delas será. Um layout ingênuo de uma laje por slot devolve a maior parte do ganho do batching. O Capítulo 8 traz a solução do sistema operacional: dividir o cache em pequenos blocos físicos, desacoplá-los das posições lógicas de token com uma tabela de páginas, e deixar uma política de evicção reclamar ou compartilhar blocos entre sequências. O PagedAttention é o movimento que torna o problema de KV do batching contínuo tratável.


Próximo — Capítulo 8: Gerenciamento de KV Cache de Próxima Geração. PagedAttention, evicção H2O, InfiniGen e a economia do prefix caching.

Quer o panorama completo? O capítulo do livro inclui a implementação executável de batching estático, o escalonador completo de batching contínuo no espírito do vLLM/TGI, o traço passo a passo trabalhado de seis requisições atravessando um motor de quatro slots e a discussão de preempção/evicção/controle de admissão para a qual o artigo não tem espaço. Veja o LLM Primer VI na Amazon →

SHO
SHO
CTO e Fundador da RECEIPTROLLER. Focado em dados, movido pela inovação, sempre curioso.