MiniCPM-V 4.7
MiniCPM-V Multimodal Series
把模型接入自己的服务:vLLM 与 SGLang 面向高吞吐的 GPU 服务,llama.cpp 与 Ollama 面向本地与端侧运行。按硬件与场景选择其一,本页给出各自的安装、启动与调用步骤。
MiniCPM-V 4.7 提供两个尺寸,各框架均通过切换模型路径使用:
| 尺寸 | HuggingFace ID | ModelScope ID |
|---|---|---|
| 1B(dense) | openbmb/MiniCPM-V-4.7-1B | OpenBMB/MiniCPM-V-4.7-1B |
| 35B-A3B(MoE) | openbmb/MiniCPM-V-4.7-35B-A3B | OpenBMB/MiniCPM-V-4.7-35B-A3B |
| 框架 | 状态 | 适用场景 |
|---|---|---|
| vLLM | 上游已支持(PR #58674) | 高吞吐 GPU 服务 |
| SGLang | 走 fork tc-mb/sglang,上游 PR 进行中 | 高吞吐 GPU 服务 |
| llama.cpp | 上游已支持(PR #29416) | 本地 CPU / Metal |
| Ollama | 模型代码已就绪,运行时待内置 llama.cpp 同步 | 本地快速体验 |
MiniCPM-V 4.7 注册为 MiniCPMV4_7ForConditionalGeneration,需 transformers >= 5.18.0,各框架均无需 trust_remote_code。MiniCPM-V 4.7 使用 Qwen3.5 词表,stop token 为 [248044, 248046](MiniCPM-V 4.5 是 [1, 151645])。
vLLM
MiniCPM-V 4.7 已在 PR #58674 合入官方 vLLM main。无需 fork —— 从上游安装即可,确保 checkout 在该提交之后。
环境准备
# 新建干净的 conda 环境
conda create -n vllm-v47 python=3.10 -y
conda activate vllm-v47
# 从上游 main 安装(需 CUDA toolkit;HEAD 需含 #58674)
git clone https://github.com/vllm-project/vllm.git
cd vllm
MAX_JOBS=6 VLLM_USE_PRECOMPILED=1 pip install --editable . -v
一旦含 #58674 的 vLLM 正式版发布,pip install -U vllm 即可,无需编译。
视频推理需安装视频模块:
pip install vllm[video]
验证安装:
python -c "import vllm, transformers; print('vllm', vllm.__version__, '| transformers', transformers.__version__)"
启动 API 服务
vllm serve <model_path> \
--dtype auto \
--max-model-len 8192 \
--api-key token-abc123 \
--gpu_memory_utilization 0.9 \
--max-num-batched-tokens 8192
<model_path>:本地路径,或openbmb/MiniCPM-V-4.7-1B/openbmb/MiniCPM-V-4.7-35B-A3B。--api-key:API 访问密钥。--max-model-len:最大上下文长度(MiniCPM-V 4.7 支持到 256K,按显存先设小)。--gpu_memory_utilization:显存利用率。
图片推理
from openai import OpenAI
import base64
openai_api_key = "token-abc123" # 需与 vllm serve 传入的一致
openai_api_base = "http://localhost:8000/v1"
client = OpenAI(api_key=openai_api_key, base_url=openai_api_base)
with open('./assets/airplane.jpeg', 'rb') as file:
image = "data:image/jpeg;base64," + base64.b64encode(file.read()).decode('utf-8')
chat_response = client.chat.completions.create(
model="<model_path>",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "请描述这张图片"},
{"type": "image_url", "image_url": {"url": image}},
],
}],
extra_body={
# 4.7 使用 Qwen3.5 词表,stop token 与 4.6 相同
"stop_token_ids": [248044, 248046],
# 关闭 <think> 块以获得直答
"chat_template_kwargs": {"enable_thinking": False},
}
)
print(chat_response.choices[0].message.content)
视频推理
from openai import OpenAI
import base64
openai_api_key = "token-abc123"
openai_api_base = "http://localhost:8000/v1"
client = OpenAI(api_key=openai_api_key, base_url=openai_api_base)
with open('./videos/video.mp4', 'rb') as video_file:
video_base64 = base64.b64encode(video_file.read()).decode('utf-8')
chat_response = client.chat.completions.create(
model="<model_path>",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{
"role": "user",
"content": [
{"type": "text", "text": "请描述这段视频"},
{"type": "video_url", "video_url": {"url": f"data:video/mp4;base64,{video_base64}"}},
],
},
],
extra_body={"stop_token_ids": [248044, 248046]},
)
print(chat_response.choices[0].message.content)
调整单视频帧切片预算:
extra_body = {
"stop_token_ids": [248044, 248046],
"mm_processor_kwargs": {"max_slice_nums": 2},
}
多图 / 多视频
启动时提高 --limit-mm-per-prompt 预算:
# 单请求最多 5 图 + 2 视频
vllm serve <model_path> --dtype auto --max-model-len 16384 --api-key token-abc123 \
--gpu_memory_utilization 0.9 \
--limit-mm-per-prompt '{"image": 5, "video": 2}'
离线推理
from transformers import AutoProcessor
from PIL import Image
from vllm import LLM, SamplingParams
MODEL_NAME = "<model_path>" # 或 "openbmb/MiniCPM-V-4.7-1B"
image = Image.open("./assets/airplane.jpeg").convert("RGB")
processor = AutoProcessor.from_pretrained(MODEL_NAME)
llm = LLM(
model=MODEL_NAME,
max_model_len=8192,
disable_mm_preprocessor_cache=True,
limit_mm_per_prompt={"image": 5},
)
messages = [{
"role": "user",
"content": [
{"type": "image"},
{"type": "text", "text": "请描述这张图片的内容"},
],
}]
prompt = processor.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
inputs = {"prompt": prompt, "multi_modal_data": {"image": image}}
sampling_params = SamplingParams(
stop_token_ids=[248044, 248046],
temperature=0.7,
top_p=0.8,
max_tokens=1024,
)
outputs = llm.generate(inputs, sampling_params=sampling_params)
print(outputs[0].outputs[0].text)
注意事项
- 显存:1B 单张消费级卡即可;35B-A3B(bf16 约 70 GB)需多卡或 4-bit 权重(
-AWQ/-GPTQ/-FP8/-INT4)。按硬件调--gpu_memory_utilization/--max-model-len/--max-num-batched-tokens。 - 多模态上限:多 图 / 多视频会话用
--limit-mm-per-prompt。
SGLang
MiniCPM-V 4.7 暂未合入上游 SGLang。请使用 fork tc-mb/sglang 的 Support-MiniCPM-V4.7 分支。上游 PR 进行中,合入后可直接安装 SGLang main。
安装
git clone -b Support-MiniCPM-V4.7 https://github.com/tc-mb/sglang.git
cd sglang
pip install --upgrade pip
pip install -e "python[all]"
验证环境:
python -c "import torch, transformers; print('torch', torch.__version__, '| cuda', torch.version.cuda, '| transformers', transformers.__version__)"
安装 FlashInfer(可选,推荐)
FlashInfer 的 wheel 与特定 (torch, cuda) 组合绑定。请选择与上面刚验证过的 torch + CUDA 匹配的索引 —— 不要盲目照抄 cu121/torch2.4 这类 URL。
通用索引见 flashinfer.ai/whl,例如:
| 你的 torch / CUDA | 索引 URL |
|---|---|
| torch 2.7 + CUDA 12.8 | https://flashinfer.ai/whl/cu128/torch2.7/ |
pip install flashinfer-python -i <上表对应索引 URL>
Docker 镜像与纯 CPU 回退见 SGLang 官方安装文档。
启动推理服务
# 1B
python -m sglang.launch_server --model-path openbmb/MiniCPM-V-4.7-1B --port 30000 --dtype bfloat16
# 35B-A3B(需大显存节点;用 --tp-size 跨卡分片)
python -m sglang.launch_server --model-path openbmb/MiniCPM-V-4.7-35B-A3B --port 30000 --dtype bfloat16 --tp-size 2
或指定本地路径:
python -m sglang.launch_server --model-path /your/local/MiniCPM-V-4.7-1B --port 30000 --dtype bfloat16
调用服务
curl:
curl -s http://localhost:30000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "MiniCPM-V-4.7-1B",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "What is in this image?"},
{
"type": "image_url",
"image_url": {
"url": "https://github.com/OpenSQZ/MiniCPM-V-CookBook/blob/main/inference/assets/airplane.jpeg?raw=true"
}
}
]
}
],
"max_tokens": 300,
"top_k": -1
}'
Python(OpenAI 客户端):
from openai import OpenAI
client = OpenAI(base_url="http://localhost:30000/v1", api_key="None")
response = client.chat.completions.create(
model="MiniCPM-V-4.7-1B",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What is in this image?"},
{
"type": "image_url",
"image_url": {
"url": "https://github.com/OpenSQZ/MiniCPM-V-CookBook/blob/main/inference/assets/airplane.jpeg?raw=true",
},
},
],
}
],
max_tokens=300,
extra_body={"top_k": -1, "stop_token_ids": [248044, 248046]},
)
print(response.choices[0].message.content)
- 若
image_url本机不可达,换成本地路径 / base64 data URL。 - 若模型在答案后继续输出,传入
stop_token_ids = [248044, 248046]。 - 如需关闭
<think>块,传chat_template_kwargs={"enable_thinking": false}(或服务端等价默认值)。
llama.cpp
MiniCPM-V 4.7 已合入官方 llama.cpp(PR #29416)。请使用该 PR 之后(含)的 checkout 构建。
每个尺寸使用对应的一套 GGUF:
| 尺寸 | LLM 文件 | mmproj |
|---|---|---|
| 1B | MiniCPM-V-4_7-1B-Q4_K_M.gguf | mmproj-model-f16.gguf |
| 35B-A3B | MiniCPM-V-4_7-35B-A3B-Q4_K_M.gguf | mmproj-model-f16.gguf |
构建 llama.cpp
git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
用 CMake 构建(详见 build 文档):
# CPU / Metal
cmake -B build
cmake --build build --config Release
# CUDA
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release
获取 GGUF 文件
下载官方 GGUF(语言模型 GGUF 与视觉投影 mmproj):
- HuggingFace:MiniCPM-V-4.7-1B-gguf · MiniCPM-V-4.7-35B-A3B-gguf
- ModelScope:
OpenBMB/MiniCPM-V-4.7-1B-gguf/OpenBMB/MiniCPM-V-4.7-35B-A3B-gguf
每个仓库提供完整的 K-quant 档位(F16、Q8_0、Q6_K、Q5_K_M、Q5_K_S、Q5_1、Q5_0、Q4_K_M、Q4_K_S、Q4_1、Q4_0)以及两个 mmproj(mmproj-model-f16.gguf、mmproj-model-f16-4x.gguf)。35B-A3B 仓库额外提供 mix_q3gud_im(14.4 GiB 的 imatrix 混合量化,推荐用于显存受限设备)。
也可以从 PyTorch 权重自行转换,步骤见量化。
模型推理
近期 llama.cpp 默认 --reasoning 为 auto,会依据对话模板开启思考。MiniCPM-V 4.7 模板默认开启思考,因此普通问答请显式传 --reasoning off。
cd build/bin/
# F16 权重(1B)
./llama-mtmd-cli \
-m /path/to/MiniCPM-V-4.7-1B/MiniCPM-V-4_7-1B-F16.gguf \
--mmproj /path/to/MiniCPM-V-4.7-1B/mmproj-model-f16.gguf \
-c 8192 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 \
--reasoning off \
--image xx.jpg -p "What is in the image?"
# 量化 INT4 权重(35B-A3B)
./llama-mtmd-cli \
-m /path/to/MiniCPM-V-4.7-35B-A3B/MiniCPM-V-4_7-35B-A3B-Q4_K_M.gguf \
--mmproj /path/to/MiniCPM-V-4.7-35B-A3B/mmproj-model-f16.gguf \
-c 8192 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 \
--reasoning off \
--image xx.jpg -p "What is in the image?"
# 交互模式
./llama-mtmd-cli \
-m /path/to/MiniCPM-V-4.7-1B/MiniCPM-V-4_7-1B-Q4_K_M.gguf \
--mmproj /path/to/MiniCPM-V-4.7-1B/mmproj-model-f16.gguf \
-c 8192 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 \
--reasoning off \
--image xx.jpg -i
开启思考(重 OCR / 推理任务)用 --reasoning on(--jinja 默认已开):
./llama-mtmd-cli \
-m /path/to/MiniCPM-V-4.7-1B/MiniCPM-V-4_7-1B-Q4_K_M.gguf \
--mmproj /path/to/MiniCPM-V-4.7-1B/mmproj-model-f16.gguf \
-c 8192 --image xx.jpg --jinja --reasoning on -p "What is in the image?"
参数参考:
| 参数 | 说明 |
|---|---|
-m, --model | 语言模型 GGUF 路径 |
--mmproj | 视觉投影 GGUF 路径 |
--image | 输入图片路径 |
-p, --prompt | 提示词 |
-c, --ctx-size | 最大上下文长度 |
-rea, --reasoning [on|off|auto] | 是否开启思考。默认 auto(读模板)。普通问答用 off |
--jinja | 使用模型 Jinja 对话模板(近期构建默认开启) |
Ollama
安装 Ollama
- macOS:Ollama.dmg
- Windows:OllamaSetup.exe
- Linux:
curl -fsSL https://ollama.com/install.sh | sh - Docker:Docker Hub 上的
ollama/ollama
从注册表运行
待内置引擎更新的正式版发布后,从 Ollama 注册表拉取官方模型:
ollama run openbmb/minicpm-v4.7
命令行中,提示词与图片路径用空格分隔:
What is in the picture? xx.jpg
API 调用:
import base64, requests
with open("xx.jpg", "rb") as image_file:
encoded_string = base64.b64encode(image_file.read()).decode("utf-8")
data = {
"model": "openbmb/minicpm-v4.7",
"prompt": "What is in the picture?",
"stream": False,
"images": [encoded_string], # 可放多张 base64 图片
}
response = requests.post("http://localhost:11434/api/generate", json=data)
加载本地 GGUF
要加载本地 GGUF(如自定义量化或指定尺寸),需创建一个 Modelfile。
vim minicpmv4.7.Modelfile
Modelfile 内容(1B 示例):
FROM ./MiniCPM-V-4.7-1B-gguf/MiniCPM-V-4_7-1B-Q4_K_M.gguf
FROM ./MiniCPM-V-4.7-1B-gguf/mmproj-model-f16.gguf
TEMPLATE """{{- if .Messages }}{{- range $i, $_ := .Messages }}{{- $last := eq (len (slice $.Messages $i)) 1 -}}<|im_start|>{{ .Role }}{{ .Content }}{{- if $last }}{{- if (ne .Role "assistant") }}<|im_end|><|im_start|>assistant{{ end }}{{- else }}<|im_end|>{{ end }}{{- end }}{{- else }}{{- if .System }}<|im_start|>system{{ .System }}<|im_end|>{{ end }}{{ if .Prompt }}<|im_start|>user{{ .Prompt }}<|im_end|>{{ end }}<|im_start|>assistant{{ end }}{{ .Response }}{{ if .Response }}<|im_end|>{{ end }}"""
SYSTEM """You are a helpful assistant."""
PARAMETER top_p 0.8
PARAMETER num_ctx 8192
PARAMETER stop ["<|im_start|>", "<|im_end|>"]
PARAMETER temperature 0.7
35B-A3B 时,把第一个 FROM 改为 MiniCPM-V-4.7-35B-A3B-gguf/MiniCPM-V-4_7-35B-A3B-Q4_K_M.gguf。
创建并运行:
ollama create minicpm-v4.7 -f minicpmv4.7.Modelfile
ollama run minicpm-v4.7
说明
- 模板:MiniCPM-V 4.7 的
chat_template.jinja与 MiniCPM-V 4.6 逐字节相同,故上面的TEMPLATE与openbmb/minicpm-v4.6所用一致。 - 不设
RENDERER:与官方openbmb/minicpm-v4.6一致(familyqwen35、无 renderer 字段),Ollama 走 native 模式,使用 GGUF 内嵌对话模板 + mmproj。 - 思考:模板默 认开启;如需直答,可通过请求传
enable_thinking: false(或改用支持chat_template_kwargs的运行时)。