跳转至

GLM-5.3-Flash

1 简介

GLM-5.3-Flash 是 GLM-5 系列中首个原生多模态模型。它基于 GLM 系列中首次结合稀疏注意力和线性注意力的混合架构构建,采用流形约束超连接(mHC),并在 30T token 的多模态预训练语料上进行训练。该模型总参数量为 320B,但仅有 18B 激活参数,在基准测试和实际工作负载上以十分之一的价格超越 GLM-5.2,同时在编码和智能体基准上接近 Claude Opus 4.8。GLM-5.3-Flash 还支持通过 reasoning_effort 参数(low、high、max)控制思考预算。

本文档介绍该模型的主要验证步骤,包括支持的特性、特性配置、环境准备、单节点部署、1P1D Prefill-Decode(PD)分离部署、多节点部署,以及精度与性能评估。

本文档基于 vLLM-Ascend v0.30.0RC1,该版本支持在 Atlas 800I A2 和 Atlas 800I A3 上部署 GLM-5.3-Flash。950DT Products 当前为实验性支持,将在后续版本中正式支持。

2 支持的特性

请参考支持特性列表获取该模型的支持特性矩阵。

请参考特性指南获取特性的配置方法。

GLM-5.3-Flash 目前在昇腾上仅支持 model runner V1,因此所有 Atlas 800I A3 脚本均显式设置 VLLM_USE_V2_MODEL_RUNNER=0。

3 前提条件

3.1 模型权重

  • GLM-5.3-Flash-w8a8-mxfp8 (950DT Products mxfp8 Quantized):需要 1 个 950DT Products(96GB × 8)节点。下载模型权重。
  • GLM-5.3-Flash-w8a8:单节点部署需要 1 个 Atlas 800I A3(128GB × 8)节点,1P1D PD 分离部署需要 2 个节点。下载模型权重。
  • GLM-5.3-Flash-w8a8:需要 2 个 Atlas 800I A2(64GB × 8)节点。下载模型权重。

  • 您可以使用 msmodelslim 直接对模型进行量化。

建议将模型权重下载到多个节点的共享目录中,例如 /root/.cache/

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

如果您想部署多节点环境,需要根据验证多节点通信环境进行验证。

4 安装

4.1 Docker 镜像安装

  • 您可以使用官方 Docker 镜像直接运行 GLM-5.3-Flash。

在每个节点上启动 docker 镜像。

export IMAGE=quay.io/ascend/vllm-ascend:glm-5.3-flash-a5-openeuler
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/bin/urma_admin:/usr/bin/urma_admin \
-v /lib/route.conf:/lib/route.conf \
-itd $IMAGE bash

在每个节点上启动 docker 镜像。

export IMAGE=quay.io/ascend/vllm-ascend:v0.30.0rc1-a3
export NAME=vllm-ascend

# Run the container using the defined variables
# Note: If you are running bridge network with docker, please expose available ports for multiple nodes communication in advance
docker run --rm \
--name $NAME \
--net=host \
--shm-size=100g \
--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 /etc/hccn.conf:/etc/hccn.conf:ro \
-v /root/.cache:/root/.cache \
-it $IMAGE bash

在每个节点上启动 docker 镜像。

export IMAGE=quay.io/ascend/vllm-ascend:v0.30.0rc1
export NAME=vllm-ascend

docker run --rm \
--name $NAME \
--net=host \
--shm-size=500g \
--privileged \
--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/Ascend/driver:/usr/local/Ascend/driver \
-v /usr/local/Ascend/firmware:/usr/local/Ascend/firmware \
-v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
-v /usr/local/sbin:/usr/local/sbin \
-v /etc/hccn.conf:/etc/hccn.conf:ro \
-v /root/.cache:/root/.cache \
-it $IMAGE bash

5 在线服务部署

Note

请勿为 GLM-5.3-Flash 设置 enable_thinking: false / thinking: false,否则输出质量可能会下降。

5.1 单节点在线部署

  • 量化模型 GLM-5.3-Flash-w8a8-mxfp8 可部署在 1 个 950DT Products(96GB × 8)上。

运行以下脚本执行在线推理。

export VLLM_USE_V2_MODEL_RUNNER=0
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_BUFFSIZE=1024

vllm serve Eco-Tech/GLM-5.3-Flash-w8a8-mxfp8 \
  --host 0.0.0.0 \
  --port 8000 \
  --data-parallel-size 1 \
  --tensor-parallel-size 8 \
  --enable-expert-parallel \
  --seed 1024 \
  --quantization ascend \
  --served-model-name glm \
  --max-num-seqs 32 \
  --max-model-len 132096 \
  --max-num-batched-tokens 8192 \
  --trust-remote-code \
  --gpu-memory-utilization 0.9 \
  --limit-mm-per-prompt '{"image":1,"video":0}' \
  --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY", "cudagraph_capture_sizes": [1,2,4,8,16,32,64,96,128]}' \
  --speculative-config '{"num_speculative_tokens": 3, "method": "deepseek_mtp", "enforce_eager": true}'
  • 量化模型 GLM-5.3-Flash-w8a8 可以部署在 1 个 Atlas 800I A3(64GB × 16)上。

运行以下脚本执行在线推理。

#!/bin/sh

export VLLM_USE_V2_MODEL_RUNNER=0
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True

export HCCL_OP_EXPANSION_MODE="AIV"
export HCCL_BUFFSIZE=1024

vllm serve Eco-Tech/GLM-5.3-Flash-w8a8   \
  --host 0.0.0.0 \
  --port 8000 \
  --max-model-len 1048576 \
  --data-parallel-size 1 \
  --tensor-parallel-size 16 \
  --enable-expert-parallel \
  --seed 1024 \
  --served-model-name glm \
  --safetensors-load-strategy prefetch \
  --max-num-seqs 32 \
  --max-num-batched-tokens 8192 \
  --trust-remote-code \
  --quantization ascend \
  --kv-cache-dtype int8 \
  --limit-mm-per-prompt '{"image":1,"video":0}' \
  --gpu-memory-utilization 0.92 \
  --speculative-config '{"num_speculative_tokens": 5, "method": "deepseek_mtp", "enforce_eager": false}' \
  --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
  --additional-config '{"multistream_overlap_shared_expert": true}' \
  --api-server-count 1

关键参数说明

下面仅描述该模型/场景特有的关键参数。max-model-len 和 max-num-seqs 需要根据实际使用场景进行设置。

模型特有参数:

  • --data-parallel-size 1:运行单个 DP rank。--tensor-parallel-size 在 950DT Products上为 8,在 Atlas 800I A3 上为 16。建议使用此布局,以平衡 w8a8 权重的内存容量与计算效率。
  • --enable-expert-parallel:GLM-5.3-Flash 采用 MoE 架构,必须启用此参数。
  • --quantization ascend:为 w8a8 量化权重启用昇腾量化。
  • --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}':仅在 Decode 阶段启用图捕获,通过降低算子启动开销提升 Decode 性能。
  • --limit-mm-per-prompt '{"image":1,"video":0}':所有部署示例均设置为每个提示词最多允许 1 张图像,并禁用视频输入。
  • --speculative-config:使用 GLM-5.3-Flash 的 DeepSeek 风格 MTP 草稿头启用多 Token 预测(MTP)推测解码。单节点示例在 950DT Products 上使用 3 个推测 Token,在 Atlas 800I A3 上使用 5 个。950DT Products 使用 enforce_eager: true 让 MTP 草稿模型以 eager 模式运行;Atlas 800I A3 使用 enforce_eager: false 启用草稿模型的图模式。v0.30.0RC1 已支持 GLM-5.3-Flash 的 MTP 草稿图执行,其他 GLM 模型的强制 eager 限制不适用于此模型。

5.2 多节点混部部署

  • 量化模型 GLM-5.3-Flash-w8a8 可以部署在 2 个 Atlas 800I A2(64GB × 8)节点上,跨两个节点使用 DP2(每个节点一个 DP rank),节点内使用 TP8。

分别在两个节点上运行以下脚本。

节点 0

# this obtained through ifconfig
# nic_name is the network interface name corresponding to local_ip of the current node
nic_name="xxxx"
local_ip="xx.xx.xx.1"

# The value of node0_ip must be consistent with the value of local_ip set in node0 (master node)
node0_ip="xx.xx.xx.1"

export VLLM_USE_V2_MODEL_RUNNER=0
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_OP_EXPANSION_MODE=AIV
export HCCL_BUFFSIZE=1024
export VLLM_RPC_TIMEOUT=3600000
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=3000
export HCCL_EXEC_TIMEOUT=3600
export HCCL_CONNECT_TIMEOUT=1200
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export HCCL_IF_IP=$local_ip
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7

vllm serve /path/to/GLM-5.3-Flash-w8a8 \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 133120 \
    --data-parallel-size 2 \
    --data-parallel-size-local 1 \
    --data-parallel-start-rank 0 \
    --data-parallel-address $node0_ip \
    --data-parallel-rpc-port 12321 \
    --tensor-parallel-size 8 \
    --enable-expert-parallel \
    --seed 1024 \
    --served-model-name glm \
    --safetensors-load-strategy prefetch \
    --max-num-seqs 32 \
    --max-num-batched-tokens 8192 \
    --trust-remote-code \
    --quantization ascend \
    --limit-mm-per-prompt '{"image":1,"video":0}' \
    --gpu-memory-utilization 0.85 \
    --speculative-config '{"num_speculative_tokens":3,"method":"deepseek_mtp","enforce_eager":true}' \
    --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY","cudagraph_capture_sizes":[4,8,16,32,64,96,128]}' \
    --api-server-count 1

节点 1

# this obtained through ifconfig
# nic_name is the network interface name corresponding to local_ip of the current node
nic_name="xxxx"
local_ip="xx.xx.xx.2"

# The value of node0_ip must be consistent with the value of local_ip set in node0 (master node)
node0_ip="xx.xx.xx.1"

export VLLM_USE_V2_MODEL_RUNNER=0
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_OP_EXPANSION_MODE=AIV
export HCCL_BUFFSIZE=1024
export VLLM_RPC_TIMEOUT=3600000
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=3000
export HCCL_EXEC_TIMEOUT=3600
export HCCL_CONNECT_TIMEOUT=1200
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export HCCL_IF_IP=$local_ip
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7

vllm serve /path/to/GLM-5.3-Flash-w8a8 \
    --host 0.0.0.0 \
    --port 8000 \
    --headless \
    --max-model-len 133120 \
    --data-parallel-size 2 \
    --data-parallel-size-local 1 \
    --data-parallel-start-rank 1 \
    --data-parallel-address $node0_ip \
    --data-parallel-rpc-port 12321 \
    --tensor-parallel-size 8 \
    --enable-expert-parallel \
    --seed 1024 \
    --served-model-name glm \
    --safetensors-load-strategy prefetch \
    --max-num-seqs 32 \
    --max-num-batched-tokens 8192 \
    --trust-remote-code \
    --quantization ascend \
    --limit-mm-per-prompt '{"image":1,"video":0}' \
    --gpu-memory-utilization 0.85 \
    --speculative-config '{"num_speculative_tokens":3,"method":"deepseek_mtp","enforce_eager":true}' \
    --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY","cudagraph_capture_sizes":[4,8,16,32,64,96,128]}'

关键参数说明

多节点网络和数据并行配置:

  • HCCL_IF_IP、GLOO_SOCKET_IFNAME、TP_SOCKET_IFNAME、HCCL_SOCKET_IFNAME:用于多节点通信的网络接口配置。将 nic_name 设置为网络接口名称(通过 ifconfig 获取),并将 local_ip 设置为当前节点的 IP 地址。每个节点都必须正确配置这些参数,才能实现成功的多节点通信。
  • --data-parallel-size 2 --data-parallel-size-local 1:在两个节点上运行两个 DP rank,每个节点一个 rank;每个 rank 在其节点内使用 TP8。
  • --data-parallel-start-rank:当前节点的起始 DP rank 偏移量。节点 0 使用 0,节点 1 使用 1。
  • --data-parallel-address:数据并行主节点(节点 0)的 IP 地址。必须与主节点的 local_ip 一致。
  • --data-parallel-rpc-port 12321:数据并行主节点通信的 RPC 端口。所有节点必须相同。
  • --headless:表示非主节点(在节点 1 上使用)。不要在节点 0 上使用。

5.3 1P1D PD 分离部署

Atlas 800I A3 和 Atlas 800I A2 部署均使用同一个 launch_online_dp.py 脚本,为每个本地 DP rank 启动一个 vLLM 进程。在按照下方各平台说明操作前,请将该脚本保存到每个 Prefill 和 Decode 节点。

5.3.1 准备 DP 启动器

import argparse
import multiprocessing
import subprocess


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("--template", default="./run_p.sh")
    parser.add_argument("--dp-size", type=int, required=True)
    parser.add_argument("--tp-size", type=int, default=1)
    parser.add_argument("--dp-size-local", type=int, default=-1)
    parser.add_argument("--dp-rank-start", type=int, default=0)
    parser.add_argument("--dp-address", required=True)
    parser.add_argument("--dp-rpc-port", default="12325")
    parser.add_argument("--vllm-start-port", type=int, default=8000)
    args = parser.parse_args()
    if args.dp_size_local == -1:
        args.dp_size_local = args.dp_size
    return args


def run(args, devices, port, dp_rank):
    subprocess.run(
        [
            "bash",
            args.template,
            devices,
            str(port),
            str(args.dp_size),
            str(dp_rank),
            args.dp_address,
            args.dp_rpc_port,
            str(args.tp_size),
        ],
        check=True,
    )


if __name__ == "__main__":
    args = parse_args()
    processes = []
    for i in range(args.dp_size_local):
        devices = ",".join(
            str(device)
            for device in range(i * args.tp_size, (i + 1) * args.tp_size)
        )
        process = multiprocessing.Process(
            target=run,
            args=(
                args,
                devices,
                args.vllm_start_port + i,
                args.dp_rank_start + i,
            ),
        )
        processes.append(process)
        process.start()
    for process in processes:
        process.join()

启动器通过 $1 到 $7 向各角色脚本依次传入可见设备、引擎端口、全局 DP 大小、DP rank、DP 地址、DP RPC 端口和 TP 大小。

本示例使用两台 Atlas 800I A3 服务器。Prefill 节点运行 2 个 DP rank,每个 rank 使用 TP8(DP2/TP8);Decode 节点运行 8 个 DP rank,每个 rank 使用 TP2(DP8/TP2)。两种布局均使用各自服务器的全部 16 个逻辑设备。MooncakeConnectorV2 将 KV cache 从 Prefill 引擎传输至 Decode 引擎。

启动服务前,请将以下脚本中的 LOCAL_IP、NIC_NAME 和 MODEL_PATH 替换为部署环境的实际值。这些脚本适用于使用 HCCS 且设备 RoCE 端口关闭的 Atlas 800I A3 超节点,显式选择 hccs:device 进行设备通信;socket 接口变量仍用于选择主机网络。其他网络拓扑需要相应调整资源配置。

Atlas 800I A3 服务脚本和启动命令

启动 Prefill 节点

在 Prefill 节点上,将以下脚本保存为 run_p.sh。启动器通过位置参数传入可见设备、API 端口、DP 配置和 TP 大小。

#!/usr/bin/env bash
# Usage: bash run_p.sh <visible_devices> <http_port> <dp_size> \
#   <dp_rank> <dp_address> <rpc_port> <tp_size>

# This Atlas 800I A3 supernode uses HCCS; its device RoCE ports are down.
export ASCEND_GLOBAL_RESOURCE_CONFIG='{"comm_resource_config.protocol_desc":["hccs:device"]}'
export ASCEND_LOCAL_COMM_RES='{"version":"1.2"}'

LOCAL_IP="<PREFILL_NODE_IP>"
NIC_NAME="<NETWORK_INTERFACE>"
MODEL_PATH="<YOUR_MODEL_PATH>"

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 PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export VLLM_USE_V2_MODEL_RUNNER=0
export HCCL_OP_EXPANSION_MODE=AIV
export HCCL_BUFFSIZE=1024
export ASCEND_RT_VISIBLE_DEVICES="$1"

exec vllm serve "$MODEL_PATH" \
  --host 0.0.0.0 \
  --port "$2" \
  --data-parallel-size "$3" \
  --data-parallel-rank "$4" \
  --data-parallel-address "$5" \
  --data-parallel-rpc-port "$6" \
  --tensor-parallel-size "$7" \
  --enable-expert-parallel \
  --seed 1024 \
  --served-model-name glm \
  --safetensors-load-strategy prefetch \
  --max-num-seqs 64 \
  --max-model-len 1048576 \
  --max-num-batched-tokens 4096 \
  --trust-remote-code \
  --quantization ascend \
  --limit-mm-per-prompt '{"image":1,"video":0}' \
  --gpu-memory-utilization 0.92 \
  --tool-call-parser glm47 \
  --reasoning-parser glm45 \
  --enable-auto-tool-choice \
  --kv-cache-dtype int8 \
  --prefix-cache-retention-interval None \
  --speculative-config '{"num_speculative_tokens": 5, "method": "deepseek_mtp", "enforce_eager": true}' \
  --additional-config '{
    "enable_flashcomm1": true,
    "enable_dsa_cp": true,
    "enable_prefill_mc2": true,
    "enable_fused_mc2": 1,
    "enable_shared_expert_dp": true,
    "multistream_overlap_shared_expert": false
  }' \
  --kv-transfer-config \
  '{"kv_connector": "MooncakeConnectorV2", "kv_role": "kv_producer", "kv_port": "36680"}'

启动 2 个 DP2/TP8 Prefill 引擎。--dp-address 使用 Prefill 节点的 IP 地址,启动器分配 API 端口 9081-9082。

python launch_online_dp.py \
  --template ./run_p.sh \
  --dp-size 2 \
  --tp-size 8 \
  --dp-address "<PREFILL_NODE_IP>" \
  --vllm-start-port 9081

启动 Decode 节点

在 Decode 节点上,将以下脚本保存为 run_d.sh。Decode 为目标模型使用 FULL_DECODE_ONLY 图模式,为 MTP 草稿模型启用图模式,并启用 FlashComm1。

#!/usr/bin/env bash
# Usage is the same as run_p.sh.

# This Atlas 800I A3 supernode uses HCCS; its device RoCE ports are down.
export ASCEND_GLOBAL_RESOURCE_CONFIG='{"comm_resource_config.protocol_desc":["hccs:device"]}'
export ASCEND_LOCAL_COMM_RES='{"version":"1.2"}'

LOCAL_IP="<DECODE_NODE_IP>"
NIC_NAME="<NETWORK_INTERFACE>"
MODEL_PATH="<YOUR_MODEL_PATH>"

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 PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export VLLM_USE_V2_MODEL_RUNNER=0
export HCCL_OP_EXPANSION_MODE=AIV
export HCCL_BUFFSIZE=1024
export ASCEND_RT_VISIBLE_DEVICES="$1"

exec vllm serve "$MODEL_PATH" \
  --host 0.0.0.0 \
  --port "$2" \
  --data-parallel-size "$3" \
  --data-parallel-rank "$4" \
  --data-parallel-address "$5" \
  --data-parallel-rpc-port "$6" \
  --tensor-parallel-size "$7" \
  --enable-expert-parallel \
  --seed 1024 \
  --served-model-name glm \
  --safetensors-load-strategy prefetch \
  --max-num-seqs 32 \
  --max-model-len 1048576 \
  --max-num-batched-tokens 192 \
  --trust-remote-code \
  --quantization ascend \
  --limit-mm-per-prompt '{"image":1,"video":0}' \
  --gpu-memory-utilization 0.92 \
  --tool-call-parser glm47 \
  --reasoning-parser glm45 \
  --enable-auto-tool-choice \
  --kv-cache-dtype int8 \
  --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
  --speculative-config '{"num_speculative_tokens": 5, "method": "deepseek_mtp", "enforce_eager": false}' \
  --additional-config '{
    "multistream_overlap_shared_expert": true,
    "recompute_scheduler_enable": true,
    "enable_flashcomm1": true
  }' \
  --kv-transfer-config \
  '{"kv_connector": "MooncakeConnectorV2", "kv_role": "kv_consumer", "kv_port": "36580"}'

启动 8 个 DP8/TP2 Decode 引擎。--dp-address 使用 Decode 节点的 IP 地址,启动器分配 API 端口 9900-9907。

python launch_online_dp.py \
  --template ./run_d.sh \
  --dp-size 8 \
  --tp-size 2 \
  --dp-address "<DECODE_NODE_IP>" \
  --vllm-start-port 9900

部署 PD 代理

所有 Prefill 和 Decode 引擎就绪后,在 Prefill 容器中打开另一个终端,启动负载均衡代理。代理监听端口 8081,将请求分发至 Prefill 端点 9081-9082,再将 Decode 工作转发至端点 9900-9907。

#!/usr/bin/env bash

P_IP="${P_IP:-<PREFILL_NODE_IP>}"
P_N=${P_N:-2}
P_PORT0=${P_PORT0:-9081}
D_IP="${D_IP:-<DECODE_NODE_IP>}"
D_N=${D_N:-8}
D_PORT0=${D_PORT0:-9900}

unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY all_proxy
python /vllm-workspace/vllm-ascend/examples/disaggregated_prefill_v1/load_balance_proxy_server_example.py \
  --host 0.0.0.0 \
  --port 8081 \
  --prefiller-hosts $(printf "$P_IP %.0s" $(seq 1 "$P_N")) \
  --prefiller-ports $(seq "$P_PORT0" $((P_PORT0 + P_N - 1))) \
  --decoder-hosts $(printf "$D_IP %.0s" $(seq 1 "$D_N")) \
  --decoder-ports $(seq "$D_PORT0" $((D_PORT0 + D_N - 1)))

关键参数说明

  • --data-parallel-size 和 --tensor-parallel-size 分别指定 Prefill 的 DP2/TP8 和 Decode 的 DP8/TP2 布局。两种布局均使用各自 Atlas 800I A3 节点的全部 16 个逻辑设备。
  • --data-parallel-address 和 --data-parallel-rpc-port 协调同一角色内的 DP rank。Prefill 和 Decode 使用各自节点的 IP 地址。由于两个角色运行在不同主机上,可以复用默认 RPC 端口 12325。
  • --vllm-start-port 9081 为 Prefill 分配 API 端口 9081-9082,--vllm-start-port 9900 为 Decode 分配端口 9900-9907。代理必须能够访问所有端点。
  • 两个角色均使用 --max-model-len 1048576、--kv-cache-dtype int8,以及包含 5 个推测 Token 的 MTP 推测解码。MTP 草稿模型在 Prefill 上使用 enforce_eager: true,在 Decode 上使用 enforce_eager: false。
  • VLLM_USE_V2_MODEL_RUNNER=0 为此配置的两个角色显式选择 model runner V1。
  • Prefill 使用 --max-num-seqs 64 和 --max-num-batched-tokens 4096,Decode 使用 --max-num-seqs 32 和 --max-num-batched-tokens 192。请根据目标工作负载分别调整两个角色的调度限制。
  • Prefill 设置 --prefix-cache-retention-interval None。部署 KV Cache 池时,请按照第 5.4 节调整前缀缓存配置。
  • Decode 使用 FULL_DECODE_ONLY 图模式。两个角色均显式启用 FlashComm1。
  • Prefill 设置 enable_dsa_cp: true、enable_prefill_mc2: true、enable_fused_mc2: 1 和 enable_shared_expert_dp: true,同时设置 multistream_overlap_shared_expert: false。Decode 设置 multistream_overlap_shared_expert: true 和 recompute_scheduler_enable: true。
  • Prefill 和 Decode 均使用 --limit-mm-per-prompt '{"image":1,"video":0}',每个提示词最多允许 1 张图像,并禁用视频输入。
  • MooncakeConnectorV2 在两个角色之间传输 KV cache。Prefill 的 kv_role 必须为 kv_producer,Decode 必须为 kv_consumer。各角色的 KV 端口必须在各自主机上可用。
  • ASCEND_GLOBAL_RESOURCE_CONFIG 选择 hccs:device,ASCEND_LOCAL_COMM_RES 为该 HCCS 超节点设置资源配置版本 1.2。HCCL_IF_IP 和所有 socket 接口变量必须选择所配置节点 IP 所在的主机网络。主机防火墙必须允许 DP RPC、引擎、Mooncake 和代理端口。

本示例使用四台 Atlas 800I A2(64GB × 8)服务器:两个 Prefill 节点各运行 1 个使用 TP8 的 DP rank(全局为 DP2/TP8),两个 Decode 节点各运行 4 个使用 TP2 的 DP rank(全局为 DP8/TP2)。每个 Prefill rank 使用 8 个设备,每个 Decode rank 使用 2 个设备,各服务器上的本地 rank 合计使用全部 8 个设备。MooncakeConnectorV2 将 KV cache 从 Prefill 引擎传输至 Decode 引擎。拓扑中两个 Prefill 节点分别命名为 P0/P1,两个 Decode 节点分别命名为 D0/D1。P0 提供 Prefill API 端点,P1 以 headless 模式运行。代理访问两个 Decode 节点上的 API 端点。

第 5.2.1 节中的共享启动器 launch_online_dp.py 用于在全部四个节点上启动引擎。请将以下通用服务模板和各节点的包装脚本分别保存到对应节点,并替换所有 IP、网卡名称和模型路径占位符。

通用 Prefill 模板

将以下脚本保存为 P0 和 P1 上的 run_p.sh。下方的节点包装脚本提供 LOCAL_IP 及 API/headless 角色。

#!/usr/bin/env bash
# Usage: bash run_p.sh <visible_devices> <http_port> <dp_size> \
#   <dp_rank> <dp_address> <rpc_port> <tp_size>

: "${LOCAL_IP:?Set LOCAL_IP in the P0 or P1 wrapper}"
: "${NIC_NAME:?Set NIC_NAME in the P0 or P1 wrapper}"
: "${MODEL_PATH:?Set MODEL_PATH in the P0 or P1 wrapper}"

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 VLLM_HOST_IP="$LOCAL_IP"
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export VLLM_USE_V2_MODEL_RUNNER=0
export HCCL_OP_EXPANSION_MODE=AIV
export HCCL_BUFFSIZE=1024
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=3000
export HCCL_EXEC_TIMEOUT=3600
export HCCL_CONNECT_TIMEOUT=1200
export VLLM_RPC_TIMEOUT=3600000
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=10
export ASCEND_RT_VISIBLE_DEVICES="$1"

exec vllm serve "$MODEL_PATH" \
  --host 0.0.0.0 \
  --port "$2" \
  --data-parallel-size "$3" \
  --data-parallel-rank "$4" \
  --data-parallel-address "$5" \
  --data-parallel-rpc-port "$6" \
  --tensor-parallel-size "$7" \
  --enable-expert-parallel \
  --enable-chunked-prefill \
  --enable-prefix-caching \
  --seed 1024 \
  --served-model-name glm \
  --safetensors-load-strategy prefetch \
  --max-model-len 200000 \
  --max-num-seqs 64 \
  --max-num-batched-tokens 8192 \
  --trust-remote-code \
  --quantization ascend \
  --gpu-memory-utilization 0.92 \
  --async-scheduling \
  --enforce-eager \
  --tool-call-parser glm47 \
  --reasoning-parser glm45 \
  --enable-auto-tool-choice \
  --speculative-config '{"num_speculative_tokens": 3, "method": "deepseek_mtp", "enforce_eager": true}' \
  ${SERVER_ROLE_ARGS:-} \
  --kv-transfer-config '{
    "kv_connector": "MooncakeConnectorV2",
    "kv_role": "kv_producer",
    "kv_port": "30000",
    "kv_connector_extra_config": {
      "use_ascend_direct": true,
      "prefill": {"dp_size": 2, "tp_size": 8},
      "decode": {"dp_size": 8, "tp_size": 2}
    }
  }'

P0 和 P1 包装脚本

将以下 run_p0.sh 保存到 P0。P0 提供 Prefill API 端点。

#!/usr/bin/env bash
export LOCAL_IP="<PREFILL_NODE0_IP>"
export NIC_NAME="<PREFILL_NODE0_NIC>"
export MODEL_PATH="<YOUR_MODEL_PATH>"
export SERVER_ROLE_ARGS="--api-server-count 1"
exec bash ./run_p.sh "$@"

将以下 run_p1.sh 保存到 P1。P1 是以 headless 模式运行的 Prefill rank。

#!/usr/bin/env bash
export LOCAL_IP="<PREFILL_NODE1_IP>"
export NIC_NAME="<PREFILL_NODE1_NIC>"
export MODEL_PATH="<YOUR_MODEL_PATH>"
export SERVER_ROLE_ARGS="--headless"
exec bash ./run_p.sh "$@"

使用共享启动器启动两个 Prefill rank:

# P0
python launch_online_dp.py \
  --template ./run_p0.sh \
  --dp-size 2 \
  --tp-size 8 \
  --dp-size-local 1 \
  --dp-rank-start 0 \
  --dp-address "<PREFILL_NODE0_IP>" \
  --dp-rpc-port 12321 \
  --vllm-start-port 9081

# P1
python launch_online_dp.py \
  --template ./run_p1.sh \
  --dp-size 2 \
  --tp-size 8 \
  --dp-size-local 1 \
  --dp-rank-start 1 \
  --dp-address "<PREFILL_NODE0_IP>" \
  --dp-rpc-port 12321 \
  --vllm-start-port 9082

通用 Decode 模板

将以下 run_d.sh 保存到 D0 和 D1。Decode 为目标模型使用 FULL_DECODE_ONLY 图模式,并保持 FlashComm1 禁用。下方的节点包装脚本提供 LOCAL_IP。

#!/usr/bin/env bash
# Usage: bash run_d.sh <visible_devices> <http_port> <dp_size> \
#   <dp_rank> <dp_address> <rpc_port> <tp_size>

: "${LOCAL_IP:?Set LOCAL_IP in the D0 or D1 wrapper}"
: "${NIC_NAME:?Set NIC_NAME in the D0 or D1 wrapper}"
: "${MODEL_PATH:?Set MODEL_PATH in the D0 or D1 wrapper}"

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 VLLM_HOST_IP="$LOCAL_IP"
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True,pin_memory_expandable_segments:True
export VLLM_USE_V2_MODEL_RUNNER=0
export HCCL_OP_EXPANSION_MODE=AIV
export HCCL_BUFFSIZE=1024
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=3000
export HCCL_EXEC_TIMEOUT=3600
export HCCL_CONNECT_TIMEOUT=1200
export VLLM_RPC_TIMEOUT=3600000
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=10
# Reserve disjoint HCCL port ranges per DP rank so multiple engines on
# one node never share host/NPU socket ports.
export HCCL_HOST_SOCKET_PORT_RANGE="$((60000 + $4 * 100))-$((60099 + $4 * 100))"
export HCCL_NPU_SOCKET_PORT_RANGE="$((60000 + $4 * 100))-$((60099 + $4 * 100))"
export ASCEND_RT_VISIBLE_DEVICES="$1"

exec vllm serve "$MODEL_PATH" \
  --host 0.0.0.0 \
  --port "$2" \
  --data-parallel-size "$3" \
  --data-parallel-rank "$4" \
  --data-parallel-address "$5" \
  --data-parallel-rpc-port "$6" \
  --tensor-parallel-size "$7" \
  --enable-expert-parallel \
  --enable-chunked-prefill \
  --enable-prefix-caching \
  --seed 1024 \
  --served-model-name glm \
  --safetensors-load-strategy prefetch \
  --max-model-len 200000 \
  --max-num-seqs 32 \
  --max-num-batched-tokens 1024 \
  --trust-remote-code \
  --quantization ascend \
  --gpu-memory-utilization 0.85 \
  --skip-mm-profiling \
  --limit-mm-per-prompt '{"image":1,"video":0}' \
  --async-scheduling \
  --tool-call-parser glm47 \
  --reasoning-parser glm45 \
  --enable-auto-tool-choice \
  --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
  --speculative-config '{"num_speculative_tokens": 3, "method": "deepseek_mtp", "enforce_eager": true}' \
  --kv-transfer-config '{
    "kv_connector": "MooncakeConnectorV2",
    "kv_role": "kv_consumer",
    "kv_port": "30100",
    "kv_connector_extra_config": {
      "use_ascend_direct": true,
      "prefill": {"dp_size": 2, "tp_size": 8},
      "decode": {"dp_size": 8, "tp_size": 2}
    }
  }'

D0 和 D1 包装脚本

将以下 run_d0.sh 保存到 D0:

#!/usr/bin/env bash
export LOCAL_IP="<DECODE_NODE0_IP>"
export NIC_NAME="<DECODE_NODE0_NIC>"
export MODEL_PATH="<YOUR_MODEL_PATH>"
exec bash ./run_d.sh "$@"

将以下 run_d1.sh 保存到 D1:

#!/usr/bin/env bash
export LOCAL_IP="<DECODE_NODE1_IP>"
export NIC_NAME="<DECODE_NODE1_NIC>"
export MODEL_PATH="<YOUR_MODEL_PATH>"
exec bash ./run_d.sh "$@"

在每个 Decode 节点上启动 4 个 DP8/TP2 引擎。D0 的 --dp-rank-start 为 0,D1 为 4。两个节点的 --dp-address 均为 D0 的 IP 地址,启动器为每个节点分配 API 端口 9900-9903。

# D0
python launch_online_dp.py \
  --template ./run_d0.sh \
  --dp-size 8 \
  --tp-size 2 \
  --dp-size-local 4 \
  --dp-rank-start 0 \
  --dp-address "<DECODE_NODE0_IP>" \
  --vllm-start-port 9900

# D1
python launch_online_dp.py \
  --template ./run_d1.sh \
  --dp-size 8 \
  --tp-size 2 \
  --dp-size-local 4 \
  --dp-rank-start 4 \
  --dp-address "<DECODE_NODE0_IP>" \
  --vllm-start-port 9900

启动顺序

按以下顺序启动服务:各组的第一个节点、其余节点、代理。

  1. 完成全部四个节点的容器及多节点通信检查。
  2. 使用上方的启动器命令启动 P0(--dp-rank-start 0)。P0 提供 Prefill API 端点,并作为 Prefill DP 主节点。
  3. 使用对应的启动器命令启动 D0(--dp-rank-start 0)。D0 作为 Decode DP 主节点,并提供 4 个 API 端点。
  4. 启动 P0 和 D0 后,立即使用各自的命令启动 P1 和 D1(--dp-rank-start 1 和 --dp-rank-start 4)。每个 DP 组在其全部 rank 启动后完成初始化。
  5. 全部 10 个引擎就绪后,使用 curl http://127.0.0.1:<port>/v1/models 验证 P0、D0 和 D1 上的 API 端点,并检查 headless 节点 P1 的初始化日志。启动代理,然后向 <PREFILL_NODE0_IP>:8081 发送请求。

部署 PD 代理

在任一 Prefill 容器中打开另一个终端,启动负载均衡代理。代理监听端口 8081,将 Prefill 请求发送至 P0 API 端点,并将 Decode 工作转发至 8 个 Decode 端点。

#!/usr/bin/env bash

P0_IP="${P0_IP:-<PREFILL_NODE0_IP>}"
D0_IP="${D0_IP:-<DECODE_NODE0_IP>}"
D1_IP="${D1_IP:-<DECODE_NODE1_IP>}"

unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY all_proxy
python /vllm-workspace/vllm-ascend/examples/disaggregated_prefill_v1/load_balance_proxy_server_example.py \
  --host 0.0.0.0 \
  --port 8081 \
  --prefiller-hosts "$P0_IP" \
  --prefiller-ports 9081 \
  --decoder-hosts "$D0_IP" "$D0_IP" "$D0_IP" "$D0_IP" "$D1_IP" "$D1_IP" "$D1_IP" "$D1_IP" \
  --decoder-ports 9900 9901 9902 9903 9900 9901 9902 9903

与 Atlas 800I A3 布局相比的关键参数差异

  • Atlas 800I A2 使用与 Atlas 800I A3 相同的全局 Prefill DP2/TP8 和 Decode DP8/TP2 配置,但每个角色分布在两个各有 8 个设备的节点上。Atlas 800I A3 的每个角色运行在一个具有 16 个逻辑设备的节点上。
  • P0 和 P1 使用共享启动器,每个节点运行 1 个本地 DP rank。P0 通过 --api-server-count 1 提供 Prefill API;P1 以 headless 模式运行。D0 和 D1 通过各自的节点包装脚本,各运行 4 个提供 API 服务的 DP8/TP2 引擎。
  • kv_connector_extra_config 启用 use_ascend_direct,直接在 NPU 之间传输 KV,并声明实际的 Prefill 和 Decode {dp_size, tp_size} 拓扑。声明的值必须与实际部署一致。
  • Prefill 使用 --max-num-seqs 64、--max-num-batched-tokens 8192 和 --enforce-eager;Decode 使用 --max-num-seqs 32、--max-num-batched-tokens 1024 和 FULL_DECODE_ONLY 图模式。两个角色均使用 --async-scheduling。
  • 两个角色均通过 VLLM_USE_V2_MODEL_RUNNER=0 使用 model runner V1,与本指南其他标签页一致。VLLM_HOST_IP 指定其他引擎在 KV 传输时用于访问本引擎的 IP 地址。
  • Atlas 800I A2 上的 MTP 推测解码使用 3 个推测 Token。enforce_eager: true 使 MTP 草稿模型使用 eager 模式。
  • Decode 上的 HCCL_HOST_SOCKET_PORT_RANGE 和 HCCL_NPU_SOCKET_PORT_RANGE 为每个 DP rank 预留互不重叠的 100 个端口(起始端口为 60000 + rank * 100)。当多个引擎共用一个节点时,这些端口范围可避免 HCCL 主机侧 socket 在不同 rank 之间意外共用端口,导致引擎启动阻塞。
  • 其余超时和运行时变量(VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS、HCCL_EXEC_TIMEOUT、HCCL_CONNECT_TIMEOUT、VLLM_RPC_TIMEOUT、OMP_PROC_BIND、OMP_NUM_THREADS)是针对该模型规模验证过的 Atlas 800I A2 启动默认值。除非环境要求其他值,否则请保持这些设置。
  • HCCL_IF_IP 和所有 socket 接口变量必须选择所配置节点 IP 使用的服务网络。主机防火墙必须允许 DP RPC、引擎、Mooncake 和代理端口。

5.4 使用 KV Cache 池的 Prefill-Decode 分离部署

本节在 Atlas 800I A3 上使用 Memcache 后端,在 Atlas 800I A2 上使用 Mooncake 后端。请选择与第 5.3 节中的 PD 拓扑对应的平台说明。两个平台均使用 MultiConnector 组合以下两个连接器:

  • MooncakeConnectorV2 继续将 KV cache 从 Prefill 传输至 Decode。
  • AscendStoreConnector 支持 Prefill 在 KV Cache 池中查询、加载和保存缓存前缀,减少重复的 Prefill 计算。

有关后端安装、硬件依赖、内存大小、缓存淘汰和租户选项,请参阅 KV Cache 池部署指南。

复用第 5.3 节中的 Atlas 800I A3 Prefill DP2/TP8 和 Decode DP8/TP2 拓扑、启动器及代理端点映射。

准备 Memcache 后端

请按照场景 2:Memcache 后端完成前置检查和内存大小配置。Atlas 800I A3 HCCS 配置使用 device_sdma,需要灵衢计算网络 1.5 或更高版本。还需检查指南中HDK 和 CANN 版本兼容性参考列出的 HDK 和 CANN 要求。在 Prefill 和 Decode 两个节点上启动 Atlas 800I A3 容器时,必须在第 4.1 节的 Docker 启动命令中配置以下只读挂载:

-v /etc/hccn.conf:/etc/hccn.conf:ro \

第 4.1 节的 Docker 镜像已经包含 memfabric-hybrid 和 memcache-hybrid。在每个容器中定位已安装的 Memcache 包:

pip show memcache_hybrid

pip show 输出中的 Location 字段对应以下命令中的 <PYTHON_SITE_PACKAGES>。请将 <CONFIG_DIRECTORY> 替换为各节点上存放配置文件的绝对路径。

本示例在 Prefill 和 Decode 两个节点的 DDR 内存中存储池化 KV cache。Memcache LocalService 在各个 vLLM worker 内部初始化,每个 worker 向池中贡献 20GB DDR 内存。Decode 通过 MooncakeConnectorV2 接收 KV cache。

在 Prefill 节点上创建 mmc-meta.conf:

ock.mmc.meta_service_url = tcp://<PREFILL_NODE_IP>:5000
ock.mmc.meta_service.config_store_url = tcp://<PREFILL_NODE_IP>:6000
ock.mmc.meta_service.metrics_url = http://<PREFILL_NODE_IP>:8000
ock.mmc.log_level = info

在 Prefill 和 Decode 两个节点上创建以下 mmc-local.conf:

ock.mmc.meta_service_url = tcp://<PREFILL_NODE_IP>:5000
ock.mmc.local_service.config_store_url = tcp://<PREFILL_NODE_IP>:6000
ock.mmc.log_level = info
ock.mmc.local_service.world_size = 256
ock.mmc.local_service.protocol = device_sdma
ock.mmc.local_service.dram.size = 20GB
ock.mmc.local_service.max.dram.size = 1024GB
ock.mmc.local_service.storage.enabled = false

dram.size 指定为每个 worker 分配的 DDR 容量。Prefill(DP2/TP8)和 Decode(DP8/TP2)各启动 16 个 worker。每个 worker 分配 20GB 时,每个节点贡献 320GB,DDR 池总容量为 640GB。请为操作系统和 vLLM 预留足够的 DDR 内存。使用 device_sdma 时,每个非零容量值均需按 1GB 对齐。

world_size 是 Memcache 支持的最大 LocalService 数量。所有 worker 的配置必须一致,且足以容纳本部署中的 32 个 worker。

添加池化环境变量

在 run_p.sh 和 run_d.sh 中,保留第 5.3 节的环境变量,并在 exec vllm serve 前添加以下导出语句:

MEMCACHE_PACKAGE_DIR="<PYTHON_SITE_PACKAGES>/memcache_hybrid"
PYTHON_LIB_DIR="$(python -c 'import sysconfig; print(sysconfig.get_config_var("LIBDIR"))')"

export PYTHONHASHSEED=0
export MMC_LOCAL_CONFIG_PATH="<CONFIG_DIRECTORY>/mmc-local.conf"
export LD_LIBRARY_PATH="${MEMCACHE_PACKAGE_DIR}/lib:${PYTHON_LIB_DIR}:${LD_LIBRARY_PATH:-}"

# Atlas 800I A3 HCCS fabric-memory pooling.
export ACL_OP_INIT_MODE=1
export ASCEND_ENABLE_USE_FABRIC_MEM=1

两个节点须使用相同的 PYTHONHASHSEED 和 Memcache 服务端点。请保留第 5.3 节的 HCCS 通信设置,包括 ASCEND_GLOBAL_RESOURCE_CONFIG 和 ASCEND_LOCAL_COMM_RES。

更新 Prefill 和 Decode 连接器

部署 Atlas 800I A3 KV Cache 池时,请在第 5.3 节的 run_p.sh 和 run_d.sh 中添加 --enable-prefix-caching,并保持分块预填充启用(模型默认行为)。GLM-5.3-Flash 包含线性注意力状态,AscendStoreConnector 要求 mamba_cache_mode=align;启用前缀缓存后,模型配置会选择此模式。此配置需要保持混合 KV cache 管理器启用,并禁用 use_layerwise。

将 run_p.sh 最后的 --kv-transfer-config 参数替换为以下片段。除上述前缀缓存调整外,请保留第 5.3 节中的其他 Atlas 800I A3 Prefill 参数,包括 --max-num-seqs 64。

  --kv-transfer-config \
  '{
    "kv_connector": "MultiConnector",
    "kv_role": "kv_producer",
    "engine_id": "glm53-flash-prefill-dp'"$4"'",
    "kv_connector_extra_config": {
      "connectors": [
        {
          "kv_connector": "MooncakeConnectorV2",
          "kv_role": "kv_producer",
          "kv_port": "36680"
        },
        {
          "kv_connector": "AscendStoreConnector",
          "kv_role": "kv_producer",
          "kv_connector_extra_config": {
            "backend": "memcache",
            "memcache_dp_init_barrier": true,
            "use_layerwise": false,
            "lookup_rpc_port": '"$((37000 + $4))"'
          }
        }
      ]
    }
  }'

将 run_d.sh 最后的 --kv-transfer-config 参数替换为以下片段。除上述前缀缓存调整外,请保留第 5.3 节中的其他 Atlas 800I A3 Decode 参数,包括 FULL_DECODE_ONLY 图模式和 MTP 配置。

  --kv-transfer-config \
  '{
    "kv_connector": "MultiConnector",
    "kv_role": "kv_consumer",
    "engine_id": "glm53-flash-decode-dp'"$4"'",
    "kv_connector_extra_config": {
      "connectors": [
        {
          "kv_connector": "MooncakeConnectorV2",
          "kv_role": "kv_consumer",
          "kv_port": "36580"
        },
        {
          "kv_connector": "AscendStoreConnector",
          "kv_role": "kv_consumer",
          "kv_connector_extra_config": {
            "backend": "memcache",
            "memcache_dp_init_barrier": true,
            "use_layerwise": false,
            "consumer_is_to_load": false,
            "consumer_is_to_put": false,
            "lookup_rpc_port": '"$((37100 + $4))"'
          }
        }
      ]
    }
  }'

$4 是 launch_online_dp.py 传入的 DP rank。每个引擎必须具有唯一的 engine_id 和 lookup_rpc_port;子连接器继承外层的 engine_id。Prefill 的查询端口为 37000-37001,Decode 为 37100-37107。请保留第 5.3 节中各角色的 Mooncake KV 基础端口,其 worker 和调度器会根据拓扑计算各自的端口。

每个 DP 组的所有 rank 均须将 memcache_dp_init_barrier 设置为 true。它在 Memcache 初始化后、NPU 图捕获前同步 worker。请如上所示,将该参数设置在 AscendStoreConnector 子连接器中。

启动服务

按以下顺序启动服务:Memcache MetaService、Decode、Prefill、代理。每个 vLLM worker 会在启动期间初始化自己的 Memcache LocalService。

  1. 在 Prefill 容器中的独立终端启动 MetaService。确保两个节点均可访问端口 5000 和 6000,且指标端口 8000 可用。
MEMCACHE_PACKAGE_DIR="<PYTHON_SITE_PACKAGES>/memcache_hybrid"
PYTHON_LIB_DIR="$(python -c 'import sysconfig; print(sysconfig.get_config_var("LIBDIR"))')"
export LD_LIBRARY_PATH="${MEMCACHE_PACKAGE_DIR}/lib:${PYTHON_LIB_DIR}:${LD_LIBRARY_PATH:-}"
export MMC_META_CONFIG_PATH="<CONFIG_DIRECTORY>/mmc-meta.conf"
python -c "from memcache_hybrid import MetaService; MetaService.main()"
  1. 使用第 5.3 节中的 Atlas 800I A3 启动器命令启动 Decode,等待端口 9900-9907 上的全部 8 个 Decode 引擎就绪,且其 Memcache LocalService 已预留配置的 DDR 池内存。
  2. 使用第 5.3 节中的 Atlas 800I A3 启动器命令启动 Prefill,等待端口 9081-9082 上的两个 Prefill 引擎就绪,且其 Memcache LocalService 已预留配置的 DDR 池内存。
  3. 启动第 5.3 节中的 Atlas 800I A3 代理,使用第 6 节的示例向 <PREFILL_NODE_IP>:8081 发送推理请求。

验证 KV Cache 复用

通过代理发送长度超过一个缓存块的提示词以预热缓存池,然后重复发送具有相同前缀的请求。检查 Prefill 输出,确认缓存池保存、查询、加载和缓存命中成功;检查 Decode 输出,确认 P→D 传输成功。

代理在两个 Prefill 引擎之间分发请求。重复请求也可能命中某个引擎的本地前缀缓存,因此需要在另一个 Prefill rank 上确认缓存池加载或命中信息,以验证共享池复用。只有完整且可缓存的块会被复用,末尾不完整的块仍可能需要计算。

复用第 5.3 节中的 launch_online_dp.py 启动器、P0/P1 和 D0/D1 脚本、Prefill DP2/TP8 和 Decode DP8/TP2 拓扑,以及代理配置。Atlas 800I A2 节点不具备 Atlas 800I A3 HCCS 网络,缓存池通过 Atlas 800I A2 RoCE 网络运行,使用 P2PHANDSHAKE 元数据服务器和 ascend 协议,不适用 Atlas 800I A3 的 fabric 内存环境变量。

有关后端安装、内存大小、缓存淘汰和租户选项,请参阅 KV Cache 池部署指南。

准备 Mooncake 配置

第 4.1 节中的 Atlas 800I A2 Docker 命令已挂载 /etc/hccn.conf。请按照 KV Cache 池部署指南安装 Mooncake 后端,然后在两个 Prefill 节点上创建以下 mooncake.json。Mooncake Master 运行在第一个 Prefill 容器中,地址为 <PREFILL_NODE0_IP>:50088。

{
  "metadata_server": "P2PHANDSHAKE",
  "protocol": "ascend",
  "device_name": "",
  "master_server_address": "<PREFILL_NODE0_IP>:50088",
  "global_segment_size": "8GB",
  "preferred_segment": true,
  "prefer_alloc_in_same_node": true,
  "enable_ssd_offload": false,
  "tenant_id": "default"
}

两个 Decode 节点使用相同的 JSON 配置,但将 global_segment_size 设置为 0。全部四个节点须使用相同的 tenant_id。global_segment_size 按 worker 注册:DP2/TP8 分布在两个 Prefill 节点上,每个节点启动 8 个 worker。验证过的示例为每个 worker 分配 8GB,池总容量为 128GB。请根据可用主机内存调整每个 worker 的容量,并保持每个非零段大小按 1GB 对齐。Decode 的 mooncake.json 中应保持 global_segment_size 为 0。

添加池化环境变量

在 run_p.sh 和 run_d.sh 中,保留第 5.3 节的环境变量,并在 exec vllm serve 前添加以下导出语句。请将 <CONFIG_DIRECTORY> 替换为该节点上存放 mooncake.json 的绝对路径。

export PYTHONHASHSEED=0
export MOONCAKE_CONFIG_PATH="<CONFIG_DIRECTORY>/mooncake.json"

所有节点必须使用相同的 PYTHONHASHSEED。不要添加 Atlas 800I A3 的 ASCEND_ENABLE_USE_FABRIC_MEM 导出语句,它仅适用于 Atlas 800I A3 HCCS 网络。KV Cache 池部署指南的通用 Atlas 800I A2 配置还建议使用大页和 HCCL_INTRA_ROCE_ENABLE;使用 P2PHANDSHAKE 元数据服务器和 ascend 协议时不需要这些设置,验证过的配置也未设置它们。

更新 Prefill 和 Decode 连接器

保持前缀缓存和分块预填充启用。此模型的 use_layerwise 必须保持为 false:GLM-5.3-Flash 的混合 KV cache 包含不可进行前缀缓存的组,而逐层缓存池传输要求所有组均可缓存,因此缓存池按整段存储和加载。也无需手动设置 --mamba-cache-mode 参数:连接器列表包含 AscendStoreConnector 时,引擎会自动将 mamba 缓存模式切换为 align。

将 run_p.sh 最后的 --kv-transfer-config 参数替换为以下片段。请保留第 5.3 节中的其他 Prefill 参数,包括 --max-num-seqs 64。

  --kv-transfer-config \
  '{
    "kv_connector": "MultiConnector",
    "kv_role": "kv_producer",
    "engine_id": "glm53-flash-prefill-dp'"$4"'",
    "kv_connector_extra_config": {
      "connectors": [
        {
          "kv_connector": "MooncakeConnectorV2",
          "kv_role": "kv_producer",
          "kv_port": "30000",
          "kv_connector_extra_config": {
            "use_ascend_direct": true,
            "prefill": {"dp_size": 2, "tp_size": 8},
            "decode": {"dp_size": 8, "tp_size": 2}
          }
        },
        {
          "kv_connector": "AscendStoreConnector",
          "kv_role": "kv_producer",
          "kv_connector_extra_config": {
            "backend": "mooncake",
            "use_layerwise": false,
            "lookup_rpc_port": '"$((37000 + $4))"'
          }
        }
      ]
    }
  }'

将 run_d.sh 最后的 --kv-transfer-config 参数替换为以下片段。请保留第 5.3 节中的其他 Decode 参数,包括 FULL_DECODE_ONLY 图模式和 MTP 配置。

  --kv-transfer-config \
  '{
    "kv_connector": "MultiConnector",
    "kv_role": "kv_consumer",
    "engine_id": "glm53-flash-decode-dp'"$4"'",
    "kv_connector_extra_config": {
      "connectors": [
        {
          "kv_connector": "MooncakeConnectorV2",
          "kv_role": "kv_consumer",
          "kv_port": "30100",
          "kv_connector_extra_config": {
            "use_ascend_direct": true,
            "prefill": {"dp_size": 2, "tp_size": 8},
            "decode": {"dp_size": 8, "tp_size": 2}
          }
        },
        {
          "kv_connector": "AscendStoreConnector",
          "kv_role": "kv_consumer",
          "kv_connector_extra_config": {
            "backend": "mooncake",
            "use_layerwise": false,
            "consumer_is_to_load": false,
            "consumer_is_to_put": false,
            "lookup_rpc_port": '"$((37100 + $4))"'
          }
        }
      ]
    }
  }'

两个角色模板均使用启动器传入的 DP rank 参数 $4 生成 engine_id 后缀和查询端口。每个引擎必须具有唯一的 engine_id 和 lookup_rpc_port;子连接器继承外层的 engine_id。Prefill 的查询端口为 37000-37001,Decode 为 37100-37107。MooncakeConnectorV2 片段中声明的 prefill 和 decode 拓扑必须与实际部署一致。

启动服务

按以下顺序启动服务:Mooncake Master → Decode → Prefill → 代理。

  1. 在第一个 Prefill 容器中的独立终端启动 Mooncake Master,确保全部四个节点均可访问端口 50088。
mooncake_master \
  --port 50088 \
  --eviction_high_watermark_ratio 0.9 \
  --eviction_ratio 0.1 \
  --default_kv_lease_ttl 11000 \
  --enable_offload=false \
  --client_ttl=120
  1. 使用第 5.3 节中的启动器命令启动 D0 和 D1(--dp-rank-start 0 和 4;每个节点在端口 9900-9903 上运行 4 个引擎),等待全部 8 个 Decode 引擎均可响应 curl /v1/models。
  2. 使用第 5.3 节中的启动器命令启动 P0 和 P1(--dp-rank-start 0 和 1;P0 在端口 9081 上提供 API 端点,P1 以 headless 模式运行),等待 P0 的 API 端点就绪,且 P1 日志确认初始化成功。
  3. 启动第 5.3 节中的 Atlas 800I A2 代理,使用第 6 节的示例向 <PREFILL_NODE0_IP>:8081 发送推理请求。

验证 KV Cache 复用

按照 Atlas 800I A3 小节中的步骤验证 KV Cache 复用。代理向 P0 API 发送请求,而 DP 组使用两个 Prefill rank。重复请求可能命中本地前缀缓存,因此需要在另一个 Prefill rank 上确认缓存池加载或命中信息,以验证共享池复用。

6 功能验证

所选部署就绪后,请查询对应的服务端点。1P1D PD 部署使用 Prefill 节点 IP 和代理端口 8081;单节点或 Atlas 800I A2 混部部署使用其 vLLM 服务提供的 API 端点。

curl http://<service_ip>:<service_port>/v1/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "glm",
        "prompt": "The future of AI is",
        "max_tokens": 50
    }'

预期结果: 此请求的预期结果是一个 JSON 负载,其中包含模型以 text_completion 格式生成的文本。

{
  "id": "cmpl-123abc",
  "object": "text_completion",
  "created": 1725444000,
  "model": "glm",
  "choices": [
    {
      "text": " incredibly promising, with rapid advancements in machine learning and autonomous systems.",
      "index": 0,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 5,
    "completion_tokens": 15,
    "total_tokens": 20
  }
}

7 精度评估

7.1 使用 AISBench

有关详细说明,请参阅使用 AISBench 进行精度评估。

7.2 PD 分离精度结果

以下精度结果使用第 5.3 节中的 Atlas 800I A3 PD 配置测得,其中 Prefill 节点采用 DP2/TP8,Decode 节点采用 DP8/TP2。评估请求通过 PD 代理发送。下表分别列出各数据集使用的生成参数。

数据集 硬件 分数 generation_kwargs
GPQA Atlas 800I A3 89.9 temperature=1.0, top_p=0.95, max_tokens=131072
MMMU-PRO Atlas 800I A3 78.4 temperature=1.0, top_p=0.95, max_tokens=98304

8 性能评估

8.1 使用 AISBench

有关详细信息,请参阅 使用 AISBench 进行性能评估。

8.2 使用 vLLM Benchmark

有关更多详细信息,请参阅 vllm benchmark。

9 性能调优

9.1 Atlas 800I A3 PD 优化

第 5.3 节的参考配置已启用以下优化。复现部署时,请使用相同的 W8A8 权重和对应角色的配置。

优化项 角色 配置 作用与约束
FlashComm1 Prefill 和 Decode enable_flashcomm1: true 优化张量并行通信。
DSA 上下文并行 Prefill enable_dsa_cp: true 分布式处理长提示词的稀疏注意力计算;使用模型运行器 V1。
Prefill MoE 通信 Prefill enable_prefill_mc2: true, enable_fused_mc2: 1, enable_shared_expert_dp: true 使用参考配置中的 W8A8 权重和 EP16 布局进行融合 MoE 通信;该角色保持 multistream_overlap_shared_expert: false。
共享专家重叠执行 Decode multistream_overlap_shared_expert: true 将共享专家计算与其他工作重叠执行;Decode 配置未启用融合 MC2。
Decode 执行 Decode FULL_DECODE_ONLY 降低解码阶段的启动开销。
MTP Prefill 和 Decode num_speculative_tokens: 5 Prefill 草稿模型保持 eager 模式,Decode 草稿模型启用图执行。
KV 容量 Prefill 和 Decode --kv-cache-dtype int8 减少长上下文场景下的 KV cache 内存消耗。

9.2 按工作负载调优

  • 分别调节各角色的 --max-num-seqs 和 --max-num-batched-tokens。参考配置在 Prefill 上使用 64 条序列和 4096 个批处理 Token,在 Decode 上使用 32 条序列和 192 个批处理 Token。修改这些上限前,请先测量首 Token 时延、每个输出 Token 的时延和吞吐量。
  • 根据所需上下文长度设置 --max-model-len,并根据可用 NPU 内存调节 --gpu-memory-utilization。参考配置在两个角色上均使用 1048576 个 Token 和 0.92 的内存利用率。
  • Decode 启用 recompute_scheduler_enable: true,以便在 Decode KV cache 不足时在 Prefill 上重新计算。Prefill 上应保持禁用。
  • 对于重复前缀,请使用第 5.4 节中的 DDR KV Cache 池配置。Prefill 和 Decode 的每个 worker 均贡献 20GB。评估复用收益时,请确认池命中情况。

10 常见问题

  • 问:如何为 GLM-5.3-Flash 启用函数调用?

答:请在 vLLM 启动命令中添加以下配置

--tool-call-parser glm47 \
--reasoning-parser glm45 \
--enable-auto-tool-choice \
  • 问:GLM-5.3-Flash 是否支持 enable_thinking: false?

答:不支持,GLM-5.3-Flash 不支持 enable_thinking。