跳转至

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支持。

请参阅功能指南获取功能配置详情。

:::{note} 支持矩阵记录了该模型的最大已验证能力。本文档中的启动示例使用实际验证设置进行在线服务和性能测试。请根据您的服务工作负载和可用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)节点 ModelScope
Qwen3.5-397B-A17B-w8a8(量化版本) 1 个 Atlas 800 A3(64GB x 16)节点或 2 个 Atlas 800 A2(64GB x 8)节点 ModelScope
Qwen3.5-397B-A17B-w4a8(量化版本) 1 个 Atlas 800 A3(64GB x 16)节点或 2 个 Atlas 800 A2(64GB x 8)节点 ModelScope
Qwen3.5-397B-A17B-w8a8-mxfp8(量化版本) 1 个 Ascend 950DT系列产品(96GB x 8)节点 ModelScope
Qwen3.5-397B-A17B-w4a4-mxfp4(量化版本) 1 个 Ascend 950DT系列产品(96GB x 8)节点 ModelScope

建议将模型权重下载到多节点共享的目录中,例如 /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-a5
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 个 Ascend 950DT系列产品(96G x 8)上执行在线推理。量化版本(Qwen3.5-397B-A17B-w8a8-mxfp8 和 Qwen3.5-397B-A17B-w4a4-mxfp4)可部署在单个 Ascend 950DT系列产品节点上,需要 --quantization ascend。

#!/bin/sh

# Load model from ModelScope to speed up download.
export VLLM_USE_MODELSCOPE=True
export HCCL_BUFFSIZE=400
export HCCL_INTRA_ROCE_ENABLE=0
export HCCL_OP_EXPANSION_MODE="AIV"
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export VLLM_ASCEND_ENABLE_PREFETCH_MLP=1

# Reduce memory fragmentation and avoid out-of-memory errors.

# Ensure the model path matches the directory recorded during download
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推理,并在1个Atlas 800 A3(64GB x 16)节点上进行W8A8部署。W8A8版本需要--quantization ascend。

#!/bin/sh

# Load model from ModelScope to speed up download.
export VLLM_USE_MODELSCOPE=True
export HCCL_BUFFSIZE=1024
export HCCL_OP_EXPANSION_MODE="AIV"
export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True

# Reduce memory fragmentation and avoid out-of-memory errors.

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

# Ensure the model path matches the directory recorded during download
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, "enforce_eager": true}' \
  --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
  --additional-config '{"enable_cpu_binding":true, "enable_fused_mc2":1}'

对于W8A8部署,需要2个Atlas 800 A2 (64G x 8)节点。多节点MP部署请参考第5.2节。

常见问题提示:如果服务启动失败、HBM 不足或请求未按预期调度,请先参考公共 FAQ,然后查看第 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缓存大小,但如果运行时内存高于性能分析运行时的内存,则可能触发OOM。
  • --enable-prefix-caching 启用前缀缓存。对于Qwen3.5,当混合KV缓存管理器将块大小调整为较大值时,短前缀可能不会被缓存。
  • --quantization ascend 为W8A8模型启用Ascend量化。部署BF16模型时请移除该选项。
  • --speculative-config 启用Qwen3.5 MTP投机解码。如果工作负载对首token延迟敏感,或者环境中MTP不稳定,请减少 num_speculative_tokens 或移除该选项。
  • --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' 启用完整解码ACLGraph重放以减少调度开销。
  • --additional-config 启用Ascend特定优化。enable_fused_mc2 启用MoE融合算子,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

# Get these values through ifconfig.
# nic_name is the network interface name corresponding to local_ip.
nic_name="xxxx"
local_ip="xxxx"

export VLLM_USE_MODELSCOPE=True
export HCCL_BUFFSIZE=1024
export HCCL_IF_IP=$local_ip
export HCCL_SOCKET_IFNAME=$nic_name
export GLOO_SOCKET_IFNAME=$nic_name
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True

# Ensure the model path matches the directory recorded during download
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

# Get these values through ifconfig.
# nic_name is the network interface name corresponding to local_ip.
nic_name="xxxx"
local_ip="xxxx"

export VLLM_USE_MODELSCOPE=True
export HCCL_BUFFSIZE=1024
export HCCL_IF_IP=$local_ip
export HCCL_SOCKET_IFNAME=$nic_name
export GLOO_SOCKET_IFNAME=$nic_name
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True

# The value of node0_ip must be consistent with local_ip on node 0.
node0_ip="xxxx"

# Ensure the model path matches the directory recorded during download
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和HCCL_SOCKET_IFNAME将HCCL和Gloo通信绑定到选定的网络。
  • multistream_overlap_shared_expert在MoE工作负载上重叠共享专家计算以获得更好的吞吐量。

5.3 基于Ray的多节点部署

对于基于Ray的分布式部署,请参考Ray分布式部署(Qwen/Qwen3-235B-A22B)。相同的模型权重、通信验证和参数调优原则适用于Qwen3.5-397B-A17B。

常见问题提示:如果Ray工作节点无法互相发现,请先检查Ray集群状态,然后验证MP部署中使用的相同HCCL和网络接口设置。

5.4 Prefill-Decode分离(A3)

PD分离将预填充和解码分配到不同的服务组。预填充节点处理大的提示块,解码节点负责token生成,代理在它们之间转发请求。此模式适用于需要分别调整预填充和解码资源比例的生产服务场景。

我们推荐使用Mooncake进行部署。有关通用PD分离工作流程,请参考Mooncake。

对于Atlas 800 A3 (64G x 16),我们建议为Qwen3.5-397B-A17B-w8a8-mtp使用2个节点部署1P1D:

  • 1个Prefill节点:1个Atlas 800 A3 (64G x 16)。
  • 1个Decode节点:1个Atlas 800 A3 (64G x 16)。

在相应节点上部署run_p.sh和run_d.sh,并在prefill主节点上部署代理脚本以转发请求。

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 IP_ADDRESS=$local_ip
export NETWORK_CARD_NAME=$nic_name
export HCCL_BUFFSIZE=1536
export HCCL_IF_IP=$IP_ADDRESS
export HCCL_OP_EXPANSION_MODE="AIV"
export HCCL_SOCKET_IFNAME=$NETWORK_CARD_NAME
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:$LD_LIBRARY_PATH
export GLOO_SOCKET_IFNAME=$NETWORK_CARD_NAME
export PYTORCH_NPU_ALLOC_CONF="expandable_segments:True"

# Ensure the model path matches the directory recorded during download
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 Decode节点

在decode节点上创建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 IP_ADDRESS=$local_ip
export NETWORK_CARD_NAME=$nic_name
export HCCL_BUFFSIZE=1536
export HCCL_IF_IP=$IP_ADDRESS
export HCCL_OP_EXPANSION_MODE="AIV"
export HCCL_SOCKET_IFNAME=$NETWORK_CARD_NAME
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:$LD_LIBRARY_PATH
export GLOO_SOCKET_IFNAME=$NETWORK_CARD_NAME
export PYTORCH_NPU_ALLOC_CONF="expandable_segments:True"

# Ensure the model path matches the directory recorded during download
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在每个节点上使用多进程处理本地工作进程。
  • Prefill使用--data-parallel-size 1、--data-parallel-size-local 1和--tensor-parallel-size 16。这创建了1个TP16的DP组。
  • Decode使用--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在prefill节点上较大,在decode节点上较小,因为prefill是提示词令牌密集型的,而decode对延迟敏感。
  • recompute_scheduler_enable在decode KV缓存不足时将请求发送回prefill端以重新计算KV缓存。仅在PD模式下的decode节点上启用它。
  • --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中跟踪。
  • 建议在decode节点上使用--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}'以减少decode调度开销。

5.5 Prefill-Decode 分离部署(Ascend 950DT系列产品)

对于 Ascend 950DT系列产品(96G x 8),我们建议为 Qwen3.5-397B-A17B-w4a4-mxfp4 使用 2 个节点部署 1P1D:

  • 1 个 Prefill 节点:1 个 Ascend 950DT系列产品(96G x 8)。以 DP=1、TP=8 运行独立服务。
  • 1 个 Decode 节点:1 个 Ascend 950DT系列产品(96G x 8)。组成全局 DP=1 组,包含 1 个本地 DP rank(TP=8)。

Prefill 服务通过 Mooncake p2p 连接器将 KV 缓存推送到 decode 节点。

在相应节点上部署run_p.sh和run_d.sh,并在prefill主节点上部署代理脚本以转发请求。

5.5.1 Prefill 节点

在预填充节点上创建 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
# Get these values through ifconfig.
# nic_name is the network interface name corresponding to local_ip.
nic_name="xxx"
local_ip="xxx"

export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=30000
export HCCL_BUFFSIZE=300
export HCCL_IF_IP=$local_ip
export HCCL_SOCKET_IFNAME=$nic_name
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
export DYNAMIC_EPLB="true"
export GLOO_SOCKET_IFNAME=$nic_name
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_DFS_CONFIG="task_exception:off,inconsistent_check:off"
export HCCL_ALGO=level0:fullmesh

# Ensure the model path matches the directory recorded during download
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"
    }
  }'

常见问题提示:如果 prefill 服务长时间未就绪,请检查 ASCEND_RT_VISIBLE_DEVICES 是否包含全部 8 个 NPU,Mooncake kv_port 是否可用,以及 ascend_local_comm_res_path 是否指向可写的共享路径。

5.5.2 Decode 节点

在decode节点上创建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
# Get these values through ifconfig.
# nic_name is the network interface name corresponding to local_ip.
nic_name="xxx"
local_ip="xxx"

export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=30000
export HCCL_BUFFSIZE=1200
export HCCL_IF_IP=$local_ip
export HCCL_SOCKET_IFNAME=$nic_name
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
export DYNAMIC_EPLB="true"
export GLOO_SOCKET_IFNAME=$nic_name
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_DFS_CONFIG="task_exception:off,inconsistent_check:off"
export HCCL_ALGO=level0:fullmesh

# Ensure the model path matches the directory recorded during download
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"
    }
  }'

常见问题提示:如果 decode 节点 0 初始化失败,请检查 --data-parallel-start-rank 是否为 0,--tensor-parallel-size 是否为 8,以及 kv_connector_extra_config.decode.dp_size 是否与全局解码 DP 大小(1)匹配。

5.6 请求转发

在与预填充服务实例相同的节点上运行代理服务器。您可以在仓库示例中获取代理程序:load_balance_proxy_server_example.py。

对于 A3 PD 分离(1P1D),代理将请求转发到 1 个 prefill 节点和 1 个 decode 节点。使用逐层代理脚本。

unset ftp_proxy
unset https_proxy
unset http_proxy
python3 load_balance_proxy_server_example.py \
  --prefiller-hosts 192.xx.xx.1 \
  --prefiller-ports 30060 \
  --decoder-hosts 192.xx.xx.2 \
  --decoder-ports 30050 \
  --host 192.xx.xx.1 \
  --port 8000

例如:

cd vllm-ascend/examples/disaggregated_prefill_v1/
bash proxy.sh

对于 Ascend 950DT系列产品 PD 分离部署(1P1D),代理将请求转发到 1 个 prefill 节点和 1 个 decode 节点。请使用 layerwise 代理脚本。

unset ftp_proxy
unset https_proxy
unset http_proxy
python3 load_balance_proxy_layerwise_server_example.py \
  --prefiller-hosts 192.xx.xx.1 \
  --prefiller-ports 30060 \
  --decoder-hosts 192.xx.xx.2 \
  --decoder-ports 30050 \
  --host 192.xx.xx.1 \
  --port 8000

常见问题提示:如果请求到达代理但未返回输出,请检查代理主机列表是否包含所有健康的预填充和解码端点,并验证第6节中的服务验证请求是否通过代理端口成功。

6 功能验证

服务器启动后,发送请求以验证基本模型功能。对于单节点和多进程部署,使用节点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

  1. 详细信息请参考 使用AISBench。
  2. 执行后可获取结果。以下 Qwen3.5-397B-A17B-w8a8 在 vllm-ascend:v0.17.0rc1 上的结果仅供参考。
数据集 版本 指标 模式 vllm-api-general-chat
gsm8k - accuracy gen 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 推荐配置

以下配置在特定测试环境中经过验证,仅供参考。最佳配置取决于硬件类型、最大输入/输出长度、请求并发数、前缀缓存命中率、量化方式以及预填充/解码比例。请根据实际工作负载调整第9.2节中的参数。

场景 部署模式 NPU 总数 权重版本 关键考虑因素
长上下文 单节点在线服务 16 个 A3 NPU W8A8 MTP 使用更大的 --max-model-len 并预留足够的 KV 缓存。如果发生 OOM,请降低 --max-num-seqs。
长上下文 单节点在线服务 8 个 Ascend 950DT系列产品 NPU W4A4 MXFP4 MTP 使用 TP=8 并为 133k 上下文预留足够的 KV cache。如果发生 OOM,请降低 --max-num-seqs。
高吞吐量 多节点 MP 16 个 A2 NPU W8A8 MTP 通过 DP 增加并发,并调整 --max-num-batched-tokens 以提升 prefill 吞吐量。
低延迟 1P1D PD 分离 48 个 A3 NPU W8A8 MTP 使用独立的 prefill 和 decode DP/TP 布局,并在 decode 节点上启用完整的 decode ACLGraph。
低延迟 1P1D PD 分离部署 16 个 Ascend 950DT系列产品 NPU W4A4 MXFP4 MTP 使用一个 8-NPU prefill 节点和一个 8-NPU decode 节点。在 decode 节点上启用完整 decode ACLGraph。
Scenario Node Role NPUs TP DP Max Num Seqs Max Model Len Max Num Batched Tokens MTP Tokens Prefix Cache Main Optimizations
Long context Single node 16 16 1 128 133000 16384 3 On FullGraph, Fused MC2, CPU binding
High throughput MP node 8 per node 8 1 per node, 2 global 16 per DP 32768 4096 3 Off FullGraph, shared expert overlap, CPU binding
Low latency Prefill node 16 2 8 64 16384 4096 3 Off Recompute scheduler, Fused MC2, CPU binding
Low latency Decode node 16 per node 2 8 per node, 16 global 32 16384 128 3 Off FullGraph, recompute scheduler, Fused MC2, CPU binding

9.2 调优指南

有关通用调优方法,请参阅公开性能调优文档,有关功能描述,请参阅功能矩阵。

推荐调优顺序:

  1. 首先设置部署拓扑。使用单节点部署进行验证,使用MP部署进行简单的多节点服务,当预填充和解码需要不同资源比例时使用PD分离。
  2. 使用 --max-model-len 选择最大上下文长度。长上下文会增加KV缓存使用量,因此如果发生OOM,请减少 --max-num-seqs 或 --gpu-memory-utilization。
  3. 调整 --max-num-batched-tokens。较大的值通常可以提高预填充吞吐量,但会增加激活内存。解码密集型工作负载通常需要较小的值。
  4. 根据服务并发数调整 --max-num-seqs。超过此值的请求将在队列中等待,等待时间计入TTFT和TPOT。
  5. 调整 --gpu-memory-utilization。增加该值以提供更多KV缓存,但为运行时内存波动和专家不均衡留出余量。
  6. 调整 --speculative-config。MTP可以提高解码吞吐量,但最佳的 num_speculative_tokens 取决于接受率和工作负载。
  7. 调整ACLGraph捕获。对于解码,建议使用 FULL_DECODE_ONLY。如果手动设置 cudagraph_capture_sizes,请包含常见的解码批处理大小。使用序列并行时,请使用TP大小的倍数的捕获大小。

9.3 模型特定优化

优化项 启用方式 收益 备注
RoPE优化 默认启用 跨层复用位置编码工作以减少解码开销。 无需额外配置。
AddRMSNormQuant 融合 默认启用 融合归一化与量化操作以减少内存访问。 适用于量化路径。
类零消除 默认启用 移除注意力机制中不必要的类零张量操作。 无需额外配置。
Qwen3.5 MTP 推测解码 --speculative-config '{"method": "qwen3_5_mtp", "num_speculative_tokens": 3, "enforce_eager": true}' 在接受率良好时提升解码吞吐量。 若延迟或稳定性下降,可减少推测 token 数量。
全解码 ACLGraph --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' 降低算子调度开销,稳定解码性能。 推荐用于解码密集型服务场景。
融合 MC2 --additional-config '{"enable_fused_mc2": 1}' 启用 MoE 融合算子以提升 MoE 预填充/解码效率。 若在多 DP 大 token 场景下精度或性能下降,请禁用它并对比效果。
共享专家重叠 --additional-config '{"multistream_overlap_shared_expert": true}' 在 MoE 工作负载中重叠共享专家计算。 推荐用于 MP 吞吐量场景。
重计算调度器 --additional-config '{"recompute_scheduler_enable": true}' 在 PD 模式下解码 KV 缓存不足时,通过预填充重新计算 KV。 仅对 kv_role 为 kv_consumer 的解码节点有效。
CPU 绑定 --additional-config '{"enable_cpu_binding": true}' 提升 ARM 服务器上的 CPU 亲和性,减少调度抖动。 许多配置中默认启用,但显式设置可使配置方案更清晰。

10 常见问题

对于常见的环境、安装和通用参数问题,请参考公共 FAQ。本节仅涵盖 Qwen3.5-397B-A17B 的特定于模型的问题。

Q1: 为什么服务在启动时或刚接受请求后报告OOM?

现象: 服务在profile运行期间失败,或者成功启动但在真实流量到达时报告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 初始化超时,或 headless 节点退出。

原因: 各节点间的网络接口名称、IP 地址、DP rank 或 RPC 端口不一致。

解决方案: 首先验证多节点通信。确保HCCL_IF_IP、GLOO_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:为什么启用序列并行或Fused MC2后性能会下降?

现象: 启用通信或 MoE 融合优化后,吞吐量下降,延迟增加,或 MoE 负载变得不稳定。

原因: 这些优化依赖于工作负载。序列并行在高并发TP场景中最有用。Fused MC2可能不适用于某些多DP大token场景,在这些场景中,填充的token会使某些专家过载。

Q5:我应该如何为此模型调整 MTP 推测解码?

现象: MTP 在某些工作负载中提高了吞吐量,但在其他工作负载中可能会增加首 token 延迟或提供有限的收益。

原因: 收益取决于推测 token 接受率、请求长度和解码并发度。

解决方案: 从本文档所示的 num_speculative_tokens 设置为 3 开始。如果服务对延迟敏感或接受率较低,请减小该值或移除 --speculative-config,并比较 TTFT、TPOT 和吞吐量。