在传统的推理部署方案中,我们通常把模型跑在一个同构集群里。但如果你做过大模型性能分析,会发现一个尴尬的现象:

  • Prefill(首字生成)阶段:是典型的计算密集型任务,像是在“阅读理解”,极度依赖算力(FLOPS)。
  • Decode(后续生成)阶段:是典型的访存密集型任务,像是在“逐字吐稿”,瓶颈全在显存带宽(HBM Bandwidth)。

在昇腾910B这样的平台上,如果让同一张卡既干Prefill又干Decode,资源利用率很难打满。PD分离的核心逻辑就是把这两个阶段拆开,让Prefill和Decode各自在最适合的硬件环境中运行,配合vLLM的PagedAttention技术管理KV缓存,能大幅提升整体吞吐。

本文记录了在昇腾NPU平台上部署DeepSeek-V3-w8a8量化模型的完整过程,希望能帮到正在做类似工作的同学。

一、硬件与基础环境

相比于英伟达GPU的“开箱即用”,昇腾NPU对环境的依赖更强,尤其是驱动和固件版本。

1.1 硬件清单

项目 配置 备注
服务器 2台 Atlas 800I A2 每台16卡 NPU (910B)
网络 100GbE RoCE 用于节点间KV Cache传输
操作系统 Ubuntu 22.04 推荐LTS版本

1.2 关键软件版本

迁移的第一步是“对齐版本”。昇腾的CANN包、PyTorch插件(torch_npu)和vLLM版本必须严格对应,否则会报各种莫名其妙的符号错误。

组件 版本 说明
CANN 8.2.RC1 核心驱动层,低于此版本不支持部分新算子
PyTorch 2.5.1 CPU版本即可
torch_npu 2.5.1.post1 必须与CANN版本配套
vLLM 0.9.1 官方主线
vLLM-ascend 0.9.1-dev 昇腾适配插件

二、环境准备:从物理层到Docker

2.1 物理层检查:NPU健康度

在部署前,必须确认NPU之间的互联(HCCL)是通的。很多时候跑不起来是因为卡之间的通信被防火墙或者是配置挡住了。

执行命令 <font style="background-color:rgb(187,191,196);">npu-smi info</font>,查看所有 NPU 的运行状态。核心目的是验证 NPU 设备是否正常识别、无硬件错误(如供电异常、硬件故障等),确保底层硬件基础可用:

出现这个截图就代表已经成功了,然后执行循环命令遍历 0-15 号 RoCE 网卡(集群通信依赖的高速网卡):<font style="background-color:rgb(187,191,196);">for i in {0..15}; do hccn_tool -i $i -ip -g; done</font>。核心目的是确认每块 RoCE 网卡都已正确配置 IP 地址,这是集群节点间数据传输的网络基础。

2.2 构建纯净的Docker环境

为了不污染宿主机,强烈建议使用Docker。容器环境能避免很多依赖冲突的问题。如果不是root用户,先切换:

sudo su - root
mkdir /home/<your_name>

出现如上所示结果,然后输入密码后,mkdir /home/<your_name>输入指令,这里替换路径中的<your_name>,换成我们自己的。

然后创建容器:

# 启动容器
docker run -it --privileged --name=vllm_pd_deploy \
  --net=host --shm-size=500g \
  --device=/dev/davinci_manager \
  --device=/dev/hisi_hdc \
  --device=/dev/devmm_svm \
  --device=/dev/davinci0 \
  --device=/dev/davinci1 \
  --device=/dev/davinci2 \
  --device=/dev/davinci3 \
  --device=/dev/davinci4 \
  --device=/dev/davinci5 \
  --device=/dev/davinci6 \
  --device=/dev/davinci7 \
  --device=/dev/davinci8 \
  --device=/dev/davinci9 \
  --device=/dev/davinci10 \
  --device=/dev/davinci11 \
  --device=/dev/davinci12 \
  --device=/dev/davinci13 \
  --device=/dev/davinci14 \
  --device=/dev/davinci15 \
  -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
  -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \
  -v /etc/hccn.conf:/etc/hccn.conf \
  -v /home/:/home \
  mindie:2.1.RC1-800I-A2-py311-ubuntu22.04-x86_64 \
  /bin/bash

三、依赖安装:填平兼容性鸿沟

这一步是迁移工作中最耗时的部分。

3.1 安装CANN Toolkit与Kernel

昇腾社区下载三个安装包:

  • Ascend-cann-toolkit_*.run (开发套件)
  • Ascend-cann-kernels-*.run (算子包)
  • Ascend-cann-nnal_*.run (神经网络加速库)

安装前确保目标目录有10GB以上可用空间:

chmod a+x Ascend-cann-kernels-910b_8.2.RC1_linux-x86_64.run
chmod a+x Ascend-cann-nnal_8.2.RC1_linux-x86_64.run
chmod a+x Ascend-cann-toolkit_8.2.RC1_linux-x86_64.run

# 先做检查
./Ascend-cann-toolkit_8.2.RC1_linux-x86_64.run --check
./Ascend-cann-toolkit_8.2.RC1_linux-x86_64.run --install --install-path=/home/<your_name>/cann_8.2.rc1

./Ascend-cann-kernels-910b_8.2.RC1_linux-x86_64.run --check
./Ascend-cann-kernels-910b_8.2.RC1_linux-x86_64.run --install --install-path=/home/<your_name>/cann_8.2.rc1

./Ascend-cann-nnal_8.2.RC1_linux-x86_64.run --check
./Ascend-cann-nnal_8.2.RC1_linux-x86_64.run --install --install-path=/home/<your_name>/cann_8.2.rc1

# 配置环境变量(每次进容器都要执行)
source /home/<your_name>/cann_8.2.rc1/ascend-toolkit/set_env.sh
source /home/<your_name>/cann_8.2.rc1/nnal/atb/set_env.sh

3.2 安装 PyTorch NPU 适配版

这里不能用官方的PyTorch,必须用华为维护的torch-npu

配置华为镜像源,否则找不到特定版本:

pip config set global.extra-index-url "https://download.pytorch.org/whl/cpu/ https://mirrors.huaweicloud.com/ascend/repos/pypi"

看到Writing to /home/service/.config/pip/pip.conf,就代表配置完成,之后进行安装torch:

pip install torch==2.5.1 torchvision==0.20.1

这里我们之前已经安装过了,最后进行NPU插件的安装,这里要注意版本号一定要对应:

pip install torch-npu==2.5.1.post1.dev20250619

3.3 编译安装 vLLM-Ascend

目前的pip源里通常不是最新的适配版本,建议源码编译,首先安装主vLLM,直接从git上进行拉取:

git clone https://github.com/vllm-project/vllm.git

这里显示正在拉取,稍微等一会便会拉取成功,显示如下:

Receiving objects: 100% (146677/146677), 122.55 MiB | 5.47 MiB/s, done.

Resolving deltas: 100% (115600/115600), done.

切换到所需目录下面:cd vllm && git checkout releases/v0.9.1,然后设置TARGET_DEVICE=empty避免编译CUDA依赖: VLLM_TARGET_DEVICE=empty pip install -v -e . 完成上面的工作后,需要再次安装昇腾适配插件,这里也同样是在git上进行拉取:

git clone https://github.com/vllm-project/vllm-ascend

四、部署流程

4.1 生成ranktable配置文件

在两台设备上都执行这个脚本,生成集群拓扑配置:

cd /home/<your_name>/vllm-ascend/examples/disaggregate_prefill_v1/

bash gen_ranktable.sh \
  --ips 141.61.41.163 141.61.41.164 \
  --npus-per-node 16 \
  --network-card-name ens3f0 \
  --prefill-device-cnt 16 \
  --decode-device-cnt 16

参数解释:

  • ips: P节点和D节点的IP,P在前D在后
  • npus-per-node: 每台机器的NPU数量
  • network-card-name: 网卡名称(用ifconfig查看)
  • prefill-device-cnt: Prefill用的卡数
  • decode-device-cnt: Decode用的卡数

4.2 编写Prefill启动脚本

在P节点创建start_prefill.sh:

#!/bin/bash

# 环境变量配置
export HCCL_IF_IP=141.61.41.163
export GLOO_SOCKET_IFNAME="ens3f0"
export TP_SOCKET_IFNAME="ens3f0"
export HCCL_SOCKET_IFNAME="ens3f0"
export DISAGGREGATED_PREFILL_RANK_TABLE_PATH=/home/<your_name>/vllm-ascend/examples/disaggregate_prefill_v1/ranktable.json
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=32
export VLLM_USE_V1=1
export VLLM_LLMDD_RPC_PORT=5559

# 启动Prefill服务
vllm serve /home/models/DeepSeek-V3.1-w8a8-rot-mtp \
  --host 0.0.0.0 \
  --port 20002 \
  --data-parallel-size 1 \
  --data-parallel-size-local 1 \
  --api-server-count 1 \
  --data-parallel-address 141.61.41.163 \
  --data-parallel-rpc-port 13356 \
  --tensor-parallel-size 16 \
  --enable-expert-parallel \
  --quantization ascend \
  --seed 1024 \
  --served-model-name deepseek \
  --max-model-len 32768 \
  --max-num-batched-tokens 32768 \
  --max-num-seqs 64 \
  --trust-remote-code \
  --enforce-eager \
  --gpu-memory-utilization 0.9 \
  --kv-transfer-config '{
    "kv_connector": "LLMDataDistCMgrConnector",
    "kv_buffer_device": "npu",
    "kv_role": "kv_producer",
    "kv_parallel_size": 1,
    "kv_port": "20001",
    "engine_id": "0",
    "kv_connector_module_path": "vllm_ascend.distributed.llmdatadist_c_mgr_connector"
  }'

4.3 编写Decode启动脚本

在D节点创建start_decode.sh:

#!/bin/bash

# 环境变量配置
export HCCL_IF_IP=141.61.41.164
export GLOO_SOCKET_IFNAME="ens3f0"
export TP_SOCKET_IFNAME="ens3f0"
export HCCL_SOCKET_IFNAME="ens3f0"
export DISAGGREGATED_PREFILL_RANK_TABLE_PATH=/home/<your_name>/vllm-ascend/examples/disaggregate_prefill_v1/ranktable.json
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=32
export VLLM_USE_V1=1
export VLLM_LLMDD_RPC_PORT=5659

# 启动Decode服务
vllm serve /home/models/DeepSeek-V3.1-w8a8-rot-mtp \
  --host 0.0.0.0 \
  --port 20002 \
  --data-parallel-size 1 \
  --data-parallel-size-local 1 \
  --api-server-count 1 \
  --data-parallel-address 141.61.41.164 \
  --data-parallel-rpc-port 13356 \
  --tensor-parallel-size 16 \
  --enable-expert-parallel \
  --quantization ascend \
  --seed 1024 \
  --served-model-name deepseek \
  --max-model-len 8192 \
  --max-num-batched-tokens 256 \
  --max-num-seqs 64 \
  --trust-remote-code \
  --gpu-memory-utilization 0.9 \
  --kv-transfer-config '{
    "kv_connector": "LLMDataDistCMgrConnector",
    "kv_buffer_device": "npu",
    "kv_role": "kv_consumer",
    "kv_parallel_size": 1,
    "kv_port": "20001",
    "engine_id": "0",
    "kv_connector_module_path": "vllm_ascend.distributed.llmdatadist_c_mgr_connector"
  }' \
  --additional-config '{"torchair_graph_config": {"enabled":true}}'

4.4 启动服务

分别在两个节点执行启动脚本:

# P节点
bash start_prefill.sh

# D节点  
bash start_decode.sh

看到Application startup complete.就说明启动成功了。

4.5 启动负载均衡代理

在P节点开一个新的终端窗口,先配置环境变量:

source /home/<your_name>/cann_8.2.rc1/ascend-toolkit/set_env.sh
source /home/<your_name>/cann_8.2.rc1/nnal/atb/set_env.sh

然后运行代理服务:

cd /home/<your_name>/vllm-ascend/examples/disaggregate_prefill_v1/

python load_balance_proxy_server_example.py \
  --host 141.61.41.163 \
  --port 1025 \
  --prefiller-hosts 141.61.41.163 \
  --prefiller-ports 20002 \
  --decoder-hosts 141.61.41.164 \
  --decoder-ports 20002

启动成功后会显示初始化的prefill和decode客户端数量:

4.6功能验证

API接口测试

开一个新的终端,发送测试请求:

curl http://141.61.41.163:1025/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek",
    "prompt": "how is it today",
    "max_tokens": 50,
    "temperature": 0
  }'

加上-v参数可以看详细的请求响应过程。返回结果中的choice/text就是模型生成的文本:

性能压测

在P节点运行benchmark脚本:

source /home/<your_name>/cann_8.2.rc1/ascend-toolkit/set_env.sh
source /home/<your_name>/cann_8.2.rc1/nnal/atb/set_env.sh

cd /home/<your_name>/vllm/benchmarks/

python benchmark_serving.py \
  --backend vllm \
  --dataset-name random \
  --random-input-len 10 \
  --random-output-len 100 \
  --num-prompts 10 \
  --ignore-eos \
  --model deepseek \
  --tokenizer /home/models/DeepSeek-V3.1-w8a8-rot-mtp \
  --host 141.61.41.163 \
  --port 1025 \
  --endpoint /v1/completions \
  --max-concurrency 4 \
  --request-rate 4

测试结果会显示吞吐量、延迟等关键指标:

五、踩过的坑

问题1: 找不到torch-npu包

使用pip 25.1.1安装时提示找不到匹配的版本:

解决办法: 配置正确的镜像源


pip uninstall torch

pip config set global.trusted-host "download.pytorch.org mirrors.huaweicloud.com mirrors.aliyun.com"

pip config set global.extra-index-url "https://download.pytorch.org/whl/cpu/ https://mirrors.huaweicloud.com/ascend/repos/pypi"

pip install torchvision==0.20.1

pip install torch-npu==2.5.1.post1.dev20250619

问题2: torch和torch-npu依赖冲突

安装vllm-ascend时报错:Cannot install torch-npu==2.5.1.post1 and torch>=2.5.1 because these package versions have conflicting dependencies.

解决办法: 清理环境后重装


pip uninstall torch==2.5.1 torch-npu==2.5.1.post1.dev20250619 -y

pip cache purge

pip config unset global.extra-index-url

pip config set global.extra-index-url "https://download.pytorch.org/whl/cpu/ https://mirrors.huaweicloud.com/ascend/repos/pypi"

pip install torch==2.5.1

pip install torch-npu==2.5.1.post1.dev20250619

# 验证安装

pip show torch torch-npu | grep Version

问题3: NPU显存溢出

启动服务时报错:RuntimeError: NPU out of memory. Tried to allocate 898.00 MiB...

原因: 没有按量化模式加载模型

解决办法: 在vllm serve命令中加上--quantization ascend

问题4: 量化算子不支持float16

报错信息:Tensor scale not implemented for DT_FLOAT16, should be in dtype support list [DT_UINT64,DT_BFLOAT16,DT_INT64,DT_FLOAT,].

原因: aclnnQuantMatmulV4算子不支持float16类型

解决办法: 修改模型config.json文件,把torch_dtypefloat16改成bfloat16

问题5: HCCL通信初始化失败

报错:RuntimeError: createHCCLComm:torch_npu/csrc/distributed/ProcessGroupHCCL.cpp:2166 HCCL function error...

原因: HCCL_IF_IP环境变量配置错误

解决办法: 检查并修正启动脚本中的HCCL_IF_IP,确保和本机IP一致

  • 解决:严格锁死版本。不要直接 pip install vllm,一定要拉取 release 分支的代码进行安装。

总结

PD分离部署对大模型推理性能提升确实有明显效果,但配置过程比较繁琐,需要注意的点也很多。希望这份实战记录能帮大家少踩一些坑。一旦打通了HCCL通信链路,配合vLLM的PD分离架构,昇腾910B在DeepSeek这种大参数模型上的吞吐表现是相当可观的。

如果在部署过程中遇到其他问题,建议先查看官方文档和社区讨论,很多常见问题都有解决方案,注明:昇腾PAE案例库对本文写作亦有帮助。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐