跳到主要内容

Qwen3 VL 模型部署

本章节包含 Qwen3 VL 系列模型的部署脚本,脚本涉及的参数说明、PD 分离一键部署说明见 快速开始

信息

启动 SGLang 服务前切换python虚拟环境到sglang-0.5.6,执行命令:workon sglang-0.5.6source ~/.virtualenvs/sglang-0.5.6/bin/activate

Qwen3VL-2/4/8B

本示例使用 1卡(TP1)部署 Qwen3-VL-2B-Instruct。 对于 Qwen3-VL-4B-Instruct 和 Qwen3-VL-8B-Instruct,修改 MODEL_PATH 环境变量和 served-model-name 参数即可。

启动脚本 Launch_server.sh

#!/bin/bash
source ~/.virtualenvs/sglang-0.5.6/bin/activate

export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:/usr/local/musa/lib:$LD_LIBRARY_PATH

export MUSA_LAUNCH_BLOCKING=0
export MUSA_ENABLE_LLC_OPT=1

export MCCL_IB_GID_INDEX=3
export MCCL_NET_SHARED_BUFFERS=0
export MCCL_PROTOS=2
export GLOO_SOCKET_IFNAME=bond0
export TP_SOCKET_IFNAME=bond0
export SGLANG_TORCH_PROFILER_DIR=/tmp/traces
export VLLM_PATCH_MUSA_CUSTOM_OPS=1

export MATE_FORCE_JIT=1

SGLANG_DECODE_PORT=20133
MASTER_IP=127.0.0.1
NODE_RANK=0
WORLD_SIZE=1
MODEL_PATH=/data/models/Qwen3-VL-2B-Instruct-FP8/
log_path=logs-sglang-server/$(hostname)-$(basename $MODEL_PATH)
mkdir -p $log_path
log_file=$(date "+%Y%m%d_%H%M").log
touch $log_path/$log_file
rm -f $log_path/latest
ln -s $log_file $log_path/latest
export MUSA_VISIBLE_DEVICES=$run_GPU
python3 -m sglang.launch_server \
--model ${MODEL_PATH} \
--served-model-name qwen3-vl-2b-instruct-fp8 \
--trust-remote-code \
--cuda-graph-max-bs 256 \
--disable-overlap-schedule \
--tp-size 1 \
--pp-size 1 \
--mem-fraction-static 0.8 \
--attention-backend fa3 \
--mm-attention-backend fa3 \
--moe-runner-backend deep_gemm \
--sampling-backend flashinfer \
--dist-init-addr ${MASTER_IP}:5303 \
--nnodes 1 \
--node-rank 0 \
--max-prefill-tokens 4096 \
--chunked-prefill-size -1 \
--disable-radix-cache \
--port ${SGLANG_DECODE_PORT} \
--host 127.0.0.1 \
--decode-log-interval 1 2>&1 | tee $log_path/$log_file

Qwen3VL-32B

本示例使用 4卡(TP4)部署。

启动脚本 qwen3_vl_32b_server.sh

#!/bin/bash
source ~/.virtualenvs/sglang-0.5.6/bin/activate

export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:/usr/local/musa/lib:$LD_LIBRARY_PATH
export MUSA_LAUNCH_BLOCKING=0
export MUSA_ENABLE_LLC_OPT=1

export MCCL_IB_GID_INDEX=3
export MCCL_NET_SHARED_BUFFERS=0
export MCCL_PROTOS=2
export GLOO_SOCKET_IFNAME=bond0
export TP_SOCKET_IFNAME=bond0
export SGLANG_TORCH_PROFILER_DIR=/tmp/traces
export VLLM_PATCH_MUSA_CUSTOM_OPS=1

export MATE_FORCE_JIT=1
export LD_LIBRARY_PATH=/usr/local/musa/lib:${LD_LIBRARY_PATH}

SGLANG_DECODE_PORT=20133
MASTER_IP=127.0.0.1
NODE_RANK=0
WORLD_SIZE=1
MODEL_PATH=/data/models/Qwen3-VL-32B-Instruct-FP8/
log_path=logs-sglang-server/$(hostname)
mkdir -p $log_path
log_file=$(date "+%Y%m%d_%H%M").log
touch $log_path/$log_file
rm -f $log_path/latest
ln -s $log_file $log_path/latest
python3 -m sglang.launch_server \
--model ${MODEL_PATH} \
--served-model-name qwen3-vl-32b-instruct-fp8 \
--trust-remote-code \
--cuda-graph-max-bs 256 \
--disable-overlap-schedule \
--tp-size 4 \
--dp-size 1 \
--mem-fraction-static 0.8 \
--attention-backend fa3 \
--mm-attention-backend fa3 \
--sampling-backend flashinfer \
--dist-init-addr ${MASTER_IP}:5303 \
--nnodes 1 \
--node-rank 0 \
--chunked-prefill-size -1 \
--disable-radix-cache \
--port ${SGLANG_DECODE_PORT} \
--host 0.0.0.0 \
--decode-log-interval 1 2>&1 | tee $log_path/$log_file

Qwen3-VL-30B-A3B-Instruct

本示例使用 2卡(TP2)部署。

Qwen3-VL-30B-A3B-Instruct 启动脚本 qwen3_vl_30b_a3b_server.sh

#!/bin/bash
source ~/.virtualenvs/sglang-0.5.6/bin/activate

export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:/usr/local/musa/lib:$LD_LIBRARY_PATH
export MUSA_LAUNCH_BLOCKING=0
export MUSA_ENABLE_LLC_OPT=1
export MCCL_IB_GID_INDEX=3
export MCCL_NET_SHARED_BUFFERS=0
export MCCL_PROTOS=2
export GLOO_SOCKET_IFNAME=bond0
export TP_SOCKET_IFNAME=bond0
export VLLM_PATCH_MUSA_CUSTOM_OPS=1

export MATE_FORCE_JIT=1

get_master_ip() {
local hostname_ip=$(hostname -I 2>/dev/null | awk '{print $1}')

if [ -n "$hostname_ip" ] && [ "$hostname_ip" != "127.0.0.1" ]; then
echo "$hostname_ip"
return
fi

}

CURRENT_TIME=$(date "+%Y%m%d_%H%M%S")
SGLANG_DECODE_PORT=20133
MASTER_IP=$(get_master_ip)
NODE_RANK=0
WORLD_SIZE=1
WORK_HOME="$PWD"
LOG_DIR=$WORK_HOME/output/$CURRENT_TIME/
mkdir -p "$LOG_DIR"

export MUSA_VISIBLE_DEVICES=0,1
export SGLANG_TORCH_PROFILER_DIR=$WORK_HOME/traces
MODEL_PATH=/data/models/Qwen3-VL-30B-A3B-Instruct-FP8/
nohup python3 -m sglang.launch_server \
--model-path ${MODEL_PATH} \
--served-model-name qwen3-vl-30b-a3b-instruct-fp8 \
--trust-remote-code \
--disable-overlap-schedule \
--cuda-graph-max-bs 512 \
--tp-size 2 \
--ep-size 2 \
--pp-size 1 \
--mem-fraction-static 0.8 \
--attention-backend fa3 \
--enable-cache-report \
--mm-attention-backend fa3 \
--moe-runner-backend deep_gemm \
--enable-dp-attention \
--enable-dp-lm-head \
--moe-dense-tp-size 1 \
--sampling-backend flashinfer \
--dist-init-addr ${MASTER_IP}:5303 \
--nnodes ${WORLD_SIZE} \
--node-rank ${NODE_RANK} \
--chunked-prefill-size -1 \
--max-prefill-tokens 4096 \
--context-length 16384 \
--disable-radix-cache \
--port ${SGLANG_DECODE_PORT} \
--host 0.0.0.0 \
--decode-log-interval 1 > "${LOG_DIR}/${MASTER_IP}_$(date '+%Y%m%d_%H%M%S').log" 2>&1 &

echo -e "Main log file: \033[34m$LOG_DIR\033[0m"

Qwen3-VL-235B-A22B-Instruct

本示例部署方式为1P1D,请准备两台机器。模型使用FP8,如需运行BF16版本,修改 MODEL_PATH 环境变量和 served-model-name 参数即可。

Prefill启动脚本 prefill_server.sh

#!/bin/bash
source ~/.virtualenvs/sglang-0.5.6/bin/activate

export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:/usr/local/musa/lib:$LD_LIBRARY_PATH
export PATH=/root/.virtualenvs/sglang-0.5.6/bin/:$PATH
export MUSA_LAUNCH_BLOCKING=0
export MUSA_ENABLE_LLC_OPT=1

export MCCL_IB_GID_INDEX=3
export MCCL_NET_SHARED_BUFFERS=0
export MCCL_PROTOS=2
export GLOO_SOCKET_IFNAME=bond0
export TP_SOCKET_IFNAME=bond0

export MC_ENABLE_DEST_DEVICE_AFFINITY=1

export SGLANG_SET_CPU_AFFINITY=1
export SGLANG_DEEP_GEMM_BLOCK_M=256
# 如果模型为 BF16 数据类型则打开该环境变量
export SGLANG_DEEPEP_BF16_DISPATCH=0
export SGLANG_ENABLE_TORCH_INFERENCE_MODE=true

export SGLANG_DISAGGREGATION_QUEUE_SIZE=8
export SGLANG_DISAGGREGATION_THREAD_POOL_SIZE=16
export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600

export VLLM_PATCH_MUSA_CUSTOM_OPS=1

export MATE_FORCE_JIT=1

# 获取当前环境的 RDMA 设备名列表,在启动时作为 disaggregation-ib-device 参数值
IB_DEVS=()

for dev in /sys/class/infiniband/*; do
ibdev=$(basename "$dev")
for port in "$dev"/ports/*; do
# 速率(如 200 Gb/sec)
rate=$(cat "$port/rate" 2>/dev/null)
# link_layer: InfiniBand / Ethernet (RoCE)
link=$(cat "$port/link_layer" 2>/dev/null)
# 状态为 Up
state=$(cat "$port/state" 2>/dev/null)
# 只要是 200G/400G 且状态为 Up(IB 或 RoCE 都收)
if [[ "$rate" == *"200 Gb"* || "$rate" == *"400 Gb"* ]] && [[ "$state" == "4"* ]]; then
IB_DEVS+=("$ibdev")
break
fi
done
done
# 排序 + 去重
IB_DEVS_SORTED=$(printf "%s\n" "${IB_DEVS[@]}" | sort -V | uniq)
# 生成 MCCL / SGLang 变量
MCCL_IB_HCA=$(echo "$IB_DEVS_SORTED" | paste -sd, -)
SGLANG_IB_DEVICES="$MCCL_IB_HCA"
echo "IB_DEVICES=$MCCL_IB_HCA"
# 获取 RDMA 设备名列表结束

NODE_RANK=$1
PREFILL_IP="${2}:5303"
LOG_DIR=$3
MODEL_PATH=$4
HOST_IP=$5

WORLD_SIZE=1
WORK_HOME="$PWD"
export SGLANG_TORCH_PROFILER_DIR=$WORK_HOME/P${NODE_RANK}_traces

mkdir -p "${LOG_DIR}"

nohup python3 -m sglang.launch_server \
--model-path ${MODEL_PATH} \
--served-model-name qwen3-vl-235b-a22b-instruct-fp8 \
--trust-remote-code \
--disable-overlap-schedule \
--disable-cuda-graph \
--tp-size 8 \
--dp-size 8 \
--ep-size 8 \
--pp-size 1 \
--mem-fraction-static 0.85 \
--attention-backend fa3 \
--enable-cache-report \
--mm-attention-backend fa3 \
--moe-runner-backend deep_gemm \
--sampling-backend flashinfer \
--moe-dense-tp-size 1 \
--enable-dp-lm-head \
--enable-dp-attention \
--moe-a2a-backend deepep \
--deepep-mode normal \
--dist-init-addr $PREFILL_IP \
--nnodes ${WORLD_SIZE} \
--node-rank ${NODE_RANK} \
--chunked-prefill-size -1 \
--max-running-requests 64 \
--disable-radix-cache \
--port 20133 \
--host 0.0.0.0 \
--load-balance-method round_robin \
--disaggregation-mode prefill \
--disaggregation-ib-device $SGLANG_IB_DEVICES > "${LOG_DIR}/P${NODE_RANK}_${HOST_IP}_$(date '+%Y%m%d_%H%M%S').log" 2>&1 &

Decode启动脚本 decode_server.sh

#!/bin/bash
source ~/.virtualenvs/sglang-0.5.6/bin/activate

export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:/usr/local/musa/lib:$LD_LIBRARY_PATH
export PATH=/root/.virtualenvs/sglang-0.5.6/bin/:$PATH
export MUSA_LAUNCH_BLOCKING=0
export MUSA_ENABLE_LLC_OPT=1

export MCCL_IB_GID_INDEX=3
export MCCL_NET_SHARED_BUFFERS=0
export MCCL_PROTOS=2
export GLOO_SOCKET_IFNAME=bond0
export TP_SOCKET_IFNAME=bond0

export MC_ENABLE_DEST_DEVICE_AFFINITY=1

export SGLANG_SET_CPU_AFFINITY=1
export SGLANG_DEEP_GEMM_BLOCK_M=256
# 如果模型为 BF16 数据类型则打开该环境变量
export SGLANG_DEEPEP_BF16_DISPATCH=0
export SGLANG_ENABLE_TORCH_INFERENCE_MODE=true

export SGLANG_DISAGGREGATION_QUEUE_SIZE=8
export SGLANG_DISAGGREGATION_THREAD_POOL_SIZE=16
export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600

export SGLANG_DEEPEP_LL_USE_NVLINK=1
export SGLANG_DEEPEP_LL_DISABLE_RECV_HOOK=1
export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=128

export VLLM_PATCH_MUSA_CUSTOM_OPS=1

export MATE_FORCE_JIT=1

# 获取当前环境的 RDMA 设备名列表,在启动时作为 disaggregation-ib-device 参数值
IB_DEVS=()

for dev in /sys/class/infiniband/*; do
ibdev=$(basename "$dev")
for port in "$dev"/ports/*; do
# 速率(如 200 Gb/sec)
rate=$(cat "$port/rate" 2>/dev/null)
# link_layer: InfiniBand / Ethernet (RoCE)
link=$(cat "$port/link_layer" 2>/dev/null)
# 状态为 Up
state=$(cat "$port/state" 2>/dev/null)
# 只要是 200G/400G 且状态为 Up(IB 或 RoCE 都收)
if [[ "$rate" == *"200 Gb"* || "$rate" == *"400 Gb"* ]] && [[ "$state" == "4"* ]]; then
IB_DEVS+=("$ibdev")
break
fi
done
done
# 排序 + 去重
IB_DEVS_SORTED=$(printf "%s\n" "${IB_DEVS[@]}" | sort -V | uniq)
# 生成 MCCL / SGLang 变量
MCCL_IB_HCA=$(echo "$IB_DEVS_SORTED" | paste -sd, -)
SGLANG_IB_DEVICES="$MCCL_IB_HCA"
echo "IB_DEVICES=$MCCL_IB_HCA"
# 获取 RDMA 设备名列表结束

NODE_RANK=$1
DECODER_IP="${2}:5403"
LOG_DIR=$3
MODEL_PATH=$4
HOST_IP=$5

WORLD_SIZE=1
export SGLANG_TORCH_PROFILER_DIR=$WORK_HOME/D${NODE_RANK}_traces

nohup python3 -m sglang.launch_server \
--model-path ${MODEL_PATH} \
--served-model-name qwen3-vl-235b-a22b-instruct-fp8 \
--trust-remote-code \
--disable-overlap-schedule \
--cuda-graph-bs $(seq 1 32) \
--tp-size 8 \
--ep-size 8 \
--dp-size 8 \
--mem-fraction-static 0.76 \
--attention-backend fa3 \
--enable-cache-report \
--mm-attention-backend fa3 \
--moe-runner-backend deep_gemm \
--enable-dp-lm-head \
--moe-dense-tp-size 1 \
--enable-dp-attention \
--moe-a2a-backend deepep \
--deepep-mode low_latency \
--sampling-backend flashinfer \
--dist-init-addr $DECODER_IP \
--nnodes ${WORLD_SIZE} \
--node-rank ${NODE_RANK} \
--disable-radix-cache \
--port 20143 \
--host 0.0.0.0 \
--ep-num-redundant-experts 0 \
--load-balance-method round_robin \
--prefill-round-robin-balance \
--disaggregation-mode decode \
--disaggregation-ib-device $SGLANG_IB_DEVICES > "${LOG_DIR}/D${NODE_RANK}_${HOST_IP}_$(date '+%Y%m%d_%H%M%S').log" 2>&1 &

Router启动脚本 router.sh

#!/bin/bash
source ~/.virtualenvs/sglang-0.5.6/bin/activate

export PATH=/root/.virtualenvs/sglang-0.5.6/bin/:$PATH
PREFILL_IP="http://${1}:20133"
DECODE_IP="http://${2}:20143"
LOG_DIR=$3

ulimit -n 65535
nohup python -m sglang_router.launch_router \
--pd-disaggregation \
--mini-lb \
--prefill $PREFILL_IP \
--decode $DECODE_IP \
--host 0.0.0.0 \
--request-timeout-secs 7200 \
--port 30000 > "${LOG_DIR}/router_$(date '+%Y%m%d_%H%M%S').log" 2>&1 &

hostfile文件示例

192.168.100.101
192.168.100.102

一键运行脚本 run.sh

#!/bin/bash
WORKSPACE=$(pwd)

# 检查 hostfile 是否存在
if [ ! -f "$WORKSPACE/hostfile" ]; then
echo "Error: $WORKSPACE/hostfile not found!"
exit 1
fi

# 读取 hostfile 到数组
mapfile -t hosts < "$WORKSPACE/hostfile"

echo "Using hosts:"
printf '%s\n' "${hosts[@]}"

# prefill - 使用第一个节点作为 prefill 服务器
ssh -p 62216 ${hosts[0]} "cd $WORKSPACE && bash prefill_server.sh 0 ${hosts[0]} ./logs /data/models/Qwen3-VL-235B-A22B-Instruct-FP8/ ${hosts[0]}" &

# decode - 使用第二个节点作为 decoder 服务器
ssh -p 62216 ${hosts[1]} "cd $WORKSPACE && bash decode_server.sh 0 ${hosts[1]} ./logs /data/models/Qwen3-VL-235B-A22B-Instruct-FP8/ ${hosts[1]}" &

# router - 在第一个节点上启动 router
ssh -p 62216 ${hosts[0]} "cd $WORKSPACE && bash router.sh ${hosts[0]} ${hosts[1]} ./logs" &

echo "All services started in background"