基于vLLM的小米MiMo-V2.5大模型高性能推理服务构建与OpenAI兼容网关部署实践

基于vLLM的小米MiMo-V2.5大模型高性能推理服务构建与OpenAI兼容网关部署实践

项目 内容
文档版本 v1.0
文档日期 2026-04-29
文档作者 Richard < richard@ponfey.com >
适用系统 Rocky Linux 10.2(内核 6.12.x)
适用软件 vLLM ≥ 0.29(v1,2026-04 起已 Day0 适配 MiMo-V2.5)、Python 3.10–3.12、FastAPI、uvicorn
适用模型 XiaomiMiMo/MiMo-V2.5(310B 稀疏 MoE,15B 激活,多模态,HF/ModelScope)

目录

  1. 文档说明
  2. 总体架构
  3. 环境准备
  4. 获取模型权重
  5. 安装 vLLM
  6. 启动 vLLM OpenAI 兼容服务
  7. SK 密钥鉴权与 FastAPI 网关
  8. 集成测试
  9. 生产化部署
  10. 性能调优
  11. 常见问题 FAQ
  12. 参考资料

1. 文档说明

1.1 目的

  • 在 Rocky Linux 10 上配置多卡 GPU 环境并安装 vLLM;
  • 下载并加载 小米 MiMo-V2.5(310B 稀疏 MoE、15B 激活、原生多模态)模型权重;
  • 以OpenAI 兼容接口(/v1/chat/completions 等)对外提供文本与多模态推理服务;
  • 使用 FastAPI 网关 对客户端请求做 SK(Secret Key)密钥鉴权、限流与转发;
  • 完成 systemd 托管、监控、安全加固与常见问题排查。

1.2 术语表

术语 说明
vLLM 高性能大模型推理引擎,提供 PagedAttention、Continuous Batching、KV Cache 管理等能力,内置 OpenAI 兼容 API 服务
MiMo-V2.5 小米 2026-04-22 开源的 310B 参数稀疏 MoE 多模态模型,激活 15B,训练 48T tokens,MIT 协议
MoE Mixture-of-Experts,混合专家,稀疏激活:总参数 310B,每次仅激活 15B 专家
Hybrid SWA 混合滑动窗口注意力:绝大多数层做局部窗口注意力、少数关键层保留全局视野,KVCache 降至 Full Attention 的约 1/7
MTP Multi-Token Prediction,多 token 预测,MiMo-V2.5 原生支持 3 层,用于 decode 加速
SK Secret Key,客户端访问网关所需持有的密钥,用于鉴权
OpenAI 兼容接口 与 OpenAI API 协议一致的 HTTP 接口(/v1/chat/completions、/v1/completions、/v1/models 等)
KV Cache 推理过程中缓存的注意力键值对,显存占用大头;MiMo-V2.5 因 Hybrid SWA 显著减小
TP Tensor Parallelism,张量并行,将模型权重切分到多张 GPU 上
PP Pipeline Parallelism,流水线并行,按层切分跨多卡/多机
SSE Server-Sent Events,vLLM 流式输出的传输方式
多模态编码器 MiMo-V2.5 自带的视觉 / 音频 / 视频编码器,经轻量 projector 与语言主干对齐

1.3 约定

  • 文中模型本地路径统一使用 /data/vllm/models/MiMo-V2.5;
  • 服务名统一为 mimo-v2.5(对应 --served-model-name,与小米开放平台 Model ID 一致);
  • SK 示例值为 sk-richard-11223355,生产环境务必替换为强随机密钥。

2. 总体架构

整个系统分为三层:客户端 → FastAPI 网关 → vLLM 推理服务。

flowchart LR
    A[客户端 / 业务系统<br/>文本 + 图片 / 音频] -->|"Authorization: Bearer SK"| B["FastAPI 网关<br/>0.0.0.0:8080"]
    B -->|"SK 校验 + 限流 + 审计日志"| C{鉴权通过?}
    C -- 否 --> D["401 Unauthorized"]
    C -- 是 --> E["vLLM OpenAI 兼容服务<br/>127.0.0.1:8000<br/>TP=4 多卡"]
    E --> F["MiMo-V2.5<br/>310B MoE · 15B 激活<br/>多模态 Encoder · Hybrid SWA · MTP"]
    G["运维监控<br/>Prometheus / Grafana"] -.->|"/metrics"| E

请求鉴权时序:

sequenceDiagram
    participant C as 客户端
    participant G as FastAPI 网关
    participant V as vLLM
    C->>G: POST /v1/chat/completions(Authorization: Bearer SK)
    G->>G: SK 哈希比对(常数时间) + 限流检查
    alt 鉴权失败
        G-->>C: 401 Invalid SK / 429 Rate Limited
    else 鉴权通过
        G->>V: POST /v1/chat/completions(注入内部密钥)
        V-->>G: SSE / JSON 响应(支持多模态、流式)
        G-->>C: 原样透传(支持流式)
    end

安全设计要点:

  1. vLLM 只监听 127.0.0.1:8000,不直接对外暴露;
  2. 网关是唯一对外入口,负责 SK 鉴权、限流、审计;
  3. vLLM 自身再叠加一层 --api-key 内部密钥(纵深防御),即使网关被穿透,vLLM 也不会裸奔;
  4. 网关与 vLLM 之间走内网回环,密钥通过环境变量注入,不落盘到代码。

3. 环境准备

3.1 硬件与显存规划

MiMo-V2.5 是 310B 参数的稀疏 MoE 多模态模型,激活参数仅 15B,但推理仍需加载全部 310B 权重,因此显存需求取决于精度与上下文长度:

部署形态 权重体积(约) 推荐硬件 适用场景
BF16(原始精度) 约 620 GB 8 × A100/H100 80G(TP≥8) 生产高精度、1M 长上下文
FP8(官方默认,E4M3 Mixed) 约 293 GB 4 × A100/H100 80G(TP=4) 生产主流选择,官方推荐
FP4 量化 约 155 GB 2 × H100/A100 80G(TP=2) 或 4 × 40G 成本敏感、开发测试

注意

MiMo-V2.5 原生支持最长 1M(1024K)上下文,得益于 Hybrid SWA 架构,其 KV Cache 仅约为 Full Attention 的 1/7,但仍会随 --max-model-len 线性增长。生产环境通常将上下文设为 32K–131K,显存有限时优先缩小 --max-model-len,而不是降低 --gpu-memory-utilization。

其余硬件建议:

项目 建议
CPU 建议 ≥ 32 核(TP=4 时;TP 越高核数越多,EP 场景需更多内存通道)
内存 建议 ≥ 512 GB(加载约 293 GB FP8 权重 + PyTorch 运行时开销)
系统盘 NVMe SSD ≥ 1 TB(模型权重 + 依赖 + 日志)
网络 生产环境 10GbE+,TP 多卡间需 NVLink / PCIe 高速互联

3.2 Rocky Linux 10 基础配置

# 更新系统

dnf update -y

# 部署基础工具链

dnf install -y epel-release

dnf install -y git curl wget htop tmux

dnf install -y python3 python3-pip python3-devel gcc gcc-c++ make

# 确认版本

cat /etc/rocky-release

uname -r

python3 --version

3.3 NVIDIA 驱动与 CUDA

使用 NVIDIA 官方仓库安装驱动与 CUDA Toolkit:

# 添加 NVIDIA CUDA 仓库

dnf config-manager --add-repo 
  https://developer.download.nvidia.com/compute/cuda/repos/rhel10/x86_64/cuda-rhel10.repo

dnf clean expire-cache

# 安装驱动(latest-dkms 便于内核升级后自动重建)

dnf module install -y nvidia-driver:latest-dkms

# 安装 CUDA 工具链(vLLM 的 wheel 自带 CUDA runtime,工具链主要用于编译扩展)

dnf install -y cuda-toolkit

# 验证驱动与 GPU 可见性(多卡应全部列出)

nvidia-smi

若 nvidia-smi 提示版本过低,vLLM 官方 wheel 对驱动版本有最低要求(通常需要 ≥ 535/570 系列),请升级到最新稳定驱动。安装完成后建议重启一次,确保内核模块加载。

3.4 Python 虚拟环境

# 为 vLLM 单独建虚拟环境,避免污染系统 Python

mkdir -p /opt/vllm-venv /opt/models /opt/llm-gateway

python3 -m venv /opt/vllm-venv

# 后续命令统一先激活环境

source /opt/vllm-venv/bin/activate

pip install -U pip wheel setuptools

4. 获取模型权重

4.1 从 Hugging Face 下载

source /opt/vllm-venv/bin/activate

pip install -U huggingface_hub

hf download XiaomiMiMo/MiMo-V2.5 --local-dir /data/vllm/models/MiMo-V2.5

国内网络不佳时,可设置镜像:

export HF_ENDPOINT=https://hf-mirror.com

后再执行下载。

4.2 从 ModelScope 下载(国内推荐)

source /opt/vllm-venv/bin/activate

pip install -U modelscope

modelscope download --model XiaomiMiMo/MiMo-V2.5 --local_dir /data/vllm/models/MiMo-V2.5

vLLM 也支持直接使用 ModelScope 仓库 ID 并配合环境变量:

export VLLM_USE_MODELSCOPE=true

MiMo-V2.5 系列在 HF / ModelScope 均提供 MiMo-V2.5(chat/指令版)、MiMo-V2.5-Base、MiMo-V2.5-DFlash 等权重,统一托管于 HF 集合 XiaomiMiMo/mimo-v25。如需 FP4 量化版,可在 HF / ModelScope 搜索 MiMo-V2.5 + FP4 / DFlash 等社区或官方仓库。

4.3 目录结构与校验

下载完成后确认关键文件齐全:

ls -lh /data/vllm/models/MiMo-V2.5

# 预期包含:config.json、tokenizer.json、*.safetensors(310B 权重约 17 个分片、约 293 GB)、
#           generation_config.json、merges.txt、vocab.json 等

# 检查权重是否完整(safetensors 自带哈希校验)

python - <<'EOF'
from safetensors import safe_open
f = safe_open("/data/vllm/models/MiMo-V2.5/model-00001-of-00017.safetensors", framework="pt")
print("tensor 数量:", len(f.keys()))
EOF

5. 安装 vLLM

5.1 pip 安装

source /opt/vllm-venv/bin/activate

# 建议安装当前最新稳定版(vLLM 已于 2026-04 对 MiMo-V2.5 完成 Day0 适配)

pip install -U vllm

安装后可用 pip show vllm 确认版本号。vLLM 从 0.29 起默认使用 V1 引擎(V0 已弃用),Continuous Batching、Chunked Prefill、KV Cache 管理等能力内置默认开启。若需精确回退,可指定如 pip install vllm==0.29.0;若后续升级,请先阅读对应版本 Release Notes。

5.2 验证安装

source /opt/vllm-venv/bin/activate

vllm --version

python -c "import vllm; print(vllm.__version__)"

能正常输出版本号即安装成功。


6. 启动 vLLM OpenAI 兼容服务

6.1 最小启动命令(FP8 权重,TP=4)

source /opt/vllm-venv/bin/activate

vllm serve /data/vllm/models/MiMo-V2.5 
  --host 127.0.0.1 
  --port 8000 
  --served-model-name mimo-v2.5 
  --tensor-parallel-size 4 
  --max-model-len auto 
  --gpu-memory-utilization 0.95 
  --max-num-seqs 256 
  --generation-config vllm 
  --trust-remote-code

启动成功后,控制台会输出监听地址 Uvicorn running on http://127.0.0.1:8000 以及 Application startup complete. 等日志,并显示已加载的 TP 秩与 GPU 显存分布。

6.2 关键参数详解

参数 说明 建议值
--host 监听地址,只绑回环,由网关转发 127.0.0.1
--port 服务端口 8000
--served-model-name 客户端请求时使用的模型名 mimo-v2.5
--api-key vLLM 自身接口密钥(纵深防御) 强随机串
--tensor-parallel-size 张量并行卡数(FP8 权重 293 GB 单卡装不下,须多卡) 按硬件:FP8=4、BF16≥8
--pipeline-parallel-size 流水线并行层数(多机/超长权重时使用) 按硬件
--max-model-len 最大上下文长度 auto 或生产 32768–131072
--gpu-memory-utilization KV Cache 可用显存比例上限 0.90–0.95
--max-num-seqs 单批并发序列数上限 128–512
--generation-config 使用 vLLM 内置 GenerationConfig 解析生成配置(MiMo 官方推荐) vllm
--enable-mtp 开启多 token 预测加速(MiMo 原生 3 层 MTP;若版本不支持改用 --speculative-config) 按需开启
--quantization 量化方式:fp8 / fp4(mxfp4)按权重类型 按权重类型
--distributed-executor-backend 分布式执行后端,多机时可设 mp 按部署
--trust-remote-code 信任模型仓库中的自定义代码 官方权重必需

MTP 加速提示:MiMo-V2.5 原生支持 3 层 MTP(Multi-Token Prediction)。在 vLLM 中除 --enable-mtp 外,也可通过 --speculative-config '{"method":"mtp","num_speculative_tokens":3}' 精确启用,官方 MTP 用法见 vLLM MTP 文档。

长上下文提示:MiMo-V2.5 原生支持最长 1M 上下文。--max-model-len auto 会按模型 config 自动推断;若显存不足,手动设为 32768–131072 等业务对齐值,不要无脑拉满 1M 造成 KV Cache 浪费(即便 Hybrid SWA 已将 KV Cache 降至 1/7)。

6.3 生产推荐启动脚本(FP8 · TP=4 示例)

#!/usr/bin/env bash
# /opt/scripts/start_vllm.sh
set -e

export VLLM_LOGGING_LEVEL=info

source /opt/vllm-venv/bin/activate

exec vllm serve /data/vllm/models/MiMo-V2.5 
  --host 127.0.0.1 
  --port 8000 
  --served-model-name mimo-v2.5 
  --tensor-parallel-size 4 
  --api-key "${VLLM_API_KEY}" 
  --max-model-len 131072 
  --gpu-memory-utilization 0.95 
  --max-num-seqs 256 
  --generation-config vllm 
  --enable-mtp 
  --trust-remote-code

多模态能力:MiMo-V2.5 原生支持图像、视频、音频理解。客户端在 messages 中按 OpenAI 协议传入 image_url(及 vLLM 支持的多模态字段)即可,vLLM 会自动调用内置视觉 / 音频编码器处理,编码器经轻量 projector 与语言主干对齐,无需单独起编码服务。

6.4 服务自检

# 1) 健康检查(vLLM 原生端点)

curl -s http://127.0.0.1:8000/health            # 期望输出 {"status":"ok"} 或 ok

# 2) 查看已加载模型列表(需要 api-key 时带上)

curl -s http://127.0.0.1:8000/v1/models 
  -H "Authorization: Bearer ${VLLM_API_KEY}"

# 3) 直接调用验证(仅本机测试;生产必须走网关)

curl -s http://127.0.0.1:8000/v1/chat/completions 
  -H "Authorization: Bearer ${VLLM_API_KEY}" 
  -H "Content-Type: application/json" 
  -d '{
    "model": "mimo-v2.5",
    "messages": [{"role": "user", "content": "你好,请用一句话自我介绍"}],
    "max_tokens": 128,
    "stream": false
  }'

7. SK 密钥鉴权与 FastAPI 网关

7.1 鉴权设计

鉴权模型:

  1. 平台为每个调用方(应用 / 团队 / 租户)颁发独立 SK(sk- 开头,≥ 32 位随机串);
  2. 客户端请求时在 Authorization: Bearer <SK> 中携带;
  3. 网关对 SK 做 SHA-256 哈希后与白名单做常数时间比较(防时序攻击),并记录调用方与时间戳用于审计;
  4. 通过后可做按 SK 的限流(每分钟请求数上限),再转发至 vLLM。

密钥管理规范:

  • 数据库中只存 SK 的哈希(加盐),不存明文;本文示例为了简洁用环境变量明文列表,生产建议接入密钥管理服务(Vault / KMS);
  • SK 支持轮换:新旧 SK 同时有效一段时间,客户端灰度切换后再下线旧值;
  • 网关日志中只记录 SK 前缀(如 sk-xxxx…),禁止记录完整密钥。

7.2 网关工程结构

/opt/llm-gateway/

├── requirements.txt

└── app/

    └── main.py

requirements.txt:

fastapi>=0.115

uvicorn[standard]>=0.32

httpx>=0.27

7.3 网关核心代码

/opt/llm-gateway/app/main.py:

import hashlib
import hmac
import os
import time
import httpx
from fastapi import Depends, FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse, StreamingResponse

# ---------------------------------------------------------------------------
# 配置(通过环境变量注入,生产建议放入 /etc/llm-gateway/gateway.env)
# 依赖 pip install fastapi httpx uvicorn
# ---------------------------------------------------------------------------
VLLM_BASE_URL = os.getenv("VLLM_BASE_URL", "http://127.0.0.1:8000")
VLLM_API_KEY = os.getenv("VLLM_API_KEY", "")  # 网关 -> vLLM 的内部密钥
SK_LIST = [s.strip() for s in os.getenv("SK_LIST", "").split(",") if s.strip()]
RATE_LIMIT = int(os.getenv("RATE_LIMIT", "60"))  # 每个 SK 每分钟最大请求数

# 只保存 SK 的 SHA-256 哈希,避免明文泄露
SK_HASHES = {hashlib.sha256(sk.encode()).hexdigest() for sk in SK_LIST}

app = FastAPI(title="LLM Gateway", version="1.0.0")

client = httpx.AsyncClient(
    base_url=VLLM_BASE_URL,
    timeout=httpx.Timeout(600.0, connect=10.0),  # 长生成任务需大读超时
)

# 简单内存限流表:{sk_hash: [请求时间戳]}
_ratelimit: dict[str, list[float]] = {}

def _verify_sk(request: Request) -> str:
    """校验客户端 SK,返回 sk_hash 用于限流。鉴权失败抛出 401/429。"""
    auth = request.headers.get("Authorization", "")
    sk = auth.removeprefix("Bearer ").strip() if auth.startswith("Bearer ") else auth.strip()
    if not sk:
        raise HTTPException(status_code=401, detail="Missing SK")

    digest = hashlib.sha256(sk.encode()).hexdigest()
    if not any(hmac.compare_digest(digest, h) for h in SK_HASHES):
        raise HTTPException(status_code=401, detail="Invalid SK")

    now = time.time()
    window = _ratelimit.setdefault(digest, [])
    window[:] = [t for t in window if now - t < 60]  # 只保留近 60s
    if len(window) >= RATE_LIMIT:
        raise HTTPException(status_code=429, detail="Rate limit exceeded")
    window.append(now)
    return digest

def _vllm_headers(request: Request) -> dict:
    """转发到 vLLM 的请求头:注入内部密钥。"""
    headers = {"Content-Type": request.headers.get("Content-Type", "application/json")}
    if VLLM_API_KEY:
        headers["Authorization"] = f"Bearer {VLLM_API_KEY}"
    return headers

async def _proxy(request: Request, body: bytes, path: str):
    """将请求代理到 vLLM,支持 SSE 流式透传。"""
    try:
        upstream = await client.build_request(
            "POST", path, content=body, headers=_vllm_headers(request)
        )
        resp = await client.send(upstream, stream=True)
    except httpx.HTTPError as exc:
        raise HTTPException(status_code=503, detail=f"Upstream unavailable: {exc}")

    if resp.headers.get("content-type", "").startswith("text/event-stream"):
        return StreamingResponse(
            resp.aiter_bytes(),
            status_code=resp.status_code,
            media_type="text/event-stream",
            headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"},
        )
    return StreamingResponse(
        resp.aiter_bytes(),
        status_code=resp.status_code,
        media_type=resp.headers.get("content-type", "application/json"),
    )

# ---------------------------------------------------------------------------
# 路由
# ---------------------------------------------------------------------------
@app.get("/health")
async def health():
    """网关存活检查,并探测 vLLM 是否可达。"""
    try:
        r = await client.get("/health")
        if r.status_code == 200:
            return {"status": "ok", "vllm": "up"}
        return JSONResponse({"status": "degraded", "vllm": r.status_code}, status_code=503)
    except Exception:
        return JSONResponse({"status": "down", "vllm": "unreachable"}, status_code=503)

@app.get("/v1/models")
async def models(_: str = Depends(_verify_sk)):
    r = await client.get("/v1/models", headers=_vllm_headers())
    return r.json()

@app.post("/v1/chat/completions")
async def chat_completions(request: Request, _: str = Depends(_verify_sk)):
    body = await request.body()
    return await _proxy(request, body, "/v1/chat/completions")

@app.post("/v1/completions")
async def completions(request: Request, _: str = Depends(_verify_sk)):
    body = await request.body()
    return await _proxy(request, body, "/v1/completions")

@app.on_event("shutdown")
async def shutdown():
    await client.aclose()

代码要点:

  • 鉴权依赖(Depends(_verify_sk))自动作用于所有业务路由,新增接口不会漏鉴权;
  • hmac.compare_digest 做常数时间比较;
  • 流式响应设置 X-Accel-Buffering: no,避免 Nginx 等反向代理缓冲导致 “首字延迟”;
  • 超时设置为 600 秒,兼容长上下文、长生成的请求。

7.4 环境变量配置

/etc/llm-gateway/gateway.env(示例,生产请用强随机密钥并妥善保管):

# 网关 -> vLLM

VLLM_BASE_URL=http://127.0.0.1:8000

VLLM_API_KEY=vllm-internal-key-change-me

# 合法 SK 列表(逗号分隔,可同时存在新旧密钥以便轮换)

SK_LIST=sk-richard-11223355,sk-richard-2244667788

# 限流:每个 SK 每分钟最多请求数

RATE_LIMIT=60

7.5 启动网关

mkdir -p /opt/llm-gateway

# 将 app/main.py 与 requirements.txt 放入 /opt/llm-gateway 后:

source /opt/vllm-venv/bin/activate

cd /opt/llm-gateway

pip install -r requirements.txt

# 前台启动(验证用)

set -a && source /etc/llm-gateway/gateway.env && set +a

uvicorn app.main:app --host 0.0.0.0 --port 8080

多 worker 时(--workers N)内存限流按进程独立计数,属于近似限流;严格限流请改用 Redis 计数。


8. 集成测试

8.1 curl 测试

BASE=http://127.0.0.1:8080

# 1) 健康检查(无需鉴权)

curl -s $BASE/health

# 2) 正常调用(非流式)

curl -s $BASE/v1/chat/completions 
  -H "Authorization: Bearer sk-test-123456" 
  -H "Content-Type: application/json" 
  -d '{
    "model": "mimo-v2.5",
    "messages": [{"role": "user", "content": "用一句话介绍 MiMo-V2.5"}],
    "max_tokens": 128,
    "stream": false
  }'

# 3) 流式调用

curl -N -s $BASE/v1/chat/completions 
  -H "Authorization: Bearer sk-test-123456" 
  -H "Content-Type: application/json" 
  -d '{
    "model": "mimo-v2.5",
    "messages": [{"role": "user", "content": "写一首关于大模型的小诗"}],
    "max_tokens": 256,
    "stream": true
  }'

# 4) 错误密钥 → 期望 401

curl -s -o /dev/null -w "HTTP %{http_code}n" 
  $BASE/v1/chat/completions 
  -H "Authorization: Bearer sk-wrong-key" 
  -H "Content-Type: application/json" 
  -d '{"model":"mimo-v2.5","messages":[{"role":"user","content":"hi"}]}'

# 输出: HTTP 401

# 5) 缺失密钥 → 期望 401

curl -s -o /dev/null -w "HTTP %{http_code}n" 
  $BASE/v1/chat/completions 
  -H "Content-Type: application/json" 
  -d '{"model":"mimo-v2.5","messages":[{"role":"user","content":"hi"}]}'

# 输出: HTTP 401

8.2 OpenAI SDK 测试(Python)

source /opt/vllm-venv/bin/activate

pip install openai
from openai import OpenAI

client = OpenAI(
    api_key="sk-test-123456",               # 网关下发的 SK
    base_url="http://127.0.0.1:8080/v1",    # 指向网关
)

resp = client.chat.completions.create(
    model="mimo-v2.5",
    messages=[{"role": "user", "content": "解释一下什么是 MoE"}],
    stream=True,
)

for chunk in resp:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

MiMo-V2.5 具备强 agentic 推理能力,流式输出中可能先出现 reasoning_content(思考过程)再出现 content(最终回答),SDK 按需展示即可。

8.3 压测建议

# vLLM 自带压测工具(走直连,用于基准性能基线)

vllm bench serve 
  --model /data/vllm/models/MiMo-V2.5 
  --dataset-name random 
  --random-input 512 --random-output 256 
  --num-prompts 200 --request-rate 10 
  --save-result --result-dir /opt/bench

# 网关层压测:用 wrk / hey 打网关,重点观察鉴权链路与流式吞吐

9. 生产化部署

9.1 systemd 托管

vLLM 服务(/etc/systemd/system/vllm.service):

[Unit]

Description=vLLM OpenAI Compatible Server (MiMo-V2.5)

After=network-online.target

Wants=network-online.target

[Service]

Type=simple

User=vllm

Group=vllm

EnvironmentFile=/etc/vllm/vllm.env

ExecStart=/opt/vllm-venv/bin/vllm serve /data/vllm/models/MiMo-V2.5 
    --host 127.0.0.1 --port 8000 
    --served-model-name mimo-v2.5 
    --tensor-parallel-size 4 
    --max-model-len 131072 
    --gpu-memory-utilization 0.95 
    --max-num-seqs 256 
    --generation-config vllm 
    --enable-mtp 
    --trust-remote-code

Restart=on-failure

RestartSec=10

LimitNOFILE=65535

[Install]

WantedBy=multi-user.target

FastAPI 网关服务(/etc/systemd/system/llm-gateway.service):

[Unit]

Description=LLM Gateway (FastAPI + SK Auth)

After=network-online.target vllm.service

Wants=network-online.target

[Service]

Type=simple

User=vllm

Group=vllm

EnvironmentFile=/etc/llm-gateway/gateway.env

WorkingDirectory=/opt/llm-gateway

ExecStart=/opt/vllm-venv/bin/uvicorn app.main:app 
    --host 0.0.0.0 --port 8080

Restart=on-failure

RestartSec=5

LimitNOFILE=65535

[Install]

WantedBy=multi-user.target

创建服务用户并启用:

useradd -r -s /usr/sbin/nologin vllm

usermod -aG video,render vllm          # 赋予 GPU 访问权限

systemctl daemon-reload

systemctl enable --now vllm llm-gateway

systemctl status vllm llm-gateway

9.2 防火墙与 SELinux

# 只对公网开放网关端口 8080

firewall-cmd --permanent --add-port=8080/tcp

firewall-cmd --reload

# vLLM 仅绑定 127.0.0.1,无需开放 8000 外网端口

# 查看 SELinux 状态

getenforce

# 若为 Enforcing 且服务启动异常(如无法监听端口),

# 用 audit2allow 生成策略,而不是直接 setenforce 0:

ausearch -m avc --start recent | audit2allow -M llm_gateway

semodule -i llm_gateway.pp

9.3 日志与监控

日志:

# 查看服务日志

journalctl -u vllm -f

journalctl -u llm-gateway -f

# 网关审计(建议接入 ELK / Loki):记录调用方 SK 前缀、模型、耗时、token 数

监控:

  • vLLM 内置 Prometheus 指标端点 http://127.0.0.1:8000/metrics,包含吞吐(tokens/s)、请求延迟分位数、KV Cache 使用率、GPU 利用率等;
  • 在 Prometheus 中配置抓取任务后,用 Grafana 展示关键面板(vllm:num_requests_running、vllm:gpu_cache_usage_perc 等);
  • 网关侧可用 prometheus_client 暴露 gateway_requests_total、gateway_sk_active 等业务指标。

9.4 安全加固清单

措施 说明
密钥轮换 SK 定期轮换,新旧并存灰度切换
传输加密 网关对外暴露时,前端加 Nginx/Caddy 终止 TLS(HTTPS)
请求签名(进阶) 在 SK 基础上叠加 HMAC-SHA256 签名(时间戳 + 请求体哈希),防重放与篡改
超时与限流 网关设置读超时与每 SK 限流;必要时按模型、按 IP 分级限流
最小权限 vLLM / 网关用独立低权限用户运行;模型目录只读
审计日志 记录调用方、时间、模型、输入 / 输出长度,脱敏后留存

10. 性能调优

场景 调优手段
显存不足 / OOM 降低 --max-model-len 与 --max-num-seqs;改用 FP4 量化;加大 --tensor-parallel-size
吞吐优先 提高 --max-num-seqs 至 256–512;开启 --enable-mtp(MiMo 原生 3 层 MTP);保证 --gpu-memory-utilization ≥ 0.90
首 token 延迟优先 调小 --max-num-seqs(减少排队);开启 --enable-chunked-prefill(V1 默认开启);长提示词场景配合前缀缓存
长上下文业务 设置 --max-model-len 与业务对齐(32K/128K),不要无脑拉满 1M 造成 KV Cache 浪费(Hybrid SWA 已降至 1/7)
多卡扩展 FP8 用 --tensor-parallel-size 4;更大规模加 --pipeline-parallel-size;横向扩容部署多个 vLLM 副本,前置负载均衡
MoE 负载 稀疏激活下单 token 计算成本低,主要瓶颈在权重加载与多卡通信;EP(Expert Parallelism)场景关注专家负载均衡(参考 MiMo 推理优化实践)
思考模式控制 客户端可通过 reasoning_effort、max_thinking_tokens 等参数调节推理深度(参考 vLLM Reasoning 文档)

基准建议:上线前用 vllm bench serve 在目标硬件上建立吞吐 / 延迟基线(见 8.3),后续调参以基线数据为准,避免拍脑袋。


11. 常见问题 FAQ

Q1:启动报 CUDA out of memory?

降低 --max-model-len、--max-num-seqs、--gpu-memory-utilization 之一;或改用 FP4 量化、增加 TP 卡数(310B 权重 FP8 约 293 GB,单卡无法容纳,至少 TP=4 张 80G)。

Q2:模型下载很慢或失败?

设置 export HF_ENDPOINT=https://hf-mirror.com;或改用 ModelScope:export VLLM_USE_MODELSCOPE=true,或 modelscope download 到本地目录。310B 权重约 293 GB,注意磁盘空间 ≥ 1 TB。

Q3:客户端报 model not found?

检查请求中的 model 字段与 --served-model-name 是否一致(本文为 mimo-v2.5)。

Q4:流式输出被缓冲、首字很慢?

确认网关转发了 X-Accel-Buffering: no;若前端还有 Nginx,设置 proxy_buffering off;。

Q5:如何传入图片 / 音频做多模态理解?

MiMo-V2.5 原生支持多模态。客户端在 messages 中按 OpenAI 协议传入 image_url(图片 URL 或 base64)等字段即可;vLLM 会自动调用内置视觉 / 音频编码器处理,编码器经轻量 projector 与语言主干对齐,无需单独起编码服务。

Q6:--max-model-len 设 1M 报错或显存不足?

MiMo-V2.5 原生支持 1M 上下文,但长上下文的 KV Cache 即便被 Hybrid SWA 压到 1/7 依然可观。显存有限时手动将 --max-model-len 调到 32768–131072,不要无脑拉满 1M。

Q7:vLLM 升级后部分旧参数不识别?

vLLM 0.29 起默认 V1 引擎,--enable-chunked-prefill 等旧参数已内置或移除;以当前版本文档为准,必要时用 vllm serve --help 核对。

Q8:SK 泄露了怎么办?

立即在网关的 SK_LIST 中下线该密钥并重启网关;若接入了密钥管理系统,直接吊销对应 SK,同时检查审计日志中该 SK 的历史调用。

Q9:多副本部署后网关限流不准?

内存限流按进程独立计数;多 worker / 多副本场景改用 Redis 集中计数。

Q10:如何验证鉴权是否真正生效?

用无密钥、错误密钥、正确密钥分别请求网关,确认返回 401 / 401 / 200;再直连 127.0.0.1:8000,确认未设置 vLLM --api-key 时直连被防火墙 / 绑定限制住。


12. 参考资料


声明

本文命令与参数基于 vLLM(2026-10 最新稳定版)、Rocky Linux 10.2、XiaomiMiMo/MiMo-V2.5 官方权重编写(截止 2026-4-29);模型 ID、仓库地址、软件版本以官方最新发布为准。

上一篇
下一篇