配置与部署

系统要求

要求 最低配置
GPU NVIDIA GPU,显存 > 28GB
操作系统 Linux
Python 3.10
CUDA 与 PyTorch 2.8.0 兼容
FFmpeg 用于视频帧提取和推理结果可视化

资源消耗参考

资源 Token2Wav(默认)
显存(每 Worker,初始化后) ~21.5 GB
模型加载时间 ~16s
模式切换延迟 < 0.1ms

torch.compile 模式首次推理额外 ~60s 编译耗时。


依赖安装

使用 install.sh(推荐)

# 1. 安装 Python 3.10(推荐 miniconda)
mkdir -p ./miniconda3_install_tmp
wget https://repo.anaconda.com/miniconda/Miniconda3-py310_25.11.1-1-Linux-x86_64.sh \
    -O ./miniconda3_install_tmp/miniconda.sh
bash ./miniconda3_install_tmp/miniconda.sh -b -u -p ./miniconda3
source ./miniconda3/bin/activate

# 2. 一键安装
bash ./install.sh

install.sh 自动完成以下步骤: 1. 在 .venv/base 创建 Python venv 虚拟环境 2. 安装 PyTorch 2.8.0 + torchaudio 3. 安装 requirements.txt 中的所有依赖 4. 验证安装结果

手动安装

source ./miniconda3/bin/activate
python -m venv .venv/base
source .venv/base/bin/activate

pip install "torch==2.8.0" "torchaudio==2.8.0"
pip install -r requirements.txt

Python 依赖清单

类别 版本
核心 ML transformers 4.51.0
accelerate 1.12.0
safetensors >= 0.7.0
MiniCPM-o minicpmo-utils[all] >= 1.0.5
Web 服务 fastapi >= 0.128.0
uvicorn >= 0.40.0
httpx >= 0.28.0
websockets >= 16.0
python-multipart
数据 pydantic >= 2.11.0
numpy >= 2.2.0
工具 tqdm >= 4.67.0
测试 pytest >= 9.0.0
pytest-asyncio >= 1.3.0

配置说明

config.json

所有配置集中在项目根目录的 config.json 文件中。首次使用时从 config.example.json 复制:

cp config.example.json config.json

config.json 已在 .gitignore 中,不会被提交。

配置优先级

CLI 参数 > config.json > Pydantic 默认值

完整字段说明

model — 模型配置

字段 类型 默认值 说明
model_path str (必填) HuggingFace 格式模型目录或 Hub ID
pt_path str null 额外 .pt 权重覆盖路径
attn_implementation str "auto" Attention 实现方式

audio — 音频配置

字段 类型 默认值 说明
ref_audio_path str assets/ref_audio/ref_minicpm_signature.wav 默认 TTS 参考音频路径
playback_delay_ms int 200 前端音频播放延迟(ms),越大越平滑但延迟越高

service — 服务配置

字段 类型 默认值 说明
gateway_port int 8006 Gateway 监听端口
worker_base_port int 22400 Worker 起始端口(Worker N = base + N)
max_queue_size int 1000 最大排队请求数
request_timeout float 300.0 请求超时(秒)
compile bool false 启用 torch.compile 加速
data_dir str "data" 数据存储目录
eta_chat_s float 15.0 Chat 任务基准 ETA(秒)
eta_streaming_s float 20.0 Streaming 任务基准 ETA(秒)
eta_audio_duplex_s float 120.0 Audio Duplex 任务基准 ETA(秒)
eta_omni_duplex_s float 90.0 Omni Duplex 任务基准 ETA(秒)
eta_ema_alpha float 0.3 ETA EMA 平滑系数
eta_ema_min_samples int 3 ETA EMA 最少样本数

duplex — 双工配置

字段 类型 默认值 说明
pause_timeout float 60.0 Duplex 暂停超时(秒),超时后自动释放 Worker

最小配置

{
  "model": {
    "model_path": "openbmb/MiniCPM-o-4_5"
  }
}

完整配置示例

{
  "model": {
    "model_path": "openbmb/MiniCPM-o-4_5",
    "pt_path": null,
    "attn_implementation": "auto"
  },
  "audio": {
    "ref_audio_path": "assets/ref_audio/ref_minicpm_signature.wav",
    "playback_delay_ms": 200,
    "chat_vocoder": "token2wav"
  },
  "service": {
    "gateway_port": 8006,
    "worker_base_port": 22400,
    "max_queue_size": 1000,
    "request_timeout": 300.0,
    "compile": false,
    "data_dir": "data",
    "eta_chat_s": 15.0,
    "eta_streaming_s": 20.0,
    "eta_audio_duplex_s": 120.0,
    "eta_omni_duplex_s": 90.0,
    "eta_ema_alpha": 0.3,
    "eta_ema_min_samples": 3
  },
  "duplex": {
    "pause_timeout": 60.0
  }
}

Attention Backend

控制模型推理使用的 Attention 实现,通过 attn_implementation 字段配置。

行为 适用场景
"auto"(默认) 检测到 flash-attn → flash_attention_2;否则 → sdpa 推荐
"flash_attention_2" 强制使用 Flash Attention 2 确认已安装 flash-attn
"sdpa" PyTorch 内置 SDPA 无法编译 flash-attn
"eager" 朴素 Attention 仅 debug

性能对比(A100):flash_attention_2sdpa 快约 5-15%,sdpaeager 快数倍。

注意:Audio(Whisper)子模块始终使用 SDPA(与 flash_attention_2 不兼容)。Vision / LLM / TTS 遵循配置。


启动与停止

一键启动(start_all.sh)

# 使用所有可用 GPU
CUDA_VISIBLE_DEVICES=0,1,2,3 bash start_all.sh

# 指定 GPU
CUDA_VISIBLE_DEVICES=0,1 bash start_all.sh

# 启用 torch.compile(实验性)
bash start_all.sh --compile

# 降级为 HTTP(不推荐,麦克风/摄像头 API 需要 HTTPS)
bash start_all.sh --http

start_all.sh 执行流程: 1. 解析命令行参数(--http, --compile) 2. 从 config.py 读取端口配置 3. 检测可用 GPU 数量 4. 为每个 GPU 启动一个 Worker 进程(nohup) 5. 等待所有 Worker 健康检查通过 6. 启动 Gateway 进程 7. 输出访问地址和日志路径

手动启动

# Worker(每张 GPU 一个)
CUDA_VISIBLE_DEVICES=0 PYTHONPATH=. .venv/base/bin/python worker.py \
    --worker-index 0 --gpu-id 0

# Gateway
PYTHONPATH=. .venv/base/bin/python gateway.py \
    --port 8006 --workers localhost:22400

CLI 参数

Worker 参数

python worker.py \
    --model-path /path/to/model \
    --pt-path /path/to/weights.pt \
    --ref-audio-path /path/to/ref.wav \
    --worker-index 0 \
    --gpu-id 0 \
    --compile

Gateway 参数

python gateway.py \
    --port 8006 \
    --workers localhost:22400,localhost:22401 \
    --http

停止服务

pkill -f "gateway.py|worker.py"

模型下载

自动下载(默认)

model_path 设为 openbmb/MiniCPM-o-4_5 时,首次启动自动从 HuggingFace 下载。

手动下载

HuggingFace CLI

pip install -U huggingface_hub
huggingface-cli download openbmb/MiniCPM-o-4_5 --local-dir /path/to/MiniCPM-o-4_5

hf-mirror(中国)

export HF_ENDPOINT=https://hf-mirror.com
huggingface-cli download openbmb/MiniCPM-o-4_5 --local-dir /path/to/MiniCPM-o-4_5

ModelScope(中国)

pip install modelscope
modelscope download --model OpenBMB/MiniCPM-o-4_5 --local_dir /path/to/MiniCPM-o-4_5

测试

Schema 单元测试(无需 GPU)

PYTHONPATH=. .venv/base/bin/python -m pytest tests/test_schemas.py -v

Processor 测试(需要 GPU)

CUDA_VISIBLE_DEVICES=0 PYTHONPATH=. .venv/base/bin/python -m pytest \
    tests/test_chat.py tests/test_streaming.py tests/test_duplex.py -v -s

API 集成测试(需要先启动服务)

PYTHONPATH=. .venv/base/bin/python -m pytest tests/test_api.py -v -s

测试文件说明

文件 说明
test_schemas.py Schema 单元测试
test_chat.py Chat 推理测试
test_streaming.py Streaming 推理测试
test_duplex.py Duplex 推理测试
test_api.py API 集成测试
test_queue.py 队列逻辑测试
test_queue_stress.py 队列压力测试
test_integration.py 集成测试
test_e2e.py 端到端测试
bench_duplex_ws.py Duplex WebSocket 性能基准测试
mock_worker.py Mock Worker(用于无 GPU 测试)
js/queue-scenario.test.js 前端队列场景测试(Vitest)
js/countdown-timer.test.js 倒计时组件测试(Vitest)

运行时目录结构

data/
├── sessions/                  # 会话录制数据
   ├── omni_abc123/
      ├── meta.json
      ├── recording.json
      ├── user_audio/
      ├── ai_audio/
      └── ...
   └── ...
└── ref_audio/                 # 上传的参考音频
    ├── registry.json
    └── *.wav

tmp/
├── gateway.pid                # Gateway 进程 PID
├── gateway.log                # Gateway 日志
├── worker_0.pid               # Worker 0 PID
├── worker_0.log               # Worker 0 日志
└── diag_omni_*.jsonl          # 诊断日志