Qwen Flash-Next NVFP4 en vLLM: parches al loader y ajuste de memoria
Un despliegue documentado paso a paso: 186,4 GB de checkpoint, dos incompatibilidades en el cargador y una configuración final de 131.072 tokens de contexto con 16 secuencias.

Poner Qwen Flash-Next NVFP4 a servir en vLLM no fue cuestión de cambiar un flag. Hicieron falta parches en el cargador, un override de la configuración de atención y una búsqueda de memoria que aguantara tráfico concurrente de verdad. El resultado final: 131.072 tokens de contexto, límite de 16 secuencias y tres rondas de 16 peticiones simultáneas completadas sin que el contenedor registrara un reinicio. Los parches y las notas de validación están en el repositorio de notas del despliegue, que contiene extractos y validaciones, no una imagen de runtime completa.
De 186,4 GB a un tensor que no encaja
El checkpoint ocupaba 31 archivos, unos 186,4 GB en total, y un solo shard PLE se llevaba cerca de 102,4 GB. El montaje fue un volumen dedicado con ext4 y la CLI de Hugging Face con ocho workers de descarga a través de un proxy local. La transferencia se atascó en torno a los 14 GB; tras reiniciar, el progreso apareció en 4,7 GB y luego reanudó a unos 93 MiB/s. El contador sirve para mirar, no como prueba de que el checkpoint esté listo. Conviene separar dos cosas: el tamaño en disco no predice la VRAM que consumirá el proceso, y con PLE en CPU offload parte del trabajo de carga ocurre en el host.
Antes de afinar memoria aparecieron dos incompatibilidades. La primera, en la configuración de atención: doce entradas de capa usaban qwen_sparse_attention y la ruta del runtime esperaba full_attention. Se resolvió con un override local, pero el autor avisa de que superar el parseo de configuración no demuestra que ambos ajustes sean equivalentes en cómputo: no hubo comparación controlada de calidad ni de comportamiento de atención antes y después.
La segunda estaba en la tabla de embeddings PLE. El loader esperaba shards con sufijo numérico y el checkpoint exponía la tabla completa bajo un nombre de tensor con el índice vacío, además de un desajuste de nombres entre la forma larga con prefijo y la forma corta que aparecía al cargar. El arreglo pasó por tres iteraciones: la primera reconoció el sufijo vacío y no bastó; la segunda manejó la tabla completa con validación de forma, pero solo el prefijo largo; la tercera sumó el nombre corto y cargó. La validación de forma es la parte que no se debe saltar: un desajuste tiene que fallar al cargar, donde se puede explicar, y no convertirse después en un problema de inferencia.
Antes de sustituir el servidor anterior se guardó su configuración de contenedor y un objetivo de rollback, para no añadir variables mientras se tocaba lo nuevo.
Qué mide el test de 48 peticiones
El test de 48 peticiones pertenece a la línea base inicial, con caché KV en bfloat16. El trabajo posterior sobre B12x se describe por separado y no hereda ese resultado, aunque la documentación de la API B12x de FlashInfer sirve de referencia para esa parte. El parche del loader se empaquetó como una capa fina sobre la imagen original del contenedor, reemplazando un único módulo.
Lo aprovechable de este caso no es la cifra de contexto, sino el método: tratar el layout del checkpoint como un problema propio, validar dimensiones antes de copiar y no dar por bueno que dos configuraciones de atención son intercambiables solo porque el runtime arranque. Queda por ver si alguien hace la comparación de calidad que aquí se dejó fuera.

