我们把 DeepSeek V4 跑上了昇腾 910B:真正难的不是模型启动,而是把 Agent 工具调用跑通

这篇文章不想写成那种“复制命令,一路成功”的教程。

因为真实部署根本不是那样。

真实情况是:你以为你在部署一个模型,结果你是在和 模型格式、推理框架、NPU 生态、Docker 容器、Transformers、vLLM-Ascend、OpenClaw、工具调用协议 一起打架。

这次我们搞的是:

DeepSeek-V4-Flash
昇腾 910B × 8
vLLM-Ascend
OpenAI Compatible API
OpenClaw 工具调用

听起来一句话很简单:

在昇腾 910B 上部署 DeepSeek V4,然后接 OpenClaw。

但真正上手以后才知道,这里面每一步都有坑,而且不是小坑,是那种你一脚踩下去,半天都不知道自己掉哪儿了的坑。


一开始我们以为:模型下载下来,vLLM 一跑就完事了

最开始的想法很朴素。

模型下载好了:

/data/models/DeepSeek-V4-Flash

机器也有:

Ascend 910B × 8
每卡 64GB

vLLM-Ascend 也拉好了。

那不就是:

vllm serve /data/models/DeepSeek-V4-Flash

然后起来一个 OpenAI API,完事?

结果第一棒就被打醒了。

日志直接报:

The checkpoint you are trying to load has model type `deepseek_v4`
but Transformers does not recognize this architecture

这句话很关键。它的意思不是“模型坏了”,也不是“显卡不行”,而是:

当前加载链路不认识 deepseek_v4 这个模型结构

也就是说,模型是新模型,但框架生态还没完全跟上。

这个时候很多人会误判:

是不是 transformers 版本低?
是不是 pip install -U transformers 就好了?
是不是模型没下完整?
是不是昇腾不支持?

其实都不是核心。

核心是:昇腾上跑 DeepSeek V4,不能随便拿一个原版权重就上,要用昇腾适配过的版本。

后来我们换成:

DeepSeek-V4-Flash-w8a8-mtp

这才进入了正确路线。


第一个认知:能跑的不是“原版模型”,而是“昇腾适配版模型”

很多人看到 ModelScope 上有:

deepseek-ai/DeepSeek-V4-Flash

就觉得这个肯定能跑。

但在昇腾上,事情不是这么简单。

真正适合我们这台机器的,是:

DeepSeek-V4-Flash-w8a8-mtp

这个名字里有两个关键词:

w8a8
mtp

w8a8 代表它是量化适配版本。
mtp 代表它带多 token 预测 / 推理优化相关能力。
更重要的是,它是给 vLLM-Ascend 路线准备的。

我们最后实际跑的是:

/data/models/DeepSeek-V4-Flash-w8a8-mtp

这一步走对以后,模型终于能加载了。

但注意:模型能加载,不等于系统能用。

这是这次部署里最大的感悟。


跑通 API 的那一刻,其实只是刚刚开始

当服务日志里出现:

Application startup complete

那一刻确实挺兴奋。

再一测:

curl http://127.0.0.1:8000/v1/models

有返回。

再测:

curl http://127.0.0.1:8000/v1/chat/completions

也能回复。

这个时候看起来已经成功了。

如果只是做普通对话,这一步确实差不多了。

但我们的目标不是普通聊天。

我们要接的是 OpenClaw,要让它能安装技能、读取文件、调用工具、执行命令。

也就是说,我们要跑的是 Agent 场景。

结果真正的大坑从这里开始。


OpenClaw 一接上,模型开始“说工具话”,但没人听得懂

OpenClaw 一调用,我们看到了类似这样的回复:

<read>
<path>D:~gateway\node_modules\openclaw\skills\skill-vetter-1.0.0\SKILL.md</path>
</read>

还有这种:

<|DSML|tool_calls>
<|DSML|invoke name="exec">
...
</|DSML|invoke>
</|DSML|tool_calls>

第一次看到这个,很容易懵。

因为从模型角度看,它其实不是乱输出。
它是在尝试调用工具。

但问题是:
它输出的是 DSML / XML 风格的工具调用格式,而 OpenClaw 期望的是 OpenAI tool_calls JSON 格式。

所以系统没有把它当工具调用执行,而是把它当普通文本吐出来了。

这就是我们一直说的:

DSML 泄漏

表面现象是模型输出 <read><web_fetch><tool_calls>
本质问题是:

模型会调用工具
但推理框架没有把工具调用解析成 OpenAI 标准 tool_calls

这一步特别容易误判。

很多人会说:

模型不行。
OpenClaw 不行。
vLLM 不行。
工具调用不支持。

其实准确说是:

工具调用协议没有对齐

我们试过各种 parser,结果发现默认镜像没有 deepseek_v4

为了解决工具调用,我们开始试 parser。

先试:

--enable-auto-tool-choice
--tool-call-parser deepseek

直接报:

invalid tool call parser: deepseek

日志里列出支持的 parser:

deepseek_v3
deepseek_v31
deepseek_v32
...

没有 deepseek

那就改成:

--tool-call-parser deepseek_v3

再试:

--tool-call-parser deepseek_v32

这时候服务能起来了。

但问题是,OpenClaw 里仍然可能看到 <read><web_fetch> 这种文本泄漏。

后来我们才明白:

deepseek_v32 不是 deepseek_v4

DeepSeek V4 的工具调用标签和 V3.2 不完全一样。

那就试:

--tool-call-parser deepseek_v4

结果又炸了:

invalid tool call parser: deepseek_v4

这时候才真正确认:
当前 vllm-ascend:v0.13.0rc3 默认没有 deepseek_v4 parser。

这不是命令写错,也不是模型路径错。

就是镜像里没有这个功能。


我们也试过升级 vLLM,结果又踩了一个更大的坑

既然 v0.13.0rc3 没有,那是不是升级镜像就好了?

我们试过新版本。

结果发现:昇腾版 vLLM-Ascend 和主线 vLLM 不是完全同步的。

有些主线能力,Ascend 分支并没有及时合入。

更麻烦的是,vLLM 和 vLLM-Ascend 是强绑定的。

我们当时还遇到过一个典型错误:

ImportError: cannot import name 'set_random_seed' from 'vllm.utils.torch_utils'

这个错误的本质就是:

vllm 主库版本
和
vllm-ascend 插件版本
不匹配

这个坑非常致命。

因为它会让你误以为:

可能少装了一个包。
可能 Python 环境坏了。
可能 torch_npu 有问题。

实际上不是。

是你把一套原本匹配好的 Ascend 推理环境拆散了。

所以后面我们总结出来一句话:

昇腾环境不要乱 pip install,不要乱升级 vLLM,不要乱换 Transformers。

尤其是生产环境。


最危险的一步:pip install -e . 差点把环境带沟里

我们拿到 DeepSeek V4 Agentic Support 补丁之后,一开始想当然地执行:

pip install -e .

或者:

pip install -e . --no-deps

看起来很正常,对吧?

Python 项目打完 patch,重新 editable install,一般都是这么干。

结果在 vLLM-Ascend 容器里,这一步非常危险。

因为它会触发 vLLM 的构建流程,进入 CPU backend 编译路径。

日志里出现了:

Target device: cpu
Downloading Arm Compute Library

然后它开始从 GitHub 拉:

ARM-software/ComputeLibrary

最后因为网络问题失败:

Failed to clone repository

这一步我们踩得非常深。

后来才明白:

我们只是改 Python 层的 tokenizer / tool parser / reasoning parser
根本不需要重新编译 vLLM

所以正确做法不是:

pip install -e .

而是:

git apply patch
docker commit

这条经验非常值钱。

因为很多人一看到 patch,第一反应就是重新安装。
但在昇腾容器里,重新安装很可能把原本能跑的环境搞坏。


真正正确的路线:不是编译,而是 patch + commit

最后我们走通的路线其实很清晰。

第一,使用能正常启动的基础镜像:

quay.io/ascend/vllm-ascend:v0.13.0rc3

第二,模型使用:

/data/models/DeepSeek-V4-Flash-w8a8-mtp

第三,先用已有 parser 让容器活着:

--tool-call-parser deepseek_v32

第四,把补丁拷进容器:

docker cp deepseek-v4-agentic-support.patch $CID:/tmp/

第五,在容器里的 vLLM 源码目录打补丁:

cd /vllm-workspace/vllm
git apply --check /tmp/deepseek-v4-agentic-support.patch
git apply /tmp/deepseek-v4-agentic-support.patch

第六,千万不要 pip install。

第七,直接:

docker commit $CID vllm-ascend-deepseek-v4:patched

第八,启动时改成:

--tool-call-parser deepseek_v4
--tokenizer-mode deepseek_v4
--reasoning-parser deepseek_v4
--enable-auto-tool-choice

这才是最终稳定路线。


还有一个很现实的坑:容器和宿主机经常搞混

这次部署里,还有一个特别容易踩的坑:

我到底是在宿主机里?
还是在容器里?

我们多次遇到:

docker: command not found

后来发现,是在容器里执行了 docker 命令。

判断方式很简单:

root@ceshi002:~#          一般是宿主机
root@ceshi002:/workspace# 一般是容器

但有时候容器里的 hostname 也叫 ceshi002,看起来很像宿主机。

所以最稳的方法是:

pwd
ls /

如果看到:

/vllm-workspace
/workspace

大概率就是容器。

如果要打 patch,一定要搞清楚:

patch 文件在宿主机
vLLM 源码在容器里

所以要先:

docker cp ...

再:

docker exec ...

这个看似简单,但实际操作时非常容易乱。


这次最大的感悟:跑通模型不等于跑通 Agent

很多人做大模型部署,会把目标定成:

API 返回 200

但我们这次真正意识到:

API 200 只是第一层成功

真正的 Agent 系统还要看:

tool_choice=auto 能不能工作
tools 能不能被模型理解
模型输出能不能被 parser 解析
parser 能不能转成 OpenAI tool_calls
OpenClaw 能不能接住 tool_calls
工具能不能真正执行
执行结果能不能返回模型

这才是完整链路。

我们中间有一次 API 已经返回 200 了,日志里也有:

POST /v1/chat/completions HTTP/1.1 200 OK

但 OpenClaw 页面上还是输出 <read>

这就说明:

服务成功了
但 Agent 没成功

这个区别非常关键。


为什么 DeepSeek V4 这个问题会这么绕?

因为 DeepSeek V4 的工具调用不是简单的 JSON。

它更偏向 DSML / XML 风格。

而 OpenAI 生态里,大家更习惯的是:

{
  "tool_calls": [
    {
      "type": "function",
      "function": {
        "name": "...",
        "arguments": "..."
      }
    }
  ]
}

所以中间必须有人做翻译。

这个“翻译官”就是:

tool parser

而我们缺的正是:

deepseek_v4 tool parser

没有它,模型输出的是工具调用意图,但系统看不懂。

有了它,模型输出才能被转成标准的 OpenAI tool_calls。


这次部署给我的几个经验

第一,不要迷信“官方支持”这四个字。

官方支持要看清楚:

支持的是哪个镜像?
哪个版本?
哪个分支?
CUDA 还是 Ascend?
主线 vLLM 还是 vLLM-Ascend?

同样叫 vLLM,主线和 Ascend 分支能力可能并不同步。

第二,不要轻易升级依赖。

尤其是这种组合:

torch
torch_npu
vllm
vllm-ascend
transformers
triton-ascend

它们不是普通 Python 包关系,而是一整套推理生态。

你升级一个,可能牵一发动全身。

第三,不要随便 pip install -e .。

在普通 Python 项目里,这没问题。
在 vLLM-Ascend 容器里,这可能直接触发编译,甚至拉外部依赖,最后把环境搞乱。

第四,容器临时修改必须 commit。

你在容器里 patch 了源码,如果不:

docker commit

那一删容器,全没了。

第五,Agent 部署比普通模型部署难一个层级。

普通模型看生成文本。
Agent 看协议、工具、解析器、调用链、返回格式。


如果让我重新部署一次,我会这么做

我不会再从原版模型开始试。

我会直接确认:

是否有 Ascend 适配模型
是否是 w8a8
是否是 mtp
是否有对应 vllm-ascend 镜像
是否有 tool parser 补丁
是否需要 tokenizer-mode
是否需要 reasoning-parser

然后我会直接走:

vllm-ascend:v0.13.0rc3
+
DeepSeek-V4-Flash-w8a8-mtp
+
DeepSeek V4 Agentic Support Patch
+
docker commit
+
deepseek_v4 parser

而不是中间去试:

升级 transformers
升级 vllm
openai parser
pip install -e .

这些路不是完全没意义,但对生产部署来说,成本太高,风险也太大。


最后总结一句

这次部署最大的收获不是“把 DeepSeek V4 跑起来了”。

而是我们真正搞明白了:

模型部署
和
Agent 工具调用部署
完全不是一回事

模型跑起来,只是说明算力和权重链路通了。
工具调用跑通,才说明这个模型真的能进入 Agent 系统。

对于 DeepSeek V4 这种新模型来说,难点不只是参数量,不只是显存,不只是 NPU,而是整个生态链:

模型格式
推理框架
NPU 后端
工具协议
parser
OpenAI API
Agent 客户端

少一个环节,都会出问题。

这次我们从:

Transformers 不识别 deepseek_v4

到:

invalid tool call parser

再到:

DSML 泄漏

再到:

pip install 触发 CPU 编译

再到:

vllm 和 vllm-ascend 版本冲突

最后才走到:

patch + commit + deepseek_v4 parser

这条路踩了很多坑,但也正因为这样,这套经验才有价值。

如果你只是想“看起来跑了”,可能很快。
但如果你想“真的能用”,尤其是接 OpenClaw、接工具、接 Agent,那就必须把这些坑一个一个踩明白。

一句话:

DeepSeek V4 在昇腾上不是不能跑。
真正难的是:让它像一个 Agent 一样可靠地调用工具。

这才是这次部署最值得写出来的地方。

Logo

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

更多推荐