1. 昇腾 910B 单机跑 DeepSeek-V4 的真实场景与前置判断
昇腾 910B 上跑 DeepSeek-V4,这件事在纸面上看是「国产算力 + 国产开源大模型」的顺理成章,但真正落到单机部署时,卡点往往不在模型本身,而在驱动、CANN、推理引擎和调度平台这四层能不能对齐。DeepSeek-V4 系列基于 MoE 架构,推理阶段只激活部分参数,但权重体积和显存占用依然不小,尤其是长上下文场景下 KV Cache 的膨胀速度很快。昇腾 910B 单机通常以 8 卡形态出现,单卡 64GB HBM,整机 512GB 显存,这个容量跑 DeepSeek-V4 的量化版本是够的,但前提是推理引擎能正确识别 NPU 设备、显存池化策略合理、并发请求不会把显存打爆。
GPUStack 在这里扮演的角色是「集群控制面 + 推理引擎编排器」。它本身不直接做推理计算,而是负责把 vLLM、SGLang 这类推理引擎以容器方式拉起,管理模型权重挂载、端口暴露、API Key 分发和节点健康检查。对于昇腾 910B 单机场景,GPUStack 的价值在于:你不需要手动写一堆 docker run 命令去挂载 NPU 设备、配置 CANN 环境变量、调 vLLM 的 tensor parallel 参数,而是通过一份 YAML 或控制台表单把这些参数固化下来,后续换模型、调并发、看指标都在同一个界面里完成。
适合谁看这篇:手上有昇腾 910B 单机或小集群、想快速验证 DeepSeek-V4 推理可用性的工程团队;已经在用 vLLM 或 SGLang 但被 NPU 适配问题折腾过的同学;以及需要给内部业务方提供一个「能跑起来、能压出数」的推理端点,而不是只停留在 benchmark 截图上的场景。
我试过在 910B2 八卡机上从零走一遍,踩过的坑主要集中在三个地方:CANN 版本和驱动版本不匹配导致 npu-smi 能看到卡但容器里 torch.npu 不可用;Ascend Docker Runtime 没配好导致容器启动后找不到 /dev/davinci* 设备;GPUStack 注册 Worker 时节点标签和实际 NPU 型号对不上,调度器把任务派到了错误的节点。下面按可复制的步骤拆开讲。
2. TaoToken 前置准备与 GPUStack 控制面安装
在开始昇腾侧配置之前,先把模型访问和 API 管理的链路理清楚。DeepSeek-V4 的权重可以从官方渠道获取,但如果你希望有一个统一的 API 入口来管理多个模型、做 Key 分发和用量统计,TaoToken 的模型对话和 API 网关能力可以先用起来。它的控制台地址是 https://taotoken.net/console ,API 端点是 https://taotoken.net/api ,不额外加 UTM 参数。对于后续要做压测的场景,你可以先在 TaoToken 上创建一个测试用的 API Key,把 DeepSeek-V4 的调用链路跑通,确认请求格式和返回结构,再回到本地 GPUStack 做私有化部署的对照。
这一步不是必须的,但建议做。原因是:本地 GPUStack 拉起 DeepSeek-V4 之后,你暴露出来的推理端点也是 OpenAI 兼容格式,提前用 TaoToken 的 API 文档核对一遍请求体字段(model、messages、max_tokens、stream),能避免本地部署完成后发现客户端 SDK 对不上。接入文档在 https://taotoken.net/doc ,API Key 管理在 https://taotoken.net/api-keys 。
回到 GPUStack 控制面安装。GPUStack Server 本身不依赖 GPU,可以跑在 CPU 节点上,也可以直接跑在 910B 节点上。单机场景下我建议直接跑在 910B 节点,省去跨节点网络配置。前提是 Docker 已经装好,执行docker info能看到正常输出。
启动 GPUStack Server 容器:
sudo docker run -d --name gpustack \ --restart unless-stopped \ -p 80:80 \ --volume gpustack-data:/var/lib/gpustack \ swr.cn-south-1.myhuaweicloud.com/gpustack/gpustack:v2.1.2 \ --debug --bootstrap-password GPUStack@123参数逐个说:-p 80:80把 Web 控制台暴露在 80 端口,如果 80 被占用可以改成-p 9999:80,后续访问就用 9999。--volume gpustack-data:/var/lib/gpustack做数据持久化,模型服务配置、计量数据、API Key 都存在这个卷里,容器重建不会丢。--bootstrap-password是初始化 admin 用户的密码,第一次登录后建议改掉。--debug开调试日志,排查 Worker 注册失败时很有用。
启动后看日志确认服务正常:
docker logs -f gpustack日志里出现Starting GPUStack server和Server started之类的字样就说明控制面起来了。浏览器访问http://<Server主机IP>:80,用 admin / GPUStack@123 登录。登录后第一件事是创建一个 Docker 类型的集群,这个集群是后续 Worker 节点的归属容器。集群创建时会给一个 token,Worker 节点接入时要用。
如果你后续要做长期编码或 Agent 类任务,需要更稳定的推理后端和更高的并发配额,可以了解 TaoToken 的 Coding Plan:https://taotoken.net/coding-plan 。它和本地 GPUStack 不冲突,本地负责私有化推理,TaoToken 负责外部模型调用和统一网关。
3. 昇腾 910B 驱动核对与 GPUStack Worker 接入配置
这一节是整篇最容易翻车的地方。昇腾 910B 的软件栈分四层:NPU 驱动、CANN 工具包、Ascend Docker Runtime、推理引擎(vLLM-Ascend 或 SGLang)。GPUStack 在拉起推理容器时,会依赖前三层已经就绪。
先做驱动版本核对。在目标节点执行:
npu-smi info输出里会显示驱动版本和固件版本。DeepSeek-V4 这类 MoE 模型对 CANN 版本有要求,建议驱动版本不低于 25.5,CANN 版本不低于 8.0.RC3。如果版本偏低,先升级驱动和 CANN,不要跳过这一步直接装 GPUStack,否则后面容器里 torch.npu 初始化会报RuntimeError: Initialize device failed。
接着检查 Ascend Docker Runtime 是否配置正确:
sudo docker info 2>/dev/null | grep -q "ascend" && echo "Ascend Container Toolkit OK" || (echo "Ascend Container Toolkit not configured"; exit 1)如果输出Ascend Container Toolkit OK,说明 Docker 已经识别到 ascend 运行时,容器里可以访问 NPU 设备。如果输出not configured,需要安装 Ascend Docker Runtime。安装包从昇腾社区获取,安装后重启 Docker 服务:
sudo systemctl restart docker然后重新执行上面的检查命令确认。
接下来在 GPUStack 控制台添加 Worker 节点。控制台里选择「添加节点」,系统会生成一段接入命令,类似:
sudo docker run -d --name gpustack-worker \ --restart unless-stopped \ --privileged \ --network host \ --volume /var/lib/gpustack:/var/lib/gpustack \ --volume /usr/local/Ascend:/usr/local/Ascend \ --volume /usr/local/dcmi:/usr/local/dcmi \ --volume /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \ --volume /dev/davinci*:/dev/davinci* \ swr.cn-south-1.myhuaweicloud.com/gpustack/gpustack:v2.1.2 \ --server-url http://<ServerIP>:80 \ --token <集群Token>关键挂载项说明:/usr/local/Ascend是 CANN 安装目录,容器里推理引擎需要调用这里的算子库;/usr/local/dcmi是设备管理接口;/dev/davinci*是 NPU 设备节点,不挂载容器里看不到卡。--privileged在昇腾场景下通常需要,因为推理容器要访问设备文件和共享内存。
如果你用 GPUStack 的 YAML 配置方式注册推理后端,可以参考下面这份片段,路径和字段名按实际环境调整:
backend: vllm model: deepseek-v4 model_path: /data/models/DeepSeek-V4 device: ascend tensor_parallel_size: 8 max_model_len: 32768 gpu_memory_utilization: 0.9 dtype: bfloat16 trust_remote_code: true extra_env: ASCEND_RT_VISIBLE_DEVICES: "0,1,2,3,4,5,6,7" HCCL_WHITELIST_DISABLE: "1"tensor_parallel_size: 8对应八卡;max_model_len先设 32768,压测稳定后再往上调;gpu_memory_utilization在 NPU 上对应显存池化比例,0.9 是保守值。ASCEND_RT_VISIBLE_DEVICES显式指定可见设备,避免容器里设备编号错乱。
Worker 注册成功后,在 GPUStack 控制台的节点列表里能看到该节点状态为 Ready,NPU 型号和显存容量会显示出来。如果状态一直是 Pending,看 Worker 容器日志:
docker logs -f gpustack-worker常见原因是 token 过期或 server-url 写错。
4. 拉起 DeepSeek-V4 推理服务与验证请求
Worker 就绪后,在 GPUStack 控制台创建模型服务。选择 DeepSeek-V4,推理引擎选 vLLM(昇腾场景下 vLLM-Ascend 适配相对成熟),模型路径填权重实际挂载路径。如果权重在宿主机/data/models/DeepSeek-V4,Worker 容器启动时要确保这个路径被挂载进去,否则推理引擎找不到权重文件。
启动后观察推理容器日志,重点看这几行:Loading model weights、NPU blocks initialized、Uvicorn running on http://0.0.0.0:8000。如果卡在Loading model weights超过十分钟,可能是权重文件不完整或磁盘 IO 瓶颈;如果报HCCL相关错误,检查HCCL_WHITELIST_DISABLE和网卡配置。
服务起来后,GPUStack 会暴露一个 OpenAI 兼容端点,通常是http://<ServerIP>:80/v1-openai/<model-name>或类似路径,具体以控制台显示为准。用 curl 验证:
curl http://<ServerIP>:80/v1-openai/deepseek-v4/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <GPUStack API Key>" \ -d '{ "model": "deepseek-v4", "messages": [{"role": "user", "content": "用一句话解释 MoE 架构"}], "max_tokens": 128, "temperature": 0.7 }'返回里能看到choices[0].message.content就说明推理链路通了。如果返回 401,检查 API Key 是否在 GPUStack 控制台正确生成;如果返回model not found,检查请求体里的 model 名称和控制台注册的名称是否一致。
验证通过后,用 Python 客户端做一轮简单请求,确认流式输出正常:
from openai import OpenAI client = OpenAI( base_url="http://<ServerIP>:80/v1-openai/deepseek-v4", api_key="<GPUStack API Key>" ) resp = client.chat.completions.create( model="deepseek-v4", messages=[{"role": "user", "content": "写一个快速排序"}], stream=True ) for chunk in resp: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="")流式输出正常意味着推理引擎的 tokenizer 和 detokenizer 工作正常,后续压测才有意义。
5. 并发压测与常见报错排查
压测用 vLLM 自带的 benchmark 脚本或 locust 都行。我习惯用 vLLM 的benchmark_serving.py,指定并发数和请求数:
python benchmark_serving.py \ --backend openai \ --base-url http://<ServerIP>:80/v1-openai/deepseek-v4 \ --model deepseek-v4 \ --dataset-name sharegpt \ --num-prompts 200 \ --request-rate 10 \ --max-concurrency 16重点看三个指标:TTFT(首 token 延迟)、TPOT(每 token 输出时间)、吞吐(tokens/s)。八卡 910B 跑 DeepSeek-V4 量化版,并发 16 时 TTFT 通常在几百毫秒到一秒出头,TPOT 在几十毫秒量级,具体数值取决于量化精度和上下文长度。压测过程中用npu-smi info观察显存占用和 NPU 利用率,如果显存接近打满且利用率上不去,说明 batch size 或 max_model_len 设得太大,需要回调。
常见报错对照:
401 Unauthorized:API Key 错误或没带 Authorization 头。检查 GPUStack 控制台生成的 Key 是否复制完整,请求头格式是Bearer <key>。
local proxy failed或connection refused:推理容器没起来或端口没暴露。先docker ps看容器状态,再看容器日志确认 Uvicorn 是否监听在预期端口。
Error reading choices或返回体里 choices 为空:通常是请求体格式不对,比如 messages 里 role 写错,或者 max_tokens 设成了 0。用 curl 最小请求体先验证。
OAuth或token expired:GPUStack Worker 注册 token 过期,重新在控制台生成接入命令并重启 Worker 容器。
HCCL timeout:多卡通信超时,检查ASCEND_RT_VISIBLE_DEVICES是否和实际卡数一致,以及 HCCL 网卡配置。
压测完成后,把 TTFT、TPOT、吞吐和显存峰值记下来,作为后续调参的基线。如果并发上去后吞吐不增反降,多半是 KV Cache 碎片化或调度策略问题,可以尝试调小max_model_len或开启 vLLM 的 chunked prefill。
6. 从验证到长期运行:API 管理与模型切换
本地 GPUStack 跑通之后,日常使用还需要一个统一的 API 入口来管理 Key、切换模型、看用量。TaoToken 的 API Keys 管理页面 https://taotoken.net/api-keys 可以创建多个 Key 分给不同业务方,模型对话入口 https://taotoken.net/chat 用来快速验证模型返回是否符合预期。如果你后续要接入 Claude Code 或做 Agent 类开发,Anthropic 兼容端点在 https://taotoken.net/claude-code-anthropic ,Coding Plan 在 https://taotoken.net/coding-plan 。
本地 GPUStack 和 TaoToken 的分工可以这样理解:GPUStack 负责私有化推理和 NPU 资源调度,TaoToken 负责外部模型调用、Key 分发和统一网关。两者都暴露 OpenAI 兼容接口,客户端代码只需要改 base_url 和 api_key 就能切换。压测数据用来判断本地 910B 单机能不能扛住业务峰值,如果扛不住,可以把部分流量切到 TaoToken 上的 DeepSeek-V4,做混合部署。
最后提醒一点:昇腾 910B 的 CANN 和驱动版本更新比较频繁,每次升级后建议重新跑一遍npu-smi info和容器内torch.npu.is_available()检查,确认推理链路没断。GPUStack 的版本也建议锁定在 v2.1.2 这类经过验证的 tag,不要盲目追 latest。