【Bug已解决】[Bug]: Qwen3.5 397B NVFP4 Crashes on B300 解决方案 【Bug已解决】[Bug]: Qwen3.5 397B NVFP4 Crashes on B300 解决方案一、现象长什么样在 B300NVIDIA Blackwell 架构 GPU上加载 Qwen3.5-397B 的 NVFP4 量化版做推理时启动或首次前向崩溃RuntimeError: NVFP4 kernel launch failed: invalid configuration or unsupported on this device或更具体的CUDA error: an illegal instruction was encountered (NVFP4 指令在当前微码/驱动下不被支持)几个典型表征只在 B300 这种 Blackwell GPU NVFP4 量化组合出现fp16/ fp8 在 B300 正常、或 NVFP4 在其它卡如 B200正常说明问题在B300 这个具体型号对 NVFP4 kernel 的支持状态——可能是微码/驱动版本、或 B300 与 B200 的 NVFP4 指令支持细节有差异。报错在内核启动 / FP4 指令执行NVFP4 是 Blackwell 的 4-bit 浮点micro-scaling需要特定硬件指令如mma的 NVFP4 变体和匹配的 CUTLASS/Flash 内核。B300 若驱动/微码未完全开启这些指令内核就 illegal instruction。大模型397B才暴露小模型可能走的路径不同或还没触发那条 NVFP4 内核397B 必走 NVFP4 全量路径于是必崩。这不是模型权重坏而是B300 上的 NVFP4 软件栈驱动/微码/CUTLASS还没完全支持 Qwen3.5-397B 走的 NVFP4 kernel。下面给出定位与修复能力探测 优雅降级。二、背景NVFP4NVIDIA 4-bit 浮点带 per-block micro-scaling是 Blackwellsm_100引入的。它的 kernel 需要GPU 架构 sm_100BlackwellB200/B300 都算但 B300 的具体 SKU 在驱动/微码上可能延迟开启部分 FP4 指令匹配的驱动 CUDA toolkit CUTLASS/Flash 版本NVFP4 kernel 由较新的 CUTLASS/FlashAttention 提供版本不对就内核不存在或指令非法正确的张量布局micro-scaling 块NVFP4 权重带 scaling 元数据布局不对也会内核崩溃。Qwen3.5-397B 是 MoE 大模型全量 NVFP4 推理会密集触发这些 kernel。B300 若上述任一环节不齐就崩。根因是部署前没有探测B300 是否真正支持该 NVFP4 kernel直接硬上。修复就是启动期能力探测 不支持则优雅降级fp8/fp16。下面用可运行代码实现NVFP4 能力探测 降级。三、根因拆成三条根因B300 驱动/微码未完全开启 NVFP4 指令NVFP4 的某些 kernel 指令在 B300 的具体微码版本下尚未启用导致illegal instruction。根因是硬件/微码能力未就绪不是软件 bug。CUTLASS/Flash 版本与 NVFP4 kernel 不匹配提供 NVFP4 kernel 的 CUTLASS/Flash 版本和 vLLM 期望的不一致内核缺失或签名错。根因是软件栈版本不对齐。缺少能力探测 降级机制vLLM 直接尝试 NVFP4不支持就崩没有先探测、不支持就回退 fp8/fp16的兜底。根因是没有优雅降级路径。修复方向启动期做 NVFP4 能力探测架构 sm 驱动 内核可用性支持才走 NVFP4否则自动降级到 fp8/fp16并给出清晰日志。四、最小可运行复现下面复现B300 不支持 NVFP4 时硬上导致崩溃的判定逻辑用架构/驱动探测def nvfp4_supported(gpu_arch, driver_cuda, cutlass_has_nvfp4): 探测 NVFP4 是否可用。 if gpu_arch 100: return False, GPU 架构 sm_100NVFP4 不支持 if not cutlass_has_nvfp4: return False, 当前 CUTLASS/Flash 版本未提供 NVFP4 kernel # B300 特有某些微码版本下 NVFP4 指令未完全开启 if gpu_arch 100 and driver_cuda 12.8: return False, fB300 需驱动 CUDA{12.8} 才启用 NVFP4 指令当前 {driver_cuda} return True, ok # 复现B300 (arch100) 驱动 12.6微码未就绪 ok, why nvfp4_supported(100, 12.6, True) print(复现:, ok, why)复现: False B300 需驱动 CUDA12.8...即复现了B300 上 NVFP4 不该硬上。下面加降级。五、解决方案第一层最小直接修复最小修复启动期探测 NVFP4 能力不支持则降级到 fp8/fp16并打清晰日志。from dataclasses import dataclass from typing import Optional dataclass class ModelRequest: quantization: str # nvfp4 / fp8 / fp16 def select_quant_for_device(req: ModelRequest, gpu_arch: int, driver_cuda: str, cutlass_has_nvfp4: bool): 按设备能力选择实际量化方式NVFP4 不支持则降级。 if req.quantization ! nvfp4: return req.quantization # 本来就不是 NVFP4 ok, why nvfp4_supported(gpu_arch, driver_cuda, cutlass_has_nvfp4) if ok: print([info] 设备支持 NVFP4按请求使用 NVFP4) return nvfp4 # 优雅降级NVFP4 → fp8 → fp16 print(f[warn] NVFP4 不可用{why}降级到 fp8) return fp8 # 复现修复 req ModelRequest(quantizationnvfp4) chosen select_quant_for_device(req, gpu_arch100, driver_cuda12.6, cutlass_has_nvfp4True) print(最终量化:, chosen) # fp8不崩这一层改动让 B300 上 NVFP4 不可用时自动降级到 fp8而不是直接崩溃且打出清晰原因。六、解决方案第二层结构化改进把量化能力探测 降级做成结构化组件覆盖架构/驱动/内核三维探测并支持多级降级链nvfp4 → fp8 → fp16。from dataclasses import dataclass, field from typing import List dataclass class DeviceCapability: gpu_arch: int driver_cuda: str nvfp4_kernel_available: bool class QuantFallbackChain: NVFP4 → FP8 → FP16 多级降级。 CHAIN [nvfp4, fp8, fp16] def __init__(self, dev: DeviceCapability): self.dev dev def _supports(self, q: str) - bool: if q nvfp4: return (self.dev.gpu_arch 100 and self.dev.nvfp4_kernel_available and self.dev.driver_cuda 12.8) if q fp8: return self.dev.gpu_arch 90 # fp8 需 sm_90 return True # fp16 总能跑 def resolve(self, requested: str) - str: # 从 requested 在链上的位置往后找第一个支持的 start self.CHAIN.index(requested) if requested in self.CHAIN else 0 for q in self.CHAIN[start:]: if self._supports(q): return q raise RuntimeError(设备不支持任何可用量化nvfp4/fp8/fp16 均不可用) # 用法 dev DeviceCapability(gpu_arch100, driver_cuda12.6, nvfp4_kernel_availableTrue) fb QuantFallbackChain(dev) print(Qwen3.5-397B 实际量化:, fb.resolve(nvfp4)) # → fp8QuantFallbackChain把降级逻辑集中、可扩展加新格式只需往CHAIN加且每次降级都基于三维探测避免硬上不支持的 NVFP4。七、解决方案第三层断言 / CI 守护NVFP4 降级最怕探测漏了又硬上。用断言守两条不变量def check_nvfp4_fallback_invariants(dev: DeviceCapability): fb QuantFallbackChain(dev) # 不变量 1请求 nvfp4 但设备不支持必须降级不得直接返回 nvfp4 if not fb._supports(nvfp4): assert fb.resolve(nvfp4) ! nvfp4 # 不变量 2任何设备至少能跑 fp16 assert fb.resolve(fp16) fp16 # 不变量 3sm100 设备不得走 nvfp4 if dev.gpu_arch 100: assert fb._supports(nvfp4) is False return True def test_nvfp4_on_b300(): # B300 驱动 12.6nvfp4 不支持 → fp8 dev DeviceCapability(100, 12.6, True) check_nvfp4_fallback_invariants(dev) assert QuantFallbackChain(dev).resolve(nvfp4) fp8 # B200 驱动 12.8nvfp4 支持 dev2 DeviceCapability(100, 12.8, True) check_nvfp4_fallback_invariants(dev2) assert QuantFallbackChain(dev2).resolve(nvfp4) nvfp4 print(OK: NVFP4 B300 降级不变量通过) if __name__ __main__: test_nvfp4_on_b300()把test_nvfp4_on_b300接进 CI任何探测漏了又硬上 NVFP4的改动都会立即红。八、排查清单Qwen3.5-397B NVFP4 在 B300 崩溃按序查确认是 NVFP4 kernel 不支持还是权重问题fp16/fp8 在 B300 能跑说明设备和权重 OK问题在 NVFP4 路径内核/指令。查 B300 驱动/微码版本NVFP4 指令在 B300 可能需要较新驱动如 CUDA 12.8。nvidia-smi看驱动支持 CUDA低于要求就升级驱动。查 CUTLASS/Flash 版本提供 NVFP4 kernel 的库版本要匹配。版本不对内核缺失或指令非法升级到支持 NVFP4 的版本。启动期做能力探测用nvfp4_supported探测架构/驱动/内核三维不支持就降级别硬上。优雅降级链NVFP4 → fp8 → fp16。B300 不支持 NVFP4 时自动用 fp8精度略降但能跑远比崩溃好。区分 B200 与 B300同为 BlackwellB300 的微码开启节奏可能不同别假设B200 能跑 B300 就能跑按实际探测结果决定。CI 接test_nvfp4_on_b300覆盖驱动 12.6→fp8 / 驱动 12.8→nvfp4两类锁死降级逻辑。九、小结Qwen3.5-397B NVFP4 在 B300 崩溃的根因是B300 的 NVFP4 软件栈驱动/微码/CUTLASS未完全支持 Qwen3.5-397B 走的 NVFP4 kernel而 vLLM 直接硬上导致 illegal instruction。三层修复第一层select_quant_for_device启动期探测 NVFP4 能力不支持则降级 fp8 并打清晰日志第二层QuantFallbackChain三维探测架构/驱动/内核 多级降级链nvfp4→fp8→fp16集中且可扩展第三层CI 断言守住不支持不得返回 nvfp4 / 至少 fp16 可用 / sm100 不走 nvfp4任何硬上立即红。落实后B300 上 Qwen3.5-397B 要么用 NVFP4驱动够新要么自动降级 fp8 继续服务不再因 NVFP4 内核不支持而崩溃。