MiniMax-M2 是一个为 Agent 和代码而生的开源大模型:规划并执行长链条工具调用、协同 Shell、浏览器、Python 执行器和各类 MCP 工具是它的主战场 [1]。把它部署到 vLLM 上,第一笔账不是参数而是显存——权重约 220GB,每 1M 上下文 token 还要再加约 240GB [1]。这篇按 96GB×4 卡与 144GB×8 卡两档配置走完部署全程,并以工具调用实测收尾。
面向 Agent 场景直接决定了部署形态:这类负载里模型要频繁地在思考和工具调用之间切换,响应结构必须被服务端正确解析才能被上层框架消费。所以启动命令里两个解析器缺一不可——没有工具解析器,模型的调用意图会以纯文本形式出现;没有思考解析器,推理过程会和答案混在一起。上层框架拿到的是结构化的 tool_calls 和分开的思考内容,编排逻辑才写得下去。
显存账与卡数选择
显存算清楚,卡数就定了 [1]:96G×4 卡支持约 40 万 token 总上下文,144G×8 卡能到约 300 万。两档对应两种并行策略:4 卡走纯张量并行,8 卡额外开专家并行。参考环境是 8 张 RTX PRO 6000(每卡 96GB)[ ^1]。如果显存吃紧,调低 --mem-fraction-static 或缩 --max-model-len 都能换出空间 [1]。
并发和上下文的规划值得单独想一遍:40 万 token 的总上下文是全实例共享的预算,不是单请求上限。假设每个会话平均占用 8K 上下文,4 卡档大约承载 50 个并发会话;再往上要么牺牲单请求长度,要么上 8 卡档。Agent 负载的特点恰恰是多轮长对话,历史消息不断累积,会话数要按这个口径打折——规划时按平均上下文的 1.5 到 2 倍预留才稳妥。
环境与安装
依赖建议装在虚拟环境里避免冲突 [1]。安装用 uv 锁版本,vLLM 走 nightly 源 [1]:
pip install --upgrade pip
pip install uv==0.9.7
[ -d ".venv" ] || uv venv
source .venv/bin/activate
uv pip install modelscope==1.31.0
uv pip install openai==2.6.1
uv pip install 'triton-kernels @ git+https://github.com/triton-lang/triton.git@v3.5.0#subdirectory=python/triton_kernels' vllm --extra-index-url https://wheels.vllm.ai/nightly --prerelease=allowtriton-kernels 从 GitHub 源码安装,这一步依赖网络质量,失败多半卡在克隆仓库上。
模型下载
vLLM 首次启动会自动从 Hugging Face 拉取并缓存模型;网络受限时可以先用 modelscope 手动下载,模型名 MiniMaxAI/MiniMax-M2 [1]:
# model_download.py
from modelscope import snapshot_download
model_dir = snapshot_download('MiniMaxAI/MiniMax-M2', cache_dir='/root/autodl-tmp', revision='master')
print(f"模型下载成功,保存到: {model_dir}")权重很大,带宽不足时可以先在高带宽机器下载再拷贝到目标机 [1]。
脚本方式的价值在工程侧:参数固化在代码里,改配置走代码评审而不是口头约定;launch_server_cmd 返回进程句柄,配套的 wait_for_server 阻塞到服务就绪,启动脚本可以直接嵌入健康检查流程。日志重定向、异常重启、就绪探测这些运维要素都有了挂载点。命令行方式则适合临时验证——一行起服务,观察日志,用完即走。
服务启动:按卡数自动选命令
启动方式有两种,脚本方式便于固定参数与日志。脚本按检测到的 GPU 数量选命令,不是 4 卡或 8 卡就直接报错 [1]:
import torch
from vLLM.utils import launch_server_cmd, wait_for_server
gpu_count = torch.cuda.device_count() if torch.cuda.is_available() else 0
if gpu_count == 4:
cmd = (
"SAFETENSORS_FAST_GPU=1 vllm serve "
"MiniMaxAI/MiniMax-M2 --trust-remote-code "
"--tensor-parallel-size 4 "
"--enable-auto-tool-choice --tool-call-parser minimax_m2 "
"--reasoning-parser minimax_m2_append_think"
)
elif gpu_count == 8:
cmd = (
"SAFETENSORS_FAST_GPU=1 vllm serve "
"MiniMaxAI/MiniMax-M2 --trust-remote-code "
"--enable_expert_parallel --tensor-parallel-size 8 "
"--enable-auto-tool-choice --tool-call-parser minimax_m2 "
"--reasoning-parser minimax_m2_append_think"
)
else:
raise RuntimeError(f"建议使用 4 或 8 张 GPU,当前检测到: {gpu_count}")server_process, port = launch_server_cmd(cmd, port=8000)
wait_for_server(f"http://127.0.0.1:{port}")
print(f"vLLM Server started: http://127.0.0.1:{port}")命令行等价写法,4 卡版 [1]:
SAFETENSORS_FAST_GPU=1 vllm serve \
MiniMaxAI/MiniMax-M2 --trust-remote-code \
--tensor-parallel-size 4 \
--enable-auto-tool-choice --tool-call-parser minimax_m2 \
--reasoning-parser minimax_m2_append_think8 卡版多一个 --enable_expert_parallel [1]:
SAFETENSORS_FAST_GPU=1 vllm serve \
MiniMaxAI/MiniMax-M2 --trust-remote-code \
--enable_expert_parallel --tensor-parallel-size 8 \
--enable-auto-tool-choice --tool-call-parser minimax_m2 \
--reasoning-parser minimax_m2_append_think两个解析器是启动命令的固定搭配:--tool-call-parser minimax_m2 处理工具调用格式,--reasoning-parser minimax_m2_append_think 处理思考内容。模型大,首次加载可能超过半小时,服务起来后监听 http://127.0.0.1:8000/v1 [1]。起好后先用 curl 快速验证链路 [1]:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMaxAI/MiniMax-M2",
"messages": [
{"role": "system", "content": [{"type": "text", "text": "You are a helpful assistant."}]},
{"role": "user", "content": [{"type": "text", "text": "Which team won the worldcup in 2022?"}]}
]
}'采样参数里 temperature 1.0 看似激进,实则是推理模型的常态:思考阶段需要足够的随机性探索解题路径,压得太低反而让模型陷入重复推理。真正要确定性的是参数抽取和分类这类结构化任务,那时再单独压低。分层使用采样参数——Agent 编排调用用官方推荐值,抽取类调用用低温——是一个值得写进调用规范的细节。
三种调用姿势
补全、聊天、流式各来一遍,全部走 OpenAI SDK。补全接口用官方推荐采样参数 [1]:
# test_completion.py
from openai import OpenAI
client = OpenAI(
api_key="EMPTY",
base_url="http://127.0.0.1:8000/v1",
)
response = client.completions.create(
model="MiniMaxAI/MiniMax-M2",
prompt="简要介绍一下 MiniMax M2 模型的特点。",
max_tokens=8192,
top_p=0.95,
temperature=1.0,
)
print(response)聊天接口的回复里,思考过程包在 <think> 标签里,最终答案在其后 [1]:
# test_chat.py
from openai import OpenAI
client = OpenAI(
api_key="EMPTY",
base_url="http://127.0.0.1:8000/v1",
)
response = client.chat.completions.create(
model="MiniMaxAI/MiniMax-M2",
messages=[
{"role": "user", "content": "MiniMAX公司的愿景是什么?你觉得他们会成功吗,请作出详细分析。"}
],
max_tokens=8192,
top_p=0.95,
temperature=1.0,
)
msg = response.choices[0].message
print("MiniMax-M2:", msg.content)流式接口适合长生成任务,逐块打印 delta [1]:
# test_streaming.py
from openai import OpenAI
client = OpenAI(
api_key="EMPTY",
base_url="http://127.0.0.1:8000/v1",
)
stream = client.chat.completions.create(
model="MiniMaxAI/MiniMax-M2",
messages=[{"role": "user", "content": "请写一篇题为Agent时代大模型应用落地要点的调研报告。"}],
stream=True,
max_tokens=32768,
top_p=0.95,
temperature=1.0,
)
for chunk in stream:
delta = chunk.choices[0].delta
if delta and delta.content:
print(delta.content, end="", flush=True)流式跑长报告这类任务时注意 max_tokens 要给足,32768 的预算在思考加正文两者之间分配;给小了会在正文写完前截断。
工具描述的质量直接决定调用准确率:参数说明里的示例值会被模型当作格式参照,枚举类型比自由文本更可控,必填字段要让模型无从跳过。多工具场景下还要注意函数命名——名字本身承载语义,含糊的名字会诱发误选。每次调用结束后把结果以工具消息回传并进入下一轮,是 Agent 循环的标准节奏,客户端只需维护好消息列表的顺序。
工具调用实测
M2 在 vLLM 部署时默认启用工具调用,模型自己判断何时需要外部工具并输出结构化参数 [1]。示例定义一个天气查询函数和对应的工具描述 [1]:
# test_tool_calling.py
from openai import OpenAI
import json
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
def get_weather(location: str, unit: str):
return f"Getting the weather for {location} in {unit}..."
tool_functions = {"get_weather": get_weather}tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City and state, e.g., 'San Francisco, CA'"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["location", "unit"]
}
}
}]请求里的模型名直接从模型列表接口动态读取,避开写死路径的坑 [1]:
response = client.chat.completions.create(
model=client.models.list().data[0].id,
messages=[{"role": "user", "content": "What's the weather like in San Francisco? use celsius."}],
tools=tools,
tool_choice="auto"
)
print(response)
tool_call = response.choices[0].message.tool_calls[0].function
print(f"Function called: {tool_call.name}")
print(f"Arguments: {tool_call.arguments}")
print(f"Result: {get_weather(**json.loads(tool_call.arguments))}")实测结果干净利落:模型选中 get_weather,参数为 {"location": "San Francisco, CA", "unit": "celsius"}——问题里只说了 San Francisco,模型按工具描述里的示例补全了州名缩写,单位严格按用户要求取摄氏度 [1]。
参数速查
收个尾 [1]:请求里的 model 必须与启动时指定一致;--tensor-parallel-size 常设为 GPU 数;8 卡示例开 --enable_expert_parallel;--enable-auto-tool-choice 让模型自主发起工具调用;max_tokens 过大徒增显存和时延;要确定性输出就压低 temperature 和 top_p。采样参数官方推荐 temperature=1.0、top_p=0.95、top_k=20 [1]。
本文改编自 Datawhale 开源教程《self-llm》的 MiniMax-M2 vLLM 部署一节[1],原文以 Apache-2.0 许可证发布。
来源
- 12-MiniMax-M2 vLLM 部署调用 | self-llmDatawhale self-llm (Apache-2.0)
引用本页: MiniMax-M2 用 vLLM 部署. TellWorld, https://www.tellworld.net/zh/practice/practice-minimax-m2-vllm. 更新于 2026-11-14