Resultados finales: Gemma 4 / Qwen 3.6 / Nemotron 3 en NVIDIA DGX Spark

Actualización de octubre 2026. Estos son los resultados anteriores (abril a septiembre de 2026), con imágenes antiguas. La nueva ronda en el mismo equipo con vLLM 0.31.0, contexto de 128K y 4 usuarios simultáneos está en Benchmarks, junto con recetas listas para copiar. Importante: Nemotron 3 Super 120B-A12B ya funciona con vLLM 0.31.0 (16,1 tok/s; 23,0 con MTP; ~95 GB), así que la falla con vLLM descrita abajo aplica solo a la imagen antigua gemma4-0505-cu130.

Para una guía rápida de uso, véase Inicio. Este documento conserva el detalle completo de resultados y notas técnicas.

Hardware / software base

ComponenteValor
HardwareNVIDIA DGX Spark (GB10 Grace Blackwell)
CPU20 cores ARM64 (aarch64)
GPUNVIDIA GB10 (sm_121)
Memoria128 GB LPDDR5x unificada (~121 GB usable)
Driver NVIDIA580.142
CUDA13.0
Docker29.2.1
NVIDIA Container Toolkit1.19.0

Restricción crítica del GB10: no tiene compute FP4 nativo. Los checkpoints NVFP4 se ejecutan vía el backend Marlin (--moe-backend marlin), que descomprime FP4 → BF16 en runtime. Esto explica por qué los tok/s están por debajo de lo que se vería en un B200 con FP4 nativo.


Resumen de resultados

Benchmark realizado con prompt de ~120 tokens en español, max_tokens=512, temperatura 0.7, midiendo decode tok/s (descartando TTFT de la primera corrida fría).

ModeloCheckpoint usadoContenedor vLLMMejor decode tok/sTTFT calienteVRAM usadaNotas
Qwen 3.6 35B-A3Bnvidia/Qwen3.6-35B-A3B-NVFP4vllm/vllm-openai:nightly~76 tok/s~0.10 s~22 GBRecomendado actual. W4A16 NVFP4 (modelopt), backend flashinfer, KV cache FP8, backend Marlin para SM121, parser qwen3_coder, 262K contexto, 1 secuencia. Recupera los ~75–77 tok/s usando la ventana completa del modelo.
Gemma 4 26B-A4B ITbg-digitalservices/Gemma-4-26B-A4B-it-NVFP4 + gemma4_patched.pyvllm/vllm-openai:gemma4-cu130~49.5 tok/s~0.08 s~22 GBMayor velocidad bruta para agentes. Requiere parche community.
Qwen 3.6 35B-A3BRedHatAI/Qwen3.6-35B-A3B-NVFP4vllm/vllm-openai:gemma4-0505-cu130~42.2 tok/s~0.10 s~22 GBFormato compressed-tensors. Fallback estable.
Nemotron-3-Nano-Omni-30B-A3Bnvidia/NVIDIA-Nemotron-3-Nano-Omni-30B-A3B-Reasoning-NVFP4vllm/vllm-openai:gemma4-0505-cu130~40.0 tok/s~0.10 s~40 GBMultimodal oficial: texto + imagen funcionan. Audio aún no probado funcional en este contenedor.
Qwen 3.6 35B-A3B (n-gram speculative)RedHatAI/Qwen3.6-35B-A3B-NVFP4vllm/vllm-openai:gemma4-0505-cu130~34–37 tok/s~0.10 s~22 GBEmpeora para texto no repetitivo.
Qwen 3.6 35B-A3B TRT-LLM (MLP-only NVFP4)Cuantiizado con Model Optimizer 0.44.0 desde Qwen/Qwen3.6-35B-A3B BF16nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc13~34.5 tok/s~0.09 s~41 GBFormato modelopt NVFP4 MLP-only + KV FP8. Funciona con TRT-LLM PyTorch backend. El chat template no genera thinking limpio en nuestras pruebas.
Gemma 4 26B-A4B IT (oficial)nvidia/Gemma-4-26B-A4B-NVFP4vllm/vllm-openai:gemma4-0505-cu130~30.1 tok/s~0.20 s~21 GBFunciona sin parche, pero es ~20 tok/s más lento.
Nemotron-3-Nano-30B-A3Bnvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc13~28.8 tok/s~0.22 s~118 GBModelo denso BF16. Ocupa casi toda la memoria unificada.
Nemotron-3-Nano-30B-A3Bnvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16vllm/vllm-openai:gemma4-0505-cu130~28.3 tok/s~0.20 s~72 GBAlternativa vLLM. Requiere liberar VRAM de otros servicios.
Nemotron-3-Super-120B-A12Bnvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc13~14.7 tok/s~0.29 s~110 GBCheckpoint NVFP4 oficial. Mayor calidad, menor velocidad por más expertos activos.
Gemma 4 31B ITnvidia/Gemma-4-31B-IT-NVFP4vllm/vllm-openai:gemma4-0505-cu130~6.7 tok/s~1.8 s~31 GBDenso, limitado por ancho de banda. No recomendable si se busca fluidez.
Qwen 3.6 35B-A3B (MTP)RedHatAI/Qwen3.6-35B-A3B-NVFP4vllm/vllm-openai:gemma4-0505-cu130Error de carga––moe_backend='marlin' no es soportado por el drafter no cuantizado. Requiere más investigación.
Gemma 4 26B-A4B en TensorRT-LLM 1.3.0rc13nvidia/Gemma-4-26B-A4B-NVFP4nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc13Error de carga––Transformers en el contenedor no reconoce model_type: gemma4.
Qwen 3.6 35B-A3B en TensorRT-LLM 1.3.0rc13nvidia/Qwen3.6-35B-A3B-NVFP4nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc13Error de carga––AssertionError en quant_algo del checkpoint modelopt NVFP4.
Nemotron-3-Super-120B-A12Bnvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4vllm/vllm-openai:gemma4-0505-cu130———No viable: CUDA OOM al inicializar el engine; el Spark se colgó en el primer intento por falta de memoria.

Conclusiones rápidas


Scripts recomendados

1. Gemma 4 26B-A4B (mejor velocidad)

Requiere descargar bg-digitalservices/Gemma-4-26B-A4B-it-NVFP4 y tener gemma4_patched.py en el mismo directorio.

#!/usr/bin/env bash
# run-gemma4-26b-a4b.sh

docker run -d --name gemma4-26b-a4b \
  --gpus all \
  --ipc host \
  --network host \
  --shm-size 64gb \
  -v ~/vllm/gemma4-26b-a4b-nvfp4-community:/models/gemma4 \
  -v ~/vllm/gemma4-26b-a4b-nvfp4-community/gemma4_patched.py:/usr/local/lib/python3.12/dist-packages/vllm/model_executor/models/gemma4.py \
  -e HF_HOME=/models \
  vllm/vllm-openai:gemma4-cu130 \
    --model /models/gemma4 \
    --served-model-name gemma-4-26b-a4b \
    --host 0.0.0.0 --port 8000 \
    --quantization modelopt \
    --moe-backend marlin \
    --trust-remote-code \
    --kv-cache-dtype fp8 \
    --max-model-len 32768 \
    --max-num-seqs 2 \
    --max-num-batched-tokens 4096 \
    --gpu-memory-utilization 0.90 \
    --enable-prefix-caching \
    --enable-auto-tool-choice \
    --tool-call-parser pythonic

2. Qwen 3.6 35B-A3B (mejor calidad-velocidad)

Requiere descargar nvidia/Qwen3.6-35B-A3B-NVFP4. Esta es la configuración ganadora: usa el backend Marlin para NVFP4 en SM121, KV cache FP8 y torch.compile/CUDAGraph activos.

#!/usr/bin/env bash
# run-qwen36-35b-a3b.sh

docker run -d --name qwen36-35b-a3b \
  --gpus all \
  --ipc host \
  --network host \
  --shm-size 64gb \
  -v ~/vllm/qwen3.6-35b-a3b-nvfp4-nvidia:/models/qwen3.6 \
  -v $(pwd)/chat-templates:/chat-templates \
  -e HF_HOME=/models \
  -e VLLM_TARGET_DEVICE=cuda \
  -e VLLM_TEST_FORCE_FP8_MARLIN=1 \
  -e VLLM_MARLIN_USE_ATOMIC_ADD=1 \
  vllm/vllm-openai:cu129-nightly-aarch64 \
    --model /models/qwen3.6 \
    --served-model-name qwen3.6-35b-a3b \
    --host 0.0.0.0 --port 8000 \
    --trust-remote-code \
    --tensor-parallel-size 1 \
    --attention-backend flashinfer \
    --moe-backend marlin \
    --gpu-memory-utilization 0.92 \
    --max-model-len 262144 \
    --max-num-seqs 1 \
    --max-num-batched-tokens 32768 \
    --enable-chunked-prefill \
    --async-scheduling \
    --enable-prefix-caching \
    --limit-mm-per-prompt '{"image":4}' \
    --load-format fastsafetensors \
    --kv-cache-dtype fp8 \
    --tool-call-parser qwen3_coder \
    --enable-auto-tool-choice \
    --chat-template /chat-templates/qwen3.6-miaai.jinja \
    --default-chat-template-kwargs '{"enable_thinking":true,"preserve_thinking":false,"auto_disable_thinking_with_tools":true}'

3. Qwen 3.6 35B-A3B con TensorRT-LLM (cuantizado MLP-only NVFP4)

Requiere generar el checkpoint con TensorRT Model Optimizer (ver registro de trabajo). El checkpoint resultante ocupa ~22 GB.

#!/usr/bin/env bash
# run-qwen36-35b-a3b-trtllm.sh

docker run -d --name qwen36-35b-a3b-trtllm \
  --gpus all \
  --ipc host \
  --network host \
  --shm-size 64gb \
  -v ~/vllm/qwen3.6-35b-a3b-nvfp4-mlponly-user:/models/qwen3.6 \
  -e HF_HOME=/models \
  nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc13 \
    trtllm-serve /models/qwen3.6 \
    --host 0.0.0.0 --port 8000 \
    --backend pytorch \
    --max_seq_len 32768 \
    --max_batch_size 2 \
    --kv_cache_dtype fp8

4. Nemotron-3-Nano-30B-A3B con TensorRT-LLM (BF16)

Requiere descargar nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16 (~89 GB).

#!/usr/bin/env bash
# run-nemotron3-nano-30b-a3b-trtllm.sh

docker run -d --name nemotron3-nano-30b-a3b-trtllm \
  --gpus all \
  --ipc host \
  --network host \
  --shm-size 64gb \
  -v ~/vllm/nemotron3-nano-30b-a3b-bf16:/models/nemotron \
  -e HF_HOME=/models \
  nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc13 \
    trtllm-serve /models/nemotron \
    --host 0.0.0.0 --port 8000 \
    --backend pytorch \
    --max_seq_len 8192 \
    --max_batch_size 1 \
    --kv_cache_dtype fp8

5. Nemotron-3-Super-120B-A12B con TensorRT-LLM (NVFP4)

Requiere descargar nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4 (~75 GB).

#!/usr/bin/env bash
# run-nemotron3-super-120b-a12b-trtllm.sh

docker run -d --name nemotron3-super-120b-a12b-trtllm \
  --gpus all \
  --ipc host \
  --network host \
  --shm-size 64gb \
  -v ~/vllm/nemotron3-super-120b-a12b-nvfp4:/models/nemotron \
  -e HF_HOME=/models \
  nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc13 \
    trtllm-serve /models/nemotron \
    --host 0.0.0.0 --port 8000 \
    --backend pytorch \
    --max_seq_len 8192 \
    --max_batch_size 1 \
    --kv_cache_dtype fp8

6. Nemotron-3-Nano-30B-A3B con vLLM (BF16)

Requiere descargar nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16 (~89 GB). Es una alternativa vLLM al script de TRT-LLM; úsala si prefieres el stack vLLM y has liberado suficiente VRAM.

#!/usr/bin/env bash
# run-nemotron3-nano-30b-a3b-vllm.sh

docker run -d --name nemotron3-nano-30b-a3b-vllm \
  --gpus all \
  --ipc host \
  --network host \
  --shm-size 64gb \
  -v ~/vllm/nemotron3-nano-30b-a3b-bf16:/models/nemotron \
  -e HF_HOME=/models \
  vllm/vllm-openai:gemma4-0505-cu130 \
    --model /models/nemotron \
    --served-model-name nemotron3-nano-30b-a3b \
    --host 0.0.0.0 --port 8000 \
    --kv-cache-dtype fp8 \
    --max-model-len 8192 \
    --max-num-seqs 1 \
    --max-num-batched-tokens 4096 \
    --gpu-memory-utilization 0.90 \
    --trust-remote-code

7. Nemotron-3-Nano-Omni-30B-A3B con vLLM (multimodal NVFP4)

Requiere descargar nvidia/NVIDIA-Nemotron-3-Nano-Omni-30B-A3B-Reasoning-NVFP4 (~21 GB). Es la opción oficial de NVIDIA para texto + imagen + video + audio.

#!/usr/bin/env bash
# run-nemotron3-nano-omni-vllm.sh

docker run -d --name nemotron3-nano-omni-vllm \
  --gpus all \
  --ipc host \
  --network host \
  --shm-size 64gb \
  -v ~/vllm/nemotron3-nano-omni-30b-a3b-reasoning-nvfp4:/models/nemotron \
  -e HF_HOME=/models \
  vllm/vllm-openai:gemma4-0505-cu130 \
    --model /models/nemotron \
    --served-model-name nemotron3-nano-omni \
    --host 0.0.0.0 --port 8000 \
    --quantization modelopt_fp4 \
    --moe-backend marlin \
    --kv-cache-dtype fp8 \
    --max-model-len 8192 \
    --max-num-seqs 1 \
    --max-num-batched-tokens 4096 \
    --gpu-memory-utilization 0.90 \
    --trust-remote-code

Para probar la multimodalidad:

# Imagen
python3 benchmarks/test_multimodal.py nemotron3-nano-omni image /ruta/a/imagen.png

# Audio (aún con problemas de formato en este contenedor)
python3 benchmarks/test_multimodal.py nemotron3-nano-omni audio /ruta/a/audio.wav

8. Gemma 4 31B IT (si se necesita el modelo denso)

Requiere descargar nvidia/Gemma-4-31B-IT-NVFP4.

#!/usr/bin/env bash
# run-gemma4-31b.sh

docker run -d --name gemma4-31b \
  --gpus all \
  --ipc host \
  --network host \
  --shm-size 64gb \
  -v ~/vllm/gemma4-31b-it-nvfp4:/models/gemma31 \
  -e HF_HOME=/models \
  vllm/vllm-openai:gemma4-0505-cu130 \
    --model /models/gemma31 \
    --served-model-name gemma-4-31b-it \
    --host 0.0.0.0 --port 8000 \
    --quantization modelopt \
    --trust-remote-code \
    --kv-cache-dtype fp8 \
    --max-model-len 32768 \
    --max-num-seqs 2 \
    --max-num-batched-tokens 4096 \
    --gpu-memory-utilization 0.90 \
    --enable-prefix-caching \
    --enable-auto-tool-choice \
    --tool-call-parser pythonic

9. Qwen 3.6 35B-A3B con contexto largo (262K × 1 sesión)

Requiere descargar nvidia/Qwen3.6-35B-A3B-NVFP4. Esta es la configuración recomendada para agentes con contextos largos en el Spark. El script principal run-qwen36-35b-a3b.sh usa 262K/1 sesión; run-qwen36-35b-a3b-extreme-context-2seq.sh es un alias para el mismo script.

./scripts/run-qwen36-35b-a3b.sh

Importante: Qwen 3.6 requiere --tool-call-parser qwen3_coder (más robusto para multi-turn que el anterior qwen3_xml); sin parser, vLLM devuelve XML en content y el array nativo tool_calls queda vacío, por lo que agentes como Hermes/OpenClaw no ejecutan las herramientas. Omitimos --reasoning-parser porque el checkpoint nvidia/Qwen3.6-35B-A3B-NVFP4 no genera etiquetas <think></think>; con el parser activo, el razonamiento queda en el campo reasoning y content aparece vacío en los agentes.

Configuración estable: --max-num-seqs 1 con --max-model-len 262144 y gpu-memory-utilization 0.92. El límite duro del modelo es 262,144 tokens; configuramos LiteLLM/Hermes para 237K de input + 25K de output.


Nemotron-3 Super 120B-A12B con vLLM: por qué no funcionó

Resuelto en vLLM 0.31.0: revisa Benchmarks y la receta nemotron3-super-120b-nvfp4-mtp-v031.

Se hicieron dos intentos de servir nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4 con vllm/vllm-openai:gemma4-0505-cu130 usando el comando:

docker run -d --name vllm-nemotron3-super --gpus all --ipc host --network host --shm-size 64gb \
  -v ~/vllm/nemotron3-super-120b-a12b-nvfp4:/models/nemotron \
  -e HF_HOME=/models \
  vllm/vllm-openai:gemma4-0505-cu130 \
    --model /models/nemotron --served-model-name nemotron3-super-120b-a12b \
    --host 0.0.0.0 --port 8000 --quantization modelopt_fp4 \
    --moe-backend marlin --kv-cache-dtype fp8 --max-model-len 8192 \
    --max-num-seqs 1 --max-num-batched-tokens 4096 \
    --gpu-memory-utilization 0.90 --trust-remote-code

Primer intento

El contenedor cargó los 17 shards del checkpoint (~75 GB en disco) en ~8 min. Los últimos logs mostraron:

Loading weights took 489.67 seconds
WARNING ... Your GPU does not have native support for FP4 computation ...
Using MoEPrepareAndFinalizeNoDPEPModular
Using uncalibrated q_scale 1.0 ...

Antes de que el servidor HTTP levantara, el Spark se colgó y tuvo que reiniciarse. La causa fue agotamiento de memoria: en paralelo corrían dos servidores llama-server con modelos Qwen GGUF que ocupaban ~76 GB de la memoria unificada.

Segundo intento (después de liberar memoria)

Tras detener los servicios qwen27-local.service y qwen35-local.service (llama-server), el sistema quedó con ~117 GB libres. Sin embargo, vLLM falló inmediatamente al inicializar el EngineCore:

torch.AcceleratorError: CUDA error: out of memory
  File "/usr/local/lib/python3.12/dist-packages/vllm/utils/mem_utils.py", line 108, in measure
    self.free_memory, self.total_memory = current_platform.mem_get_info(device)

Es decir, vLLM no pudo ni siquiera medir la memoria disponible sin encontrar un OOM.

Diagnóstico

El modelo tiene una arquitectura híbrida Mamba-MoE (NemotronHForCausalLM) con:

Aunque los pesos en disco ocupan ~75 GB, al descomprimir FP4 → BF16 vía Marlin y reservar bloques de KV cache según --gpu-memory-utilization 0.90, el footprint supera el margen seguro de 128 GB unificados. El V1 engine de vLLM también compila kernels con torch.compile/inductor, lo que añade overhead de memoria adicional.

Comparación con TensorRT-LLM

El mismo checkpoint con trtllm-serve --backend pytorch --max_seq_len 8192 --max_batch_size 1 --kv_cache_dtype fp8 carga y sirve establemente a ~14.7 tok/s usando ~110 GB. TRT-LLM reserva un presupuesto de memoria fijo (modelo + KV cache para seq_len/batch dados + activaciones) en lugar del esquema porcentual y dinámico de vLLM.

Conclusión: en DGX Spark, Nemotron-3 Super 120B-A12B solo debe usarse con TensorRT-LLM. vLLM es viable para Nemotron-3 Nano (30B) y Nano Omni (30B multimodal), pero no para el Super.


Escalado de contexto largo: Qwen 3.6 35B-A3B

Para flujos de agentes que necesitan ingerir contextos largos (bases de código, historial de conversación, RAG, trazas multi-turno), usamos nvidia/Qwen3.6-35B-A3B-NVFP4 en el DGX Spark con vLLM nightly, backend Marlin y KV cache FP8:

--model /models/qwen3.6 \
--trust-remote-code \
--tensor-parallel-size 1 \
--attention-backend flashinfer \
--moe-backend marlin \
--gpu-memory-utilization 0.92 \
--max-model-len 262144 \
--max-num-seqs 1 \
--max-num-batched-tokens 32768 \
--enable-chunked-prefill \
--async-scheduling \
--enable-prefix-caching \
--load-format fastsafetensors \
--kv-cache-dtype fp8 \
--enable-auto-tool-choice \
--tool-call-parser qwen3_coder

Variables de entorno pasadas al contenedor:

-e VLLM_TEST_FORCE_FP8_MARLIN=1 \
-e VLLM_MARLIN_USE_ATOMIC_ADD=1

1 sesión concurrente es la configuración estable recomendada, ya que deja margen para LiteLLM, ASR y otros servicios auxiliares. Con --max-model-len 262144 usamos el límite duro del modelo. Configuramos LiteLLM/Hermes para 237K de input + 25K de output, evitando ContextWindowExceededError en contextos largos.

Escalado de contexto en una sola sesión

Tokens de entradaTokens de salidaTTFTDecode tok/sNotas
1,000320.28 s45.57Línea base caliente.
50,0006427.1 s45.66Primera llamada grande; incluye algo de JIT warmup.
100,0006422.87 s39.80TTFT más rápido que 50K porque los kernels ya están calientes.
180,00064~50 s~35Estable dentro del límite operativo de 262K.
200,0006465.45 s33.17Estable, memoria ~120 GB (dato histórico con 240K/1 sesión).
250,00064––Cerca del límite operativo actual de 262K; usar solo para sesiones de contexto extremo.

Comportamiento de memoria

Guía práctica para agentes


Por qué vLLM (con Marlin) y no TensorRT-LLM para Qwen 3.6

Probamos dos caminos para servir Qwen 3.6 35B-A3B en el DGX Spark:

CaminoVelocidadEstabilidadNotas
vLLM nightly + nvidia/Qwen3.6-35B-A3B-NVFP4 + Marlin~76 tok/sEstable tras el fix de MarlinOpción más rápida hoy.
TensorRT-LLM 1.3.0rc13 + cuantización MLP-only NVFP4 manual~34 tok/sEstableRequiere cuantizar desde BF16; el checkpoint NVFP4 oficial no carga.

TensorRT-LLM funcionó, pero fue casi 2× más lento que vLLM. El motivo por el que vLLM fallaba antes no era vLLM en sí, sino el backend FP4/CUTLASS por defecto en GB10 (SM121). Al cambiar al backend Marlin para NVFP4 se resolvieron los crashes y la saturación de memoria, pudiendo quedarnos con la velocidad de vLLM.

¿Qué es Marlin?

Marlin es un backend de kernels de GPU optimizado para ejecutar pesos cuantizados — especialmente 4-bit (INT4/FP4) — en GPUs NVIDIA. Para modelos MoE como Qwen 3.6, vLLM lo expone mediante --moe-backend marlin.

El GB10 del DGX Spark no tiene compute FP4 nativo (SM121 no tiene un path FP4/CUTLASS funcional para estos checkpoints). Marlin lo soluciona así:

  1. Lee los pesos FP4/cuantizados desde disco.
  2. Los descomprime a BF16 en runtime dentro de kernels CUDA optimizados.
  3. Usa sus propios kernels GEMM en lugar de los kernels CUTLASS FP4 que fallan.

En GPUs más nuevas con FP4 nativo (p. ej. B200) el backend CUTLASS FP4 sería más rápido. En el Spark, Marlin es el único camino que entrega tanto velocidad como estabilidad con el checkpoint NVFP4 de NVIDIA.

Las variables de entorno adicionales fuerzan a vLLM a seleccionar kernels compatibles con Marlin para operaciones FP8/Marlin y evitan problemas de atomic-add en esta arquitectura:

-e VLLM_TEST_FORCE_FP8_MARLIN=1 \
-e VLLM_MARLIN_USE_ATOMIC_ADD=1

Sin Marlin, vLLM recurre a kernels CUTLASS FP4 que crashean o se cuelgan en SM121 — exactamente los errores bmm_fp8 / CUDNN_STATUS_EXECUTION_FAILED_CUDA_DRIVER que vimos antes.


Integración con Open WebUI / n8n

Todos los servidores exponen la API OpenAI-compatible en http://localhost:8000/v1. Usa la URL base y el served-model-name como modelo.

HerramientaURL baseModelo
Open WebUIhttp://localhost:8000/v1gemma-4-26b-a4b / qwen3.6-35b-a3b
n8n (OpenAI node)http://localhost:8000/v1igual que arriba
API keycualquier valor (vLLM no valida por defecto)–

Nota: solo un contenedor puede escuchar en el puerto 8000 a la vez. Para correr varios modelos simultáneamente, usa puertos distintos (ej. 8001, 8002) o un proxy como LiteLLM.


Notas técnicas importantes

  1. ARM64: verifica siempre que la imagen Docker tenga manifest arm64.
  2. Marlin obligatorio para MoE NVFP4 en GB10: --moe-backend marlin.
  3. KV cache FP8: ahorra memoria, pero usa factores de escala del checkpoint; si no existen, vLLM advierte que puede haber pérdida de precisión.
  4. Prefix caching: acelera requests con contexto compartido o prompts largos repetidos.
  5. Tool calling: Qwen 3.6 requiere --enable-auto-tool-choice --tool-call-parser qwen3_coder; el parser qwen3_coder es más robusto para multi-turn que el anterior qwen3_xml. Sin parser, vLLM devuelve XML en content y el array nativo tool_calls queda vacío, por lo que Hermes/OpenClaw no ejecutan las herramientas. Omitimos --reasoning-parser para el checkpoint nvidia/Qwen3.6-35B-A3B-NVFP4 porque no genera etiquetas <think></think>; con el parser activo, el razonamiento queda en el campo reasoning y content aparece vacío en los agentes. Gemma 4 también soporta gemma4 nativo, no probado a fondo aquí.
  6. max-num-batched-tokens: para modelos con input multimodal (Gemma 4), debe ser >= max_tokens_per_mm_item (ej. 2496 para Gemma 4, 4096 por defecto).
  7. TensorRT Model Optimizer en GB10: la cuantización de Qwen 3.6 desde BF16 requiere convertir el checkpoint VLM a text-only y usar la memoria total de GPU (no la libre) porque accelerate no entiende el pool unificado de 128 GB.
  8. TRT-LLM PyTorch backend lee hf_quant_config.json; usa --backend pytorch y --kv_cache_dtype fp8 para checkpoints NVFP4 HF.

Intento con TensorRT-LLM oficial

Se probaron los contenedores y flujos oficiales de NVIDIA para Spark:

ContenedorVersión TRT-LLMGemma 4 26BQwen 3.6 35BNemotron 3 NanoNemotron 3 Super
nvcr.io/nvidia/tensorrt-llm/release:spark-single-gpu-dev1.1.0rc3No soporta gemma4Error de argumentos / quantização––
nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc101.3.0rc10No soporta gemma4AssertionError quant_algo––
nvcr.io/nvidia/tensorrt-llm/release:1.3.0rc131.3.0rc13No soporta gemma4AssertionError quant_algo (pre-cuantizado), OK cuantizado MLP-onlyOK BF16OK NVFP4

Errores encontrados

Resultado de la cuantización propia de Qwen 3.6

Se siguió el flujo oficial: partimos del modelo base BF16 (Qwen/Qwen3.6-35B-A3B), convertimos el checkpoint VLM a text-only (qwen3_5_moe_text), y cuantizamos con TensorRT Model Optimizer 0.44.0 a formato HF NVFP4.

IntentoQuant configTamañoResultado al servir con TRT-LLM 1.3.0rc13
Full NVFP4--qformat nvfp4~20 GBNotImplementedError: Qwen3.5 split linear-attention packing no soporta tensores input_scale/weight_scale de la atención lineal cuantizada.
MLP-only NVFP4--qformat nvfp4_mlp_only~22 GBCarga y sirve correctamente: ~34.4 decode tok/s, TTFT caliente ~0.09 s, ~41 GB de memoria unificada.

El checkpoint MLP-only cuantiza los expertos MoE y las capas MLP a NVFP4, dejando la atención (incluyendo la atención lineal híbrida de Qwen3.5/3.6) en BF16. Es compatible con el backend PyTorch de TRT-LLM y ofrece una velocidad intermedia entre Gemma 4 31B denso y Qwen 3.6 RedHatAI/vLLM.

Resultado de Nemotron 3 con TensorRT-LLM 1.3.0rc13

ModeloCheckpointFormatoDecode tok/sTTFT calienteMemoria picoNotas
Nemotron-3-Nano-30B-A3Bnvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16BF16~28.8~0.22 s~118 GBCarga directa. Casi llena el pool unificado.
Nemotron-3-Super-120B-A12Bnvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4NVFP4 (MIXED_PRECISION)~14.7~0.29 s~110 GBMayor modelo, más expertos activos (A12B), por eso es más lento que Nano.
Nemotron-3-Nano-Omni-30B-A3Bnvidia/NVIDIA-Nemotron-3-Nano-Omni-30B-A3B-Reasoning-NVFP4NVFP4 (MIXED_PRECISION)~40.0~0.10 s~40 GBMultimodal vía vLLM. Imagen probada y funcional. Audio no funcionó por decodificación del contenedor.

Los checkpoints oficiales de NVIDIA funcionan out-of-the-box con trtllm-serve --backend pytorch. El Nano en BF16 está al límite de la memoria unificada; el Super en NVFP4 deja un poco más de margen. El Omni, por su parte, requiere vLLM para chat multimodal; TRT-LLM 1.3.0rc13 falló al parsear el formato OpenAI multimodal.

Comparativa vLLM vs TensorRT-LLM para Nemotron 3:

ModelovLLM tok/sTRT-LLM tok/svLLM memoriaTRT-LLM memoriaRecomendación
Nano-30B-A3B BF16~28.3~28.8~72 GB~118 GBAmbos funcionan. TRT-LLM usa más memoria pero es el stack oficial.
Super-120B-A12B NVFP4No viable (OOM/colgado)~14.7—~110 GBSolo TRT-LLM en GB10.
Nano-Omni-30B-A3B NVFP4~40.0No probado / parse multimodal falla~40 GB—Solo vLLM para multimodal.

La razón principal por la que el Super no funciona con vLLM es la gestión de memoria: vLLM V1 reserva memoria agresivamente (--gpu-memory-utilization 0.90) para PagedAttention y compila kernels con torch.compile, mientras que TRT-LLM reserva un presupuesto fijo calculado a partir de max_seq_len y max_batch_size. Para un modelo de 120B con 512 expertos y arquitectura híbrida Mamba-MoE, el overhead de vLLM excede los 128 GB unificados.

Interpretación

Los blueprints oficiales de NVIDIA para Spark (build.nvidia.com/spark/trt-llm/instructions) funcionan con modelos específicos como nvidia/Llama-3.1-8B-Instruct-FP4, openai/gpt-oss-* y nvidia/Nemotron-3-Nano-Omni-30B-A3B-Reasoning-BF16, pero no directamente con los checkpoints NVFP4 pre-cuantizados de Gemma 4 26B-A4B ni Qwen 3.6 35B-A3B tal como están publicados en HuggingFace.

Para usar TensorRT-LLM con Qwen 3.6 hoy hay dos caminos:

  1. Opción funcional probada: cuantizar el modelo base BF16 con Model Optimizer usando --qformat nvfp4_mlp_only y servir con trtllm-serve --backend pytorch.
  2. Full NVFP4: requiere que TRT-LLM agregue soporte para los tensores de escala de la atención lineal de Qwen3.5/3.6; actualmente falla.

Para Gemma 4 26B-A4B sería necesario esperar una versión de TRT-LLM con soporte nativo de gemma4 en su stack de transformers, o cuantizar el modelo base desde cero.

Dado lo anterior, vLLM es la opción más rápida y sencilla hoy para Gemma 4 y Qwen 3.6 pre-cuantizados; TRT-LLM es viable para Qwen 3.6 si se cuantiza manualmente en formato MLP-only.


Recomendación final

Para uso con agentes locales en DGX Spark, la configuración ganadora es:

Gemma 4 31B dense debe reservarse solo para tareas donde la calidad del modelo denso justifique los ~7 tok/s.

Si tu framework de agentes (OpenClaw, Hermes, etc.) necesita la ventana de contexto más grande práctica en un solo GPU local, Qwen 3.6 35B-A3B en vLLM es la opción clara: entrega el límite duro de 262,144 tokens con 1 sesión concurrente por defecto. Configuramos LiteLLM/Hermes para 237K de input + 25K de output, maximizando el contexto usable.

Nemotron 3:

Multimodalidad (imagen/audio):