Artigo
Inferência NVFP4 em GPUs Blackwell SM120: vLLM, FlashInfer e o que funcionou
Novas arquiteturas de GPU costumam ser vendidas como upgrades simples. Para times de inferência, a realidade é mais complicada.
Este post compartilha notas de campo generalizadas sobre colocar um modelo de linguagem grande quantizado em NVFP4 em produção em GPUs Blackwell SM120. O trabalho original veio de uma implantação real, mas os detalhes aqui foram deliberadamente anonimizados: sem nome de cliente, sem nome exato de modelo, sem IDs de conta, sem tags internas de imagem, sem datas de benchmark e sem identificadores de trace de produção.
A versão curta:
SM120 funcionou bem depois que a stack de serving foi montada com cuidado, mas ainda não era um caminho padrão sem surpresas.
A receita estável exigiu um build recente do vLLM, suporte ao FlashInfer b12x, configuração explícita para SM120, pesos ModelOpt NVFP4 no modelo-alvo, KV cache em FP8 e separação cuidadosa entre o modelo-alvo e o drafter especulativo.
A lição mais importante não foi uma versão de pacote ou flag de runtime. Foi uma fronteira:
O contrato de quantização NVFP4 do modelo-alvo não pode vazar para um modelo drafter (draft model) que não seja NVFP4.
Limite das afirmações
Estas são notas de campo generalizadas de uma implantação anonimizada, publicadas em 3 de junho de 2026. Não são uma receita universal para SM120 nem um guia congelado de versões de pacote. As lições duráveis são sobre o contrato de serving: alvo de GPU, build do vLLM, suporte FlashInfer/CUTLASS, formato do checkpoint ModelOpt NVFP4, dtype do KV cache, configuração do drafter especulativo, comportamento de proxy/gateway, tracing e benchmark reproduzível.
Antes de copiar qualquer flag ou receita de imagem, valide contra seu SKU exato de GPU, versão do CUDA, versão do vLLM, versão do FlashInfer, checkpoint do modelo e caminho real das requisições.
Afirmações seguras e inseguras
As afirmações reutilizáveis são:
- Checkpoints NVFP4 grandes podem rodar em SM120 com um stack vLLM recente e suporte ao FlashInfer b12x.
- SM120 deve ser configurado explicitamente; configurações padrão de arquiteturas mais antigas não bastam.
- Pesos ModelOpt NVFP4 no alvo funcionaram com KV cache em FP8 neste setup de serving.
- A decodificação especulativa funcionou uma vez que o drafter foi configurado como uma identidade de modelo separada, com sua própria precisão e layout.
- A configuração de quantização NVFP4 do modelo-alvo não pode vazar para um drafter não NVFP4.
- A melhoria reprodutível de decodificação especulativa foi substancial, mas menor do que os primeiros picos observados.
- Teste de carga com perfil de produção revelou características de estabilidade que prompts de brinquedo não teriam mostrado.
- Tracing de benchmark deve ser habilitado antes de execuções importantes, não reconstruído depois.
- Saúde de runtime, saúde de proxy e saúde de gateway precisam ser validadas separadamente.
A afirmação insegura seria:
Este stack entrega o pico inicial de taxa de tokens como performance em regime estável.
Ele atingiu números mais altos por pouco tempo. Essas observações foram reais, mas não foram reprodutíveis o suficiente para virar manchete.
Por que isso não foi apenas mais uma migração de GPU
Uma migração típica de inferência começa com uma suposição simples: se o modelo roda em uma GPU NVIDIA recente, deve rodar na próxima com apenas pequenos ajustes.
Essa suposição não se sustentou aqui.
A implantação combinou várias peças em movimento ao mesmo tempo:
- Nova arquitetura de GPU
- Pesos NVFP4 no modelo-alvo
- Serving com contexto longo
- KV cache em FP8
- Kernels do FlashInfer
- Decodificação especulativa
- Roteamento de requisições compatível com OpenAI
- Tool calling e comportamento de parser
Cada peça pode funcionar isoladamente. A dificuldade é fazer com que todo o caminho de serving concorde sobre kernels, metadados do modelo, layout de quantização, formato de cache e semântica de requisição.
A primeira lição prática foi:
Trate SM120 como um alvo de primeira classe, não como uma substituição transparente para arquiteturas NVIDIA mais antigas.
As configurações padrão antigas não foram suficientes. O runtime e o stack de kernels precisavam saber explicitamente que o alvo era compute 12.0f / 120f.
SM120 não significa “qualquer Blackwell”.
O alvo importante aqui era SM120 / compute 12.0. Não assuma que toda GPU Blackwell, toda imagem CUDA ou todo pacote de kernels pré-compilado usa o mesmo alvo de arquitetura. Peças de datacenter Blackwell usam compute capabilities diferentes das classes SM120 de workstation/desktop. Antes do benchmark, registre o SKU exato da GPU, compute capability, versão do CUDA, linhagem da imagem de runtime, pacote de kernels e caminho de roteamento.
Escolha de runtime: use o caminho que de fato sobe
Avaliamos mais de um caminho de serving. Runtimes otimizados de mais baixo nível são atrativos para inferência NVFP4 e podem, no futuro, se tornar a melhor opção à medida que o suporte a SM120 amadureça.
Para esta implantação, contudo, o caminho prático foi vLLM com uma imagem customizada.
A pergunta decisiva não foi:
Qual runtime deveria ser o mais rápido em teoria?
Foi:
Qual runtime consegue carregar os pesos quantizados, escolher os kernels corretos, lidar com o perfil real das requisições, sobreviver a health checks/probes repetidos e permanecer depurável quando algo falha?
Para alvos de hardware novos, essa distinção importa. Um runtime teoricamente mais rápido não é útil se não consegue inicializar o modelo de forma confiável ou suportar o caminho de API de produção.
A receita da imagem: torne SM120 explícito
As imagens de release padrão não foram suficientes. A imagem que funcionou partiu de uma imagem recente do vLLM compatível com OpenAI e adicionou configuração explícita do FlashInfer para SM120:
FROM vllm/vllm-openai:nightly
ENV FLASHINFER_CUDA_ARCH_LIST=12.0f \
FLASHINFER_FORCE_SM=120f \
FLASHINFER_DISABLE_VERSION_CHECK=1
Sobre FLASHINFER_DISABLE_VERSION_CHECK=1: use somente quando você já tiver verificado separadamente o caminho de wheel, cubin e cache JIT para sua GPU alvo. Não é conselho genérico. Essa flag silencia uma trava de segurança que existe por um motivo, e só é segura quando você já sabe o conjunto de kernels com o qual está rodando.
A imagem também precisou de componentes recentes de CUTLASS e FlashInfer, incluindo wheels nightly, cubins e suporte a cache JIT para a geração de CUDA correspondente.
As versões exatas dos pacotes vão mudar rapidamente, então a lição duradoura não é “copie esta imagem para sempre”.
A lição duradoura é:
Não assuma que um alvo de GPU novo está incluído em toda imagem de release, wheel pré-compilado, cache de kernel ou pacote de cubin.
Se o stack silenciosamente cair para kernels não suportados, ou se os cubins corretos estiverem faltando, as falhas resultantes podem parecer alheias ao suporte da arquitetura. Você pode ver erros de inicialização, checagens de versão, incompatibilidades de shape ou falhas de runtime que na verdade são sintomas de um caminho SM120 incompleto.
Houve também uma sutileza de container runtime: a mesma imagem pode se comportar de forma diferente dependendo do runtime do nó e da configuração de usuário do container. Valide a imagem sob a mesma camada de orquestração, mesmo caminho de plugin de GPU e mesmo usuário de runtime que a produção vai usar.
Sucesso em Docker local não é o mesmo que sucesso em deploy de produção.
NVFP4 subiu antes da decodificação especulativa
A primeira faixa estável foi inferência NVFP4 sem decodificação especulativa:
- Pesos do alvo: checkpoint ModelOpt NVFP4
- Quantização: ModelOpt
- KV cache: FP8
- Backend de GEMM: caminho FlashInfer CUTLASS NVFP4
Uma configuração de runtime representativa ficou assim:
--enable-chunked-prefill
--enable-prefix-caching
--quantization=modelopt_fp4
--kv-cache-dtype=fp8
Confirme a flag de quantização correta do vLLM para a versão instalada. A documentação atual do vLLM identifica modelopt_fp4 para checkpoints ModelOpt NVFP4; snippets mais antigos e algumas builds nightly podem aceitar modelopt como atalho. Valide contra a versão exata do vLLM que você está rodando antes de copiar essa configuração.
A implantação também usou configurações de contexto longo e limites delimitados de batch/concorrência apropriados para o workload. Esses valores devem ser ajustados por ambiente em vez de copiados diretamente.
Esse baseline foi estável, mas não entregou o alvo completo de performance. Para gerações curtas e isoladas, o caminho não especulativo ficou na faixa baixa dos 30 tokens/s neste setup.
Isso tornou a decodificação especulativa a próxima alavanca óbvia.
A decodificação especulativa expôs o bug real
A falha mais interessante apareceu somente depois que a decodificação especulativa entrou em cena.
O modelo-alvo era NVFP4. O modelo drafter (draft model) não era.
Essa distinção é fácil de perder.
Em muitos setups de decodificação especulativa, o modelo-alvo e o drafter são tratados como muito próximos. Eles podem compartilhar um tokenizer ou uma família de arquitetura. Mas não são necessariamente o mesmo artefato de modelo. O drafter pode usar precisão diferente, layout de checkpoint diferente, contrato de metadados diferente ou shape de pesos diferente.
O caminho quebrado, na prática, reutilizou a configuração de quantização NVFP4 do alvo para o drafter. Isso produziu incompatibilidades de shape e falhas de assertion durante a inicialização.
A correção foi conceitualmente simples, mas importante:
Configure o drafter como uma identidade de modelo própria, com sua própria precisão e seu próprio layout.
O formato que funcionou foi:
- Modelo-alvo: checkpoint NVFP4
- Drafter: checkpoint de assistente/draft separado
- KV cache: FP8
- Janela de draft: número fixo pequeno de tokens especulativos
- Backend: caminho FlashInfer CUTLASS NVFP4
Essa é a lição técnica mais reutilizável da implantação.
Qualquer modelo-alvo NVFP4 grande usando decodificação especulativa pode bater nessa classe de problema se o drafter não for, de fato, a mesma arquitetura e o mesmo layout quantizado.
Mapa de modos de falha
A forma mais útil de ler o resto deste post é como um conjunto de modos de falha que você consegue reconhecer rápido, validar e direcionar para a correção certa.
| Sintoma | Causa provável | Passo de validação | Correção |
|---|---|---|---|
| Erros de inicialização, checagens de versão, incompatibilidades de shape no carregamento do modelo | Imagem padrão não tem como alvo compute 12.0 / 120f | Inspecione FLASHINFER_CUDA_ARCH_LIST e o conjunto de cubins na imagem | Construa uma imagem com SM120 explícito, configuração correta do FlashInfer e wheels/cubins verificados |
| Fallback silencioso de kernel ou throughput degradado | Wheels ou cubins para SM120 ausentes | Confirme a presença de kernels NVFP4 CUTLASS para SM120 na imagem em execução | Atualize wheels/cubins; não dependa apenas de desabilitar checagens de versão |
| Incompatibilidade de shape ou falha de assertion ao inicializar decodificação especulativa | Configuração de quantização NVFP4 vazou do alvo para um drafter não NVFP4 | Inspecione precisão, layout e metadados do drafter de forma independente do alvo | Configure o drafter como identidade de modelo separada, com precisão e layout próprios |
| Runtime direto saudável, gateway retorna erros | Rota, endpoint picker, registro de serviço ou mapeamento de modelo ausente | Chame o modelo via runtime, proxy interno e gateway externo separadamente | Trate cada camada como uma superfície de saúde própria; corrija a entrada de roteamento ausente |
| Autoscaler mantém capacidade limitada após scale-up | Limites de recurso foram zerados via patch em vez de removidos | Reveja os campos de limite de GPU, não apenas o estado nominal do pod | Remova os campos inteiramente em vez de sobrescrever com um objeto vazio |
| Não é possível reconstruir um benchmark histórico com alta fidelidade | Tracing não foi habilitado antes da execução | Verifique a variável de ambiente de tracing e a configuração de success-callback do proxy | Habilite tracing antes da próxima execução; não dependa de logs de spend como fonte de replay |
Semântica de parser faz parte do serving
Geração crua de tokens não é suficiente para prontidão de produção.
O caminho de serving precisou suportar a mesma semântica de requisição que a aplicação:
- Templates de chat
- Comportamento de parser de reasoning
- Parsing de tool calls
- Prompts de contexto longo
- Completions curtas
- Rajadas de requisições no estilo agente
Um modelo pode parecer saudável em testes diretos de completion e ainda falhar sob o perfil real das requisições de produção.
Flags de parser, formatação de requisição e comportamento de tool call fazem parte da história de performance porque determinam se o benchmark consegue rodar. O teste correto não é apenas “o modelo consegue retornar tokens?”. É:
O modelo consegue servir o caminho real de requisição da aplicação corretamente e de forma repetida?
A história de performance mudou depois da reprodução
Os primeiros resultados pareciam espetaculares.
Depois de habilitar a decodificação especulativa, algumas execuções isoladas sugeriram uma melhoria muito maior sobre o baseline não especulativo. Teria dado uma manchete excelente.
Então tentamos reproduzir.
Medições repetidas via chamadas diretas ao runtime, via proxy interno ao cluster e via gateway externo convergiram para baixo.
| Medição | Padrão observado | Confiança | Como usar |
|---|---|---|---|
| Baseline NVFP4 não especulativo | Faixa baixa dos 30 tokens/s para gerações curtas isoladas | Média/alta para este setup | Baseline útil; não é um número universal de SM120 |
| Execuções iniciais com decodificação especulativa | Melhoria aparente muito maior | Baixa como métrica de manchete | Manter apenas em nota interna |
| Resultado reproduzido com decodificação especulativa | Aproximadamente 2–3x sobre o baseline não especulativo | Maior | Usar como a história honesta |
| Serving concorrente com saídas curtas | Baixos milhares de tokens/s agregados | Específica ao workload | Sinal útil com perfil de produção |
| Caminho completo de proxy/gateway | Precisou de validação separada | Alta importância | Obrigatório antes de planejamento de capacidade |
A conclusão honesta passou a ser:
A decodificação especulativa foi estável e significativamente mais rápida, mas a melhoria reprodutível ficou mais perto de 2–3x do que do pico inicial.
Esse ainda é um resultado forte. Só não é o número que queríamos inicialmente.
Um pico de curta duração pode ser real sem ser representativo.
Carga com perfil de produção importa mais do que prompts de brinquedo
O benchmark mais útil não foi um prompt de brinquedo.
O workload representativo tinha uma forma parecida com produção:
- Prompts longos
- Completions curtas
- Rajadas de passos de agente concorrentes
- Classes de requisição mistas
- Turnos ocasionais de contexto muito longo
- Tempo realista entre requisições
Reprodução exata não foi possível porque os corpos históricos de prompts e payloads de tool não haviam sido capturados. Em vez disso, o benchmark preservou a forma do workload: timing, alvos de tokens e classe de cenário.
Esse tipo de replay consegue responder perguntas operacionais úteis:
- O pod de serving permanece estável?
- Acumula fila?
- Como o prefill de contexto longo afeta o throughput de decode?
- O prefix caching ajuda?
- O caminho do gateway introduz falhas?
- As configurações de parser são compatíveis com a aplicação?
Não consegue responder perguntas que exigem prompts históricos byte a byte ou payloads de tool exatos.
Sob a fatia de carga testada, o caminho de serving permaneceu estável e não acumulou fila. Requisições de contexto longo continuaram lentas, mas não quebraram o runtime.
Esse é um sinal útil de produção, mesmo não sendo um plano de capacidade definitivo.
Tracing precisa estar ligado antes do benchmark
Uma lição desconfortável foi que algumas execuções históricas não puderam ser reconstruídas com alta fidelidade.
Logs de spend e métricas agregadas foram úteis, mas não foram suficientes. Mostravam timing, contagens de tokens, códigos de status e throughput aproximado. Não recuperavam corpos completos de prompts, payloads de tool ou contexto de trace externo.
Para próximas execuções, tracing precisa ser habilitado antes de o benchmark começar.
Para stacks de proxy compatíveis com OpenAI, isso geralmente significa verificar duas coisas:
environment:
TRACING_API_KEY: ...
proxy_settings:
success_callback:
- tracing_backend
Os nomes exatos variam por proxy e por provedor de tracing, mas o princípio não muda:
Variáveis de ambiente sozinhas podem não habilitar traces. O proxy normalmente precisa de configuração explícita de callback.
Uma vez que o tracing esteja conectado corretamente, próximas execuções de benchmark podem ser reproduzidas e analisadas com muito mais fidelidade.
Lições operacionais do caminho de serving
O runtime de modelo era apenas uma parte da implantação. O restante do caminho de serving expôs várias lições de infraestrutura.
Primeiro, fixe o alvo de hardware durante o benchmark.
É fácil comparar resultados entre diferentes tamanhos de nó de GPU, configurações de memória ou pools de runtime e atribuir a diferença, sem querer, à quantização ou aos kernels. Notas de benchmark devem registrar o alvo de hardware, a linhagem da imagem de runtime, a revisão do modelo, o pacote de kernel e o caminho de roteamento.
Segundo, limites de autoscaler podem falhar fechados.
Se a capacidade de GPU for reduzida zerando limites de recurso via patch, restaurar a capacidade pode exigir remover esses campos em vez de sobrescrevê-los com um objeto vazio. Caso contrário, o autoscaler pode continuar tratando CPU, memória ou GPU como limitados.
Terceiro, um pod de decode saudável não é o mesmo que um caminho de serving externo saudável.
Chamadas diretas ao runtime podem ter sucesso enquanto o gateway retorna erros, porque falta uma rota, um endpoint picker, um registro de serviço ou um mapeamento de modelo. Para prontidão de produção, teste todas as camadas:
- Endpoint direto do runtime
- Caminho interno de proxy ou service mesh
- Caminho de gateway externo
Um modelo não está realmente no ar até que o caminho real de requisição da aplicação funcione.
Checklist prático para serving NVFP4 em SM120
Para times trazendo modelos semelhantes para SM120, este checklist é um bom ponto de partida.
1. Valide a matriz de suporte completa
Não valide apenas a GPU ou apenas o modelo. Valide a combinação:
- Arquitetura de GPU
- Versão do CUDA
- Versão do vLLM
- Versão do FlashInfer
- Suporte ao CUTLASS
- Formato de quantização
- Dtype do KV cache
- Modo de decodificação especulativa
- Comportamento de parser
- Caminho de gateway/proxy
2. Torne SM120 explícito
Defina configuração do FlashInfer específica para a arquitetura e verifique que a imagem inclui os wheels, cubins e comportamento de cache JIT corretos.
FLASHINFER_CUDA_ARCH_LIST=12.0f
FLASHINFER_FORCE_SM=120f
FLASHINFER_DISABLE_VERSION_CHECK=1
3. Mantenha as configurações de alvo e drafter separadas
O modelo-alvo e o drafter podem diferir em:
- Precisão
- Metadados de quantização
- Layout de checkpoint
- Variante de arquitetura
- Suposições de tokenizer
- Shape de pesos
Trate-os como contratos separados.
4. Faça benchmark em todos os caminhos de serving
Meça performance de runtime direto, performance de proxy interno e performance de gateway externo separadamente. Não assuma que um representa os outros.
5. Reporte números reprodutíveis
Mantenha o pico em notas internas, mas use a medição repetida como manchete.
6. Ligue o tracing antes da execução
Sem traces completos, replay futuro se torna baseado em forma, não em requisição exata.
Resumo final
SM120 não foi uma migração simples, mas se tornou um alvo prático de serving uma vez que o stack foi montado com cuidado.
O formato que funcionou foi:
- Runtime vLLM recente
- Suporte ao FlashInfer b12x / SM120
- Configuração explícita de compute
12.0f/120f - Checkpoint NVFP4 no modelo-alvo via ModelOpt
- KV cache em FP8
- Modelo de assistente/draft separado para decodificação especulativa
- Validação do caminho de produção passando por proxy e gateway
Esse stack produziu uma faixa de serving estável e significativamente mais rápida do que o baseline NVFP4 não especulativo.
O resultado final não foi o número de manchete do início. Foi melhor: um caminho reprodutível e depurável para inferência NVFP4 de modelos grandes em SM120.
Relacionados
Continue lendo
Leituras relacionadas a este tema.

29/05/2026
14 min de leitura
Claude Opus 4.8: o ranking não é seu benchmark
Continuar leitura
19/05/2026
9 min de leitura
Sandbox Governado para Agentes de IA na AWS
Continuar leitura
07/05/2026
9 min de leitura
Servidor AWS MCP: acesso seguro e governado à AWS para agentes de IA
Continuar leitura
23/04/2026
8 min de leitura

