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-mxfp8Qwen3.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.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.shrun_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_sizedecode.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.shrun_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#

  1. 详情请参考使用AISBench

  2. 执行后,您可以获得结果。以下Qwen3.5-397B-A17B-w8a8vllm-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.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,请包含常见的解码批量大小。使用 FlashComm1 时,捕获大小应为 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"}'

减少算子分发开销,稳定解码性能。

推荐用于解码密集型服务。

FlashComm1

--additional-config '{"enable_flashcomm1": true}'

在大 TP 和高并发场景下减少通信开销。

可能对低并发工作负载无帮助。

Fused 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_rolekv_consumer 的解码节点上有效。

CPU 绑定

--additional-config '{"enable_cpu_binding": true}'

在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_IPGLOO_SOCKET_IFNAMETP_SOCKET_IFNAMEHCCL_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和吞吐量。