学习进度 · 登录后可记录
模型项目地址:OpenBMB/MiniCPM-V-4_5 课程难度:中级 · 需要 vLLM-ascend 基础和 Python 多模态开发经验 | 预估学时:30~45 分钟 部署架构:基于 vLLM-Ascend 推理引擎 + 昇腾 NPU + OpenAI 兼容 API 部署
本章结束后,你能够:
VLLM_LIMIT_MM_PER_PROMPT 关键环境变量本节课的目标是:在昇腾 NPU 上,基于 vLLM-Ascend 推理引擎,部署 MiniCPM-V-4_5——OpenBMB 开源的轻量级多模态大语言模型,支持纯文本理解、图片理解、OCR 识别等能力。
MiniCPM-V-4_5 的优势非常适合昇腾部署:模型整体仅 4.5B 参数,但支持百万上下文长度,同时具备优秀的 OCR 和多模态理解能力。小参数意味着更低显存占用,昇腾 910B 单卡即可轻松运行。
很多习惯了 CUDA 的开发者会认为:不就是在 vLLM 上加个多模态支持,直接改一下设备字符串不就行了?——这又是典型的 CUDA 思维定势。
多模态大模型与纯文本 LLM 在昇腾架构上的本质差异:
| 计算特征 | 纯文本 LLM | 多模态 LLM(MiniCPM-V-4_5) |
|---|---|---|
| 核心算子 | 连续矩阵乘(Cube 密集型) | MatMul + Vision Encoder 下采样 + Attention(Cube + Vector 混合) |
| 输入特征 | 离散 token 序列 | 文本 + 图片(像素张量)混合输入 |
| 显存特征 | KV Cache 占比高 | 图像特征张量占比高,多图场景更明显 |
| 关键配置 | max-model-len 控制上下文长度 | 必须额外配置 limit-mm-per-prompt 限制单prompt图像数量 |
┌──────────────────────────────────────────────────────┐
│ vLLM OpenAI 兼容 API 服务层 │
│ ┌────────────────────────────────────────────────┐ │
│ │ vllm serve → 兼容 /v1/chat/completions │ │
│ │ ├─ /health → 健康检查 │ │
│ │ └─ /v1/chat/completions → 纯文本/图片推理 │ │
│ └──────────────────┬───────────────────────────────┘ │
│ │ │
├─────────────────────┼────────────────────────────────┤
│ vLLM-Ascend 推理引擎 │
│ ┌──────────────────────┐ ┌──────────────────┐ │
│ │ PagedAttention NPU │ │ 多模态输入处理 │ │
│ │ 显存管理 │ │ (图片编码 + 特征插入)│ │
│ └──────────────────────┘ └──────────────────┘ │
│ ┌──────────▼──────────┐ │
│ │ CUBE+Vector 混合执行 │
├──────────────────────────────────────────────────────┤
│ 昇腾 NPU 硬件层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Scalar │ │ Vector │ │ CUBE 矩阵乘 │ │
│ │ 控制流 │ │ 图像下采样│ │ Attention 计算│ │
│ └──────────┘ └──────────┘ └──────────────┘ │
└──────────────────────────────────────────────────────┘设计思路:MiniCPM-V-4_5 模型权重托管在 AtomGit 平台,必须使用 atomgit_hub 工具下载。这一步只需要安装工具,不执行下载。
# [工具安装] 安装 atomgit SDK
!pip install -U atomgit atomgit_hub -i https://mirrors.huaweicloud.com/repository/pypi/simple设计思路:所有模型必须从 AtomGit 平台获取,禁止从其他平台默认源下载。使用 snapshot_download 将模型下载到本地固定路径 /opt/atomgit/MiniCPM-V-4_5。
# [模型下载] 从 AtomGit 平台下载 MiniCPM-V-4_5 模型
from atomgit_hub import snapshot_download
# 下载模型到本地固定路径
model_repo = "OpenBMB/MiniCPM-V-4_5"
local_dir = "/opt/atomgit/MiniCPM-V-4_5"
snapshot_download(model_repo, local_dir=local_dir)
print(f"模型已下载到: {local_dir}")设计思路:这是昇腾多模态部署中最容易踩坑的一步。和纯文本 LLM 不同,多模态模型必须额外配置 VLLM_LIMIT_MM_PER_PROMPT 环境变量,否则 vLLM-Ascend 无法正确计算图片显存占用。同时,必须成对设置昇腾设备变量:ASCEND_RT_VISIBLE_DEVICES + 清空 CUDA_VISIBLE_DEVICES。
# [环境准备] 杀掉旧进程避免端口占用
!pkill -f api_server || true# [昇腾多模态] 必须设置这个环境变量(限制每张prompt最多支持10张图片)
!export VLLM_LIMIT_MM_PER_PROMPT='{"image": 10}'# [设备配置] 设置 NPU 可见设备,禁用 CUDA 回退
!export ASCEND_RT_VISIBLE_DEVICES=0
!export CUDA_VISIBLE_DEVICES=# [服务启动] 后台启动 vLLM 服务,日志写入 vllm_server.log
!mkdir -p /opt/atomgit/MiniCPM-V-4_5
!cd /opt/atomgit/MiniCPM-V-4_5
!nohup vllm serve /opt/atomgit/MiniCPM-V-4_5 \
--served-model-name MiniCPM-V-4_5 \
--host 0.0.0.0 \
--port 8000 \
--dtype bfloat16 \
--trust-remote-code \
--max-num-seqs 2 \
--max-model-len 2048 \
--gpu-memory-utilization 0.8 \
--limit-mm-per-prompt '{"image": 10}' \
> vllm_server.log 2>&1 &
!echo "✅ 服务正在启动,请等待 10 秒..."
!sleep 10
!echo "📝 最后 30 行日志(检查是否启动成功):"
!tail -n 30 vllm_server.log设计思路:MiniCPM-V-4_5 支持三种输入场景,我们分别验证:纯文本对话、图片 URL 推理、Base64 图片推理。所有测试都通过 OpenAI 兼容的 /v1/chat/completions 接口完成。
# [测试1] 验证纯文本理解能力
import requests
payload = {
"model": "MiniCPM-V-4_5",
"messages": [
{"role": "user", "content": "请用中文写一首关于秋天的五言绝句。"}
],
"max_tokens": 100
}
print("🚀 正在测试纯文本能力...")
response = requests.post("http://localhost:8000/v1/chat/completions", json=payload)
if response.status_code == 200:
print(response.json()['choices'][0]['message']['content'])
else:
print(f"Error: {response.status_code}")
print(response.text)# [测试2] 验证图片 URL 理解能力
import requests
import json
url = "http://localhost:8000/v1/chat/completions"
payload = {
"model": "MiniCPM-V-4_5",
"messages": [{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": "https://cdn-static.gitcode.com/_nuxtaihub/chatexample_64.png"}},
{"type": "text", "text": "请详细描述这张图片的内容。"}
]
}],
"max_tokens": 512,
"temperature": 0.7
}
headers = {"Content-Type": "application/json"}
print("🚀 正在发送图片 URL 请求...")
response = requests.post(url, headers=headers, data=json.dumps(payload), timeout=120)
if response.status_code == 200:
print("✅ 请求成功!响应内容:\n")
print(response.json()['choices'][0]['message']['content'])
else:
print(f"❌ 请求失败,状态码: {response.status_code}")
print("错误详情:", response.text)# [测试3] 验证 Base64 本地图片理解能力
import requests
import base64
# 1. 下载图片并转为 Base64
image_url = "https://cdn-static.gitcode.com/_nuxtaihub/chatexample_64.png"
try:
response = requests.get(image_url)
response.raise_for_status()
base64_image = base64.b64encode(response.content).decode('utf-8')
print("✅ 图片已成功下载并转换为 Base64")
except Exception as e:
print(f"❌ 图片下载失败: {e}")
import sys
sys.exit()
# 2. 构造请求体
payload = {
"model": "MiniCPM-V-4_5",
"messages": [
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{base64_image}"
}
},
{
"type": "text",
"text": "请详细描述这张图片的内容。"
}
]
}
],
"max_tokens": 512
}
# 3. 发送请求
api_url = "http://localhost:8000/v1/chat/completions"
headers = {"Content-Type": "application/json"}
print("🚀 正在发送 Base64 图片请求...")
response = requests.post(api_url, headers=headers, json=payload)
# 4. 打印结果
if response.status_code == 200:
result = response.json()
content = result['choices'][0]['message']['content']
print("\n--- 模型回答 ---")
print(content)
else:
print(f"❌ 请求失败: {response.status_code}")
print(response.text)VLLM_LIMIT_MM_PER_PROMPT很多习惯了 CUDA + vLLM 的开发者在这里容易踩坑:以为纯文本部署能跑,多模态直接加参数就行,结果启动时报错 path string is NULL。
根本原因:昇腾 vLLM 对于多模态输入,需要提前知道每张 prompt 最多容纳多少张图片,才能提前分配显存。如果不设置 VLLM_LIMIT_MM_PER_PROMPT 环境变量,显存分配逻辑会走 CUDA 分支,导致昇腾驱动报错。
解决方案:启动服务前,必须在环境变量中设置:
export VLLM_LIMIT_MM_PER_PROMPT='{"image": 10}'同时,在 vllm serve 命令行参数中也必须重复一次该配置,确保前后一致。
CUDA_VISIBLE_DEVICES另一个高频踩坑点:只设置了 ASCEND_RT_VISIBLE_DEVICES=0,忘记清空 CUDA_VISIBLE_DEVICES。
问题表现:vLLM 启动正常,但推理时 PyTorch 报 CUDA not available 或者直接段错误。
根本原因:torch_npu 在初始化时会检查 CUDA_VISIBLE_DEVICES 的值。如果该变量非空,PyTorch 会优先尝试 CUDA 路径,失败后才回退到 NPU——但回退过程中 vLLM 已经完成了设备初始化,导致状态不一致。
解决方案:始终成对设置:
export ASCEND_RT_VISIBLE_DEVICES=0 # 指定昇腾可见设备
export CUDA_VISIBLE_DEVICES= # 必须清空,防止 CUDA 回退| 环境变量 | 默认值 | 说明 |
|---|---|---|
VLLM_LIMIT_MM_PER_PROMPT | {"image": 10} | 必须设置,限制每张 prompt 最多支持多少张图片 |
ASCEND_RT_VISIBLE_DEVICES | 0 | 昇腾 NPU 可见设备 ID |
CUDA_VISIBLE_DEVICES | (空) | 必须清空,防止 CUDA 回退导致初始化失败 |
MODEL_DIR | /opt/atomgit/MiniCPM-V-4_5 | 模型本地目录 |
PORT | 8000 | API 服务监听端口 |
| 问题 | 原因 | 解决方案 |
|---|---|---|
ModuleNotFoundError: No module named 'atomgit_hub' | 安装后未重启内核 | 重启 Jupyter 内核后重试 |
path string is NULL | 未设置 VLLM_LIMIT_MM_PER_PROMPT | 停止旧服务,设置环境变量后重新启动 |
No CUDA GPUs are available | CUDA_VISIBLE_DEVICES 未清空 | 执行 export CUDA_VISIBLE_DEVICES= 后重新启动 |
| 端口 8000 被占用 | 旧服务未正确停止 | 执行 pkill -f api_server 杀掉旧进程,重新启动 |
| 图片推理返回空结果 | Base64 格式错误 | 检查 Base64 是否添加了 data:image/png;base64, 前缀 |
| 模型加载极慢 | 未正确从本地加载 | 确认模型完整下载到 /opt/atomgit/MiniCPM-V-4_5 目录 |
GET /health响应:200 OK 表示服务正常运行。
POST /v1/chat/completions
Content-Type: application/json请求体:完全兼容 OpenAI ChatCompletion 格式:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
model | string | ✅ | 必须填写 MiniCPM-V-4_5 |
messages | array | ✅ 对话消息数组 | |
messages[].role | string | ✅ user / assistant / system | |
messages[].content | string / array | ✅ 纯文本为 string,多模态为 array | |
messages[].content[].type | string | ✅ text / image_url | |
messages[].content[].text | string | ❌ 文本内容(type=text 时必填) | |
messages[].content[].image_url | dict | ❌ 图片信息(type=image_url 时必填) | |
messages[].content[].image_url.url | string | ✅ 图片 URL 或 data:image/png;base64,... | |
max_tokens | int | ❌ 最大生成 token 数,默认 512 | |
temperature | float | ❌ 采样温度,默认 0.7 |
响应:完全兼容 OpenAI ChatCompletion 响应格式,回复文本在 choices[0].message.content。
登录后即可查看完整教程内容、运行代码和参
与学习互动
还没有账号?