国产 GPU 适配到底在适配什么:从 CUDA 生态到 vLLM 插件机制的执行链拆解
在一套兼容的 NVIDIA 环境里,部署一个大模型可能只需要一条命令:
1 | vllm serve /models/Qwen \ |
换到国产 GPU 上,同样的模型、同样的 Python 代码,却可能遇到一长串看似互不相关的问题:PyTorch 认不出设备;权重能加载但执行 Attention 时异常退出;BF16 正常而 FP8 不被支持;单卡能跑但 Tensor Parallel 起不来;能出字但速度远低于预期;短上下文正常而长上下文 OOM;CUDA Graph、投机解码、MoE 这些优化全部不可用。
这些问题指向同一个根源:大模型推理并不直接跑在 GPU 硬件上,而是跑在一整套软硬件协同的执行体系上。 换一张卡,换掉的是整条链路。
一、模型不认识 GPU
以 Transformer 为例,无论 Qwen、DeepSeek 还是 GLM,模型首先描述的是一组数学计算——线性变换 、注意力 。这些公式没有指定必须用 NVIDIA、海光还是昇腾。从数学意义上,只要硬件能正确完成运算,就具备执行模型的基础条件。
但断层出现在下一步:
数学表达能够跨平台,不代表计算程序可以直接跨平台。
GPU 不会去读 Transformer 公式。推理框架要把数学运算翻译成具体算子,再经由编程运行时、设备驱动、硬件指令执行。而不同 GPU 的计算单元组织、指令集、矩阵计算能力、内存层级、编程接口差异显著——针对 CUDA 手写的高性能 Kernel,不能默认在其他硬件上运行。
CUDA 生态的隐性依赖
NVIDIA 上部署容易,一个重要原因是 CUDA 生态经过长期积累,已形成一套成熟的计算软件体系:
| 组件 | 职责 |
|---|---|
| CUDA Runtime | 显存、Stream、Event、Kernel 启动 |
| cuBLAS | 高性能矩阵计算 |
| NCCL | 多 GPU 集合通信 |
| CUTLASS | 高性能矩阵计算模板 |
| FlashAttention | 针对显存访问优化的 Attention 实现 |
| PyTorch | 张量计算与模型运行 |
| vLLM / SGLang | 推理执行与服务调度 |
这里有个容易含混的点:FlashAttention 并不是 CUDA Toolkit 的内置组成部分,CUTLASS 与 FlashAttention 也不属于同一软件层级。 它们只是共同构成了 NVIDIA 平台上常见的高性能推理生态。推理框架调用的某个算子,内部可能直接用 CUDA Kernel,也可能经 Triton、CUTLASS 或其他计算库间接执行。
所以硬件迁移时要处理的不是一行 device="cuda",而是整条计算执行路径。
适配的三个目标
工程上必须把「适配」拆成三个不能混为一谈的目标:
- 功能适配——让模型正确运行。设备识别、权重加载、算子执行、数据类型支持、输出结果验证。
- 性能适配——让模型充分发挥硬件能力。GEMM、Attention、MoE、KV Cache、低精度计算、多卡通信优化。
- 生产适配——让模型长期稳定提供服务。高并发调度、内存管理、故障恢复、可观测性、容器部署、分布式扩展。
一个模型能输出「你好」,只证明部分基本推理链路打通了。它不能证明长上下文、多卡并行、高并发调度或性能优化达到了生产可用水平。 这个区分是本篇后面所有内容的前提。
二、七层软件栈
理解适配,先要有一张知识地图。把大模型推理系统抽象成七层:
1 | ┌─────────────────────────────┐ |
这是逻辑结构图,不意味着实际执行时所有调用都严格逐层经过。推理框架的自定义算子完全可能绕过 PyTorch 的通用算子实现,直接调用专用 Kernel。但这张图能帮我们定位:某一项适配工作发生在哪一层。
2.1 计算硬件
对大模型推理,需要重点看四个硬件属性:
- 计算架构:NVIDIA 用 SM(Streaming Multiprocessor)组织计算资源,AMD 用 CU(Compute Unit)。不同架构对应不同的线程执行、寄存器分配、共享内存与矩阵计算实现。
- 矩阵计算能力:Linear、MLP、MoE 专家网络都依赖高效 GEMM。是否具备原生 BF16 / FP8 / INT8 高性能计算能力,直接决定量化策略与吞吐表现。
- 显存容量与带宽:显存不仅要放权重,还要放 KV Cache、运行时工作区、临时张量与执行图相关内存。长上下文推理中容量常是主要限制;Decode 阶段显存带宽经常是关键瓶颈。
- 多卡互联:TP 与 EP 都会引入卡间通信。互联、P2P、AllReduce、AllToAll 能力不足时,即使单卡算子性能优秀,整体扩展效率仍然很低。
结论:理论 FLOPS 不能单独决定推理性能。
2.2 驱动与固件
驱动把操作系统与用户态计算软件连到 GPU:设备枚举、内存映射、命令提交、设备状态管理都在这一层。
这也解释了一个常见困惑:容器里装好了 CUDA 或某个国产 Runtime,并不代表 GPU 一定能工作——容器仍然依赖宿主机驱动、设备节点与设备访问权限。这部分机制我在 Device Plugin 的十年 里做过拆解。
驱动兼容也不是「版本号相等」这么简单。NVIDIA 官方提供了两套机制,但各自的边界都很硬:
- 小版本兼容(Minor Version Compatibility):自 CUDA 11 起,同一大版本家族内编译的应用可在满足最低驱动版本的机器上运行(CUDA 11.x 需 ≥450、12.x 需 ≥525、13.x 需 ≥580)。边界:需按
nvcc -arch=sm_xx编译;把 device code 编成 PTX 的应用在旧驱动上不工作;用到新特性可能触发cudaErrorCallRequiresNewerDriver。 - 前向兼容(Forward Compatibility):CUDA 10.0 引入,包名
cuda-compat-<major>-<minor>,用于跨大版本在新 Toolkit + 旧驱动上运行。边界:仅限 NVIDIA Data Center GPU 及部分 NGC Server Ready 的 RTX SKU、Jetson;只覆盖 CUDA 本身;只提供库而不配置查找路径;旧的 forward compat 包在新驱动上不受支持。
所以这些机制不能推导为任意版本组合都能跑。国产 GPU 同样需要严格遵循厂商发布的驱动、Firmware、Runtime、PyTorch、算子库兼容矩阵。
2.3 Runtime
Runtime 是应用程序管理和使用 GPU 的运行时接口。CUDA Runtime 提供 cudaMalloc() / cudaMemcpy() / cudaStreamCreate() / cudaDeviceSynchronize();HIP Runtime 提供对应的 hipMalloc() / hipMemcpy() / hipStreamCreate() / hipDeviceSynchronize()。
Runtime 不是驱动本身。 它提供面向应用的编程接口,底层仍需驱动、设备运行时组件与硬件完成实际执行。以 AMD ROCm 为例,HIP Runtime 与更底层的 ROCr/HSA 体系协同工作。
在国产生态中,不同厂商路线不同:海光 DCU 的 DTK 生态与昇腾的 CANN、AscendCL 体系,不能视为同一套软件接口。
2.4 算子库
如果 Runtime 负责「如何使用 GPU」,算子库负责「在 GPU 上高效完成什么计算」。典型算子包括 GEMM、RMSNorm、RoPE、FlashAttention、Paged Attention、Fused MoE、AllReduce、AllToAll。
这里是异构 GPU 适配最容易出现性能差距的地方。 同样一个 GEMM,数学上完全一致,不同实现的性能可能相差很大——原因包括矩阵分块策略、寄存器使用、共享内存访问、数据布局、矩阵计算单元利用率。
一句话区分:算子兼容解决「能不能算」,算子优化解决「能不能高效算」。
2.5 推理框架
PyTorch 提供张量运算、模型表达与底层计算能力;vLLM、SGLang 在此基础上解决服务化推理:请求排队与连续批处理、模型加载与执行、Prefill/Decode 调度、KV Cache 分配回收、多 GPU 并行、Prefix Cache、投机解码、推理 API 服务。
推理框架通常不需要重新实现所有 GPU 算子——更合理的方式是通过硬件适配层调用已有的高性能算子,只对必要部分编写专用实现。这些机制的细节我在 推理服务调度的五层责任边界 和 vLLM 源码精读 里展开过。
2.6 模型
最上层是具体模型。不同架构对底层执行能力的要求不同:
- 普通 Dense Transformer:主要依赖 GEMM、Norm、RoPE、Attention。
- MoE:进一步要求高效的专家路由、Grouped GEMM、Expert Parallel。
- MLA / 稀疏 Attention / 混合架构:可能需要专门的 Attention Backend、状态缓存或模型执行逻辑。
因此,不能因为某款国产 GPU 已经跑通了一个 Qwen Dense 模型,就认为它完整兼容所有 DeepSeek、GLM 或多模态模型。 架构越复杂,对适配栈的要求越高。
三、四条技术路线
一个常见误区是:既然 CUDA 是 NVIDIA 的编程生态,那国产 GPU 只要实现一套类似 CUDA 的接口,不就能直接跑模型了?实际情况远比这复杂。
3.1 NVIDIA:CUDA 原生生态
推理框架可直接使用成熟 CUDA 软件栈。优势不仅是 API 成熟,更在于拥有大量围绕具体硬件架构优化过的计算实现。FlashAttention 的高效运行,与寄存器使用、共享内存分块、矩阵计算与访存优化密切相关。
3.2 AMD:ROCm 与 HIP
HIP 与 CUDA 在不少 API 和编程模型上相似:
1 | // CUDA |
AMD 还提供 HIPIFY 工具辅助迁移部分 CUDA 源码。但要注意:
API 相似不等于二进制兼容,也不保证性能相同。
一个针对 NVIDIA 的 Warp、Tensor Core 或特定访存模式高度优化的 CUDA Kernel,即使代码能转成 HIP,也可能需要针对 AMD 的 Wavefront、矩阵计算单元和内存体系重新调优。而且 CUDA 专用库与硬件指令没有通用的一对一替代关系。所以异构迁移不是字符串替换,而是运行时、算子实现与硬件执行行为的重新适配。
3.3 海光:DTK / HCU 生态
海光 DCU 的适配是理解国产 GPU 工程路线的一个典型案例。这里有个命名上的常见混淆需要先厘清:DTK 是工具链(含数学库、通信库、编译器 DCC、调试优化工具),而海光 AI 软件栈的品牌叫 DAS——PyTorch、vLLM、SGLang 的适配都归在 DAS 下。把「海光的软件生态」直接等同于 DTK 并不准确。
在 vLLM 侧,海光公开了 HYGON-AI/vllm-plugin-das 项目(Apache-2.0,2026 年 6 月建仓,持续活跃;版本以分支 + wheel 形式发布,没有 GitHub Release)。它并不是重新开发整套 vLLM,而是基于上游 vLLM 的插件机制,在必要位置接入 HCU 专有实现。 其顶层包名为 vllm_hcu/。
3.4 昇腾:CANN 与 torch-npu
昇腾走另一条路线:提供 CANN 软件栈,并通过 torch-npu 等组件连接 PyTorch。在 vLLM 生态中,vllm-ascend 是面向昇腾 NPU 的硬件插件项目。
1 | vLLM |
这同样是逻辑示意——部分高性能算子可通过专用实现路径执行,不一定全部经过 PyTorch 通用算子分发。
与海光的 HIP 系生态相比,昇腾要处理的是 CANN、torch-npu、Ascend 设备执行及其专用算子体系。一个依赖 CUDA 专有机制的 Kernel,无法仅通过替换 cuda 字符串就变成能在昇腾上运行的程序,必须选择昇腾支持的编译、算子与运行机制。
3.5 路线归纳
| 平台 | 主要软件生态 | 典型框架适配方式 |
|---|---|---|
| NVIDIA GPU | CUDA | 上游原生支持为主 |
| AMD GPU | ROCm / HIP | ROCm Backend 与专用 Kernel |
| 海光 DCU | DTK / HCU | HCU 适配层及专用算子 |
| 昇腾 NPU | CANN / torch-npu | 硬件插件与专用算子 |
实际能力还需结合具体卡型与软件版本判断。寒武纪、摩尔线程、沐曦等其他国产加速器,同样要分别分析各自的驱动、Runtime、编译器、算子库与框架支持情况。顺带纠正几个常被写错的官方名称:
| 厂商 | 官方名称 | 常见错误写法 |
|---|---|---|
| 寒武纪 | NeuWare(软件开发平台)、MagicMind(推理引擎)、BANG(编程语言) | — |
| 摩尔线程 | MUSA = Meta-computing Unified System Architecture | |
| 沐曦 | MXMACA® = MetaX Advanced Computing Architecture |
所以所谓「国产 GPU 统一适配」,不是让所有硬件使用完全相同的底层代码。更现实的架构是:上层保持模型服务与推理调度接口相对统一,底层通过可扩展的 Backend 与硬件专用 Kernel 实现差异化适配。
四、vLLM 是怎么接入一张新 GPU 的
前几章讲原理,这一章进入真实开源实现。
vLLM 的核心能力不只是模型前向计算,还包括 Scheduler、KV Cache 管理、Model Runner、Worker 和分布式执行。要让 vLLM 支持新硬件,最直接的办法是改上游源码——但这样每次 vLLM 升级都要重新合并维护下游修改。因此社区逐步建立了硬件可插拔机制。
4.1 Platform Plugin:告诉 vLLM 跑在什么设备上
vLLM 使用 Python 标准的 Entry Points 机制发现插件,平台插件注册在:
1 | [project.entry-points."vllm.platform_plugins"] |
入口函数的约定是:判断当前运行环境是否支持,支持则返回 Platform 类的完整限定名字符串,不支持则返回 None。函数名由插件作者自定——官方文档示例用 register,vllm-ascend 用 register,海光用 hcu_platform_plugin:
1 | # 依据官方接口约定写出的说明性示例 |
上例为示意,
hardware_is_available()与MyPlatform并非可直接运行的实现。另外两个容易忽略的官方约束:该入口函数必须是可重入的(re-entrant),且会在每个进程中被调用。
框架启动时,插件判断环境是否匹配,匹配则返回对应 Platform 类路径。这类适配通常涉及:硬件类型识别、设备能力查询、默认执行配置、设备相关 Worker 选择、平台支持的数据类型与执行能力。
但注册 Platform 并不代表模型已经能跑。 它只解决了「框架如何认识这类硬件、如何选择后续执行路径」。
4.2 Model Runner:真正组织模型执行
Model Runner 是框架与底层模型执行的重要连接点,可以理解为推理任务的执行组织者:准备输入张量、组织前向计算、与 KV Cache 和执行模式配合。
NVIDIA 平台上相关实现可能直接调 CUDA Kernel;其他平台则需适配张量分配、执行设备、Attention Backend 和专用算子。同一套 Scheduler 逻辑有机会复用,但 Model Runner 与设备执行路径往往需要适配。 这正是插件架构的价值——尽可能保留通用推理能力,把硬件差异限制在必要的执行边界内。
4.3 Attention Backend:适配中最关键的部分之一
Attention 是推理中最核心的计算模块。以带 KV Cache 的自回归推理为例,Prefill 处理输入上下文,Decode 利用历史缓存生成新 Token。两者数学机制相关,但数据形状、访存行为与性能瓶颈并不相同。
推理框架中的 Attention Backend 不只是调一个矩阵乘法函数,它涉及:
- Q/K/V 的数据布局
- Attention Mask
- KV Cache 的组织方式
- Cache Block 映射
- Prefill / Decode 的执行路径
- GQA、MLA 等模型特殊结构
- Kernel 对输入形状与数据类型的要求
以 vLLM 的 Paged Attention 为例,它需要把逻辑上连续的 KV 序列映射到物理 Cache Block,硬件 Kernel 必须能正确解释这些 Block 的布局与索引关系。如果新硬件只有普通 Attention Kernel,却不支持框架使用的 KV Cache 访问方式,那么单纯替换 Backend 名称也无法完成适配。块管理的细节见 vLLM 源码精读。
4.4 海光插件具体适配了什么
从 vllm-plugin-das 的公开架构可以看到三个方向。
第一,使用标准插件入口。 通过 vLLM 的 Platform 与 General Plugin 注册机制接入。该仓库 setup.py 中三个 entry point 分别为:
1 | "vllm.platform_plugins": ["hcu = vllm_hcu:hcu_platform_plugin"] |
分别对应平台识别、模型注册与算子注册。
关于
VLLM_PLUGINS:它是 vLLM 提供的插件白名单,按 entry point 名(逗号分隔)匹配。语义是——不设置 = 加载全部插件;设为空字符串 = 一个都不加载。海光仓库里确实出现过VLLM_PLUGINS=hcu,hcu_model,hcu_ops,但只在测试代码中,README 与官方文档并未要求用户设置它。把它当成「必须配置的启动参数」是常见误解。
第二,使用运行时 Patch。 海光插件并非完全不修改上游执行行为,它提供运行时兼容与模块替换机制,把部分上游实现替换为 HCU 专用实现。源码中定义了两个入口:
1 | def apply_platform_patches() -> None: ... |
分别涉及平台初始化阶段与 Worker 相关执行逻辑的适配。这意味着插件化不等于零侵入。更准确的说法是:在不直接修改已安装上游源码文件的前提下,通过插件入口和受控运行时替换完成适配。
第三,保留硬件专用实现。 HCU 专有模块中包含 Attention、Linear、MoE、量化及模型执行相关代码。这说明当通用实现无法满足功能或性能要求时,仍然需要编写硬件专用实现——而插件的工程价值,是让这些差异化实现与上游代码的边界更明确。
4.5 插件化是最终方案吗
插件化是重要的工程方向,但不能自动解决所有兼容问题。因为 vLLM 内部接口会持续变化——Worker 生命周期、Model Runner、Scheduler、Attention Metadata 都可能随框架演进调整。硬件插件即使没改上游代码文件,也可能依赖内部类和函数的具体行为。
因此插件的维护成本取决于:使用了多少稳定、公开的扩展接口;替换了多少内部模块;是否依赖私有实现细节;能否跟随上游做自动化兼容测试。
插件化减少了维护上游分叉的负担,但不会消除硬件适配本身的复杂性。
五、工程实践:六步验证
假设拿到一台国产 GPU 服务器,计划部署一个 Qwen 模型。正确的顺序不是立即装最新版 vLLM 然后试各种启动参数,而是从硬件层向上逐级验证。
5.1 第一步:确认软硬件兼容矩阵
至少记录:
1 | GPU: 厂商 / 型号 / 数量 / 显存 |
最容易出问题的是随意组合不同版本的软件:驱动匹配 Runtime 但 PyTorch 编译版本不匹配;或 PyTorch 正常但与推理插件依赖的 vLLM API 不兼容。建议优先使用厂商或开源项目明确验证过的完整版本组合。
5.2 第二步:验证基础张量计算
对于使用标准 PyTorch CUDA/HIP 接口的兼容环境:
1 | import torch |
需要特别说明:PyTorch ROCm 构建官方明确沿用 torch.cuda 接口,并不使用 torch.device("rocm") 作为设备名。 但昇腾等平台应采用对应设备扩展提供的接口,不能直接套用上述代码。上面这段是 CUDA/HIP 风格的环境检查,不代表已验证所有海光 DTK 版本。
如果基础矩阵乘法都跑不了,应先定位设备 Runtime、PyTorch 或基础算子库的问题,而不是去改 vLLM 的 Scheduler。
5.3 第三步:算子正确性验证
张量计算正常后,进一步验证模型依赖的核心算子:RMSNorm、RoPE、GEMM、Attention、SiLU/SwiGLU、Fused MoE、量化计算。
正确性测试不能只检查「有没有报错」,还要比较数值结果:
1 | import torch |
rtol / atol 只是演示阈值,不是所有 GPU 或算子的统一合格标准。BF16、FP8、量化 Attention、MoE 等算子应结合数值精度、累计误差、模型语义与具体测试数据设置合理容差。
还要记住:数值正确不代表性能达标。
5.4 第四步:验证推理框架
基础算子通过后再进 vLLM / SGLang,重点检查:
- 模型能否正常加载:权重格式、模型结构、量化配置、不支持的算子。
- 单请求能否正常推理:简单输入、长输入、不同输出长度、终止条件。
- 多请求是否稳定:调度、KV Cache 分配、内存回收、不同并发下的正确性。
- 多卡是否正常:Tensor Parallel、通信库、跨卡数据交换。
- 优化功能是否可用:Prefix Cache、Graph Capture、投机解码、FP8 KV Cache。
这些功能不应因为基础推理成功就被认定已支持。
5.5 第五步:建立性能基线
进入性能适配后,不能只看每秒生成多少 Token,要建立多维度测试体系:
| 指标 | 说明 |
|---|---|
| TTFT | 首 Token 延迟 |
| TPOT | 每个输出 Token 的平均生成时间 |
| Output TPS | 输出 Token 吞吐 |
| Request TPS | 每秒完成请求数 |
| GPU Utilization | GPU 利用率 |
| Memory Usage | 显存使用 |
| P95 / P99 | 尾部延迟 |
| Error Rate | 失败请求比例 |
长上下文与高并发场景还需关注 Prefill 吞吐、排队时间、KV Cache 占用与缓存命中。测试至少应区分六类场景:单并发短输入、单并发长输入、多并发短输入、多并发长输入、混合输入输出长度、多卡与长时间稳定性。
并且必须固定模型版本、权重精度、上下文长度、并发规模、缓存状态与测试数据。只有控制变量,才能判断不同 Kernel 或 Backend 的性能差异。
5.6 第六步:适配的完成标准
建议把国产 GPU 推理适配的完成状态划分为五级:
| 等级 | 名称 | 判据 |
|---|---|---|
| L1 | 设备可用 | 系统能识别 GPU,PyTorch 或对应设备框架可执行基础张量运算 |
| L2 | 模型可运行 | 核心算子正确执行,模型可完成单请求推理并通过基础正确性检查 |
| L3 | 服务可用 | 支持连续批处理、KV Cache 管理、并发请求、必要的多卡能力与基本监控 |
| L4 | 性能可优化 | 能分析并优化 GEMM、Attention、MoE、访存与通信瓶颈,有可复现的性能基线 |
| L5 | 生产可持续 | 完整兼容矩阵、稳定性测试、版本升级验证、自动化回归、可观测与运维能力 |
这不是行业官方标准,而是一种便于工程团队管理适配成熟度的方法。它的作用是避免「模型成功启动一次」被当成「适配完成」。
六、适配的本质:重建一条执行链
回到最初的问题:国产 GPU 适配,到底在适配什么?至少包括五类工作:
- 设备和运行环境适配——GPU 如何被操作系统和应用程序识别、管理、调用。涉及驱动、Firmware、Runtime、设备权限、软件兼容性。
- 算子与计算能力适配——数学运算如何在具体硬件上执行。GEMM、Attention、Norm、MoE、量化、通信。这一层是性能优化的基础。
- 推理框架适配——vLLM / SGLang 如何组织和调度硬件执行。Platform、Worker、Model Runner、Attention Backend、KV Cache、分布式执行。
- 模型架构适配——不同模型结构对底层计算能力的特殊要求。MLA、稀疏 Attention、混合架构、MoE、多模态编码器。
- 生产工程适配——能否真正对外提供稳定服务。高并发、长上下文、性能分析、故障排查、监控、版本维护。
会走向完全统一吗
从 vLLM、SGLang 等框架的演进看,跨硬件平台支持正在增强。但硬件差异不可能仅靠一个统一接口完全抹平。更可能形成这样的分工:
- 上层统一:模型 API、服务调度、推理任务管理与部分模型执行逻辑尽可能复用。
- 中间可插拔:通过 Platform Plugin、Attention Backend、Model Runner、算子注册机制隔离硬件差异。
- 底层专用优化:针对不同 GPU 的矩阵单元、内存结构、指令集与通信能力,保留专门优化的 Kernel。
这意味着国产 GPU 的竞争力不仅取决于硬件参数,还取决于软件生态是否成熟、核心算子是否高效、能否持续跟进主流模型与推理框架的演进。
对开发者而言,理解一张 GPU 的计算能力只是开始。真正重要的是能沿着模型执行链向下追踪:
一次 Attention 调用是怎样进入推理框架的?它如何找到对应的 Backend?Backend 最终调用了哪个 Kernel?这个 Kernel 又是如何通过 Runtime 和驱动运行在具体 GPU 上的?
能完整回答这些问题,才算真正具备异构 GPU 推理适配的工程能力。
国产 GPU 适配,不是把模型搬到另一张卡上,而是在新的硬件平台上重新打通并优化「模型计算 → GPU 执行」的完整链路。