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 可以导入:
如果要部署多节点服务,需要在每个节点上设置相同的环境。
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_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, "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_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 预填充-解码分离部署¶
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.sh、run_d0.sh和run_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_enablesends 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_size和decode.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
例如:
常见问题提示:如果请求到达代理但未返回输出,请检查代理主机列表是否包含所有健康的预填充和解码端点,并验证第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-生成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 调优指南¶
通用调优方法请参考公开性能调优文档,功能描述请参考特性矩阵。
推荐调优顺序:
- 首先设置部署拓扑。验证阶段使用单节点部署,简单多节点服务使用MP部署,当prefill和decode需要不同资源比例时使用PD分离部署。
- 通过
--max-model-len选择最大上下文长度。长上下文会增加KV缓存使用量,若发生OOM,请降低--max-num-seqs或--gpu-memory-utilization。 - 调优
--max-num-batched-tokens。较大值通常能提升prefill吞吐量,但会增加激活内存。decode密集型工作负载通常需要较小值。 - 根据服务并发度调优
--max-num-seqs。超过此值的请求将在队列中等待,等待时间计入TTFT和TPOT。 - 调优
--gpu-memory-utilization。增大该值可提供更多KV缓存,但需预留空间应对运行时内存波动和专家负载不均衡。 - 调优
--speculative-config。MTP可提升decode吞吐量,但最佳num_speculative_tokens取决于接受率和工作负载。 - 调优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_IP、GLOO_SOCKET_IFNAME、TP_SOCKET_IFNAME和HCCL_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和吞吐量。