Qwen3 本地部署
服务器:HuaKun AT800 (Model 3000) / Atlas 300I Duo / Ascend 310P3
归档日期:2026-07-07
状态:Qwen3-32B-W8A8SC 已成功部署,并通过 /v1/models、/health 验证;公网暴露方案已设计(待实施)
1. 硬件与环境
项目 |
规格 |
|---|
服务器 |
HuaKun AT800 (Model 3000) |
CPU |
鲲鹏920 (ARM64 / aarch64) |
NPU |
2×Atlas 300I Duo = 4×Ascend 310P3 |
NPU 显存 |
合计约 192GB(每卡约 48GB) |
OS |
Ubuntu 22.04.5 LTS,内核 5.15.0-185-generic |
推理框架 |
vLLM-Ascend v0.22.1rc1-310p |
工作目录 |
/mnt/data/mindie |
模型服务器内网IP |
192.168.15.201 |
已验证模型 |
Qwen3-8B-W8A8SC (TP1)、Qwen3-32B-W8A8SC (TP4) |
显存硬约束(重要)
- 235B 系列:W8A8 也需 ≈235GB > 192GB → 跑不了;BF16 需 ≈470GB。
- 32B:W8A8SC ≈32GB 权重,必须用 TP=4 占满 4 卡。
- 8B/14B:W8A8SC 单卡(48GB)可放下,TP=1。
2. 经验教训(踩坑总结)
- MindIE 2.2.RC1 不支持 Qwen3:ATB 后端报
ExecutorInstanceInit failed,根因是架构不兼容。→ 改用 vLLM-Ascend。
- transformers 自建 API 不稳定:310P 上遇
libhccl.so 缺失 + 预热卡死。→ 放弃。
- 310P 不支持 triton/triton-ascend:启动 vLLM 前必须
pip uninstall -y triton-ascend triton,否则异常。
- 310P 不能依赖 max-model-len 自动探测:注意力掩码为
[max_len, max_len](float16),O(max_len²) 会 OOM。必须显式设置(如 16384 / 20480)。
- TP>1 时图模式受限:310P 硬件事件ID资源限制,TP>1 只能捕获 2 个图(如 32B 用
cudagraph_capture_sizes: [16,32]);TP=1 无此限制。
- 权重必须用专用量化版:
Eco-Tech/*-w8a8sc-310-vllm(310P 优化),不是通用 HuggingFace 权重。
- 公网暴露必须加 API Key:vLLM 默认无鉴权,裸奔=任何人烧你 GPU。
- docker-compose 中
$LD_LIBRARY_PATH 会被宿主展开为空:用 start.sh 脚本规避变量展开问题。
3. 驱动 / 固件安装(已完成,记录备查)
版本:driver 24.1.1.3、firmware 7.5.0.9.220、配套 CANN 8.3.RC2
(MindIE 2.2.RC1 需 CANN 8.3.RC2,非 9.0)
3.1 安装步骤
# 1) 建运行用户(全新安装必须先建)
groupadd HwHiAiUser
useradd -g HwHiAiUser -d /home/HwHiAiUser -m HwHiAiUser -s /bin/bash
# 2) 编译依赖
apt install -y gcc make dkms linux-headers-$(uname -r)
# 3) 安装顺序:先驱动后固件(升级才反过来)
./Ascend-hdk-310p-npu-driver_24.1.1.3_linux-aarch64.run --full
./Ascend-hdk-310p-npu-firmware_7.5.0.9.220.run --full
3.2 安装期踩坑与修复
- DKMS 编译失败(MIN 宏重定义 + -Werror):
改源码目录 /usr/src/davinci_ascend-1.0/vascend_drv/kvmdt.c 第 59 行,用 #ifndef MIN ... #endif 包裹;
并清除 -Werror:find /usr/src/davinci_ascend-1.0/ -name 'Makefile' -exec sed -i 's/-Werror//g' {} +
- 动态库路径:运行库在
/usr/local/Ascend/driver/lib64/driver/,配置
/etc/ld.so.conf.d/ascend.conf(含 driver/lib64、common、driver 三行)后 ldconfig。
- 内核模块名是
drv_vascend(非 DKMS 包名):depmod -a; modprobe drv_vascend
- 大页内存(重启后丢失会致进程被 kill):
echo 32768 > /proc/sys/vm/nr_hugepages,持久化 echo "vm.nr_hugepages = 32768" > /etc/sysctl.d/99-ascend.conf
3.3 验证
npu-smi info # 4 颗 310P3 全部 OK,驱动 24.1.1.3
4. vLLM-Ascend 部署 Qwen3-32B(当前生产配置)
4.1 目录结构
/mnt/data/mindie/
├── models/
│ └── Qwen3-32B-W8A8SC/ # 模型权重(只读)
│ └── TP4/Qwen3-32B-w8a8sc-310-vllm-tp4/
└── vllm/ # 部署文件
├── start_vllm.sh
└── docker-compose.yml
4.2 下载权重
modelscope download --model Eco-Tech/Qwen3-32B-w8a8sc-310-vllm \
--local_dir /mnt/data/mindie/models/Qwen3-32B-W8A8SC
4.3 start_vllm.sh
#!/bin/bash
pip uninstall -y triton-ascend triton 2>/dev/null
vllm serve /models/Qwen3-32B-W8A8SC/TP4/Qwen3-32B-w8a8sc-310-vllm-tp4 \
--host 0.0.0.0 --port 8080 --tensor-parallel-size 4 \
--gpu_memory_utilization 0.90 --max_num_seqs 32 \
--served_model_name qwen --dtype float16 \
--additional-config '{"ascend_compilation_config": {"fuse_norm_quant": false}}' \
--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY", "cudagraph_capture_sizes": [16,32]}' \
--quantization ascend --max_model_len 20480 \
--no-enable-prefix-caching --load_format sharded_state
4.4 docker-compose.yml
services:
vllm:
image: quay.io/ascend/vllm-ascend:v0.22.1rc1-310p
container_name: vllm-qwen32b
network_mode: host
restart: unless-stopped
shm_size: 10g
ulimits:
nofile: 65536
devices:
- /dev/davinci0
- /dev/davinci1
- /dev/davinci2
- /dev/davinci3
- /dev/davinci_manager
- /dev/devmm_svm
- /dev/hisi_hdc
volumes:
- /mnt/data/mindie/models:/models:ro
- /mnt/data/mindie/vllm/start_vllm.sh:/start.sh:ro
- /usr/local/dcmi:/usr/local/dcmi:ro
- /usr/local/bin/npu-smi:/usr/local/bin/npu-smi:ro
- /usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64:ro
- /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info:ro
- /etc/ascend_install.info:/etc/ascend_install.info:ro
- /root/.cache:/root/.cache
environment:
- ASCEND_RT_VISIBLE_DEVICES=0,1,2,3
cap_add:
- SYS_ADMIN
command: bash /start.sh
4.5 启动与验证
cd /mnt/data/mindie/vllm
docker compose down # 停掉占 davinci0 的旧 8B 容器
docker compose up -d
# 等日志 Application startup complete.
curl http://localhost:8080/health
curl http://localhost:8080/v1/models # 应返回 id=qwen, max_model_len=20480
5. 公网访问配置(可选,待实施)
拓扑:公网IP:9666 →(NAT 固定)→ 192.168.11.251:9666 →(需 relay)→ 192.168.11.201:8080
5.1 在 251 上做 TCP 转发(nginx stream,推荐)
# /etc/nginx/conf.d/qwen_relay.conf (顶层 stream,不在 http{} 内)
stream {
server {
listen 9666;
proxy_pass 192.168.11.201:8080;
proxy_connect_timeout 5s;
proxy_timeout 3600s;
}
}
nginx -t && systemctl reload nginx
5.2 加 API Key(公网必做)
在 start_vllm.sh 的 vllm serve 前加:
export VLLM_API_KEY="自己设一段长随机串"
重启容器后,客户端请求需带 Authorization: Bearer <key>。
5.3 公网调用验证
curl https://<公网IP>:9666/v1/chat/completions \
-H "Authorization: Bearer 你的密钥" \
-H "Content-Type: application/json" \
-d '{"model":"qwen","messages":[{"role":"user","content":"你好"}],
"max_completion_tokens":128,"chat_template_kwargs":{"enable_thinking":false}}'
6. 常用命令速查
用途 |
命令 |
|---|
NPU 状态 |
npu-smi info |
NPU 重置 |
npu-smi set -t reset -i 1 -c 0 |
启服务 |
cd /mnt/data/mindie/vllm && docker compose up -d |
停服务 |
docker compose down |
看日志 |
docker logs -f vllm-qwen32b |
健康检查 |
curl http://localhost:8080/health |
列模型 |
curl http://localhost:8080/v1/models |
续写测试 |
curl .../v1/completions -d '{"prompt":"...","max_completion_tokens":64}' |
7. 故障排查
- OOM / 启动即崩:检查
max_model_len 是否显式设置;降低 --gpu_memory_utilization。
- 图模式报错(TP>1):确认
cudagraph_capture_sizes 只用 [16,32],不要列更多。
- triton 相关异常:
pip uninstall -y triton-ascend triton 后重启容器。
- 进程被 kill(重启后):检查 hugepages 是否持久化(
sysctl vm.nr_hugepages)。
- 8B 与 32B 容器冲突:两者都占 davinci0,必须
docker compose down 旧的再起新的。
- NPU 看不到:
ls /dev/davinci*;确认 modprobe drv_vascend 且 npu-smi 正常。