MiniMax-M2.5#

简介#

MiniMax‑M2.5 是 MiniMax 的旗舰大语言模型,针对代码生成、智能体工具调用/搜索、复杂办公工作流等高价值场景进行了强化,重点在于推理效率和在具有挑战性任务上的端到端速度。

本文档提供了 MiniMax-M2.5 在 vLLM Ascend 上的统一部署指南,涵盖以下两种场景:

  • A3 单节点部署(Atlas 800 A3)

  • A2 双节点部署(2× Atlas 800I A2)

支持的特性#

请参阅支持的特性矩阵获取模型支持的特性列表。

请参阅特性指南获取特性的配置方法。

环境准备#

模型权重#

建议将模型权重下载到共享目录,例如 /mnt/sfs_turbo/.cache/。当前版本会自动检测 MiniMax-M2 fp8 检查点,在 NPU 上禁用 fp8 量化内核,并通过反量化为 bf16 来加载权重。一旦公开的 bf16 权重可用,此行为可能会被移除。

安装#

您可以使用官方 Docker 镜像直接运行 MiniMax-M2.5

根据您的机器类型选择镜像,并在节点上启动容器。请参考使用 Docker 安装

使用 Docker 运行#

A3(单节点)#

# Update the vllm-ascend image
export IMAGE=m.daocloud.io/quay.io/ascend/vllm-ascend:v0.20.2rc1
export NAME=vllm-ascend

# Run the container using the defined variables
# Note: If you are running bridge network with docker, please expose available ports for multiple nodes communication in advance
docker run --rm \
--name $NAME \
--net=host \
--shm-size=1g \
--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 /mnt/sfs_turbo/.cache:/home/cache \
-it $IMAGE bash

A2(双节点,在两个节点上运行)#

两个 A2 节点上创建并运行 minimax25-docker-run.sh

说明:

  • 默认配置假设使用 Atlas 800I A2 8-NPU 节点,并设置 ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7。请根据您的硬件进行更新。

  • 将模型权重目录映射到容器中(示例中映射到 /opt/data/verification/)。

#!/bin/sh
NAME=minimax2_5
DEVICES="0,1,2,3,4,5,6,7"
IMAGE=m.daocloud.io/quay.io/ascend/vllm-ascend:|vllm_ascend_version|

docker run -itd -u 0 --ipc=host --privileged \
  -e VLLM_USE_MODELSCOPE=True \
  -e PYTORCH_NPU_ALLOC_CONF=max_split_size_mb:256 \
  -e ASCEND_RT_VISIBLE_DEVICES=$DEVICES \
  --name $NAME \
  --net=host \
  --device /dev/davinci_manager \
  --device /dev/devmm_svm \
  --device /dev/hisi_hdc \
  --shm-size=1200g \
  -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 /home/:/home/ \
  -v /opt/data/verification/:/opt/data/verification/ \   # Map the model weights here
  -v /root/.cache:/root/.cache \
  -v /mnt/performance/:/mnt/performance/ \
  -it $IMAGE bash

# Start and enter the container
# bash minimax25-docker-run.sh
# docker exec -it minimax2_5 bash

多 NPU 在线推理#

A3(单节点)#

以下是在短上下文(如 3.5k/1.5k)条件下达到良好性能的推荐启动配置。

说明:

  • 如果只关心短上下文低延迟,可以显式设置 --max-model-len 32768。也可以将 tensor-parallel-size 设置为 16,将 data-parallel-size 设置为 1。

  • export VLLM_ASCEND_BALANCE_SCHEDULING=1 用于增强预填充和解码之间的调度能力。这在使用较大的 data-parallel-size 时效果显著。当并发数接近 data-parallel-size 乘以 max-num-seqs 时,可以提升性能。

export HCCL_OP_EXPANSION_MODE="AIV"
export HCCL_BUFFSIZE=1024
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
export OMP_NUM_THREADS=1
echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
sysctl -w vm.swappiness=0
sysctl -w kernel.numa_balancing=0
sysctl kernel.sched_migration_cost_ns=50000
export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
export TASK_QUEUE_ENABLE=1

export VLLM_ASCEND_ENABLE_FUSED_MC2=1
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1
export VLLM_ASCEND_BALANCE_SCHEDULING=1

vllm serve /path/to/weight/MiniMax-M2.5-w8a8-QuaRot \
    --served-model-name "MiniMax-M2.5" \
    --host 0.0.0.0 \
    --port 8000 \
    --trust-remote-code \
    --quantization ascend \
    --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
    --additional-config '{"enable_cpu_binding":true}' \
    --enable-expert-parallel \
    --tensor-parallel-size 4 \
    --data-parallel-size 4 \
    --max-num-seqs 48 \
    --max-model-len 40690 \
    --max-num-batched-tokens 16384 \
    --gpu-memory-utilization 0.85 \
    --speculative_config '{"enforce_eager": true, "method": "eagle3", "model": "/path/to/weight/Eagle3/", "num_speculative_tokens": 3}' \

备注:

  • minimax_m2_append_think<think>...</think> 保留在 content 中。

  • 如果主要依赖 /v1/responses 的推理语义,建议使用 --reasoning-parser minimax_m2 代替。

  • 为了在 128k 或 64k 等长上下文场景下获得更好的性能,我们建议进行如下更改,并可以移除 export VLLM_ASCEND_BALANCE_SCHEDULING=1

    --tensor-parallel-size 8 \
    --data-parallel-size 1 \
    --decode-context-parallel-size 1 \
    --prefill-context-parallel-size 2 \
    --cp-kv-cache-interleave-size 128 \
    --max-num-seqs 16 \
    --max-model-len 138000 \
    --max-num-batched-tokens 65536 \
    --gpu-memory-utilization 0.85 \
    --speculative_config '{"enforce_eager": true, "method": "eagle3", "model": "/path/to/weight/Eagle3/", "num_speculative_tokens": 1}' \
  • 如果要使用 curl 命令进行测试,可以在上述启动命令中添加以下命令。

    --enable-auto-tool-choice \
    --tool-call-parser minimax_m2 \
    --reasoning-parser minimax_m2_append_think \

A2(双节点,tp=8 + dp=2)#

由于跨节点张量并行(TP)可能不稳定,双节点指南使用 tp=8 + dp=2 的设置(每节点 8 个 NPU,共 16 个 NPU)。

Node0(主节点)启动脚本#

在 node0 容器中编辑 minimax25_service_node0.sh,并将占位符替换为实际值:

  • {PrimaryNodeIP}:主节点的 IP 地址(公共/集群网络)

  • {NIC}:公共/集群网络的网卡名称(通过 ifconfig 查看,例如 enp67s0f0np0

  • VLLM_TORCH_PROFILER_DIR:可选,用于存储性能分析输出的目录

# Primary node (node0)
export HCCL_IF_IP={PrimaryNodeIP}
export GLOO_SOCKET_IFNAME="{NIC}"
export TP_SOCKET_IFNAME="{NIC}"
export HCCL_SOCKET_IFNAME="{NIC}"
export HCCL_BUFFSIZE=1024
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7

export HCCL_OP_EXPANSION_MODE="AIV"
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True

export OMP_PROC_BIND=false
export OMP_NUM_THREADS=1
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1

export HCCL_INTRA_PCIE_ENABLE=1
export HCCL_INTRA_ROCE_ENABLE=0

# profiling (optional)
export VLLM_TORCH_PROFILER_WITH_STACK=0
export VLLM_TORCH_PROFILER_DIR="{profiling_dir}"

vllm serve /opt/data/verification/models/MiniMax-M2.5/ \
  --served-model-name "minimax25" \
  --host {PrimaryNodeIP} \
  --port 20004 \
  --tensor-parallel-size 8 \
  --data-parallel-size 2 \
  --data-parallel-size-local 1 \
  --data-parallel-start-rank 0 \
  --data-parallel-address {PrimaryNodeIP} \
  --data-parallel-rpc-port 2347 \
  --max-num-seqs 128 \
  --max-num-batched-tokens 65536 \
  --gpu-memory-utilization 0.92 \
  --enable-expert-parallel \
  --trust-remote-code \
  --enable-auto-tool-choice \
  --tool-call-parser minimax_m2 \
  --reasoning-parser minimax_m2_append_think \
  --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
  --mm_processor_cache_type="shm" \
  --additional-config '{"enable_cpu_binding":true}'

Node1(从节点)启动脚本#

在 node1 容器中编辑 minimax25_service_node1.sh

  • {SecondaryNodeIP}:从节点的 IP 地址

  • {PrimaryNodeIP}:主节点的 IP 地址(与 node0 相同)

  • {NIC}:同上

# Secondary node (node1)
export HCCL_IF_IP={SecondaryNodeIP}
export GLOO_SOCKET_IFNAME="{NIC}"
export TP_SOCKET_IFNAME="{NIC}"
export HCCL_SOCKET_IFNAME="{NIC}"
export HCCL_BUFFSIZE=1024
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7

export HCCL_OP_EXPANSION_MODE="AIV"
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True

export OMP_PROC_BIND=false
export OMP_NUM_THREADS=1
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1

export HCCL_INTRA_PCIE_ENABLE=1
export HCCL_INTRA_ROCE_ENABLE=0

# profiling (optional)
export VLLM_TORCH_PROFILER_WITH_STACK=0
export VLLM_TORCH_PROFILER_DIR="{profiling_dir}"

vllm serve /opt/data/verification/models/MiniMax-M2.5/ \
  --served-model-name "minimax25" \
  --host {SecondaryNodeIP} \
  --port 20004 \
  --headless \
  --tensor-parallel-size 8 \
  --data-parallel-size 2 \
  --data-parallel-size-local 1 \
  --data-parallel-start-rank 1 \
  --data-parallel-address {PrimaryNodeIP} \
  --data-parallel-rpc-port 2347 \
  --max-num-seqs 128 \
  --max-num-batched-tokens 65536 \
  --gpu-memory-utilization 0.92 \
  --enable-expert-parallel \
  --trust-remote-code \
  --enable-auto-tool-choice \
  --tool-call-parser minimax_m2 \
  --reasoning-parser minimax_m2_append_think \
  --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
  --mm_processor_cache_type="shm" \
  --additional-config '{"enable_cpu_binding":true}'

启动顺序#

在两个节点上启动服务:

# node0
bash minimax25_service_node0.sh

# node1
bash minimax25_service_node1.sh

当 node0 在日志中打印 service start 后,您可以验证服务。

验证服务#

A3(单节点)#

使用 OpenAI 兼容客户端进行测试:

from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="na")

resp = client.chat.completions.create(
    model="MiniMax-M2.5",
    messages=[{"role": "user", "content": "你好,请介绍一下你自己,并展示一次工具调用的参数格式。"}],
    max_tokens=256,
)
print(resp.choices[0].message.content)

或使用 curl 发送请求:

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MiniMax-M2.5",
    "messages": [{"role": "user", "content": "请查询上海的天气。"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_current_weather",
        "description": "Get weather by city",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string"},
            "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
          },
          "required": ["city"]
        }
      }
    }],
    "tool_choice": "auto",
    "temperature": 0,
    "max_tokens": 512
  }'

A2(双节点)#

在任意可以访问主节点的机器上运行以下命令(将 {PrimaryNodeIP} 替换为实际 IP):

curl http://{PrimaryNodeIP}:20004/v1/chat/completions \
  -H "Content-type: application/json" \
  -d '{
    "model": "minimax25",
    "messages": [{"role": "user", "content": "Hello, who are you?"}],
    "stream": false,
    "ignore_eos": true,
    "temperature": 0.8,
    "top_p": 0.8,
    "max_tokens": 200
  }'

性能参考#

A3(单节点,tp=16,4k/1k@bs16)#

结果#

基线3.5k/1k@bs=217

指标

结果

成功/失败

217/0

平均 TTFT

10316.56 毫秒

平均 TPOT

34.28 毫秒

输出 token/秒

4803.81

总 token/秒

16096.59

长上下文参考 (190k/1k@bs=4)

指标

结果

输出 token/秒

37.12

平均 TTFT

2002.37 毫秒

平均 TPOT

105.54 毫秒

平均 ITL

105.54 毫秒

A2(双节点,190k/1k,并发=4,16 个提示)#

基准测试方法#

190k/1k,并发=4,16 个提示 的场景使用 vLLM bench:

vllm bench serve --backend vllm \
  --dataset-name prefix_repetition \
  --prefix-repetition-prefix-len 175104 \   # Input: 190×1024 tokens with 90% prefix repetition
  --prefix-repetition-suffix-len 19440 \    # Input: 190×1024 tokens minus the prefix length above
  --prefix-repetition-output-len 1024 \     # Output: 1024 tokens
  --prefix-repetition-num-prefixes 1 \
  --num-prompts 16 \
  --max-concurrency 4 \
  --ignore-eos \
  --model minimax25 \
  --tokenizer {model_path} \
  --endpoint /v1/completions \
  --request-rate inf \
  --seed 1000 \
  --host {service_ip} \
  --port 20004

结果#

190k/1k,并发=4,16 个提示

指标

结果

TTFT(平均)

3305.25 毫秒

TPOT(平均)

109.83 毫秒

输出吞吐量

35.29 token/秒

前缀命中率

85%

常见问题#

  • 问:在 EP 模式下输出乱码怎么办?

    答:建议保持 --enable-expert-parallelVLLM_ASCEND_ENABLE_FLASHCOMM1=1

  • 问:为什么使用 minimax_m2_append_thinkreasoning 字段经常为空?

    答:这是预期行为。解析器将 <think>...</think> 保留在 content 中。如果您主要依赖 /v1/responses 的推理语义,请改用 --reasoning-parser minimax_m2

  • 问:启动失败,出现 HCCL 端口冲突(地址已被占用)。该怎么办?

    答:清理旧进程并重启:pkill -f "vllm serve /models/MiniMax-M2.5"

  • 问:如何处理 OOM 或启动不稳定的问题?

    答:首先减小 --max-num-seqs--max-num-batched-tokens。如有必要,降低并发和负载测试压力(例如 max-concurrency / num-prompts)。

  • 问:为什么不使用跨节点 tp=16?

    答:参考实践表明跨节点 TP 可能不稳定,因此双节点部署推荐使用 tp=8, dp=2

  • 问:如何选择 --reasoning-parser

    答:本指南使用 minimax_m2_append_think,以便将 <think>...</think> 保留在 content 中。如果您主要依赖 /v1/responses 的推理语义,请考虑使用 --reasoning-parser minimax_m2

  • 问:哪些端口必须可访问?

    答:至少需要暴露服务端口(例如 20004)和数据并行 RPC 端口(例如 2347),并确保两个节点之间可以通过网络互相访问。