这台昇腾 910B2(64GB HBM)拿到手时,我习惯性地敲了 nvidia-smi——屏幕空了。机器里一块 NVIDIA 卡都没有,光是"认卡"这一步就先卡住。这篇记的是给两天课程、40 个人共用一台机器部署大模型的全过程:从认卡、配 CANN、下模型、用 vLLM 起服务,到给 40 人做目录镜像和端口隔离。所有命令和参数都是真机实测,数据没动过。

你能直接拿去用的有这些:CANN 环境四条开机必做、1.5GB 模型下载三条路径的实测对比、vLLM 起 7B 对话服务与 0.5B 对照服务的完整 serve 参数、自写的 OpenAI 兼容向量服务、40 人隔离方案,还有 LoRA 微调 21 秒训完的甜点参数,以及 Ollama 在昇腾上的选型结论。

第一台机器拿到手,我敲的第一条命令是 nvidia-smi。

回来的是 command not found。

机器里装的是华为昇腾,一块 NVIDIA 的卡都没有。所有我背过的 CUDA 命令、所有教程里的 CUDA_VISIBLE_DEVICES、所有"一行命令起服务"的教程,从这一刻起全部作废。

我那套已经写好的部署脚本也因此整套作废。它是按 NVIDIA 写的,连最后一步的服务校验都是 nvidia-smi。后来按昇腾重写的版本,脚本名全部换成了 ascend_01 到 ascend_09。

一、先认卡:四条开机必做

1)看卡用 npu-smi info,不是 nvidia-smi。 而且要先 source 完 CANN 环境才能用。

2)起任何 NPU 进程前,必须 source 两个环境脚本:

set +u
source /usr/local/Ascend/cann/set_env.sh 2>/dev/null \
  || source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/atb/set_env.sh
set -u

少了 atb 那个,会报 libatb.so: cannot open shared object file。 而开头那个 set +u 也不能省:昇腾的 set_env.sh 内部引用了未定义变量,不开掉 nounset 就崩在这一行。

3)import torch_npu 不能省。 它是把 npu 设备注册进 torch 的插件,不 import,torch.npu.is_available() 会老老实实返回 False——然后你会以为这台机器根本没卡。

import torch
import torch_npu          # 这行不能省
print(torch.npu.is_available())

4)python 和 vllm 都得用全路径。 直接敲 python3 拿到的是系统 3.10,里面没有 torch:

/usr/local/python3.11.14/bin/python3.11 -c "import torch; print(torch.__version__)"   # 2.9.0+cpu
/usr/local/python3.11.14/bin/vllm --version                                            # 0.11.0

顺手确认这两个也在:pip show torch-npu(2.9.0)、pip show vllm-ascend(0.19.1rc1)。

国产卡的第一个坑不在算力,在你对 NVIDIA 的肌肉记忆里。

二、网络不通:1.5GB 要下十几个小时

这台机器 github.com 和 huggingface.co 都不通。意思是:不能 from_pretrained 在线拉模型,也拉不到 GitHub release。

两条应对。

一是走代理,而且必须写死版本号:

https://ghproxy.net/https://github.com/<owner>/<repo>/releases/download/v0.19.1/xxx.tar.gz

写成 /releases/latest/... 经代理会 404,它跟不了重定向。

二是大文件一律走本机中转,别在服务器上硬拉。 这是我这次最省时间的一条,实测三条路:

路径速度1.5GB 耗时
服务器直连单连接23 KB/s十几个小时
服务器并发分段(24 段)~130 KB/s3~8 小时且不稳
本机多线程下载 + SFTP 上传14 MB/s 下行约 15 分钟

差 600 倍。

顺带一个代价 3 小时的坑:并发分段把 390 段全下完了,拼接时用了 cat seg.*——那是字符串序(seg.0 seg.1 seg.10 …),拼出来顺序是乱的,zstd -t 必然失败。更蠢的是我的失败分支把全部分段删了。

要么用 for i in $(seq ...) 逐个追加,要么直接 seek 写单个文件。校验失败的时候别删分段。

三、起服务:vLLM 能起对话,起不了向量

对话服务这条实测 2.9 秒出回答:

/usr/local/python3.11.14/bin/vllm serve /model/models/Qwen2.5-7B-Instruct \
    --served-model-name qwen2.5-7b \
    --host 0.0.0.0 --port 8000 \
    --max-model-len 16384 --max-num-seqs 32 \
    --gpu-memory-utilization 0.85 \
    --api-key 你的Key

--max-num-seqs 32 是并发上限,40 个人共用一个 7B 就靠这个扛,评测类的脚本错峰跑。

再起一个 0.5B 做"大小模型对照",只占一成显存:

/usr/local/python3.11.14/bin/vllm serve /model/qwen2.5-0.5b \
    --served-model-name qwen2.5-0.5b \
    --host 0.0.0.0 --port 8002 \
    --max-model-len 4096 --max-num-seqs 16 \
    --gpu-memory-utilization 0.10 \
    --api-key 你的Key

但向量服务起不来:这一版 vllm-ascend 不认 --task embed,报 unrecognized arguments。我一开始就是照着 --task embed 写的,脚本跑空了一轮才发现。

解法是自己写一个:用 transformers + torch_npu 直接起一个 OpenAI 兼容的向量服务,Qwen3-Embedding-0.6B,1024 维。核心就三步:取 last_hidden_state 的最后一位、L2 归一化、套 OpenAI 的 /v1/embeddings 返回格式。对上层完全无感。

四、40 个人怎么共用一台机器

关键设计只有一条:远程目录刻意镜像本地目录。本地是 {代码包, 数据, 输出} 三级,服务器上是同样的三级,所以 notebook 里写死的 ../数据、../输出,传到服务器上一行都不用改。

建 40 个学员目录,核心就这几行:

SHARED=/data/fde/shared
for i in $(seq 1 40); do
    d=/data/fde/students/$(printf "s%02d" $i)
    mkdir -p "$d/代码包" "$d/输出" "$d/work"
    ln -sfn $SHARED/data "$d/数据"          # 软链共享,不是拷贝
    cp -r $SHARED/代码包/. "$d/代码包/"     # 代码每人一份副本
    done
chmod -R a-w $SHARED/data                   # 共享数据只读,改了影响全班
隔离项做法
代码每人一份副本,共享区只读
数据软链共享,只读,改了影响全班
产物各写各的 输出/
端口起 jupyter 用 88XX(XX = 自己的编号),避免互撞
微调单卡按组排队,--out 必须指向自己目录

微调也是实测出来的甜点组合:240 条样本、3 轮、batch 4,0.5B 在 910B2 上 21 秒训完,loss 从 6.37 降到 0.60。

/usr/local/python3.11.14/bin/python3.11 finetune_lora.py \
    --train ../输出/exp04_sft_train.jsonl \
    --out   ../输出/exp04_lora \
    --base  /model/qwen2.5-0.5b --epochs 3 --batch 4 \
    --lr 2e-4 --lora-r 16 --lora-alpha 32 --max-len 512 --seed 42

可训练参数只有 1.08M,占总量 0.22%。

更省事的是:vLLM 已经占掉 85% 显存的情况下,这个 0.5B 的 LoRA 照样跑得动。所以不用为了演示微调去停 7B 服务。但 3B 以上会 OOM,要用 3B 必须先停 vLLM。

五、三个反直觉的结论

一、私有化的卖点不是"快",是"稳"。

同一句问题各测三次,本机直连:

端点三次往返
自建服务器(7B)726 / 734 / 725 ms
公有云在线 API1363 / 3445 / 2719 ms

自有机器三次几乎不动,在线 API 波动 2.5 倍(排队加公网抖动)。

二、快不等于好。

7B 3394ms,0.5B 3096ms,几乎一样快。但 7B 的回答分步骤、会说"记录数据/分析原因",0.5B 也有步骤,只是更泛、更像模板。

时延接近是因为两者跑在同一块 NPU 上;差距在内容质量,不在速度。

三、换了 embedding 端点,必须重建向量。

两个 embedding 模型都是 1024 维,但实测余弦相似度只有 -0.02。

维度一样,不等于空间一样。带着旧向量切端点,检索会全部落空——表现出来是"全部拒答",你根本想不到问题出在向量上。

六、折腾一整夜,最后决定不用 Ollama

这条我最想记下来,因为它跟技术关系不大。

装 Ollama 试了五种方式,全失败:GitHub release 走代理只有 48–580KB/s 且停滞;官方 install.sh 是单连接流式,23KB/s;并发分段下完 390 段但拼错;本机下载再 SFTP 上传,传到一半本机出口被限流,服务端校验 Corrupted block;最后补齐 636MB,zstd -t 仍然报 Corrupted block。

真正让我决定砍掉的,不是"没装上",是算清了一笔账:Ollama 在昇腾上只能跑 CPU。也就是说,就算装成了,收益也薄得可怜。

于是改成:课上一律用 vLLM,Ollama 只留一张选型对比表讲定位,那批脚本标记弃用、不再维护。

沉没成本不是继续的理由。先算"装成了能好多少",再决定要不要接着装。

七、值得这么折腾吗

值得:要做国产化适配、要一批人共用一张卡、要跑微调、环境不能联网。

不值得:只是想本地跑个小模型玩玩。你自己电脑上装什么都比这快,别租服务器。

一个前提:动手前先确认机器到底是什么卡。这一步省下的时间,比后面所有优化加起来都多。

先看清你脚下站的是什么卡,再决定怎么迈腿。

本文为个人真机实测记录,命令与数据均来自实际部署过程,供国产算力环境部署参考。

 

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐