ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

昇腾910B部署Qwen3.5与vLLM Ascend实战指南

2026/9/20 11:37:30 拓冰建站 浏览量
昇腾910B部署Qwen3.5与vLLM Ascend实战指南 1. 为什么要在昇腾910B上折腾Qwen3.5加vLLM Ascend先把结论摆在前面如果你手里有一台昇腾910B的机器想跑Qwen3.5这个级别的模型又希望推理吞吐能撑住多人并发那vLLM Ascend基本是目前最省心的组合之一。我自己前前后后在三台不同配置的910B服务器上折腾过这套东西踩的坑不算少但跑通之后确实稳。Qwen3.5是通义千问系列较新的一代模型相比前代在长上下文理解、指令跟随和推理链稳定性上都有明显提升参数量覆盖了从几B到几百B的多个档位。昇腾910B是国产AI加速卡里生态相对成熟的一款单卡64GB HBM算力在FP16下大约320 TFLOPS卡间通过HCCS互联。vLLM Ascend则是vLLM社区针对昇腾硬件做的适配版本把vLLM那套PagedAttention、连续批处理continuous batching的机制搬到了昇腾的CANN软件栈上。这套组合解决的核心问题是在国产算力上用一套接近CUDA生态体验的推理框架把大模型的显存利用率和并发吞吐拉起来。传统用transformers直接推理显存浪费严重batch一开大就OOM并发上来延迟直接爆炸。vLLM的PagedAttention把KV Cache按块管理显存碎片大幅减少配合连续批处理吞吐能翻好几倍。适合谁看这篇三类人一是手里已经有910B机器、想跑通Qwen3.5推理的运维或算法工程师二是正在做国产化替代、需要评估昇腾推理性能的技术选型负责人三是对vLLM机制感兴趣、想了解它在非CUDA平台上怎么落地的人。下面我按实际部署顺序把每个环节的细节和坑都摊开讲。2. 部署前的环境盘点与方案选型2.1 硬件与驱动的前置检查动手之前先把机器状态摸清楚这一步偷懒后面会加倍还回来。昇腾910B的部署对驱动和固件版本极其敏感版本不匹配是新手最容易卡住的地方。登录机器后第一件事是确认NPU设备能被识别npu-smi info这条命令会列出所有NPU卡的状态、显存占用、温度、功耗。正常输出里应该能看到910B的型号标识和每张卡的HBM容量。如果这条命令报错或者看不到卡别急着往下走先解决驱动问题。接着查驱动和固件版本npu-smi info -t board -i 0输出里会包含驱动版本driver version和固件版本firmware version。这里有个经验驱动、固件、CANN、torch_npu四者的版本必须严格对应官方文档里有一张兼容性矩阵表务必对着查。我遇到过驱动是较新版本、但CANN装的是旧版本结果torch_npu加载时直接段错误排查了大半天才发现是版本错配。提示昇腾的版本兼容性比CUDA生态严格得多CUDA下驱动向下兼容基本没问题但昇腾这边差一个小版本都可能出问题。建议把驱动、固件、CANN、torch_npu的版本号记在一个文档里方便后续复现。2.2 软件栈的版本搭配逻辑整套软件栈从上到下是这样的最底层是驱动和固件往上是CANN异构计算架构再往上是torch_npuPyTorch的昇腾适配层最上面才是vLLM Ascend。每一层都要版本对齐。我实测下来比较稳的一套组合是CANN 8.0系列、torch_npu 2.1以上、vLLM Ascend对应版本。具体版本号建议直接查vLLM Ascend的官方仓库README里面会写明推荐的CANN和torch_npu版本。不要凭感觉装最新版最新版往往还没和vLLM Ascend对齐装上去大概率跑不起来。为什么这么强调版本因为vLLM Ascend底层调用了CANN里的大量算子接口CANN版本一变算子签名可能就变了vLLM Ascend如果没同步适配编译或运行阶段就会报找不到符号之类的错误。这跟CUDA下cudnn版本不匹配导致的问题是一个道理只是昇腾这边容错空间更小。2.3 为什么选vLLM Ascend而不是其他方案昇腾上跑大模型可选方案其实不少直接用transformers加torch_npu、用MindIE、用vLLM Ascend、或者自己写推理服务。我选vLLM Ascend主要看中三点。第一是PagedAttention带来的显存效率。传统推理里KV Cache要预分配一大块连续显存按最大序列长度预留实际用不到那么多就浪费了。PagedAttention把KV Cache切成固定大小的块按需分配显存利用率能提升到90%以上。对于Qwen3.5这种长上下文模型KV Cache占用很可观这个优化直接决定了你能开多大的batch。第二是连续批处理。传统静态batch要等一个batch里所有请求都生成完才能处理下一批短请求被长请求拖死。连续批处理是每生成一个token就检查有没有新请求可以插进来把GPU/NPU利用率拉满。实测在混合长短请求的场景下吞吐能比静态batch高2到3倍。第三是生态兼容性。vLLM的接口和OpenAI API兼容上层应用几乎不用改代码就能从CUDA切到昇腾。这对做国产化替代的团队来说迁移成本极低。MindIE是华为自家的推理框架性能也不错但生态和社区活跃度不如vLLM遇到问题查资料相对费劲。transformers加torch_npu最简单但性能和显存效率差一大截只适合单请求调试不适合生产。3. 核心细节解析与实操要点3.1 CANN与torch_npu的安装细节CANN的安装包从昇腾社区下载注意要选对架构x86还是arm和操作系统版本。安装时用--install参数装完要source环境变量source /usr/local/Ascend/ascend-toolkit/set_env.sh这一步很多人会忘结果后面import torch_npu时报找不到libascend相关的库。建议把这条source命令写进~/.bashrc省得每次开新终端都要手动执行。torch_npu的安装要和PyTorch版本对应。比如PyTorch 2.1对应torch_npu 2.1不能混装。安装命令大致是pip install torch2.1.0 pip install torch-npu2.1.0.post8装完后验证import torch import torch_npu print(torch.npu.is_available()) print(torch.npu.device_count())如果输出True和正确的卡数说明torch_npu这层通了。如果报错八成是CANN环境变量没source或者版本不匹配。注意torch_npu和PyTorch的版本对应关系不是简单的数字相等有些post版本号有特定要求。装之前一定查官方release note别想当然。3.2 vLLM Ascend的编译与安装vLLM Ascend有两种安装方式pip直接装预编译包或者从源码编译。强烈建议先试pip预编译包能省掉大量编译时间。如果预编译包和你的CANN版本不匹配再考虑源码编译。pip安装大致是pip install vllm-ascend但这里有个坑vllm-ascend依赖特定版本的vllmpip可能会自动装一个不兼容的vllm版本。稳妥做法是先手动装对应版本的vllm再装vllm-ascend用--no-deps避免它乱改依赖pip install vllm指定版本 pip install vllm-ascend --no-deps源码编译的话需要先clone仓库然后按README里的步骤设置CANN路径、编译算子。编译过程比较吃CPU和内存建议在配置好一点的机器上做编译一次大概十几分钟到半小时。编译时常见的报错是找不到CANN的头文件或库文件这时候要检查ASCEND_HOME_PATH环境变量是否指向正确的CANN安装目录。另一个常见问题是gcc版本昇腾的算子编译对gcc版本有要求太新或太旧都可能失败一般gcc 9到11比较稳。3.3 模型权重的准备与格式转换Qwen3.5的权重从官方渠道下载通常是safetensors格式。vLLM Ascend能直接加载safetensors不需要额外转换这点比早期版本方便很多。下载权重时注意几点一是确认下载的是完整权重不是分片缺失的二是检查模型配置文件config.json里的参数比如num_hidden_layers、hidden_size、num_attention_heads这些要和实际权重对应三是如果模型有tokenizer.json和tokenizer_config.json确保都在。权重存放路径建议单独放一个目录比如/data/models/Qwen3.5-xxB不要和代码混在一起。加载时用绝对路径避免相对路径带来的困惑。如果显存有限可以考虑量化版本。Qwen3.5有AWQ、GPTQ等量化权重vLLM Ascend对部分量化格式有支持但支持程度不如CUDA版vLLM全面。用之前先查vLLM Ascend的文档确认你要用的量化格式被支持。我实测AWQ在昇腾上的支持相对成熟GPTQ偶尔会有算子缺失的问题。3.4 关键参数的取值逻辑启动vLLM服务时几个参数直接决定性能和稳定性这里逐个说清楚。--tensor-parallel-size是张量并行度等于你用几张卡。910B单卡64GB跑Qwen3.5的某个中等规模版本如果单卡放不下就要用TP。TP2表示两张卡分摊模型权重。注意TP度要和卡数匹配且最好是2的幂次跨卡通信走HCCS效率比走PCIe高。--gpu-memory-utilization是显存利用率上限默认0.9。这个值决定vLLM能用多少显存来放KV Cache。设太高容易OOM设太低浪费显存。我的经验是0.85到0.92之间比较稳具体看模型大小和序列长度。如果经常OOM往下调到0.85如果显存还有富余可以往上试到0.92。--max-model-len是最大序列长度要和模型本身支持的长度匹配。Qwen3.5支持长上下文但设太长会吃掉大量KV Cache显存。如果实际业务用不到那么长就设小一点把省下的显存留给batch。--max-num-seqs是最大并发序列数控制同时处理多少请求。这个值越大吞吐越高但显存占用也越大。建议从较小值开始压测逐步往上调找到显存和吞吐的平衡点。--block-size是PagedAttention的块大小默认16。这个值影响显存碎片和调度效率一般不用改除非有特殊需求。4. 实操过程与核心环节实现4.1 从零到跑通的第一条命令假设环境都装好了权重也下载了第一条启动命令可以这样写python -m vllm.entrypoints.openai.api_server \ --model /data/models/Qwen3.5-xxB \ --tensor-parallel-size 2 \ --gpu-memory-utilization 0.9 \ --max-model-len 8192 \ --max-num-seqs 64 \ --port 8000 \ --trust-remote-code--trust-remote-code在加载Qwen系列模型时通常需要因为它的模型定义里有自定义代码。不加这个参数可能会报找不到模型类的错误。启动过程会经历几个阶段加载权重、初始化KV Cache、编译算子首次启动会慢一些、启动HTTP服务。看到类似Uvicorn running on http://0.0.0.0:8000的输出说明服务起来了。首次启动时vLLM Ascend会做一些算子编译和缓存这个过程可能持续几分钟。第二次启动会快很多因为缓存已经建好了。如果每次启动都很慢检查缓存目录是否可写或者是不是每次都在重新编译。4.2 用curl验证服务是否正常服务起来后先用最简单的请求验证curl http://localhost:8000/v1/completions \ -H Content-Type: application/json \ -d { model: /data/models/Qwen3.5-xxB, prompt: 你好请介绍一下你自己, max_tokens: 128, temperature: 0.7 }如果返回正常的生成结果说明整条链路通了。如果报错看服务端的日志通常错误信息会指出问题所在。也可以用OpenAI的Python SDK来测from openai import OpenAI client OpenAI(base_urlhttp://localhost:8000/v1, api_keydummy) resp client.chat.completions.create( model/data/models/Qwen3.5-xxB, messages[{role: user, content: 你好}], max_tokens128 ) print(resp.choices[0].message.content)用chat接口时注意Qwen3.5有对话模板vLLM会自动应用。如果发现输出格式不对检查tokenizer配置里的chat_template是否正确。4.3 压测与性能调优的实操记录跑通之后下一步是压测搞清楚这套配置的实际吞吐和延迟。我用的是一个简单的并发压测脚本模拟多个用户同时请求import concurrent.futures import time from openai import OpenAI client OpenAI(base_urlhttp://localhost:8000/v1, api_keydummy) def send_request(i): start time.time() resp client.chat.completions.create( model/data/models/Qwen3.5-xxB, messages[{role: user, content: f请写一段关于数字{i}的短文}], max_tokens256 ) return time.time() - start with concurrent.futures.ThreadPoolExecutor(max_workers32) as executor: futures [executor.submit(send_request, i) for i in range(100)] latencies [f.result() for f in futures] print(f平均延迟: {sum(latencies)/len(latencies):.2f}s) print(fP99延迟: {sorted(latencies)[int(len(latencies)*0.99)]:.2f}s)压测时观察npu-smi info里的显存占用和利用率。如果显存接近打满但利用率不高说明batch开小了可以调大--max-num-seqs。如果显存打满且频繁OOM说明开太大了要往下调。我实测下来双卡910B跑Qwen3.5中等规模版本--max-num-seqs设64、--max-model-len设8192时32并发下平均延迟在可接受范围吞吐比单请求串行高了将近一个数量级。具体数字因模型规模和序列长度而异这里给的是量级参考。调优的核心逻辑是在显存不OOM的前提下尽量把batch和并发拉满让NPU利用率维持在较高水平。NPU利用率和吞吐正相关利用率上不去说明有资源闲置。4.4 多卡并行的通信优化用TP大于1时卡间通信是性能瓶颈之一。910B的HCCS互联带宽比PCIe高不少所以尽量让TP的卡在同一台机器内且走HCCS。如果跨机器做TP通信走网络延迟会明显上升。检查卡间互联拓扑可以用npu-smi info -t topo输出会显示卡与卡之间的连接方式。如果显示HCCS说明是高速互联如果显示SYS或PCIe说明走的是较慢的通道TP效率会打折。另一个优化点是--enable-prefix-caching开启前缀缓存后多个请求如果共享相同的前缀比如相同的system promptKV Cache可以复用省掉重复计算。对于有固定system prompt的场景这个优化效果很明显。5. 常见问题与排查技巧实录5.1 启动阶段的典型报错部署过程中遇到的报错我整理成了一张速查表方便对照排查。报错现象可能原因排查方向ImportError: libascend...CANN环境变量未source执行set_env.sh检查LD_LIBRARY_PATHtorch.npu.is_available()返回False驱动或torch_npu版本不匹配查兼容性矩阵核对版本加载权重时OOM模型太大或显存利用率设太高降低gpu-memory-utilization或增加TP算子编译失败gcc版本或CANN版本问题换gcc 9-11核对CANN版本服务启动后请求超时首次编译未完成或卡死看日志等待编译完成找不到模型类未加trust-remote-code启动命令加--trust-remote-code这张表里的每一条我基本都踩过。印象最深的是算子编译失败那次报错信息很模糊只说是某个算子编译不过。后来发现是gcc版本太新gcc 13换成gcc 11就过了。昇腾的算子编译对gcc版本比较挑建议用系统自带的或者官方推荐的版本。5.2 运行阶段的性能问题服务跑起来后性能不达预期是另一个常见问题。表现是吞吐低、延迟高、NPU利用率上不去。先查NPU利用率npu-smi info -t usages -i 0如果利用率长期低于50%说明有资源闲置。可能的原因batch太小、请求串行、或者有CPU瓶颈。先调大--max-num-seqs看利用率是否上升。如果调大后OOM说明显存是瓶颈考虑用量化权重或减少max-model-len。如果利用率高但吞吐还是低可能是卡间通信瓶颈。检查TP配置确认卡间走的是HCCS。另外如果请求的输入长度差异很大连续批处理的调度开销会上升可以适当调整调度策略。还有一个容易被忽略的点是CPU预处理。tokenization和请求解析在CPU上做如果CPU性能不足会成为瓶颈。压测时用top看CPU占用如果某个核跑满考虑优化tokenizer或增加CPU资源。5.3 显存管理的避坑经验显存管理是昇腾部署里最容易出问题的地方。几个经验点第一--gpu-memory-utilization不要设太满。留一点余量给系统和其他进程设0.9比设0.95稳。我见过设0.95后跑一段时间因为显存碎片导致OOM的案例。第二KV Cache的显存占用和序列长度、并发数成正比。如果业务里长序列请求多max-model-len要设够但设太大又浪费。建议根据实际业务的P99序列长度来设不要盲目设成模型支持的最大值。第三多卡TP时每张卡的显存占用不完全一样因为有些层可能集中在某张卡上。用npu-smi info观察每张卡的显存如果某张卡明显偏高可能是负载不均考虑调整TP策略。第四长时间运行后如果出现显存缓慢增长可能是内存泄漏。vLLM Ascend的某些版本有过这类问题升级到修复版本可以解决。如果无法升级定期重启服务是个笨但有效的办法。5.4 模型加载的疑难杂症模型加载失败的原因五花八门这里列几个我遇到过的。一是权重文件不完整。下载过程中断导致某个分片缺失加载时报找不到文件或形状不匹配。解决办法是校验文件完整性对比官方提供的文件列表和MD5。二是config.json配置和权重不匹配。比如config里写的层数和实际权重层数不一致加载时会报形状错误。这种情况通常是下载了错误的权重版本或者手动改过config。三是tokenizer问题。Qwen3.5的tokenizer有特殊配置如果tokenizer文件缺失或版本不对会导致tokenization结果异常表现为生成的文本乱码或不符合预期。确保tokenizer相关文件齐全且和模型版本对应。四是量化权重和vLLM Ascend版本不兼容。某些量化格式需要特定版本的vLLM Ascend支持版本不对会报算子缺失。用之前查文档确认支持情况。6. 生产环境部署的额外考量6.1 服务化与高可用单机跑通只是第一步生产环境要考虑服务化和高可用。vLLM Ascend的OpenAI兼容接口可以直接对接上层网关用Nginx做负载均衡后面挂多个vLLM实例。多实例部署时每个实例占用的NPU卡要隔离避免互相抢资源。可以用ASCEND_RT_VISIBLE_DEVICES环境变量指定每个实例可见的卡ASCEND_RT_VISIBLE_DEVICES0,1 python -m vllm.entrypoints.openai.api_server ...这样实例A用0、1卡实例B用2、3卡互不干扰。高可用方面网关层做健康检查某个实例挂了自动摘除。vLLM Ascend有健康检查接口可以配置到网关里。另外模型加载时间长实例重启慢建议保持一定冗余实例避免单点故障导致服务不可用。6.2 监控指标的搭建生产环境必须要有监控。关键指标包括NPU利用率、显存占用、请求延迟、吞吐、错误率。NPU相关指标通过npu-smi采集可以写个脚本定时抓取推到Prometheus。vLLM自身也暴露了一些指标比如运行中的请求数、等待队列长度、KV Cache使用率这些可以通过它的metrics接口获取。监控告警的阈值设置NPU利用率持续低于30%说明资源浪费持续高于95%说明接近瓶颈显存占用超过90%要警惕OOMP99延迟超过业务容忍阈值要告警。6.3 版本升级的注意事项昇腾生态迭代快版本升级频繁。升级时要注意先在小规模环境验证确认新版本和现有模型、上层应用兼容再灰度到生产。升级CANN或驱动时最好停机操作因为升级过程中NPU不可用。升级后要重新验证torch_npu和vLLM Ascend是否正常有时候升级CANN后需要重新编译vLLM Ascend的算子。保留旧版本的安装包和环境快照万一新版本有问题可以快速回滚。昇腾的回滚比CUDA麻烦因为涉及驱动、固件、CANN多层提前准备好回滚方案能省很多事。我在实际部署中最大的体会是昇腾这套东西版本管理比技术本身更考验人。技术原理搞懂了剩下的就是和版本兼容性作斗争。把每个组件的版本号记录清楚每次变更都做验证能避开大部分坑。另外社区和官方文档是重要参考遇到问题先搜有没有人踩过同样的坑往往能省下大量排查时间。