| 型号 | 卡数 |
|---|---|
| 910 B3 | 32 |
| 软件名 | 版本 |
|---|---|
| vllm_ascend | v0.11.0rc2 |
| HDK | Ascend HDK 25.2.3 |
| CANN | 8.3.RC2 |
| HCS | 851 |
| 模型系列 | 详细模型 | 下载地址 |
|---|---|---|
| Qwen3 | Qwen3-Coder-480B-w8a8-QuaRot | https://modelers.cn/models/Modelers_Park/Qwen3-Coder-480B-A35B-Instruct-w8a8-QuaRot |
客户环境基于 vllm_ascend部署Qwen3-Coder-480B 四机大EP,需要支持健康检查及故障自动重拉功能,故需要自动化启动脚本。基于以上挑战,基于客户的实际环境给出了大EP部署脚本,以适配MA平台对接vllm_ascend实现Qwen3-Coder-480B大EP推理部署。
MA(管理平台)尚未适配Qwen3-Coder-480B大EP部署的功能,MA生成的global_rank_table表不能直接用于Qwen3-Coder-480B大EP服务部署、且其余大EP所需操作均未脚本化。
脚本自动化,包括 下载权重、ranktable文件生成(需基于MA生成的global_rank_table,提取本机IP,使用生成脚本生成部署所需的ranktable.json)、启动脚本run_dp_template.sh修改、拉起服务等步骤。
完成MA平台Qwen3-Coder-480B自动化脚本部署,完成健康检查探针开发,实现一键拉起大EP服务以及故障自动重拉。
简要描述:安装版本配套依赖关系和客户要求模型,获取对应的权重和MindIE镜像、驱动,注意使用QuaRot后缀结尾的权重以获得较优的精度。
Qwen3-Coder-480B-A35B-Instruct-w8a8-QuaRot
客户环境升级驱动需联系客户侧相关人员操作
简要描述:PD分离部署需确认MA是否支持多机多卡部署。
在"ModelArts" > "部署上线" > "在线服务" 中,单击 "部署",出现 "分布式推理" 开关选项。

简要描述:主要涉及triton(未合入主线版本)的代码手动修改,以提升性能。
**简要描述:**将需要使用但无需频繁修改的脚本打包进镜像,方便后续部署。
将目录的 scripts_merge.zip 解压后添加至镜像的 ~/480b_test/ 目录下
**简要描述:**如果客户要求AI平台不允许使用root角色镜像,则需要基于MindIE官方镜像适配ma-user用户,参考如下Dockerfile制作。
# 使用指定的基础镜像
FROM xxx:xxx
# 创建用户 ma-user 并设置其主目录、用户ID、组ID等
RUN useradd -d /home/ma-user -m -u 1000 -g 100 -s /bin/bash ma-user && \
# 创建模型存储目录
mkdir -p /home/mind/model && \
# 设置目录的所有权
chown -R 1000:100 /home/mind && \
chown -R 1000:100 /usr/local/* && \
# 将默认的 sh 替换为 bash
rm /bin/sh && ln -s /bin/bash /bin/sh
# 设置工作目录
WORKDIR /home/mind/model/
# 切换到新创建的用户
USER ma-user
# 定义容器启动时执行的命令(可选)
# ENTRYPOINT ["/bin/sh","-c","sh run.sh"]注意:如果客户侧允许使用root角色运行镜像,则可省略该步骤。(实测MA851版本可支持root角色启动推理服务)。
将制作好的vllm镜像交由客户上传至MA镜像仓。
简要描述:自动化一键启动脚本,包括 下载权重、ranktable文件生成(需基于MA生成的global_rank_table,提取本机IP,使用生成脚本生成部署所需的ranktable.json)、启动脚本run_dp_template.sh及ip修改。可参考如下脚本。
#!/bin/bash
nic_name="eth0"
export VLLM_VERSION=0.11.0
export HCCL_IF_IP=71.10.29.128 # 本机ip
export GLOO_SOCKET_IFNAME=$nic_name # ifconfig 查询的本机网口
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export DISAGGREGATED_PREFILL_RANK_TABLE_PATH=disaggregated_prefill_v1/ranktable.json # 改成对应ranktable
export VLLM_LOGGING_LEVEL="info"
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=100
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_OP_EXPANSION_MODE="AIV"
export HCCL_BUFFSIZE=1024
export TASK_QUEUE_ENABLE=1
export VLLM_USE_VI=1
export HCCL_OP_RETRY_ENABLE="{L0:0, L1:0, L2:0}"
export ASCEND_RT_VISIBLE_DEVICES=$1
export VLLM_ASCEND_ENABLE_FLASHCOMM=1
export VLLM_TORCH_PROFILER_WITH_STACK=0
export VLLM_TORCH_PROFILER_DIR="/mnt/cache/profiling/"
vllm serve /mnt/cache/Qwen3-Coder-480B-A35B-Instruct-W8A8-QuaRot \
--host 0.0.0.0 \
--enforce-eager \
--port $2 \
--enable-prefix-caching \
--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 Qwen \
--max-model-len 262144 \
--max-num-batched-tokens 4096 \
--max-num-seqs 20 \
--trust-remote-code \
--gpu-memory-utilization 0.92 \
--quantization ascend \
--enable-auto-tool-choice \
--chat-template /vllm-workspace/vllm/examples/tool_chat_template_qwen3coder.jinja \
--tool-call-parser qwen3_coder \
--kv-transfer-config \
'{
"kv_connector": "LLMDataDistCMgrConnector",
"kv_buffer_device": "npu",
"kv_role": "kv_producer",
"kv_parallel_size": "1",
"kv_port": "34569",
"engine_id": "0",
"kv_connector_module_path": "vllm_ascend.distributed.llmdatadist_c_mgr_connector"
}' \
--additional-config '{
"ascend_scheduler_config":{"enabled":false, "enable_chunked_prefill":true},
"enable_cpu_binding":true
}'#!/bin/bash
nic_name="eth0"
export VLLM_VERSION=0.11.0
export HCCL_IF_IP=71.10.29.128 # 本机ip
export GLOO_SOCKET_IFNAME=$nic_name # ifconfig 查询的本机网口
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name
export DISAGGREGATED_PREFILL_RANK_TABLE_PATH=disaggregated_prefill_v1/ranktable.json # 改成对应ranktable
export VLLM_LOGGING_LEVEL="info"
export OMP_PROC_BIND=false
export OMP_NUM_THREADS=100
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_OP_EXPANSION_MODE="AIV"
export HCCL_BUFFSIZE=1024
export TASK_QUEUE_ENABLE=1
export VLLM_USE_VI=1
export HCCL_OP_RETRY_ENABLE="{L0:0, L1:0, L2:0}"
export ASCEND_RT_VISIBLE_DEVICES=$1
export VLLM_ASCEND_ENABLE_FLASHCOMM=1
export VLLM_TORCH_PROFILER_WITH_STACK=0
export VLLM_TORCH_PROFILER_DIR="/mnt/cache/profiling/"
vllm serve /mnt/cache/Qwen3-Coder-480B-A35B-Instruct-W8A8-QuaRot \
--host 0.0.0.0 \
--port $2 \
--enable-prefix-caching \
--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 Qwen \
--max-model-len 262144 \
--max-num-batched-tokens 4096 \
--max-num-seqs 20 \
--trust-remote-code \
--gpu-memory-utilization 0.92 \
--quantization ascend \
--enable-auto-tool-choice \
--chat-template /vllm-workspace/vllm/examples/tool_chat_template_qwen3coder.jinja \
--tool-call-parser qwen3_coder \
--compilation-config '{"cudagraph_capture_sizes":[4,8,12,16,20,40,80],"cudagraph_mode": "FULL_DECODE_ONLY"}' \
--kv-transfer-config \
'{
"kv_connector": "LLMDataDistCMgrConnector",
"kv_buffer_device": "npu",
"kv_role": "kv_consumer",
"kv_parallel_size": "1",
"kv_port": "34569",
"engine_id": "0",
"kv_connector_module_path": "vllm_ascend.distributed.llmdatadist_c_mgr_connector"
}' \
--additional-config '{
"ascend_scheduler_config":{"enabled":false, "enable_chunked_prefill":true},
"enable_cpu_binding":true
}'set -x
echo "server start!"
# 0. 下载权重
mkdir -p /mnt/cache/profiling/
cd /mnt/cache/
WEIGHTS_DIR="Qwen3-Coder-480B-A35B-Instruct-W8A8-QuaRot"
if [ ! -d "$WEIGHTS_DIR" ];then
echo "下载权重"
obsutil config -i=xxx -k=xxx -e=xxx
obsutil cp obs://xxx/Qwen3-Coder-480B-A35B-Instruct-W8A8-QuaRot/ ./ -r -f &
sleep 5m
else
echo "权重目录已存在"
fi
# cp -f /mnt/cache/Qwen3-Coder-480B-A35B-Instruct-W8A8-QuaRot/tokenizer_config.json.raw /mnt/cache/Qwen3-Coder-480B-A35B-Instruct-W8A8-QuaRot/tokenizer_config.json
# 1. 更新生成ranktable.json(需要4台一起生成)
MS_GLOBAL_RANKTABLE_TABLE=/user/global/config/global_rank_table.json
while true; do
json_string=$(cat $MS_GLOBAL_RANKTABLE_TABLE)
echo $json_string
RESULT=$(jq -r '.status' $MS_GLOBAL_RANKTABLE_TABLE 2>/dev/null)
echo $RESULT
if [ "$RESULT" = "completed" ]; then
echo "MA ranktable is completed ;"
break;
fi
sleep 1;
done;
cd ~/480b_test/scripts_merges/disaggregated_prefill_v1
rm -rf ranktable.json
host_IP=$(hostname -i | xargs)
echo "host_IP = $host_IP"
sed -i 's|LOCAL_HOSTS=("71.10.29.128")|LOCAL_HOSTS=("'$host_IP'")|g' ./gen_ranktable.sh
netstat -anop
NODE_IPS=$(jq -r '.server_group_list[].server_list[].server_ip' $MS_GLOBAL_RANKTABLE_TABLE)
echo $NODE_IPS
IFS=$'\n' read -r -d '' -a ip_array <<< "$NODE_IPS"
P0="${ip_array[0]}"
P1="${ip_array[1]}"
D0="${ip_array[2]}"
D1="${ip_array[3]}"
echo "P0 = $P0"
echo "P1 = $P1"
echo "D0 = $D0"
echo "D1 = $D1"
bash gen_ranktable.sh -ips $P0 $P1 $D0 $D1 --npus-per-node 8 --network-card-name eth0 --prefill-device-cnt 16 --decode-device-cnt 16
# 2. 修改run_dp_template.sh环境配置
cd ~/480b_test/scripts_merges/
if [[ "$host_IP" = "$P0" ]] || [[ "$host_IP" = "$P1" ]]; then
echo "pppppp"
cp /mnt/obs/qwen3_coder_480b/scripts/run_dp_template_p.sh run_dp_template.sh
else
echo "ddddddd"
cp /mnt/obs/qwen3_coder_480b/scripts/run_dp_template_d.sh run_dp_template.sh
fi
sed -i 's|HCCL_IF_IP=71.10.29.128|HCCL_IF_IP="'$host_IP'"|g' ./run_dp_template.sh
# 3. 拉起服务
# [dp=4, test=4]
# cp -f /mnt/obs/qwen3_coder_480b/launch_online_dp.py ./
cd ~/480b_test/scripts_merges/
mkdir -p /mnt/cache/480b_log/
if [ "$host_IP" = "$P0" ]; then
echo "p0"
nohup python launch_online_dp.py --dp-size 4 --tp-size 4 --dp-size-local 2 --dp-rank-start 0 --dp-address $P0 --dp-rpc-port 12345 --vllm-start-port 9010 2>&1 | tee /mnt/cache/480b_log/$(date +%Y-%m-%d_%H-%M-%S)_$(hostname)_run.log &
elif [ "$host_IP" = "$P1" ]; then
echo "p1"
nohup python launch_online_dp.py --dp-size 4 --tp-size 4 --dp-size-local 2 --dp-rank-start 2 --dp-address $P0 --dp-rpc-port 12345 --vllm-start-port 9010 2>&1 | tee /mnt/cache/480b_log/$(date +%Y-%m-%d_%H-%M-%S)_$(hostname)_run.log &
elif [ "$host_IP" = "$D0" ]; then
echo "d0"
nohup python launch_online_dp.py --dp-size 4 --tp-size 4 --dp-size-local 2 --dp-rank-start 0 --dp-address $D0 --dp-rpc-port 12345 --vllm-start-port 9010 2>&1 | tee /mnt/cache/480b_log/$(date +%Y-%m-%d_%H-%M-%S)_$(hostname)_run.log &
elif [ "$host_IP" = "$D1" ]; then
echo "d1"
nohup python launch_online_dp.py --dp-size 4 --tp-size 4 --dp-size-local 2 --dp-rank-start 2 --dp-address $D0 --dp-rpc-port 12345 --vllm-start-port 9010 2>&1 | tee /mnt/cache/480b_log/$(date +%Y-%m-%d_%H-%M-%S)_$(hostname)_run.log &
fi
if [ "$host_IP" = "$P0" ]; then
echo "this is p0 and proxy"
echo "http server start!"
timeout 7h python -m http.server 1025
echo "http.server stoped"
echo "start proxy"
cd ~/480b_test/scripts_merges/ &
nohup python disaggregated_prefill_v1/load_balance_proxy_server_example.py \
--host $P0 \
--port 1025 \
--prefiller-hosts $P0 $P0 $P1 $P1 \
--prefiller-port 9010 9011 9010 9011 \
--decoder-hosts $D0 $D0 $D1 $D1 \
--decoder-port 9010 9011 9010 9011 2>&1 | tee /mnt/cache/480b_log/access.log &
echo "server start end!"
sleep 3600000000
fi
python -m http.server 1025
echo "server start end!"
sleep 3600000000将这三份启动脚本 上传至obs的 xxx/scripts/ 目录下。
健康检查脚本需要能够检测服务是否正常运行,通过构造推理请求观察服务端是否正常响应来判断,也需要结合华为云ModelArts一起使用。
健康检查脚本注意点如下:
完整健康检查脚本vllm_probe.py如下:
完整流程会在后续创建AI应用、部署服务中说明,此处简要说明与健康检查相关配置:

注意点说明:
(1) 与通常部署在MA上的mindie服务不同,vllm并不区分start、ready状态,无需配置启动探针。
(2) 就绪探针周期用于确定识别服务启动成功,参考配置表示10分钟后开始检查,之后每隔200秒检查1次,返回成功后将会标记服务启动成功。
(3) 存活探针周期不应超出在vllm_probe.py中设置的timeout时间,可以保持一致,健康检查周期与超时时间保持一致,最大失败次数2即说明服务最多在2 * 1200 s异常后重新拉起。要支持function call功能,需要在启动服务时,附带qwen3-coder-480b对应的function call参数,参考命令如下:

注意其中手动指定了chat-template,为镜像中集成的tool_chat_template_qwen3coder.jinja,是因为若不指定默认使用模型自带的tokenizer_config.json,客户环境中并没更新最新的权重文件,导致响应内容参数类型不正确:

测试function call的方法由于已经有较多文章说明,例如可以参考qwen3官网function call指导,不再本文中重复说明。
简要描述:隔离资源池可确保操作范围仅影响到本资源池内的所有物理节点。
单实例大EP需4机,1P1D
简要描述:此步骤需要在MA平台上进行操作,完成AI应用的创建。
在“AI应用 > 自定义应用”中,单击“创建应用”,创建AI应用。
元模型来源:选择“从容器镜像中选择”。
容器调用接口:以制作的vllm镜像为准,下图以HTTP协议,1025端口为例(修改端口涉及较多配置和启动脚本的修改,建议保持该值)。
配置AI应用元模型及健康检查

健康检查脚本可参考3.6节:
*注意健康检查探针使用时需要调整适配,防止探测失败。
参数设置完成后,单击“立即创建”创建AI应用。
在“部署上线 > 在线服务”中,单击“部署”。在部署服务页面参数设置完成后,即可部署PD分离服务。参数设置如下:


注意:将obs 的 xxx/scripts/ 路径映射到 /mnt/obs/qwen3_coder_480b/ 目录
等待服务状态变为“运行中”即可。
(1) 性能提升:该大EP部署方案可基本满足客户性能要求;
(2) 效率提升:客户现场开发适配MA和vllm_ascend大EP脚本,实现一键式拉起服务,整体部署效率提升300%,实现15分钟内完成服务部署。