跳转至

Qwen3.5-397B-A17B 部署教程

1.简介

Qwen3.5-397B-A17B 是一个大规模 Qwen3.5 MoE 模型,融合了多模态能力、长上下文推理、MTP 推测解码和 W8A8 量化部署,可在 Ascend 硬件上用于生产服务。

本文档描述了该模型的主要验证步骤,包括支持的特性、前提条件、安装、单节点在线部署、多节点部署、Prefill-Decode (PD) 分离、功能验证、精度和性能评估、性能调优以及常见问题解答。

Qwen3.5-397B-A17B 模型首次在 vllm-ascend:v0.17.0rc1 中得到支持。请使用 v0.17.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 个 Atlas 800 A3(64G × 16)节点或 4 个 Atlas 800 A2(64G × 8)节点。下载模型权重
  • Qwen3.5-397B-A17B-w8a8(量化版本):需要 1 个 Atlas 800 A3(64G × 16)节点或 2 个 Atlas 800 A2(64G × 8)节点。下载模型权重

建议将模型权重下载到多节点共享目录,例如 /root/.cache/,以便所有服务节点可以加载相同路径。

3.2 验证多节点通信(可选)

如果要部署多节点环境,需要按照验证多节点通信环境验证多节点通信。

4.安装

4.1 Docker 镜像安装

Select an image based on your machine type. For example, use quay.io/ascend/vllm-ascend:v0.22.1rc1 for Atlas 800 A2 and quay.io/ascend/vllm-ascend:v0.22.1rc1-a3 for Atlas 800 A3.

请参阅使用 Docker获取完整安装指南。

# Update --device according to your device.
# Atlas A2: /dev/davinci[0-7]
# Atlas A3: /dev/davinci[0-15]
# Download the model weight to /root/.cache in advance.
export IMAGE=quay.io/ascend/vllm-ascend:v0.22.1rc1
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(64G × 16)节点上的 W8A8 部署。W8A8 版本需要 --quantization ascend

运行以下脚本在 1 台 Atlas 800 A3(64G × 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, "enforce_eager": true}' \
  --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
  --additional-config '{"enable_cpu_binding":true, "enable_fused_mc2":1, "enable_flashcomm1":true}'

常见问题提示:如果服务启动失败、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 模型启用 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_flashcomm1 启用 FlashComm1,enable_cpu_binding 启用 Ascend 原生 CPU 绑定。

5.2 使用 MP 的多节点部署(推荐)

多节点 MP 部署使用 vLLM 跨节点数据并行和每个节点内的张量并行。推荐用于 2 个 Atlas 800 A2(64G × 8)节点上的 W8A8 模型。

假设您有 2 个 Atlas 800 A2 节点,并希望跨多个节点部署 Qwen3.5-397B-A17B-w8a8-mtp 模型。将 nic_namelocal_ipnode0_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, "enforce_eager": true}' \
  --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, "enforce_eager": true}' \
  --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_IPGLOO_SOCKET_IFNAMETP_SOCKET_IFNAMEHCCL_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 预填充-解码分离部署

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

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

以Atlas 800 A3(64G × 16)为例,我们建议部署1P1D(3节点)来运行Qwen3.5-397B-A17B-w8a8-mtp

  • 1个预填充节点:1台Atlas 800 A3(64G × 16)。
  • 2个解码节点:2台Atlas 800 A3(64G × 16)。

在相应节点上部署run_p.shrun_d0.shrun_d1.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="xxx"
local_ip="xxx"

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 8 \
  --data-parallel-size-local 8 \
  --api-server-count 1 \
  --data-parallel-address ${IP_ADDRESS} \
  --max-num-seqs 64 \
  --data-parallel-rpc-port 6884 \
  --tensor-parallel-size 2 \
  --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, "enable_fused_mc2":1}' \
  --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": 8,
        "tp_size": 2
      },
      "decode": {
        "dp_size": 16,
        "tp_size": 2
      }
    }
  }'

常见问题提示:如果预填充服务长时间未就绪,请检查模型路径是否共享、ASCEND_RT_VISIBLE_DEVICES是否包含全部16个NPU,以及Mooncake的kv_port是否可用。

5.4.2 解码节点0

在第一个解码节点上创建run_d0.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="xxx"
local_ip="xxx"

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

export VLLM_ENGINE_READY_TIMEOUT_S=30000
export VLLM_MOONCAKE_ABORT_REQUEST_TIMEOUT=480
export MASTER_IP_ADDRESS=$node0_ip
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 16 \
  --data-parallel-size-local 8 \
  --data-parallel-start-rank 0 \
  --api-server-count 1 \
  --data-parallel-address ${MASTER_IP_ADDRESS} \
  --max-num-seqs 32 \
  --data-parallel-rpc-port 6884 \
  --tensor-parallel-size 2 \
  --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, "enforce_eager": true}' \
  --additional-config '{"recompute_scheduler_enable": true, "enable_cpu_binding": true, "enable_fused_mc2":1}' \
  --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": 8,
        "tp_size": 2
      },
      "decode": {
        "dp_size": 16,
        "tp_size": 2
      }
    }
  }'

常见问题提示:如果解码节点0初始化失败,请检查MASTER_IP_ADDRESS是否指向解码节点0本身、--data-parallel-start-rank是否为0,以及kv_connector_extra_config.decode.dp_size是否与全局解码DP大小匹配。

5.4.3 解码节点1

在第二个解码节点上创建run_d1.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="xxx"
local_ip="xxx"

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

export VLLM_ENGINE_READY_TIMEOUT_S=30000
export VLLM_MOONCAKE_ABORT_REQUEST_TIMEOUT=480
export MASTER_IP_ADDRESS=$node0_ip
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 \
  --headless \
  --no-enable-prefix-caching \
  --enable-expert-parallel \
  --data-parallel-size 16 \
  --data-parallel-size-local 8 \
  --data-parallel-start-rank 8 \
  --data-parallel-address ${MASTER_IP_ADDRESS} \
  --max-num-seqs 32 \
  --data-parallel-rpc-port 6884 \
  --tensor-parallel-size 2 \
  --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, "enforce_eager": true}' \
  --additional-config '{"recompute_scheduler_enable": true, "enable_cpu_binding": true, "enable_fused_mc2":1}' \
  --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": 8,
        "tp_size": 2
      },
      "decode": {
        "dp_size": 16,
        "tp_size": 2
      }
    }
  }'

常见问题提示:如果解码节点1无法加入解码节点0,请检查是否设置了--headless--data-parallel-start-rank是否为8,以及--data-parallel-address是否指向解码节点0。

PD分离的关键参数:

  • --distributed-executor-backend mp在每个节点上使用多进程处理本地工作节点。
  • 预填充使用--data-parallel-size 8--data-parallel-size-local 8--tensor-parallel-size 2。这将创建8个本地DP组,每个组使用TP2。
  • 解码使用--data-parallel-size 16--data-parallel-size-local 8--tensor-parallel-size 2。解码节点0从DP rank 0开始,解码节点1从DP rank 8开始。
  • --data-parallel-address--data-parallel-rpc-port定义DP控制平面。对于解码节点,地址必须指向解码节点0。
  • --max-num-batched-tokens在预填充节点上较大,在解码节点上较小,因为预填充是提示token密集型,而解码对延迟敏感。
  • recompute_scheduler_enable sends requests back to the prefill side to recompute KV cache when decode KV cache is insufficient. Enable it only on decode nodes in PD 模式.
  • --kv-transfer-config设置Mooncake连接器。kv_role在预填充上为kv_producer,在解码上为kv_consumer
  • kv_connector_extra_config.prefill.dp_size/tp_sizedecode.dp_size/tp_size必须与实际全局DP和TP布局匹配。
  • --no-enable-prefix-caching禁用前缀缓存。对于PD分离,D节点前缀缓存的已知问题在#7944中跟踪。
  • VLLM_MOONCAKE_ABORT_REQUEST_TIMEOUT是自动释放请求的预填充器KV缓存的超时时间(秒)。
  • --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}'建议在解码节点上使用,以减少解码调度开销。

5.4.4 请求转发

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

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 141.xx.xx.3 \
  --decoder-ports 30050 30050 \
  --host 141.xx.xx.1 \
  --port 8010

例如:

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

常见问题提示:如果请求到达代理但未返回输出,请检查代理主机列表是否包含所有健康的预填充和解码端点,并验证第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

  1. 详细信息请参考使用AISBench
  2. 执行后即可获得结果,以下是 Qwen3.5-397B-A17B-w8a8vllm-ascend:v0.17.0rc1 上的结果,仅供参考。
数据集 版本 指标 模式 vllm-api-生成eral-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 基准测试

Qwen3.5-397B-A17B-w8a8 为例进行性能评估。更多详细信息请参考 vLLM 基准测试

有三个 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
高吞吐量 多节点MP 16个A2 NPU W8A8 MTP 通过DP增加并发,并调整 --max-num-batched-tokens 以优化预填充吞吐量。
低延迟 1P1D PD分离部署 48个A3 NPU W8A8 MTP 使用独立的预填充和解码DP/TP布局,并在解码节点上启用完整解码ACLGraph。
场景 节点角色 NPU TP DP 最大序列数 最大模型长度 最大批量Token数 MTP Token数 前缀缓存 主要优化
长上下文 单节点 16 16 1 128 133000 16384 3 开启 FullGraph, FlashComm1, Fused MC2, 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绑定

9.2 调优指南

通用调优方法请参考公开性能调优文档,功能描述请参考特性矩阵

推荐调优顺序:

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

9.3 模型特定优化

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

10 常见问题

常见环境、安装和通用参数问题请参考常见问题。本节仅涵盖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预留空间不足。运行时专家负载不均衡也可能导致实际推理使用的内存超过profile运行。

解决方案: 尽可能使用W8A8模型并配合--quantization ascend,降低--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_IPGLOO_SOCKET_IFNAMETP_SOCKET_IFNAMEHCCL_SOCKET_IFNAME与所选NIC匹配。确保所有节点使用相同的--data-parallel-rpc-port,非主节点使用--headless,且--data-parallel-start-rank不重叠。

Q3:为什么PD分离示例中禁用了前缀缓存?

现象: 在decode节点上启用前缀缓存时,PD分离可能表现出异常行为。

原因: D节点前缀缓存问题是一个已知限制,跟踪于#7944

解决方案: 在该限制解决前,PD分离请使用--no-enable-prefix-caching。对于非PD单节点服务,仅当工作负载包含重复前缀且缓存命中率有意义时,才启用前缀缓存。

Q4:为什么启用FlashComm1或Fused MC2后性能下降?

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

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

解决方案: 与禁用enable_flashcomm1并将enable_fused_mc2设为0的情况进行对比。若启用了FlashComm1并调优cudagraph_capture_sizes,请使用TP大小的倍数。根据实际并发度和提示长度分布保留更优设置。

Q5:如何针对此模型调优MTP推测解码?

**现象:**MTP在某些工作负载中可提升吞吐量,但在其他场景下可能增加首token延迟或收益有限。

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

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