Phase 17 - Lesson 06
SGLang e RadixAttention para Cargas de Trabalho Intensivas em Prefixos
O SGLang trata o KV cache como um recurso reutilizável de primeira classe armazenado em uma árvore radix (radix tree). Enquanto o vLLM agenda requisições com base em FCFS (first-come, first-served), o agendador baseado em cache (cache-aware scheduler) do SGLang prioriza requisições com prefixos compartilhados mais longos — efetivamente uma travessia radix de busca em profundidade (depth-first radix traversal) para que os ramos quentes (hot branches) permaneçam residentes na HBM. No Llama 3.1 8B com prompts de 1K semelhantes ao ShareGPT, o SGLang atinge ~16.200 tok/s versus ~12.500 do vLLM, uma vantagem de ~29%. Em cargas de trabalho de RAG intensivas em prefixos, a vantagem chega a 6,4x. Em cargas de trabalho de clonagem de voz, a taxa de acerto do cache superou 86%. Implementado em mais de 400.000 GPUs em 2026 nas empresas xAI, LinkedIn, Cursor, Oracle, GCP, Azure e AWS. O detalhe é que o fator de 6,4x desaparece quando a ordenação do prefixo não é consistente — a ordenação representa a alavanca do engenheiro.
Tipo: Aprender Linguagens: Python (stdlib, simulador simplificado de cache em árvore radix + agendador baseado em cache) Pré-requisitos: Phase 17 · 04 (vLLM Serving Internals), Phase 14 (Agentic RAG) Tempo: ~75 minutos
Objetivos de Aprendizagem
- Diagramar o RadixAttention: como os prefixos são armazenados em uma árvore radix e como os blocos de KV são compartilhados entre sequências enraizadas no mesmo ramo.
- Explicar o agendamento baseado em cache e por que o FCFS está errado para tráfego intensivo em prefixos.
- Calcular a aceleração esperada para uma carga de trabalho dada a taxa de acerto do cache de prefixo e a distribuição de comprimento dos prompts.
- Nomear a disciplina de ordenação de prompts que torna real a aceleração de 6,4x em vez de um benefício desperdiçado.
O Problema
O serviço clássico de inferência trata o prompt de cada requisição como opaco. Mesmo quando 5.000 requisições de RAG começam com o mesmo prompt de sistema de 2.000 tokens e o mesmo preâmbulo de recuperação, o vLLM realiza o prefill desse prefixo de 2.000 tokens 5.000 vezes. A GPU realiza o mesmo trabalho repetidamente.
A observação: prompts em cargas de trabalho agenticas e de RAG compartilham prefixos longos quase sempre. Prompt de sistema, esquemas de ferramentas, exemplos de poucas demonstrações (few-shot), cabeçalhos de recuperação, histórico de conversação — tudo se repete entre as requisições. Se você armazenasse o KV cache desse prefixo uma vez e o reutilizasse, não precisaria fazer o prefill dele novamente.
O RadixAttention faz exatamente isso. Os tokens são indexados em uma árvore radix; cada nó possui blocos de KV para a sequência de tokens em seu caminho a partir da raiz. Uma nova requisição percorre a árvore: qualquer nó cujo token corresponda reutiliza os blocos de KV desse nó. O custo do prefill torna-se proporcional ao sufixo "novo", e não ao prompt completo.
O desafio está no agendamento. Se duas requisições compartilham um prefixo de 2.000 tokens e uma terceira compartilha apenas 200 tokens do mesmo prefixo, você deseja atender as duas requisições com maior compartilhamento juntas para que o prefixo longo permaneça na HBM. O FCFS faz o oposto — atende a quem chegou primeiro, potencialmente despejando o ramo quente antes que a próxima requisição com o prefixo longo chegue.
O Conceito
A árvore radix como um índice de KV
Uma árvore radix (trie compacta) armazena sequências de tokens. Cada nó possui uma faixa de tokens e os blocos de KV computados para essa faixa. Os nós filhos estendem a sequência em um ou mais tokens.
root
|- "You are a helpful assistant..." (2.000 tokens, 124 blocos de KV)
|- "Context: <doc A>..." (500 tokens, 31 blocos)
|- "Question: Alice..." (80 tokens, 5 blocos)
|- "Question: Bob..." (95 tokens, 6 blocos)
|- "Context: <doc B>..." (520 tokens, 33 blocos)
Uma nova requisição chega com prompt de sistema + "Context:
Agendamento baseado em cache (cache-aware)
A reutilização baseada em árvore radix não tem sentido se o cache sofrer desgaste contínuo (thrashing). Duas políticas fundamentais:
- Despacho em profundidade (depth-first dispatch). Ao escolher a próxima requisição da fila, dê preferência a requisições enraizadas no mesmo ramo do conjunto em execução atual. Isso mantém o ramo quente fixado.
- LRU no nível do ramo, não do bloco. Despeje ramos inteiros (começando pelas folhas menos utilizadas recentemente) em vez de blocos individuais, para que o formato do cache corresponda ao formato radix.
O FCFS viola ambas as políticas. Uma requisição que compartilha 2.000 tokens fica atrás de uma requisição que compartilha 50 tokens, e então o ramo de 2.000 tokens é despejado para admitir a requisição de 50 tokens.
Números de benchmark que você deve memorizar
- Llama 3.1 8B, H100, prompts de 1K do ShareGPT: SGLang ~16.200 tok/s vs vLLM ~12.500 (vantagem de ~29%).
- RAG intensivo em prefixos (mesmo sistema + mesmo documento, alterando apenas a pergunta): aceleração de até 6,4x no SGLang.
- Cargas de trabalho de clonagem de voz: taxa de acerto do cache de prefixo de 86,4%.
- Taxas de acerto em produção em clientes do SGLang: 50% a 99% dependendo da disciplina de prompts.
- Implementado em mais de 400.000 GPUs em 2026.
A armadilha da ordenação
A aceleração de 6,4x depende de uma ordenação consistente dos templates de prompts. Se o cliente constrói prompts como [sistema, ferramentas, contexto, histórico, pergunta] em algumas requisições e como [sistema, contexto, ferramentas, histórico, pergunta] em outras, a árvore não conseguirá encontrar o prefixo compartilhado. O que parece ser um prefixo compartilhado para um humano representa duas sequências distintas para a árvore radix.
Alavanca do engenheiro: o template de seu prompt é uma chave de cache. Fixe a ordem. Coloque tudo o que for imutável (sistema, ferramentas, esquemas) primeiro. Coloque o contexto de recuperação em seguida. Coloque a pergunta do usuário por último. Não intercale conteúdo dinâmico no meio do prefixo.
Caso real de pesquisa: mover o conteúdo dinâmico para fora do prefixo cacheável elevou a taxa de acerto do cache de um deploy de 7% para 74% com apenas uma alteração.
Onde o RadixAttention vence e perde
Vence:
- RAG (mesmo preâmbulo de recuperação, pergunta variável).
- Agentes (mesmos esquemas de ferramentas, consulta variável).
- Chat com prompts de sistema longos.
- Cargas de trabalho de voz/visão com preâmbulos repetidos.
Perde (retorna ao nível de rendimento do vLLM):
- Geração de etapa única (single-shot) com prompts exclusivos (autocompletar código, chat livre sem prompt de sistema).
- Prompts dinâmicos em que cada requisição intercala conteúdo exclusivo no meio do prefixo.
Por que esse é um problema de agendamento, e não apenas de kernel
Você pode implementar a reutilização de KV como um truque de kernel. A percepção do SGLang é que a reutilização só compensa se o agendador mantiver o ramo quente residente. Uma política ingênua de "reutilizar se disponível" causará desgaste do cache sob carga mista. O agendador indexado por árvore radix é o que transforma o truque do kernel em uma vantagem de produção de 29%.
Relação com o vLLM
Os dois sistemas não são concorrentes rígidos. Em 2026, o vLLM adicionou o cache de prefixos (--enable-prefix-caching) e um roteador baseado em cache (vLLM Router escrito em Rust). A diferença diminuiu, mas não desapareceu totalmente — a pilha completa do SGLang é baseada em radix primeiro; o vLLM adicionou isso como extensão. Para cargas de trabalho dominadas pela reutilização de prefixos, o SGLang permanece como o padrão. Para serviços de uso geral sem fortes padrões de prefixos, o vLLM permanece igual ou superior.
Use It
O arquivo code/main.py implementa um KV cache simplificado em árvore radix mais um agendador com duas políticas: FCFS e baseado em cache. Executa a mesma carga de trabalho em ambos, relatando a taxa de acerto do cache de prefixo e a diferença de rendimento. Em seguida, executa uma carga de trabalho com "ordem misturada" para demonstrar a perda da aceleração de 6,4x.
Ship It
Esta lição produz outputs/skill-radix-scheduler-advisor.md. Dada uma descrição de carga de trabalho (formato do template de prompt, padrão de recuperação, número de locatários simultâneos), ela produz uma recomendação de ordenação de prompts e uma decisão de adoção ou não do SGLang.
Exercises
- Execute
code/main.py. Compare o FCFS e o agendador baseado em cache na mesma carga de trabalho. De onde vem a diferença — economia de prefill, economia de decodificação ou atraso na fila? - Modifique a carga de trabalho para que os prompts permutem aleatoriamente os blocos
[sistema, ferramentas, contexto]. Execute novamente. O que acontece com a taxa de acerto? Por quê? - Calcule o custo de HBM de manter um prompt de sistema de 2.000 tokens residente como um ramo radix no Llama 3.1 8B. Compare com o custo de um lote de 16 sequências sem reutilização de prefixos.
- Leia o artigo do SGLang RadixAttention. Explique em três frases por que a política de despejo LRU baseada em árvore supera a política LRU baseada em blocos sob tráfego intensivo em prefixos.
- Um cliente relata apenas 8% de taxa de acerto no cache. Nomeie três causas prováveis e o diagnóstico que você executaria para cada uma.
Key Terms
| Term | What people say | What it actually means |
|---|---|---|
| RadixAttention | "o negócio do SGLang" | KV cache indexado como uma árvore radix para que prefixos compartilhados reutilizem blocos |
| Radix tree | "trie compacta" | Árvore onde cada nó possui uma faixa de tokens e seus respectivos blocos de KV |
| Cache-aware scheduler | "ramo-quente-primeiro" | Agendador que prioriza requisições que compartilham o ramo residente |
| Prefix-cache hit rate | "quanto do seu prompt saiu de graça" | Fração de tokens de prompt atendidos a partir de blocos de KV reutilizados |
| FCFS | "primeiro a chegar, primeiro a ser atendido" | Agendamento padrão que desfaz a localidade do prefixo |
| Branch-level LRU | "despejar a folha" | Política de despejo de cache ajustada ao formato da árvore radix |
| Prompt template ordering | "a chave do cache" | A ordem dos componentes do prompt define o que a árvore pode compartilhar |
| System prompt pinning | "prefixo residente" | Manter a parte imutável do sistema fixada para evitar desgaste de despejo (eviction thrash) |
Further Reading
- SGLang GitHub — código fonte e documentação.
- SGLang documentation — detalhes de RadixAttention e agendamento.
- SGLang paper — Efficiently Programming Large Language Models (arXiv:2312.07104) — a referência de design.
- LMSYS blog — SGLang with RadixAttention — números de benchmark e racional do agendador.
- vLLM — Prefix Caching — implementação do tipo radix do próprio vLLM, para comparação.