MiniMax-M3¶
1 简介¶
MiniMax-M3 是一个支持文本、图像和视频输入的多模态大语言模型。在昇腾上,它支持 BF16 和 W8A8 部署、思考模式、推理解析、工具调用解析以及多模态输入。
本文档涵盖支持的特性、环境和模型准备、单节点部署、多节点部署、思考与解析器配置、功能验证、精度评估以及故障排查。
本文档基于最新的 vLLM-Ascend 版本编写。该模型在 main 分支上受支持。
2 支持的特性¶
模型支持矩阵请参考支持的模型。
特性配置说明请参考特性指南。
3 前提条件¶
3.1 模型权重¶
MiniMax-M3 BF16 模型需要 16 × 64 GB NPU 芯片。下载模型权重。
我们还提供 W8A8 量化模型,至少需要 8 x 64G NPU 芯片。下载模型权重。
建议将模型权重放置在共享缓存目录中。
3.2 验证多节点通信(可选)¶
对于多节点部署,请按照验证多节点通信环境验证通信环境。
4 安装¶
4.1 Docker 镜像安装¶
您可以使用官方一体化 Docker 镜像。有关可用的镜像标签和已发布版本,请参考使用 Docker。
-
步骤 1:下载最新的 Docker 镜像
-
步骤 2:启动 Docker 容器
# Set the vLLM Ascend image name. export IMAGE=quay.io/ascend/vllm-ascend:{tag} export NAME=minimax-m3-dev # Start the container with the variables defined above. # Update --device for your hardware (Atlas A3: /dev/davinci[0-15]; Atlas A2: /dev/davinci[0-7]). # If you use a Docker bridge network, open the ports required for multi-node communication in advance. docker run --rm \ --name $NAME \ --net=host \ --shm-size=100g \ --device /dev/davinci0 \ --device /dev/davinci1 \ --device /dev/davinci2 \ --device /dev/davinci3 \ --device /dev/davinci4 \ --device /dev/davinci5 \ --device /dev/davinci6 \ --device /dev/davinci7 \ --device /dev/davinci8 \ --device /dev/davinci9 \ --device /dev/davinci10 \ --device /dev/davinci11 \ --device /dev/davinci12 \ --device /dev/davinci13 \ --device /dev/davinci14 \ --device /dev/davinci15 \ --device /dev/davinci_manager \ --device /dev/devmm_svm \ --device /dev/hisi_hdc \ -v /usr/local/dcmi:/usr/local/dcmi \ -v /usr/local/Ascend/driver/tools/hccn_tool:/usr/local/Ascend/driver/tools/hccn_tool \ -v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \ -v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \ -v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \ -v /etc/ascend_install.info:/etc/ascend_install.info \ -v /root/.cache:/root/.cache \ -it $IMAGE bash -
步骤 3:编译 Rust 前端
-
步骤 4:安装验证:
启动容器后,运行以下命令验证安装:
预期结果:容器以状态 Up 列出。您还可以在容器内验证 vllm-ascend 版本:
预期结果:显示版本信息,与拉取的镜像版本一致。
5 在线服务部署¶
使用以下命令启动在线推理服务:
有关部署示例中使用的标准 vllm serve 参数的说明,请参考 vLLM Serving 参数文档。有关通过 --additional-config 传递的昇腾特定选项,请参考附加配置。有关昇腾特定的环境变量,请参考环境变量。
5.1 单节点部署¶
单节点部署在同一节点内完成 Prefill 和 Decode。BF16 模型和量化模型都可以部署在 1 台 Atlas 800 A3(64GB × 16)上。量化模型可以部署在 1 台 Atlas 800 A2(64GB × 8)上。
export PYTORCH_NPU_ALLOC_CONF="expandable_segments:True"
export HCCL_OP_EXPANSION_MODE="AIV"
export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
vllm serve ${WEIGHT_PATH} \
--served-model-name minimax-m3 \
--trust-remote-code \
--max-model-len 43008 \
--tensor-parallel-size 16 \
--enable-expert-parallel \
--max-num-seqs 16 \
--distributed_executor_backend "mp" \
--gpu-memory-utilization 0.92 \
--reasoning-parser minimax_m3 \
--limit-mm-per-prompt '{"image":1}' \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
--additional-config '{
"enable_cpu_binding": true,
"ascend_compilation_config": {
"enable_static_kernel": true,
"fuse_norm_quant": false
},
"multistream_overlap_shared_expert": true,
"weight_nz_mode": 2,
"enable_flashcomm1": true,
"enable_reduce_sample": true
}' \
--port 11223 > ${LOG_PATH} 2>&1 &
export PYTORCH_NPU_ALLOC_CONF="expandable_segments:True"
export HCCL_OP_EXPANSION_MODE="AIV"
export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
vllm serve ${WEIGHT_PATH} \
--served-model-name minimax-m3 \
--trust-remote-code \
--max-model-len 131072 \
--tensor-parallel-size 4 \
--data-parallel-size 4 --api_server_count 1 \
--max-num-batched-tokens 32768 \
--long-prefill-token-threshold 4096 \
--enable-expert-parallel \
--max-num-seqs 32 \
--distributed_executor_backend "mp" \
--gpu-memory-utilization 0.92 \
--reasoning-parser minimax_m3 \
--limit-mm-per-prompt '{"image":1}' \
--speculative-config '{"model":"${EAGLE3_WEIGHT_PATH}", "method":"eagle3", "num_speculative_tokens":3}' \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
--additional-config '{
"enable_cpu_binding": true,
"ascend_compilation_config": {
"enable_static_kernel": true,
"fuse_norm_quant": false
},
"multistream_overlap_shared_expert": true,
"enable_shared_expert_dp": true,
"weight_nz_mode": 2,
"enable_flashcomm1": true,
"enable_reduce_sample": true
}' \
--port 11223 > ${LOG_PATH} 2>&1 &
注意:在上述脚本中,max-num-seqs 设置为 16,表示调度器在单次迭代中可处理的最大序列数。请根据实际业务动态调整 max-num-seqs 参数。
对于纯文本部署,可以省略 --limit-mm-per-prompt。对于多模态部署,请根据实际请求形态配置此参数。例如,对于双图像请求,使用 --limit-mm-per-prompt '{"image":2}';对于单视频请求,使用 --limit-mm-per-prompt '{"video":1}'。
5.2 多节点部署¶
在昇腾 A2 服务器上部署 BF16 模型至少需要两个节点。不建议在没有 prefill-decode 分离的情况下在 A3 服务器上进行多节点部署。请根据实际环境更新 WEIGHT_PATH、EAGLE3_WEIGHT_PATH、LOG_PATH、local_ip、node0_ip 和 IFNAME。
在节点 0 上运行以下命令:
local_ip="${NODE0_IP}"
node0_ip="${NODE0_IP}"
export HCCL_IF_IP=$local_ip
export IFNAME="${NETWORK_INTERFACE}"
export GLOO_SOCKET_IFNAME="$IFNAME"
export TP_SOCKET_IFNAME="$IFNAME"
export HCCL_SOCKET_IFNAME="$IFNAME"
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
export VLLM_ENGINE_READY_TIMEOUT_S=3600
export HCCL_CONNECT_TIMEOUT=7200
export ASCEND_CONNECT_TIMEOUT=10000
export ASCEND_TRANSFER_TIMEOUT=10000
export VLLM_RPC_TIMEOUT=1800000
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_OP_EXPANSION_MODE="AIV"
export TASK_QUEUE_ENABLE=1
export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
vllm serve ${WEIGHT_PATH} \
--host 0.0.0.0 \
--served-model-name minimax-m3 \
--trust-remote-code \
--max-model-len 40960 \
--tensor-parallel-size 8 \
--enable-expert-parallel \
--max-num-seqs 8 \
--data-parallel-size 2 \
--data-parallel-size-local 1 \
--data-parallel-start-rank 0 \
--data-parallel-address $node0_ip \
--distributed_executor_backend "mp" \
--gpu-memory-utilization 0.94 \
--reasoning-parser minimax_m3 \
--limit-mm-per-prompt '{"image":1}' \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
--additional-config '{"enable_cpu_binding":true, "ascend_compilation_config":{"fuse_norm_quant":false}, "multistream_overlap_shared_expert": true, "weight_nz_mode": 2}' \
--port 11223 > ${LOG_PATH} 2>&1 &
在节点 1 上运行以下命令:
local_ip="${NODE1_IP}"
node0_ip="${NODE0_IP}"
export HCCL_IF_IP=$local_ip
export IFNAME="${NETWORK_INTERFACE}"
export GLOO_SOCKET_IFNAME="$IFNAME"
export TP_SOCKET_IFNAME="$IFNAME"
export HCCL_SOCKET_IFNAME="$IFNAME"
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
export VLLM_ENGINE_READY_TIMEOUT_S=3600
export HCCL_CONNECT_TIMEOUT=7200
export ASCEND_CONNECT_TIMEOUT=10000
export ASCEND_TRANSFER_TIMEOUT=10000
export VLLM_RPC_TIMEOUT=1800000
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export HCCL_OP_EXPANSION_MODE="AIV"
export TASK_QUEUE_ENABLE=1
export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
vllm serve ${WEIGHT_PATH} \
--host 0.0.0.0 \
--served-model-name minimax-m3 \
--trust-remote-code \
--headless \
--max-model-len 40960 \
--tensor-parallel-size 8 \
--enable-expert-parallel \
--max-num-seqs 8 \
--data-parallel-size 2 \
--data-parallel-size-local 1 \
--data-parallel-start-rank 1 \
--data-parallel-address $node0_ip \
--distributed_executor_backend "mp" \
--gpu-memory-utilization 0.94 \
--reasoning-parser minimax_m3 \
--limit-mm-per-prompt '{"image":1}' \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
--additional-config '{"enable_cpu_binding":true, "ascend_compilation_config":{"fuse_norm_quant":false}, "multistream_overlap_shared_expert": true, "weight_nz_mode": 2}' \
--port 11223 > ${LOG_PATH} 2>&1 &
在节点 0 上运行以下命令:
local_ip="${NODE0_IP}"
node0_ip="${NODE0_IP}"
export HCCL_IF_IP=$local_ip
export IFNAME="${NETWORK_INTERFACE}"
export GLOO_SOCKET_IFNAME="$IFNAME"
export TP_SOCKET_IFNAME="$IFNAME"
export HCCL_SOCKET_IFNAME="$IFNAME"
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
export VLLM_ENGINE_READY_TIMEOUT_S=3600
export HCCL_CONNECT_TIMEOUT=7200
export ASCEND_CONNECT_TIMEOUT=10000
export ASCEND_TRANSFER_TIMEOUT=10000
export VLLM_RPC_TIMEOUT=1800000
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=30000
export PYTORCH_NPU_ALLOC_CONF="expandable_segments:True"
export HCCL_OP_EXPANSION_MODE="AIV"
export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
vllm serve ${WEIGHT_PATH} \
--host 0.0.0.0 \
--served-model-name minimax-m3 \
--trust-remote-code \
--max-model-len 131072 \
--tensor-parallel-size 8 \
--enable-expert-parallel \
--max-num-seqs 8 \
--data-parallel-size 2 \
--data-parallel-size-local 1 \
--data-parallel-start-rank 0 \
--data-parallel-address $node0_ip \
--distributed_executor_backend "mp" \
--gpu-memory-utilization 0.92 \
--reasoning-parser minimax_m3 \
--limit-mm-per-prompt '{"image":1}' \
--speculative-config '{"model":"${EAGLE3_WEIGHT_PATH}", "method":"eagle3", "num_speculative_tokens":3}' \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
--additional-config '{"enable_cpu_binding":true, "ascend_compilation_config":{"fuse_norm_quant":false}, "multistream_overlap_shared_expert": false, "weight_nz_mode": 2, "enable_flashcomm1": true}' \
--port 11223 > ${LOG_PATH} 2>&1 &
在节点 1 上运行以下命令:
local_ip="${NODE1_IP}"
node0_ip="${NODE0_IP}"
export HCCL_IF_IP=$local_ip
export IFNAME="${NETWORK_INTERFACE}"
export GLOO_SOCKET_IFNAME="$IFNAME"
export TP_SOCKET_IFNAME="$IFNAME"
export HCCL_SOCKET_IFNAME="$IFNAME"
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
export VLLM_ENGINE_READY_TIMEOUT_S=3600
export HCCL_CONNECT_TIMEOUT=7200
export ASCEND_CONNECT_TIMEOUT=10000
export ASCEND_TRANSFER_TIMEOUT=10000
export VLLM_RPC_TIMEOUT=1800000
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=30000
export PYTORCH_NPU_ALLOC_CONF="expandable_segments:True"
export HCCL_OP_EXPANSION_MODE="AIV"
export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
vllm serve ${WEIGHT_PATH} \
--host 0.0.0.0 \
--served-model-name minimax-m3 \
--trust-remote-code \
--headless \
--max-model-len 131072 \
--tensor-parallel-size 8 \
--enable-expert-parallel \
--max-num-seqs 8 \
--data-parallel-size 2 \
--data-parallel-size-local 1 \
--data-parallel-start-rank 1 \
--data-parallel-address $node0_ip \
--distributed_executor_backend "mp" \
--gpu-memory-utilization 0.92 \
--reasoning-parser minimax_m3 \
--limit-mm-per-prompt '{"image":1}' \
--speculative-config '{"model":"${EAGLE3_WEIGHT_PATH}", "method":"eagle3", "num_speculative_tokens":3}' \
--compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' \
--additional-config '{"enable_cpu_binding":true, "ascend_compilation_config":{"fuse_norm_quant":false}, "multistream_overlap_shared_expert": false, "weight_nz_mode": 2, "enable_flashcomm1": true}' \
--port 11223 > ${LOG_PATH} 2>&1 &
5.3 多模态和 ViT DP(可选)¶
MiniMax-M3 在昇腾上支持图像和视频输入。上述部署示例将 --limit-mm-per-prompt '{"image":1}' 作为默认的多模态容量假设,因为其他推理参数是针对单图像路径调优的。
对于 ViT / 多模态编码器部分,支持数据并行执行,可以通过以下方式启用:
默认部署示例中未启用此选项,因为它可能会增加每卡内存使用量。启用 ViT DP 时,请针对目标工作负载重新评估内存相关参数,例如 --max-model-len、--max-num-seqs 和 --gpu-memory-utilization。
对于视频或图像-视频混合请求,请根据实际请求形态调整多模态限制,而不是盲目更改默认模板:
# one video
--limit-mm-per-prompt '{"video":1}'
# one image and one video
--limit-mm-per-prompt '{"image":1, "video":1}'
当在请求中使用本地媒体路径(例如 file:///path/to/video.mp4)时,请添加显式的白名单路径:
如果未指定采样的视频帧数,vLLM 将使用其默认的视频采样策略,默认采样 32 帧。对于快速功能冒烟测试,可以在请求或评估配置中设置较小的帧数,例如 8 或 16。对于基准测试运行,请遵循数据集协议。
对于 MiniMax-M3 服务,不应同时启用 FLASHCOMM1 和仅语言模型模式。FLASHCOMM1 通过 additional_config.enable_flashcomm1 启用,而仅语言模型模式通过 --language-model-only 启用。
# Enable FLASHCOMM1.
--additional-config '{"enable_flashcomm1": true}'
# Enable language-model-only mode.
--language-model-only
VLLM_ASCEND_ENABLE_FLASHCOMM1=1 保留用于兼容性,但更推荐使用 additional_config.enable_flashcomm1。
6 思考与解析器配置¶
6.1 思考模式¶
MiniMax-M3 支持三种思考模式,通过 chat_template_kwargs 中的 thinking_mode 控制:
| 模式 | 行为 | 使用场景 |
|---|---|---|
enabled |
模型在每次响应前进行思考,包括在工具结果之后 | 复杂推理、智能体 |
disabled |
不进行思考;模型直接回答 | 对延迟敏感的轮次 |
adaptive |
模型根据任务决定是否思考(未设置时的默认值) | 一般用途 |
6.1.1 请求示例¶
禁用思考(curl):
curl http://{ip}:{port}/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "minimax-m3",
"messages": [{"role": "user", "content": "who are you?"}],
"max_tokens": 100,
"stream": false,
"top_p": 0.95,
"top_k": 40,
"temperature": 1.0,
"chat_template_kwargs": {"thinking_mode": "disabled"}
}'
根据需要将 "thinking_mode" 更改为 "enabled" 或 "adaptive"。已弃用的 enable_thinking 参数(等同于 thinking_mode: "enabled")也受支持。
启用思考(Python SDK):
from openai import OpenAI
client = OpenAI(api_key="EMPTY", base_url="http://localhost:8000/v1")
response = client.chat.completions.create(
model="minimax-m3",
messages=[{"role": "user", "content": "Prove there are infinitely many primes."}],
extra_body={"chat_template_kwargs": {"thinking_mode": "enabled"}},
)
msg = response.choices[0].message
print(getattr(msg, "reasoning", None)) # the <mm:think> block
print(msg.content) # the final answer
6.2 推理解析器¶
MiniMax-M3 推理解析器(--reasoning-parser minimax_m3)从模型输出中提取思考块 <mm:think>...</mm:think>,并将其作为 reasoning 字段暴露。其余文本作为 content 返回。
6.2.1 服务器配置¶
--reasoning-parser minimax_m3 标志启用 MiniMax-M3 推理解析器,该解析器使用 <mm:think>...</mm:think> 分隔符将模型输出拆分为推理和内容:
6.2.2 输出格式¶
MiniMax-M3 使用显式的思考分隔符:
6.2.3 解析器行为¶
thinking_mode="enabled":聊天模板在提示中预填充<mm:think>。生成的文本从推理块内部开始,并在</mm:think>之后过渡到内容。thinking_mode="disabled"或默认:模型输出被视为纯内容。如果出现<mm:think>,解析器将根据分隔符进行拆分。- 流式输出:推理和内容通过
DeltaMessage.reasoning和DeltaMessage.content逐 token 增量流式传输。 - Token 计数:
<mm:think>块内的推理 token 会被正确计数。
6.3 工具调用解析器¶
MiniMax-M3 使用命名空间分隔的 XML 格式进行工具调用。通过 --tool-parser minimax_m3 启用。
6.3.1 服务器配置¶
当同时指定 --reasoning-parser minimax_m3 和 --tool-call-parser minimax_m3 时,解析器会自动协同工作,处理同时包含推理块和工具调用的响应:
vllm serve ${WEIGHT_PATH} \
--reasoning-parser minimax_m3 \
--enable-auto-tool-choice \
--tool-call-parser minimax_m3 \
...
6.3.2 工具调用格式¶
每个结构标签前都有 ]<]minimax[>[ 命名空间标记:
]<]minimax[>[<tool_call>
]<]minimax[>[<invoke name="create_order">
]<]minimax[>[<user_id>42]<]minimax[>[</user_id>
]<]minimax[>[<shipping>
]<]minimax[>[<city>Singapore]<]minimax[>[</city>
]<]minimax[>[<zip>018956]<]minimax[>[</zip>
]<]minimax[>[</shipping>
]<]minimax[>[</invoke>
]<]minimax[>[</tool_call>
6.3.3 主要特性¶
- 递归参数解析:支持嵌套对象和数组(例如,包含
city/zip的shipping)。 - 模式感知类型转换:根据函数的 JSON Schema 定义,字符串参数值会自动转换为正确的类型(整数、布尔值、对象、数组)。
- 多次调用:单个
<tool_call>块可以包含多个<invoke>块。 - 流式输出:工具名称和参数片段在接收
<invoke>块时增量流式传输。
6.3.4 请求示例(curl)¶
curl http://{ip}:{port}/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "minimax-m3",
"messages": [{"role": "user", "content": "What's the weather like in Shanghai?"}],
"max_tokens": 300,
"stream": false,
"tool_choice": "auto",
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a city",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City or country name"
}
},
"required": ["location"],
"additionalProperties": false
}
}
}
],
"chat_template_kwargs": {"thinking_mode": "disabled"}
}'
7 功能验证¶
7.1 文本¶
curl http://{ip}:{port}/v1/chat/completions \
-H "Content-Type: application/json" \
-d @- <<EOF
{
"model": "minimax-m3",
"messages": [
{
"role": "user",
"content": "Answer the following multiple choice question. The last line of your response should be of the following format: 'Answer: LETTER' (without quotes) where LETTER is one of ABCD. Think step by step before answering.\n\nA student regrets that he fell asleep during a lecture in electrochemistry, facing the following incomplete statement in a test:\nThermodynamically, oxygen is a …… oxidant in basic solutions. Kinetically, oxygen reacts …… in acidic solutions.\nWhich combination of weaker/stronger and faster/slower is correct?\n\nA) weaker – faster\nB) stronger – faster\nC) weaker - slower\nD) stronger – slower"
}
],
"max_tokens": 8000,
"temperature": 1.0
}
EOF
预期结果:答案为 C。
7.2 单张图片¶
启动服务时启用图像输入,例如 --limit-mm-per-prompt '{"image":1}'。在客户端将 ${IMAGE_PATH} 替换为本地图像路径。
IMAGE_PATH=/path/to/image.jpg
IMAGE_BASE64="$(base64 -w 0 "${IMAGE_PATH}")"
curl http://{ip}:{port}/v1/chat/completions \
-H "Content-Type: application/json" \
-d @- <<EOF
{
"model": "minimax-m3",
"messages": [
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,${IMAGE_BASE64}"}},
{"type": "text", "text": "Briefly describe this image."}
]
}
],
"max_tokens": 512,
"temperature": 0
}
EOF
7.3 单个视频¶
启动服务时启用视频输入,例如 --limit-mm-per-prompt '{"video":1}'。如果请求使用 file:// 本地视频路径,还需添加 --allowed-local-media-path / 或更窄的允许目录。如果未指定 media_io_kwargs.video.num_frames,vLLM 默认采样 32 帧。
curl http://{ip}:{port}/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "minimax-m3",
"messages": [
{
"role": "user",
"content": [
{
"type": "video_url",
"video_url": {
"url": "file:///path/to/video.mp4"
}
},
{
"type": "text",
"text": "Briefly describe the main content of this video."
}
]
}
],
"max_tokens": 512,
"temperature": 0
}'
7.4 图像和视频混合请求¶
启动服务时同时启用图像和视频输入。对于以下请求,使用 --limit-mm-per-prompt '{"image":1,"video":1}'。如果请求使用 file:// 本地视频路径,还需添加 --allowed-local-media-path / 或更窄的允许目录。
IMAGE_BASE64="$(base64 -w 0 /path/to/image.jpg)"
curl http://{ip}:{port}/v1/chat/completions \
-H "Content-Type: application/json" \
-d @- <<EOF
{
"model": "minimax-m3",
"messages": [
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,${IMAGE_BASE64}"}},
{"type": "video_url", "video_url": {"url": "file:///path/to/video.mp4"}},
{"type": "text", "text": "Describe the image and video separately, and explain whether they are related."}
]
}
],
"max_tokens": 512,
"temperature": 0
}
EOF
8 精度评估¶
8.1 使用 AISBench¶
详细说明请参阅 使用 AISBench 进行精度评估。
8.2 文本评估¶
| 数据集 | 硬件 | 分数 | max-model-len | max-num-seqs | max_out_len | batch_size | generation_kwargs |
|---|---|---|---|---|---|---|---|
| GSM8K | GPU | 96.72 | 65536 | 16 | 49152 | 16 | temperature=1.0, top_p=0.95 |
| GSM8K | NPU | 96.36 | 10240 | 16 | 9500 | 20 | temperature=1.0, top_p=0.95 |
| AIME2025 | GPU | 95@repeat4 | - | - | - | - | - |
| AIME2025 | NPU | 93.3@repeat2 | 131072 | 32 | 65536 | 8 | temperature=1.0, top_p=0.95 |
| GPQA-Diamond | GPU | 92.42 | 81920 | 64 | 75776 | 8 | temperature=0.6, top_p=0.95 |
| GPQA-Diamond | NPU | 92.42 | 131072 | 32 | 65536 | 8 | temperature=0.6, top_p=0.95 |
8.3 多模态评估¶
MiniMax-M3 多模态精度使用 AISBench 进行评估。ViT DP 路径是可选的,可通过在服务命令中添加 --mm-encoder-tp-mode data 来启用,但并非所有多模态精度测试都需要该路径。对于视频评估,如果请求或评估配置中未指定帧数,vLLM 默认采样 32 帧。
以下 Video-MME 结果是在 chunk1 和 chunk2 上测得的,并非完整数据集。
对于 Video-MME 评估,请运行启用视频输入的 vLLM OpenAI 兼容服务,并使用 AISBench 发送 Video-MME 请求。官方 AISBench 指南可能未将 Video-MME 列为内置示例,因此此处使用的关键 MiniMax-M3 设置如下:
- 使用
--limit-mm-per-prompt '{"video":1}'提供服务; - 不设置
media_io_kwargs.video.num_frames,以便 vLLM 使用默认的 32 个采样帧; - 使用
max-model-len=90112和max_out_len=8192; - 评估 Video-MME 的 chunk1 和 chunk2,而非完整数据集。
用于 Video-MME chunk1+chunk2 评估的 AISBench 命令如下:
ais_bench \
--models vllm_api_general_chat \
--datasets videomme_subset_1_2.py \
--mode all \
--dump-eval-details \
--merge-ds
videomme_subset_1_2.py 是一个本地 AISBench 数据集配置,源自原始 Video-MME 配置(如 videomme_gen.py)。它将 path 指向根据本地可用的 chunk1/chunk2 视频从完整 Video-MME 元数据中筛选出的 parquet 文件,并将 video_path 指向提取的 chunk1/chunk2 .mp4 目录。这样既保持了评估的轻量性,又保留了标准的 Video-MME 请求和评分流程。
| Dataset | Modality | Tool | Hardware | ViT DP | max-model-len | max_out_len | Input Config | generation_kwargs | Score |
|---|---|---|---|---|---|---|---|---|---|
| TextVQA | Image | AISBench | GPU | disabled | 65536 | 512 | --limit-mm-per-prompt '{"image":1}' |
temperature=1.0, top_p=0.95 | 70.82 |
| TextVQA | Image | AISBench | NPU | disabled | 65536 | 512 | --limit-mm-per-prompt '{"image":1}' |
temperature=1.0, top_p=0.95 | 72.75 |
| Video-MME chunk1+chunk2 | Video | AISBench | GPU | - | 90112 | 8192 | --limit-mm-per-prompt '{"video":1}', default 32 frames |
temperature=1.0, top_p=0.95 | 73.41 |
| Video-MME chunk1+chunk2 | Video | AISBench | NPU | - | 90112 | 8192 | --limit-mm-per-prompt '{"video":1}', default 32 frames |
temperature=1.0, top_p=0.95 | 74.21 |
9 性能调优¶
注意:以下配置在特定测试环境中经过验证,仅供参考。最佳配置取决于最大输入/输出长度、前缀缓存命中率、精度要求以及部署机器比例等因素。建议根据实际情况参考第 9.2 节进行调优。
9.1 推荐配置¶
推荐配置与第 5 章“在线服务部署”中指定的配置相同。
9.2 调优指南¶
9.2.1 通用调优参考¶
有关通用调优方法,请参阅公共性能调优文档。
有关详细的功能描述,请参阅功能指南。
10 常见问题¶
- 问:如何重新安装 vLLM Ascend?
答:使用以下命令重新安装 vLLM Ascend,并使用当前 Python 环境中的依赖进行构建:
pip install -v --no-build-isolation -e . -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com
- 问:当未设置
media_io_kwargs.video.num_frames时,视频请求变慢或超时该怎么办?
答:默认情况下,vLLM 在读取视频时会采样 32 帧。MiniMax-M3 每帧会产生大量视觉 token,因此 32 帧的视频会显著增加预填充计算量。如果请求变慢或超时,请显式将 media_io_kwargs.video.num_frames 设置为较小的值,例如 8 或 16 帧: