Qwen3.5-397B-A17B#
1 简介#
Qwen3.5-397B-A17B 是一个大规模 Qwen3.5 MoE 模型,结合了多模态能力、长上下文推理、MTP 投机解码和 W8A8 量化部署,用于在昇腾硬件上进行生产级服务。
本文档描述了该模型的主要验证步骤,包括支持特性、前提条件、安装、单节点在线部署、多节点部署、Prefill-Decode (PD) 分离、功能验证、精度与性能评估、性能调优以及常见问题解答。
Qwen3.5-397B-A17B模型首次在vllm-ascend:v0.17.0rc1中支持。请使用v0.17.0rc1或更高版本运行此模型。对于Ascend95DT,该模型从vllm-ascend:v0.23.0rc1开始支持。以下示例使用文档构建系统配置的版本占位符。
2 支持特性#
请参阅支持的特性获取该模型的支持特性矩阵,包括BF16、W8A8量化、分块预填充、自动前缀缓存、推测解码、异步调度、张量并行、专家并行、数据并行、PD分离以及ACLGraph支持。
请参考特性指南获取特性配置详情。
备注
支持矩阵记录了该模型已验证的最大能力。本文档中的启动示例使用了实际验证设置,用于在线服务和性能测试。请根据您的服务工作负载和可用 KV 缓存调整 --max-model-len、--max-num-seqs 和 --max-num-batched-tokens。
3 前提条件#
3.1 模型权重#
Qwen3.5-397B-A17B(BF16版本):需要2个Ascend 950DT(96GB x 8)节点,或2个Atlas 800 A3(64GB x 16)节点,或4个Atlas 800 A2(64GB x 8)节点。下载模型权重。Qwen3.5-397B-A17B-w8a8(量化版本):需要1个Atlas 800 A3(64GB x 16)节点或2个Atlas 800 A2(64GB x 8)节点。下载模型权重。Qwen3.5-397B-A17B-w4a8(量化版本):需要1个Atlas 800 A3(64GB x 16)节点,或2个Atlas 800 A2(64GB x 8)节点。下载模型权重。Qwen3.5-397B-A17B-w8a8-mxfp8(量化版本):需要1个Ascend 950DT(96GB x 8)节点。下载模型权重。Qwen3.5-397B-A17B-w4a4-mxfp4(量化版本):需要1个Ascend 950DT(96GB x 8)节点。下载模型权重。
建议将模型权重下载到跨多个节点的共享目录中,例如 /root/.cache/,以便所有服务节点都能加载相同的路径。
3.2 验证多节点通信(可选)#
如果要在多节点环境中部署模型,请根据验证多节点通信环境验证通信环境。
4 安装#
4.1 Docker 镜像安装#
根据您的机器类型选择镜像,并在您的节点上启动docker镜像,请参阅使用docker。
Qwen3.5-397B-A17B模型首次在vllm-ascend:v0.17.0rc1中支持。请使用v0.17.0rc1或更高版本运行此模型。对于Ascend95DT,该模型从vllm-ascend:v0.23.0rc1开始支持。
在每个节点上启动docker镜像。
export IMAGE=quay.io/ascend/vllm-ascend:v0.23.0-#TODO
export NAME=vllm-ascend
docker run --rm \
--name $NAME \
--net=host \
--shm-size=1g \
--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/davinci_manager \
--device /dev/hisi_hdc \
--device /dev/ummu \
--device /dev/uburma \
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /etc/hccl_rootinfo.json:/etc/hccl_rootinfo.json \
-v /etc/hixlep/:/etc/hixlep/ \
-v /root/.cache:/root/.cache \
-v /usr/local/sbin:/usr/local/sbin \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
-v /usr/lib64:/usr/lib64 \
-itd $IMAGE bash
在每个节点上启动docker镜像。
export IMAGE=quay.io/ascend/vllm-ascend:v0.23.0-a3
export NAME=vllm-ascend
docker run --rm \
--name $NAME \
--net=host \
--shm-size=1g \
--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 \
--device /dev/davinci_manager \
--device /dev/devmm_svm \
--device /dev/hisi_hdc \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /usr/local/Ascend/driver/tools/hccn_tool:/usr/local/Ascend/driver/tools/hccn_tool \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /root/.cache:/root/.cache \
-it $IMAGE bash
在每个节点上启动docker镜像。
export IMAGE=quay.io/ascend/vllm-ascend:v0.23.0
export NAME=vllm-ascend
docker run --rm \
--name $NAME \
--net=host \
--shm-size=1g \
--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/davinci_manager \
--device /dev/devmm_svm \
--device /dev/hisi_hdc \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /usr/local/Ascend/driver/tools/hccn_tool:/usr/local/Ascend/driver/tools/hccn_tool \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /root/.cache:/root/.cache \
-it $IMAGE bash
进入容器后,验证 vLLM 和 vLLM-Ascend 是否可以导入:
python -c "import vllm, vllm_ascend; print('vllm and vllm_ascend are ready')"
如果要部署多节点服务,请在每个节点上设置相同的环境。
4.2 源码安装#
您也可以从源码构建并安装 vllm-ascend。请参考使用 Python 设置。
如果要部署多节点服务,请在每个节点上安装相同版本的 vLLM 和 vLLM-Ascend。
5 在线服务部署#
5.1 单节点在线部署#
单节点部署在同一节点上运行Prefill和Decode。它适用于功能验证、长上下文单集群服务,以及在1个Atlas 800 A3(64GB x 16)节点上的W8A8部署。W8A8版本需要--quantization ascend。
运行以下脚本在1个Ascend 950DT(96GB x 8)上执行在线推理。量化版本(Qwen3.5-397B-A17B-w8a8-mxfp8和Qwen3.5-397B-A17B-w4a4-mxfp4)可以部署在单个Ascend 950DT节点上。
#!/bin/sh
# Load model from ModelScope to speed up download.
export VLLM_USE_MODELSCOPE=True
# Reduce memory fragmentation and avoid out-of-memory errors.
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_OP_EXPANSION_MODE="AIV"
export HCCL_BUFFSIZE=400
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=100
export TASK_QUEUE_ENABLE=1
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1
export VLLM_ASCEND_ENABLE_PREFETCH_MLP=1
export HCCL_INTRA_PCIE_ENABLE=1
export HCCL_INTRA_ROCE_ENABLE=0
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1
vllm serve Eco-Tech/Qwen3.5-397B-A17B-w4a4-mxfp4 \
--host 0.0.0.0 \
--port 8000 \
--distributed-executor-backend mp \
--data-parallel-size 1 \
--tensor-parallel-size 8 \
--enable-expert-parallel \
--seed 1024 \
--quantization ascend \
--served-model-name qwen3.5 \
--max-num-seqs 128 \
--max-model-len 133000 \
--max-num-batched-tokens 8192 \
--trust-remote-code \
--enable-prefix-caching \
--gpu-memory-utilization 0.95 \
--async-scheduling \
--speculative-config '{"method": "qwen3_5_mtp", "num_speculative_tokens": 3}' \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
--additional-config '{"enable_cpu_binding":true}'
运行以下脚本以在1个Atlas 800 A3(64GB x 16)上执行在线128K推理。
#!/bin/sh
# Load model from ModelScope to speed up download.
export VLLM_USE_MODELSCOPE=True
# Reduce memory fragmentation and avoid out-of-memory errors.
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_OP_EXPANSION_MODE="AIV"
export HCCL_BUFFSIZE=1024
export OMP_NUM_THREADS=1
export TASK_QUEUE_ENABLE=1
echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
sysctl -w vm.swappiness=0
sysctl -w kernel.numa_balancing=0
sysctl kernel.sched_migration_cost_ns=50000
export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
vllm serve Eco-Tech/Qwen3.5-397B-A17B-w8a8-mtp \
--host 0.0.0.0 \
--port 8000 \
--data-parallel-size 1 \
--tensor-parallel-size 16 \
--enable-expert-parallel \
--seed 1024 \
--quantization ascend \
--served-model-name qwen3.5 \
--max-num-seqs 128 \
--max-model-len 133000 \
--max-num-batched-tokens 16384 \
--trust-remote-code \
--gpu-memory-utilization 0.90 \
--enable-prefix-caching \
--speculative-config '{"method": "qwen3_5_mtp", "num_speculative_tokens": 3}' \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
--additional-config '{"enable_cpu_binding":true}'
对于W8A8部署,需要2个Atlas 800 A2(64GB x 8)节点。请参阅第5.2节了解多节点MP部署。
常见问题提示:如果服务启动失败、HBM 不足或请求未按预期调度,请先参考常见问题解答,然后查看第 10 节中的模型特定 FAQ。
关键参数:
--data-parallel-size 1和--tensor-parallel-size 16为一个 16-NPU A3 节点设置 DP 和 TP。--enable-expert-parallel为 MoE 层启用专家并行。不要在同一个 MoE 层中混合使用 MoE 张量并行和专家并行。--max-model-len是单个请求的最大输入加输出长度。仅在拥有足够 KV 缓存时增加此值。--max-num-seqs是每个 DP 组调度的最大活动请求数。对于性能测试,请将--max-num-seqs * --data-parallel-size设置为大于或等于测试并发数。--max-num-batched-tokens是一个调度步骤中处理的最大 token 数。较大的值可以提高预填充效率,但会消耗更多激活内存。--gpu-memory-utilization控制 vLLM 可用于计算 KV 缓存容量的 HBM 比例。较高的值会增加 KV 缓存大小,但如果运行时内存高于 profile 运行,则可能触发 OOM。--enable-prefix-caching启用前缀缓存。对于 Qwen3.5,当混合 KV 缓存管理器将块大小调整为较大值时,短前缀可能不会被缓存。--quantization ascend启用 W8A8 模型的昇腾量化。部署 BF16 模型时请移除该选项。--speculative-config启用 Qwen3.5 MTP 推测解码。如果工作负载对首 token 延迟敏感,或 MTP 在您的环境中不稳定,请减少num_speculative_tokens或移除该选项。--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}'启用完整解码 ACLGraph 重放以减少调度开销。--additional-config启用Ascend特定优化。enable_cpu_binding启用Ascend原生CPU绑定。
5.2 基于 MP 的多节点部署(推荐)#
多节点MP部署在节点间使用vLLM数据并行,在节点内使用张量并行。推荐用于2个Atlas 800 A2(64GB x 8)节点上的W8A8模型。
假设您有 2 个 Atlas 800 A2 节点,并希望跨节点部署 Qwen3.5-397B-A17B-w8a8-mtp。请将 nic_name、local_ip 和 node0_ip 替换为您环境中的实际网络接口和 IP 地址。
在节点 0 上运行以下脚本。
#!/bin/sh
export VLLM_USE_MODELSCOPE=True
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
# Get these values through ifconfig.
# nic_name is the network interface name corresponding to local_ip.
nic_name="xxxx"
local_ip="xxxx"
export HCCL_IF_IP=$local_ip
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=1
export HCCL_BUFFSIZE=1024
export TASK_QUEUE_ENABLE=1
vllm serve Eco-Tech/Qwen3.5-397B-A17B-w8a8-mtp \
--host 0.0.0.0 \
--port 8000 \
--data-parallel-size 2 \
--api-server-count 2 \
--data-parallel-size-local 1 \
--data-parallel-address $local_ip \
--data-parallel-rpc-port 13389 \
--seed 1024 \
--served-model-name qwen3.5 \
--tensor-parallel-size 8 \
--enable-expert-parallel \
--max-num-seqs 16 \
--max-model-len 32768 \
--max-num-batched-tokens 4096 \
--trust-remote-code \
--gpu-memory-utilization 0.9 \
--no-enable-prefix-caching \
--quantization ascend \
--speculative-config '{"method": "qwen3_5_mtp", "num_speculative_tokens": 3}' \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
--additional-config '{"enable_cpu_binding":true, "multistream_overlap_shared_expert": true}'
常见问题提示:如果节点 1 无法加入服务或 HCCL 初始化超时,请参考验证多节点通信环境和常见问题。确保各节点的网络接口名称、IP 地址和 RPC 端口一致。
在节点 1 上运行以下脚本。
#!/bin/sh
export VLLM_USE_MODELSCOPE=True
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
# Get these values through ifconfig.
# nic_name is the network interface name corresponding to local_ip.
nic_name="xxxx"
local_ip="xxxx"
# The value of node0_ip must be consistent with local_ip on node 0.
node0_ip="xxxx"
export HCCL_IF_IP=$local_ip
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=1
export HCCL_BUFFSIZE=1024
export TASK_QUEUE_ENABLE=1
vllm serve Eco-Tech/Qwen3.5-397B-A17B-w8a8-mtp \
--host 0.0.0.0 \
--port 8000 \
--headless \
--data-parallel-size 2 \
--data-parallel-size-local 1 \
--data-parallel-start-rank 1 \
--data-parallel-address $node0_ip \
--data-parallel-rpc-port 13389 \
--seed 1024 \
--tensor-parallel-size 8 \
--served-model-name qwen3.5 \
--max-num-seqs 16 \
--max-model-len 32768 \
--max-num-batched-tokens 4096 \
--enable-expert-parallel \
--trust-remote-code \
--gpu-memory-utilization 0.9 \
--no-enable-prefix-caching \
--quantization ascend \
--speculative-config '{"method": "qwen3_5_mtp", "num_speculative_tokens": 3}' \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
--additional-config '{"enable_cpu_binding":true, "multistream_overlap_shared_expert": true}'
常见问题提示:如果无头节点立即退出,请检查节点 0 是否已在运行、--data-parallel-address 是否指向节点 0,以及每个节点的 --data-parallel-start-rank 是否唯一。
如果服务启动成功,节点 0 上将显示以下信息:
INFO: Started server process [44610]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Started server process [44611]
INFO: Waiting for application startup.
INFO: Application startup complete.
MP 部署的关键参数:
--data-parallel-size是所有节点的全局 DP 大小。示例中使用了 2 个 DP rank。--data-parallel-size-local是当前节点上的 DP rank 数量。示例中每个 A2 节点有 1 个本地 DP rank。--data-parallel-start-rank是当前节点上的起始 DP rank。节点 0 默认从 0 开始,节点 1 从 1 开始。--data-parallel-address必须指向主 DP 节点。在节点 0 上使用节点 0 的local_ip,在其他节点上使用node0_ip。--data-parallel-rpc-port是 DP RPC 端口。在所有节点上使用相同的值,并确保端口可用。--api-server-count控制主节点上启动的 API 服务器进程数量。--headless启动一个不暴露 API 服务器的工作节点。在非主节点上使用。--tensor-parallel-size 8将一个 TP 组映射到每个 A2 节点上的 8 个 NPU。HCCL_IF_IP、GLOO_SOCKET_IFNAME、TP_SOCKET_IFNAME和HCCL_SOCKET_IFNAME将 HCCL、Gloo 和 TP 通信绑定到所选网络。multistream_overlap_shared_expert重叠共享专家计算,以在 MoE 工作负载上获得更好的吞吐量。
5.3 基于 Ray 的多节点部署#
对于基于 Ray 的分布式部署,请参考 Ray 分布式 (Qwen/Qwen3-235B-A22B)。相同的模型权重、通信验证和参数调优原则适用于 Qwen3.5-397B-A17B。
常见问题提示:如果 Ray 工作节点无法相互发现,请先检查 Ray 集群状态,然后验证 MP 部署中使用的相同 HCCL 和网络接口设置。
5.4 预填充-解码分离(A3)#
PD 分离将预填充和解码划分为不同的服务组。预填充节点处理大块提示,解码节点负责 token 生成,代理在两者之间转发请求。此模式适用于需要分别调整预填充和解码资源比例的生产服务场景。
我们推荐使用 Mooncake 进行部署。有关通用 PD 分离工作流程,请参考 Mooncake。
对于Atlas 800 A3(64GB x 16),我们建议使用2个节点部署1P1D以运行Qwen3.5-397B-A17B-w8a8-mtp:
1个Prefill节点:1个Atlas 800 A3(64GB x 16)。
1个解码节点:1个Atlas 800 A3(64GB x 16)。
在相应节点上部署run_p.sh和run_d.sh,并在预填充主节点上部署代理脚本以转发请求。
5.4.1 预填充节点#
在预填充节点上创建 run_p.sh。
#!/bin/bash
unset ftp_proxy
unset https_proxy
unset http_proxy
# Get these values through ifconfig.
# nic_name is the network interface name corresponding to local_ip.
nic_name="xxxx"
local_ip="xxxx"
export VLLM_ENGINE_READY_TIMEOUT_S=30000
export VLLM_MOONCAKE_ABORT_REQUEST_TIMEOUT=480
export IP_ADDRESS=$local_ip
export NETWORK_CARD_NAME=$nic_name
export HCCL_IF_IP=$IP_ADDRESS
export GLOO_SOCKET_IFNAME=$NETWORK_CARD_NAME
export TP_SOCKET_IFNAME=$NETWORK_CARD_NAME
export HCCL_SOCKET_IFNAME=$NETWORK_CARD_NAME
export VLLM_USE_V1=1
export HCCL_BUFFSIZE=1536
export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:$LD_LIBRARY_PATH
export PYTORCH_NPU_ALLOC_CONF="expandable_segments:True"
export VLLM_TORCH_PROFILER_WITH_STACK=0
export TASK_QUEUE_ENABLE=1
export HCCL_OP_EXPANSION_MODE="AIV"
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
vllm serve Eco-Tech/Qwen3.5-397B-A17B-w8a8-mtp \
--host ${IP_ADDRESS} \
--port 30060 \
--no-enable-prefix-caching \
--enable-expert-parallel \
--data-parallel-size 1 \
--data-parallel-size-local 1 \
--api-server-count 1 \
--data-parallel-address ${IP_ADDRESS} \
--max-num-seqs 64 \
--data-parallel-rpc-port 6884 \
--tensor-parallel-size 16 \
--seed 1024 \
--distributed-executor-backend mp \
--served-model-name qwen3.5 \
--max-model-len 16384 \
--max-num-batched-tokens 4096 \
--trust-remote-code \
--quantization ascend \
--no-disable-hybrid-kv-cache-manager \
--speculative-config '{"method": "qwen3_5_mtp", "num_speculative_tokens": 3, "enforce_eager": true}' \
--additional-config '{"enable_cpu_binding": true}' \
--gpu-memory-utilization 0.9 \
--enforce-eager \
--kv-transfer-config \
'{"kv_connector": "MooncakeLayerwiseConnector",
"kv_role": "kv_producer",
"kv_port": "23010",
"kv_connector_extra_config": {
"prefill": {
"dp_size": 1,
"tp_size": 16
},
"decode": {
"dp_size": 1,
"tp_size": 16
}
}
}'
常见问题提示:如果预填充服务长时间未就绪,请检查模型路径是否共享、ASCEND_RT_VISIBLE_DEVICES 是否包含全部 16 个 NPU,以及 Mooncake kv_port 是否可用。
5.4.2 解码节点#
在解码节点上创建run_d.sh。
#!/bin/bash
unset ftp_proxy
unset https_proxy
unset http_proxy
# Get these values through ifconfig.
# nic_name is the network interface name corresponding to local_ip.
nic_name="xxxx"
local_ip="xxxx"
export VLLM_ENGINE_READY_TIMEOUT_S=30000
export VLLM_MOONCAKE_ABORT_REQUEST_TIMEOUT=480
export IP_ADDRESS=$local_ip
export NETWORK_CARD_NAME=$nic_name
export HCCL_IF_IP=$IP_ADDRESS
export GLOO_SOCKET_IFNAME=$NETWORK_CARD_NAME
export TP_SOCKET_IFNAME=$NETWORK_CARD_NAME
export HCCL_SOCKET_IFNAME=$NETWORK_CARD_NAME
export VLLM_USE_V1=1
export HCCL_BUFFSIZE=1536
export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:$LD_LIBRARY_PATH
export PYTORCH_NPU_ALLOC_CONF="expandable_segments:True"
export VLLM_TORCH_PROFILER_WITH_STACK=0
export TASK_QUEUE_ENABLE=1
export HCCL_OP_EXPANSION_MODE="AIV"
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
vllm serve Eco-Tech/Qwen3.5-397B-A17B-w8a8-mtp \
--host ${IP_ADDRESS} \
--port 30050 \
--no-enable-prefix-caching \
--enable-expert-parallel \
--data-parallel-size 1 \
--data-parallel-size-local 1 \
--api-server-count 1 \
--data-parallel-address ${IP_ADDRESS} \
--max-num-seqs 32 \
--data-parallel-rpc-port 6884 \
--tensor-parallel-size 16 \
--seed 1024 \
--distributed-executor-backend mp \
--served-model-name qwen3.5 \
--max-model-len 16384 \
--max-num-batched-tokens 128 \
--trust-remote-code \
--quantization ascend \
--no-disable-hybrid-kv-cache-manager \
--speculative-config '{"method": "qwen3_5_mtp", "num_speculative_tokens": 3}' \
--additional-config '{"recompute_scheduler_enable": true, "enable_cpu_binding": true}' \
--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
--gpu-memory-utilization 0.96 \
--kv-transfer-config \
'{"kv_connector": "MooncakeLayerwiseConnector",
"kv_buffer_device": "npu",
"kv_role": "kv_consumer",
"kv_port": "36010",
"kv_connector_extra_config": {
"prefill": {
"dp_size": 1,
"tp_size": 16
},
"decode": {
"dp_size": 1,
"tp_size": 16
}
}
}'
常见问题提示:如果解码节点初始化失败,请检查--tensor-parallel-size是否为16,--data-parallel-size-local是否与全局解码DP大小(1)匹配,以及kv_connector_extra_config.decode.dp_size是否与全局解码DP大小匹配。
PD分离的关键参数:
--distributed-executor-backend mp在每个节点上使用多进程处理本地工作节点。预填充使用
--data-parallel-size 1、--data-parallel-size-local 1和--tensor-parallel-size 16。这将创建1个DP组,每组TP16。解码使用
--data-parallel-size 1、--data-parallel-size-local 1和--tensor-parallel-size 16。这将创建1个本地DP组,每组TP16。--data-parallel-address和--data-parallel-rpc-port定义DP控制平面。--max-num-batched-tokens在预填充节点上较大,在解码节点上较小,因为预填充是提示词令牌密集型,而解码对延迟敏感。recompute_scheduler_enable在解码KV缓存不足时将请求发送回预填充端重新计算KV缓存。仅在PD模式下在解码节点上启用此功能。--kv-transfer-config设置Mooncake连接器。kv_role在prefill上为kv_producer,在decode上为kv_consumer。kv_connector_extra_config.prefill.dp_size/tp_size和decode.dp_size/tp_size必须与实际全局DP和TP布局匹配。--no-enable-prefix-caching禁用前缀缓存。对于PD分离,D节点前缀缓存的已知问题在#7944中跟踪。VLLM_MOONCAKE_ABORT_REQUEST_TIMEOUT是自动释放请求的prefiller KV缓存的超时时间(秒)。建议在解码节点上使用
--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}'以减少解码调度开销。
5.5 预填充-解码分离(Ascend 950DT系列)#
对于Ascend 950DT(96GB x 8),我们建议使用2个节点部署1P1D以运行Qwen3.5-397B-A17B-w4a4-mxfp4:
1个预填充节点:1个Ascend 950DT(96GB x 8)。以DP=1、TP=8运行独立服务。
1个解码节点:1个Ascend 950DT(96GB x 8)。形成全局DP=1组,包含1个本地DP rank(TP=8)。
预填充服务通过Mooncake p2p连接器将KV缓存推送到解码节点。
在相应节点上部署run_p.sh和run_d.sh,并在预填充主节点上部署代理脚本以转发请求。
5.5.1 预填充节点#
在预填充节点上创建 run_p.sh。
#!/bin/bash
unset ftp_proxy
unset https_proxy
unset http_proxy
source /root/.bashrc
export PROMETHEUS_MULTIPROC_DIR=/dev/shm/vllm_metrics && mkdir -p $PROMETHEUS_MULTIPROC_DIR
export HCCL_DFS_CONFIG="task_exception:off,inconsistent_check:off"
# Get these values through ifconfig.
# nic_name is the network interface name corresponding to local_ip.
nic_name="xxx"
local_ip="xxx"
export HCCL_IF_IP=$local_ip
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export HCCL_ALGO=level0:fullmesh
export VLLM_RPC_TIMEOUT=3600000
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=30000
export HCCL_EXEC_TIMEOUT=204
export HCCL_CONNECT_TIMEOUT=180
export HCCL_BUFFSIZE=300
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=10
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export TASK_QUEUE_ENABLE=1
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
export DYNAMIC_EPLB="true"
vllm serve Eco-Tech/Qwen3.5-397B-A17B-w4a4-mxfp4 \
--host 0.0.0.0 \
--port 30060 \
--no-enable-prefix-caching \
--enable-expert-parallel \
--data-parallel-size 1 \
--data-parallel-size-local 1 \
--data-parallel-address $local_ip \
--data-parallel-rpc-port 6884 \
--tensor-parallel-size 8 \
--seed 1024 \
--distributed-executor-backend mp \
--served-model-name qwen3.5 \
--max-model-len 133000 \
--max-num-batched-tokens 8192 \
--max-num-seqs 64 \
--trust-remote-code \
--gpu-memory-utilization 0.95 \
--quantization ascend \
--async-scheduling \
--enforce-eager \
--speculative-config '{"num_speculative_tokens": 1, "method": "qwen3_5_mtp", "enforce_eager": true}' \
--additional-config '{"enable_cpu_binding": true, "multistream_overlap_shared_expert": true, "recompute_scheduler_enable": true}' \
--kv-transfer-config \
'{"kv_connector": "MooncakeConnector",
"kv_role": "kv_producer",
"kv_port": "30100",
"engine_id": "1",
"kv_connector_module_path": "vllm_ascend.distributed.kv_transfer.kv_p2p.mooncake_connector",
"kv_connector_extra_config": {
"prefill": {
"dp_size": 1,
"tp_size": 8
},
"decode": {
"dp_size": 1,
"tp_size": 8
},
"ascend_local_comm_res_path": "/etc/hixlep"
}
}'
常见问题提示:如果预填充服务长时间未就绪,请检查ASCEND_RT_VISIBLE_DEVICES是否包含全部8个NPU,Mooncake kv_port是否可用,以及ascend_local_comm_res_path是否指向可写的共享路径。
5.5.2 解码节点#
在解码节点上创建run_d.sh。
#!/bin/bash
unset ftp_proxy
unset https_proxy
unset http_proxy
source /root/.bashrc
export PROMETHEUS_MULTIPROC_DIR=/dev/shm/vllm_metrics && mkdir -p $PROMETHEUS_MULTIPROC_DIR
export HCCL_DFS_CONFIG="task_exception:off,inconsistent_check:off"
# Get these values through ifconfig.
# nic_name is the network interface name corresponding to local_ip.
nic_name="xxx"
local_ip="xxx"
export HCCL_IF_IP=$local_ip
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export HCCL_ALGO=level0:fullmesh
export VLLM_RPC_TIMEOUT=3600000
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=30000
export HCCL_EXEC_TIMEOUT=200
export HCCL_CONNECT_TIMEOUT=1800
export HCCL_BUFFSIZE=1200
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=10
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export TASK_QUEUE_ENABLE=1
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
export DYNAMIC_EPLB="true"
vllm serve Eco-Tech/Qwen3.5-397B-A17B-w4a4-mxfp4 \
--host 0.0.0.0 \
--port 30050 \
--no-enable-prefix-caching \
--enable-expert-parallel \
--data-parallel-size 1 \
--data-parallel-size-local 1 \
--api-server-count 1 \
--data-parallel-address $local_ip \
--data-parallel-rpc-port 6884 \
--tensor-parallel-size 8 \
--seed 1024 \
--distributed-executor-backend mp \
--served-model-name qwen3.5 \
--max-model-len 133000 \
--max-num-batched-tokens 240 \
--max-num-seqs 64 \
--trust-remote-code \
--gpu-memory-utilization 0.95 \
--quantization ascend \
--async-scheduling \
--speculative-config '{"num_speculative_tokens": 3, "method": "qwen3_5_mtp"}' \
--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
--additional-config '{"enable_cpu_binding": true, "multistream_overlap_shared_expert": true, "recompute_scheduler_enable": true, "ascend_compilation_config": {"enable_npugraph_ex": false}}' \
--kv-transfer-config \
'{"kv_connector": "MooncakeConnector",
"kv_role": "kv_consumer",
"kv_port": "30300",
"engine_id": "3",
"kv_connector_module_path": "vllm_ascend.distributed.kv_transfer.kv_p2p.mooncake_connector",
"kv_connector_extra_config": {
"prefill": {
"dp_size": 1,
"tp_size": 8
},
"decode": {
"dp_size": 1,
"tp_size": 8
},
"ascend_local_comm_res_path": "/etc/hixlep"
}
}'
常见问题提示:如果解码节点0初始化失败,请检查--data-parallel-start-rank是否为0,--tensor-parallel-size是否为8,以及kv_connector_extra_config.decode.dp_size是否与全局解码DP大小(1)匹配。
5.6 请求转发#
在与prefiller服务实例相同的节点上运行代理服务器。您可以在仓库示例中获取代理程序:load_balance_proxy_server_example.py。
对于A3 PD分离(1P1D),代理将请求转发到1个预填充节点和1个解码节点。使用分层代理脚本。
unset ftp_proxy
unset https_proxy
unset http_proxy
python3 load_balance_proxy_server_example.py \
--prefiller-hosts 141.xx.xx.1 \
--prefiller-ports 30060 \
--decoder-hosts 141.xx.xx.2 \
--decoder-ports 30050 \
--host 141.xx.xx.1 \
--port 8010
例如:
cd vllm-ascend/examples/disaggregated_prefill_v1/
bash proxy.sh
对于Ascend 950DT PD分离(1P1D),代理将请求转发到1个prefill节点和1个decode节点。请使用分层代理脚本。
unset ftp_proxy
unset https_proxy
unset http_proxy
python3 load_balance_proxy_layerwise_server_example.py \
--prefiller-hosts 141.xx.xx.1 \
--prefiller-ports 30060 \
--decoder-hosts 141.xx.xx.2 \
--decoder-ports 30050 \
--host 141.xx.xx.1 \
--port 8010
常见问题提示:如果请求到达代理但未返回输出,请检查代理主机列表是否包含所有健康的prefill和解码端点,并验证第6节中的服务验证请求是否通过代理端口成功。
6 功能验证#
服务器启动后,发送请求以验证基本模型功能。对于单节点和MP部署,使用节点0上的API端点。对于PD分离,使用代理端点。
curl http://<server_ip>:<port>/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5",
"prompt": "The future of AI is",
"max_tokens": 50,
"temperature": 0
}'
预期结果:HTTP状态为200,JSON响应包含一个带有生成文本的choices字段。
7 精度评估#
以下是两种精度评估方法。
7.1 使用AISBench#
详情请参考使用AISBench。
执行后,您可以获得结果。以下
Qwen3.5-397B-A17B-w8a8在vllm-ascend:v0.17.0rc1上的结果仅供参考。
数据集 |
版本 |
指标 |
模式 |
vllm-api-general-chat |
|---|---|---|---|---|
gsm8k |
- |
精度 |
生成 |
96.74 |
7.2 使用Language Model Evaluation Harness#
安装和使用详情请参考使用lm_eval。使用在线服务时,将base_url设置为第5节中启动的端点。
lm_eval \
--model local-completions \
--model_args model=qwen3.5,base_url=http://127.0.0.1:8000/v1/completions,tokenized_requests=False,trust_remote_code=True \
--tasks gsm8k \
--output_path ./
8 性能评估#
8.1 使用AISBench#
详情请参考使用AISBench进行性能评估。
8.2 使用vLLM Benchmark#
以Qwen3.5-397B-A17B-w8a8的性能评估为例。更多详情请参考vLLM benchmark。
有三个vllm bench子命令:
latency:对单批请求的延迟进行基准测试。serve:对在线服务吞吐量进行基准测试。throughput:对离线推理吞吐量进行基准测试。
以serve为例:
export VLLM_USE_MODELSCOPE=True
vllm bench serve \
--model Eco-Tech/Qwen3.5-397B-A17B-w8a8-mtp \
--served-model-name qwen3.5 \
--dataset-name random \
--random-input 200 \
--num-prompts 200 \
--request-rate 1 \
--save-result \
--result-dir ./
几分钟后,您可以获得性能评估结果。
9 性能调优#
9.1 推荐配置#
以下配置在特定测试环境中验证,仅供参考。最佳配置取决于硬件类型、最大输入/输出长度、请求并发数、前缀缓存命中率、量化方式以及prefill/decode比例。根据实际工作负载调整第9.2节中的参数。
场景 |
部署模式 |
NPU总数 |
权重版本 |
关键考虑因素 |
|---|---|---|---|---|
长上下文 |
单节点在线服务 |
16个A3 NPU |
W8A8 MTP |
使用更大的 |
长上下文 |
单节点在线服务 |
8个Ascend 950DT NPU |
W4A4 MXFP4 MTP |
使用TP=8并为133K上下文预留足够的KV缓存。如果发生OOM,请降低 |
高吞吐 |
多节点 MP |
16 个 A2 NPU |
W8A8 MTP |
通过 DP 提高并发,并调整 |
低延迟 |
1P1D PD 分离 |
48 个 A3 NPU |
W8A8 MTP |
使用独立的预填充和解码 DP/TP 布局,并在解码节点上启用全解码 ACLGraph。 |
低延迟 |
1P1D PD 分离 |
16个Ascend 950DT NPU |
W4A4 MXFP4 MTP |
使用一个8-NPU prefill节点和一个8-NPU decode节点。在decode节点上启用完整decode ACLGraph。 |
场景 |
节点角色 |
NPU |
TP |
DP |
最大序列数 |
最大模型长度 |
最大批量 Token 数 |
MTP Token |
前缀缓存 |
主要优化 |
|---|---|---|---|---|---|---|---|---|---|---|
长上下文 |
单节点 |
16 |
16 |
1 |
128 |
133000 |
16384 |
3 |
开启 |
FullGraph, FlashComm1, Fused MC2, CPU 绑定 |
长上下文 |
单个Ascend 950DT节点 |
8 |
8 |
1 |
128 |
133000 |
8192 |
3 |
开启 |
完整decode ACLGraph、FlashComm1、共享专家重叠、CPU绑定、异步调度 |
高吞吐 |
MP 节点 |
每节点 8 个 |
8 |
每节点 1 个,全局 2 个 |
每 DP 16 个 |
32768 |
4096 |
3 |
关闭 |
FullGraph, 共享专家重叠, CPU 绑定 |
低延迟 |
预填充节点 |
16 |
2 |
8 |
64 |
16384 |
4096 |
3 |
关闭 |
重计算调度器, Fused MC2, CPU 绑定 |
低延迟 |
解码节点 |
每节点 16 个 |
2 |
每节点 8 个,全局 16 个 |
32 |
16384 |
128 |
3 |
关闭 |
FullGraph, 重计算调度器, Fused MC2, CPU 绑定 |
低延迟 |
Ascend 950DT prefill节点 |
8 |
8 |
1 |
64 |
133000 |
8192 |
1 |
关闭 |
重计算调度器、共享专家重叠、CPU绑定、异步调度 |
低延迟 |
Ascend 950DT decode节点 |
8 |
8 |
1 |
64 |
133000 |
240 |
3 |
关闭 |
完整decode ACLGraph、重计算调度器、共享专家重叠、CPU绑定、异步调度 |
9.2 调优指南#
通用调优方法请参考公开性能调优文档,功能说明请参考特性矩阵。
推荐调优顺序:
首先设置部署拓扑。验证时使用单节点部署,简单的多节点服务使用 MP 部署,当预填充和解码需要不同资源比例时使用 PD 分离。
使用
--max-model-len选择最大上下文长度。长上下文会增加 KV 缓存使用量,因此若发生 OOM,请降低--max-num-seqs或--gpu-memory-utilization。调整
--max-num-batched-tokens。较大的值通常能提高预填充吞吐,但会增加激活内存。解码密集型工作负载通常需要较小的值。根据服务并发度调整
--max-num-seqs。超过此值的请求将在队列中等待,等待时间计入 TTFT 和 TPOT。调整
--gpu-memory-utilization。增大该值可提供更多 KV 缓存,但需为运行时内存波动和专家不平衡预留空间。调整
--speculative-config。MTP 可提高解码吞吐,但最佳num_speculative_tokens取决于接受率和工作负载。调整 ACLGraph 捕获。解码推荐使用
FULL_DECODE_ONLY。如果手动设置cudagraph_capture_sizes,请包含常见的解码批量大小。使用 FlashComm1 时,捕获大小应为 TP 大小的倍数。
9.3 模型特定优化#
优化项 |
启用方式 |
收益 |
备注 |
|---|---|---|---|
RoPE优化 |
默认启用 |
跨层复用位置编码计算,减少解码开销。 |
无需额外配置。 |
AddRMSNormQuant 融合 |
默认启用 |
融合归一化和量化操作,减少内存访问。 |
适用于量化路径。 |
类零消除 |
默认启用 |
移除注意力中不必要的类零张量操作。 |
无需额外配置。 |
Qwen3.5 MTP 推测解码 |
|
在接受率良好时提高解码吞吐。 |
如果延迟或稳定性下降,请减少推测 token 数量。 |
全解码 ACLGraph |
|
减少算子分发开销,稳定解码性能。 |
推荐用于解码密集型服务。 |
FlashComm1 |
|
在大 TP 和高并发场景下减少通信开销。 |
可能对低并发工作负载无帮助。 |
Fused MC2 |
|
启用 MoE 融合算子,提高 MoE 预填充/解码效率。 |
如果在多 DP 大 token 场景下精度或性能下降,请禁用它并对比。 |
共享专家重叠 |
|
在 MoE 工作负载中重叠共享专家计算。 |
推荐用于 MP 吞吐场景。 |
重计算调度器 |
|
在 PD 模式下,当解码 KV 缓存不足时,通过预填充重新计算 KV。 |
仅在 |
CPU 绑定 |
|
在ARM服务器上改善CPU亲和性并减少调度抖动。 |
在许多配置中默认启用,但显式设置可保持配置清晰。 |
10 常见问题解答#
关于常见环境、安装和通用参数问题,请参考常见问题解答。本节仅涵盖Qwen3.5-397B-A17B的模型特定问题。
Q1:为什么服务在启动时或接受请求后不久报告OOM?#
现象: 服务在性能分析运行期间失败,或者成功启动但在真实流量到达时报告OOM。
原因: Qwen3.5-397B-A17B具有高权重和KV缓存内存需求。较大的--max-model-len、--max-num-seqs、--max-num-batched-tokens或较高的--gpu-memory-utilization可能导致HBM余量不足。运行时专家负载不均衡也可能使实际推理使用的内存超过性能分析运行。
解决方案: 尽可能使用带有--quantization ascend的W8A8模型,降低--max-model-len、--max-num-seqs、--max-num-batched-tokens,或减少--gpu-memory-utilization。保持PYTORCH_NPU_ALLOC_CONF=expandable_segments:True。对于BF16或更大上下文,使用所需数量的A2/A3节点。
Q2:为什么多节点MP部署在初始化期间挂起?#
现象: 一个节点等待其他rank,HCCL初始化超时,或无头节点退出。
原因: 各节点间的网络接口名称、IP地址、DP rank或RPC端口不一致。
解决方案: 首先验证多节点通信。确保HCCL_IF_IP、GLOO_SOCKET_IFNAME、TP_SOCKET_IFNAME和HCCL_SOCKET_IFNAME与所选NIC匹配。确保所有节点使用相同的--data-parallel-rpc-port,非主节点使用--headless,并且--data-parallel-start-rank不重叠。
Q3:为什么在PD分离示例中禁用了前缀缓存?#
现象: 在解码节点上启用前缀缓存时,PD分离可能表现出异常行为。
原因: D节点前缀缓存问题是一个已知限制,跟踪于#7944。
解决方案: 在限制解决之前,对PD分离使用--no-enable-prefix-caching。对于非PD单节点服务,仅当工作负载具有重复前缀且缓存命中率有意义时,才启用前缀缓存。
Q4:为什么启用FlashComm1或Fused MC2后性能下降?#
现象: 启用通信或MoE融合优化后,吞吐量下降,延迟增加,或MoE负载变得不稳定。
原因: 这些优化依赖于工作负载。FlashComm1在高并发TP场景中最有用。Fused MC2可能不适用于某些多DP大token场景,其中填充的token会使某些专家过载。
解决方案: 与禁用enable_flashcomm1并将enable_fused_mc2设置为0的情况进行比较。如果启用了FlashComm1并且您调整了cudagraph_capture_sizes,请使用TP大小的倍数。根据实际并发和提示长度分布保留更好的设置。
Q5:如何为此模型调整MTP推测解码?#
现象: MTP在某些工作负载中提高吞吐量,但在其他工作负载中可能增加首token延迟或提供有限的收益。
原因: 收益取决于推测token接受率、请求长度和解码并发度。
解决方案: 从本文档所示的num_speculative_tokens设置为3开始。如果服务对延迟敏感或接受率较低,则减小该值或移除--speculative-config,并比较TTFT、TPOT和吞吐量。