MiniCPM-o 4.5 GGUF:Ubuntu + RTX 3060 12GB + uv 完整部署与排障手册

版本:2026-10-17(根据实际部署与故障记录整理)

目标:ModelScope 下载 MiniCPM-o 4.5 GGUF Q4_K_M,Ubuntu/NVIDIA CUDA 本地推理,官方 Comni Demo 提供中文语音半双工/全双工对话。
实测状态:用户已成功启动 HTTPS Gateway 与 Worker,中文半双工/全双工可用;网页播放缓冲改为 800 ms 后卡顿消失;长会话曾因 Stop on KV pruning 自动结束。
适用性边界:这是可复现的部署记录,不代表在其他操作系统、提交版本或同类显卡上已逐项实测。仓库会更新,请优先核对自己检出的分支、实际程序名称与日志。

目录
1. 先看结论:本次成功的配置
2. 部署结构与硬件要求
3. 准备 NVIDIA 驱动与 CUDA
4. 使用 uv 建立工具环境
5. 从 ModelScope 下载完整 GGUF 音频模型
6. 下载 llama.cpp-omni 源码:规避 GitHub TLS 断开
7. 编译 CUDA 推理引擎:规避 CURL 缺失与目标名称差异
8. uv 部署 MiniCPM-o-Demo
9. 配置 RTX 3060 与稳定播放参数
10. 启动、访问与健康检查
11. 语音测试与长会话设置
12. 日常启动、停止与重新启动
13. 实际遇到过的问题与解决方法
14. 性能监测与进一步优化
15. 备份、升级与安全建议
16. 参考资料
1. 先看结论:本次成功的配置
项目 本次配置 / 已验证状态
操作系统 Ubuntu;原安装环境按 Ubuntu 26.04 操作
显卡 NVIDIA GeForce RTX 3060,12 GB 显存
CUDA 编译器 nvcc 12.4.131(配置日志已识别)
主机 GCC GNU 13.4.0(配置日志已识别)
CUDA 架构 86(RTX 3060 Ampere / SM 8.6)
Python uv 管理的 Python 3.11
模型源 OpenBMB/MiniCPM-o-4_5-gguf(ModelScope)
主模型 MiniCPM-o-4_5-Q4_K_M.gguf
推理 llama.cpp-omni,CUDA/C++,配套 feat/web-demo 分支
网页 OpenBMB/MiniCPM-o-Demo 的 Comni 分支
HTTPS Gateway 8040;实测 /health 返回 healthy
Python Worker 22440;实测 model_loaded: true、worker_status: idle
内部 C++ 服务 典型端口 19080(由 Worker 管理)
Playback Delay 800 ms(用户实测不再断续)
Stop on KV pruning 关闭,允许发生缓存修剪后尝试继续会话
Context 建议初次设 4096;显存紧张时降为 2048,但对话更容易提早触发缓存修剪
Worker 数量 1


三个关键认识:
- uv 管理 Python 下载工具和网页服务依赖;GGUF 模型的 GPU 推理由 C++ CUDA 引擎完成,不是 uv 直接执行 GGUF。
- 官方 C++ 引擎给出的完整 Omni Q4_K_M 显存估算约 9 GB,RTX 3060 12 GB 是合理目标;但实时速度取决于硬件,不能直接套用 RTX 4090 的基准数据。
- 之前发生的两种现象是不同问题:回答断续通过更大的网页播放缓冲改善;聊几轮后自动停止是 KV 滑动窗口触发了前端的自动停止策略。
2. 部署结构与硬件要求
2.1 目录结构
本手册统一采用:
/home/<你的用户名>/env/minicpm-o-4.5/
├── .venv/                        # ModelScope 下载用的 uv 环境
├── models/
│   └── MiniCPM-o-4_5-gguf/
│       ├── MiniCPM-o-4_5-Q4_K_M.gguf
│       ├── audio/
│       ├── tts/
│       ├── token2wav-gguf/
│       └── vision/
├── llama.cpp-omni/               # C++/CUDA 推理引擎
│   └── build/bin/
└── MiniCPM-o-Demo/               # Gateway / Worker / WebUI
    ├── .venv/base/               # 官方脚本固定使用的 Python 路径
    ├── config.json
    ├── start_all.sh
    └── tmp/                     # 日志及进程 PID
不要把目录 /home/frank/... 写死在配置里,后文自动使用 $HOME 和 Python Path.resolve() 获取绝对路径。
2.2 架构
浏览器麦克风 / 音频播放
        |
        v
Gateway(HTTPS,默认 8040)
        |
        v
Python Worker(HTTP,默认 22440)
        | 由 Worker 启动、管理
        v
llama.cpp-omni C++ 服务(内部端口,典型 19080)
        |
        v
MiniCPM-o 4.5 GGUF
  ├─ Audio Encoder:输入语音
  ├─ LLM Q4_K_M:理解与推理
  ├─ TTS + Projector:生成语音 token
  └─ Token2Wav:合成语音波形
不要把 22440 或 19080 直接暴露到公网;本地使用 Gateway 即可。
3. 准备 NVIDIA 驱动与 CUDA
3.1 必须先通过的检查
nvidia-smi
nvcc --version
gcc --version
- nvidia-smi 正常:驱动与 GPU 通信正常。
- nvcc --version 正常:CUDA 编译器已存在。nvidia-smi 显示的 CUDA Version 不等于系统已经安装 nvcc。
- 本次实际看到的是 CUDA 12.4 / GCC 13.4;这是已运行的环境信息,不是要求其他电脑必须安装完全相同的版本。
如果 nvidia-smi 报驱动错误,先修复驱动、重启并重新检查,不要直接编译。可先检查:
uname -r
ubuntu-drivers devices
lsmod | grep nvidia || true
如果缺少 nvcc,按 NVIDIA CUDA 安装文档为当前 Ubuntu 版本安装兼容的 Toolkit;不要盲目混装多个 CUDA/GCC 版本。
3.2 安装系统依赖:提前规避 CURL 错误
sudo apt update
sudo apt install -y \
  git git-lfs curl wget ca-certificates \
  build-essential cmake ninja-build pkg-config \
  libssl-dev libcurl4-openssl-dev \
  libsndfile1 ffmpeg openssl
历史问题:CMake 曾报 Could NOT find CURL (missing: CURL_LIBRARY CURL_INCLUDE_DIR)。提前安装 libcurl4-openssl-dev 就能避开这个问题。curl 命令存在不代表对应 C 头文件和库开发包已安装。

4. 使用 uv 建立工具环境
4.1 安装 uv
已有 uv 则跳过安装。
curl -LsSf https://astral.sh/uv/install.sh | sh
# 若新终端已能找到 uv,这一步可省略
source ~/.bashrc
uv --version
4.2 创建目录与 Python 3.11 环境
mkdir -p ~/env/minicpm-o-4.5/{models,scripts,logs}
cd ~/env/minicpm-o-4.5

uv python install 3.11
uv venv .venv --python 3.11
source .venv/bin/activate
python --version
目录 ./.venv 专门用于下载和维护工具;后续 Demo 自己使用 MiniCPM-o-Demo/.venv/base。这是两个不同虚拟环境,不要混为一谈。
5. 从 ModelScope 下载完整 GGUF 音频模型
模型主页:https://modelscope.cn/models/OpenBMB/MiniCPM-o-4_5-gguf
5.1 安装轻量 ModelScope 下载工具
cd ~/env/minicpm-o-4.5
source .venv/bin/activate
uv pip install -U modelscope-hub
ms-hub --version
5.2 只下载 Q4 与必需组件,不下载所有量化版本
cd ~/env/minicpm-o-4.5

ms-hub download OpenBMB/MiniCPM-o-4_5-gguf \
  --local-dir "$PWD/models/MiniCPM-o-4_5-gguf" \
  --max-workers 4 \
  --include \
    'MiniCPM-o-4_5-Q4_K_M.gguf' \
    'audio/*' \
    'tts/*' \
    'token2wav-gguf/*' \
    'vision/*'
若服务端仓库以后变更了目录名,按模型仓库实际文件树修正筛选模式,不能照搬其它版本文件。
关键规避:只下载主 .gguf 无法完整实现听说;语音输入需 audio/,语音输出需 tts/ 和 token2wav-gguf/。vision/ 保留以兼容完整 Omni 模式。不要下载整个仓库中所有 Q8/F16/Q5 版本。

5.3 必需模型文件检查
cd ~/env/minicpm-o-4.5

python - <<'PY'
from pathlib import Path
p = Path('models/MiniCPM-o-4_5-gguf')
files = [
    'MiniCPM-o-4_5-Q4_K_M.gguf',
    'audio/MiniCPM-o-4_5-audio-F16.gguf',
    'tts/MiniCPM-o-4_5-tts-F16.gguf',
    'tts/MiniCPM-o-4_5-projector-F16.gguf',
    'token2wav-gguf/encoder.gguf',
    'token2wav-gguf/flow_matching.gguf',
    'token2wav-gguf/flow_extra.gguf',
    'token2wav-gguf/hifigan2.gguf',
    'token2wav-gguf/prompt_cache.gguf',
    'vision/MiniCPM-o-4_5-vision-F16.gguf',
]
missing = []
for name in files:
    f = p / name
    ok = f.is_file() and f.stat().st_size > 0
    print(('OK     ' if ok else 'MISSING'), name)
    if not ok:
        missing.append(name)
if missing:
    raise SystemExit(f'缺少 {len(missing)} 个文件;请检查下载与仓库文件树')
print('文件存在性检查通过。')
PY
这里只检查文件是否存在、非空;如果怀疑下载损坏,请对照 ModelScope 提供的文件哈希/元数据验证,不能仅凭此判断内容完整。
6. 下载 llama.cpp-omni 源码:规避 GitHub TLS 断开
推理项目(本次路线):https://github.com/tc-mb/llama.cpp-omni/tree/feat/web-demo
历史报错原文:
error: RPC 失败。curl 56 GnuTLS recv error (-9)
error: 预期仍然需要 ... 字节的正文
fetch-pack: unexpected disconnect while reading sideband packet
fatal: 过早的文件结束符(EOF)
fatal: fetch-pack:无效的 index-pack 输出
这是源码传输中断,不是 CUDA 错误,也与 GGUF 模型权重无关。
6.1 首选:浅克隆 + HTTP/1.1
cd ~/env/minicpm-o-4.5

git -c http.version=HTTP/1.1 clone \
  --depth 1 \
  --single-branch \
  --branch feat/web-demo \
  https://github.com/tc-mb/llama.cpp-omni.git
如果之前失败后留下目录,先把旧目录改名保存或确认无用再清理,避免意外覆盖自己修改的文件。
cd ~/env/minicpm-o-4.5/llama.cpp-omni
git branch --show-current
git rev-parse --short HEAD
应显示 feat/web-demo。如果 git clone 已经成功,不要再执行下面的压缩包方案。
6.2 备用:直接下载指定分支的 tar.gz
GitHub git clone 持续失败时,可不经过 fetch-pack:
cd ~/env/minicpm-o-4.5
curl -fL --retry 5 --retry-delay 3 --connect-timeout 30 \
  -o llama.cpp-omni.tar.gz \
  'https://github.com/tc-mb/llama.cpp-omni/archive/refs/heads/feat/web-demo.tar.gz'

tar -tzf llama.cpp-omni.tar.gz >/dev/null  # 验证归档可读取
mkdir -p llama.cpp-omni
tar -xzf llama.cpp-omni.tar.gz \
  --strip-components=1 -C llama.cpp-omni
压缩包不含 Git 历史,之后不能在目录内直接 git pull。如源码归档还含子模块,则按该版本 README 补充获取子模块(归档不会自动包含子模块内容)。不要把任何不明镜像脚本直接通过 curl | bash 执行。
7. 编译 CUDA 推理引擎:规避 CURL 缺失与目标名称差异
7.1 配置 CMake
cd ~/env/minicpm-o-4.5/llama.cpp-omni

cmake -S . -B build \
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DGGML_CUDA=ON \
  -DCMAKE_CUDA_ARCHITECTURES=86
本次成功识别了 CUDA 12.4.131 和 GNU 13.4.0。如果再遇 Could NOT find CURL,优先执行:
sudo apt install -y libcurl4-openssl-dev
不需要 C++ 下载功能时,另一个可选方案是重新配置并添加 -DLLAMA_CURL=OFF,但更推荐装开发包,保持功能完整。配置成功应出现 Configuring done、Generating done。
7.2 重要:区分 llama-server 与 llama-omni-server
版本差异提示:官方 Comni 中文 README 的部分内容仍写 llama-server,而较新的 llama.cpp-omni 文档使用 llama-omni-server。这是不同版本文档之间确实存在的命名差异。不要看到不同名称就直接改名、做软链接或覆盖二进制:Worker 调用的接口与目标程序必须相互兼容。你的实际环境已运行成功,未来不要无故替换当前引擎。

先查看当前源码可用的 CMake 目标:
cmake --build build --target help | grep -E 'llama-(omni-)?(server|cli)' || true
本次部署按照实际跑通的 Omni 分支编译:
cmake --build build \
  --target llama-omni-server llama-omni-cli \
  -j 4
检查:
ls -lh build/bin/llama-omni-server build/bin/llama-omni-cli
grep 'GGML_CUDA:BOOL' build/CMakeCache.txt
若你重新下载的 Demo/Worker 实际寻找 llama-server,应先核实它对应的源码提交及编译目标;只有 llama-server 真实存在于该版本 CMake 目标中,才执行:
# 仅在当前版本 Worker 确实要求、且该目标存在时执行
cmake --build build --target llama-server -j 4
检查 Worker 期望的执行程序(新版本可能在独立后端文件里):
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo  # 需已下载 Demo,见下一节

grep -R -nE 'llama-omni-server|llama-server' \
  --include='*.py' --exclude-dir='.venv' . | head -40
如果 CMake 目标和 Worker 期待的二进制/接口不一致,应使用互相配套的源码提交,而不是创建一个仅名称相同的错误软链接。
CMake 显示 GGML_CUDA:BOOL=ON 只代表 GPU 后端已编译启用,仍要在真实语音推理时用 nvidia-smi 检查利用率。

8. uv 部署 MiniCPM-o-Demo
8.1 获取 Comni 分支
cd ~/env/minicpm-o-4.5

git -c http.version=HTTP/1.1 clone \
  --depth 1 --single-branch --branch Comni \
  https://github.com/OpenBMB/MiniCPM-o-Demo.git
如果遇到同样的 GitHub TLS EOF,可以照第 6 节使用浅克隆重试或下载 Comni 分支源码归档:
https://github.com/OpenBMB/MiniCPM-o-Demo/archive/refs/heads/Comni.tar.gz
8.2 避开官方安装脚本重复创建环境:使用 uv
官方 start_all.sh 固定调用 MiniCPM-o-Demo/.venv/base/bin/python,因此在相同路径创建 uv 环境:
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo
uv venv .venv/base --python 3.11
安装 Demo 依赖。对应 Comni 分支的官方安装脚本安装了 torch==2.8.0、torchaudio==2.8.0 和 requirements.txt;采用 uv 时延续同一依赖集合:
uv pip install --python .venv/base/bin/python \
  'torch==2.8.0' 'torchaudio==2.8.0'

uv pip install --python .venv/base/bin/python -r requirements.txt

uv pip install --python .venv/base/bin/python \
  soundfile pillow requests
说明:C++ 模型主推理不是由 PyTorch 执行;不过为了与这一版官方 Python Demo 兼容,仍按原安装脚本安装所需包。这会增加磁盘占用。安装顺序应以你实际使用的 Comni 分支 install.sh、requirements.txt 为准,不要将 main 分支的教程与 Comni 混用。

简单验证:
.venv/base/bin/python - <<'PY'
import fastapi, uvicorn, httpx, numpy, torch
print('基本 Python 依赖可导入;torch:', torch.__version__)
PY
重要:这里无需再次执行 bash install.sh,以免重复创建虚拟环境、覆盖当前已工作的包组合。
8.3 可选的移动版前端
桌面网页 /、/audio_duplex 等路径通常不要求额外构建移动 React 前端。若希望启用 /mobile/,按实际仓库要求安装 Node 20.19+ 或 Bun 再构建:
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo/frontend/mobile
# 已经具备兼容的 Bun 环境才执行:
bun install
bun run --bun build:static
若没有 Bun,请依据 frontend/mobile/README.md 使用对应的 npm 构建命令;不要把移动前端构建作为普通音频 WebUI 的强制先决条件。
9. 配置 RTX 3060 与稳定播放参数
9.1 基于官方模板创建配置
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo
cp -n config.example.json config.json
cp config.json "config.json.backup.$(date +%Y%m%d-%H%M%S)"
9.2 自动写入本次推荐配置
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo

.venv/base/bin/python - <<'PY'
from pathlib import Path
import json

here = Path.cwd()
root = here.parent
p = here / 'config.json'
cfg = json.loads(p.read_text(encoding='utf-8'))

cfg['backend'] = 'cpp'
cfg.setdefault('cpp_backend', {}).update({
    'llamacpp_root': str(root / 'llama.cpp-omni'),
    'model_dir': str(root / 'models' / 'MiniCPM-o-4_5-gguf'),
    'llm_model': 'MiniCPM-o-4_5-Q4_K_M.gguf',
    'cpp_server_port': 19080,
    'ctx_size': 4096,
    'n_gpu_layers': 99,
})
cfg.setdefault('audio', {}).update({
    'ref_audio_path': 'assets/ref_audio/ref_minicpm_signature.wav',
    'playback_delay_ms': 800,
})
cfg.setdefault('service', {}).update({
    'gateway_port': 8040,
    'worker_base_port': 22440,
    'num_workers': 1,
    'request_timeout': 300.0,
    'compile': False,
})
cfg.setdefault('duplex', {}).setdefault('pause_timeout', 60.0)

p.write_text(json.dumps(cfg, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
print('已写入:', p)
print('C++:', cfg['cpp_backend'])
print('音频:', cfg['audio'])
PY
为什么这么设:
- Q4_K_M:与 12 GB 显存配置匹配;相比直接加载完整 BF16 更现实。
- num_workers = 1:单 GPU 不要启动多个独立模型 Worker。
- ctx_size = 4096:作为当前推荐起点;若有 CUDA OOM,先降到 2048。注意:增大 ctx 并不保证长期对话不会在接近 2000 token 时发生内部滑动窗口修剪。
- playback_delay_ms = 800:这是此次真实测试消除音频断续的关键,不要再默认退回 200。
- Stop on KV pruning 不是上面 JSON 中已确认的服务端配置键;应在 /audio_duplex 页面取消勾选(见第 11 节)。不要盲目往 JSON 添加该字段并假定它生效。
首次启动之前可检查配置:
.venv/base/bin/python - <<'PY'
import json
c=json.load(open('config.json', encoding='utf-8'))
print('backend:',c.get('backend'))
print('ctx_size:',c['cpp_backend']['ctx_size'])
print('playback_delay_ms:',c['audio']['playback_delay_ms'])
print('llamacpp_root:',c['cpp_backend']['llamacpp_root'])
print('model_dir:',c['cpp_backend']['model_dir'])
PY
9.3 HTTPS 证书与麦克风说明
浏览器麦克风应使用 HTTPS 或 localhost 安全上下文。官方启动脚本使用 HTTPS;不要为了绕过证书问题加 --http 并希望远程浏览器麦克风仍可正常调用。
先检查证书文件是否存在;若已经有证书,保留原文件,不要每次启动重建:
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo
mkdir -p certs
if [ ! -s certs/cert.pem ] || [ ! -s certs/key.pem ]; then
  openssl req -x509 -newkey rsa:2048 -nodes -days 365 \
    -keyout certs/key.pem -out certs/cert.pem \
    -subj '/CN=localhost'
  chmod 600 certs/key.pem
fi
这是本地测试用的自签名证书,浏览器第一次打开页面可能提示不受信任;请仅在自己的可信设备上确认例外。使用公网域名应配置受信任的 HTTPS 证书和访问控制,不能直接裸露管理与推理接口。
10. 启动、访问与健康检查
10.1 启动
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo
CUDA_VISIBLE_DEVICES=0 bash start_all.sh
实际成功日志:
[Worker 0] Ready ✓ (port 22440)
[Gateway] Ready ✓
Service is running!
Chat Demo: https://localhost:8040
特别提醒:start_all.sh 会通过 nohup 把 Gateway 与 Worker 放入后台,打印完成信息后脚本本身自动结束完全正常。不要因此误以为模型关闭、也不要连续重复启动一堆服务。
10.2 两层健康检查
# Gateway 健康检查
curl -ksS https://localhost:8040/health

# Worker 和模型状态
curl -sS http://localhost:22440/health | python3 -m json.tool
本次真实返回:
{
  "status": "healthy",
  "worker_status": "idle",
  "gpu_id": 0,
  "model_loaded": true,
  "current_session_id": null,
  "total_requests": 0,
  "avg_inference_time_ms": 0.0,
  "kv_cache_length": 21
}
- Gateway healthy:网页/网关服务正常,不等于模型一定完成加载。
- Worker model_loaded: true:模型已经加载就绪。
- worker_status: idle:当前正在待命,不是错误。
- total_requests: 0、avg_inference_time_ms: 0.0:还没有统计到推理请求,不能据此判断推理慢或快。
10.3 浏览器访问
在 Ubuntu 本机:
https://localhost:8040/
https://localhost:8040/half_duplex
https://localhost:8040/audio_duplex
https://localhost:8040/admin
https://localhost:8040/docs
只有同一台主机才能把 localhost 指向 Ubuntu 服务。如果从 Mac 访问 Ubuntu,推荐 SSH 隧道:
# 在 Mac 终端运行;修改为 Ubuntu 真实局域网 IP
ssh -N -L 8040:127.0.0.1:8040 frank@<Ubuntu-IP>
然后在 Mac 浏览器打开 https://localhost:8040。此方式避免直接公开 Worker/C++ 后端端口。-N 表示只转发端口,不进入远程 Shell。
11. 语音测试与长会话设置
11.1 推荐测试顺序
1. 打开 /half_duplex:说一句中文,检查是否能回答中文语音。
2. 打开 /audio_duplex:测试连续输入、流式输出。
3. 用同一句话比较不同 Delay,观察卡顿与首段播放延迟。
4. 在网页的 Session 设置里确认:Delay = 800 ms。
5. 取消 Stop on KV pruning(或类似 Stop on sliding window),然后重新开始会话,测试聊超过几轮的稳定性。
建议测试语句:
“你好,请用中文介绍你自己。然后讲一个大约三十秒的短故事。”

11.2 为什么 800ms 有效
过去发生的卡顿,符合 音频播放缓冲欠载:浏览器播放完已生成的片段时,后一片段还未到达。
Delay 意义
200 ms 原始值;本次环境中出现语音断续
800 ms 本次实际测试语音流畅;推荐保存为默认值
1200–2000 ms 网络或 GPU 抖动更大时的备选;代价是首段声音等待更久


如果日后再次断续,可查看页面的 Infer、Ahead、Gap 次数、PDelay 等指标:Ahead 长期逼近 0 且 Gap 不断增加,通常表明浏览器等待新语音片段。也要结合 GPU 利用率区分生成速度不够与纯粹播放缓冲过小。
11.3 为什么聊 148 秒左右会自动停止
这次出现的原始日志:
✂ KV cache pruned (sliding window): 2,039 → 2,003.
⚠ Stop-on-sliding-window enabled. Auto-stopping.
Recording: 148.0s stereo WAV (9250 KB)
解释:
1. 连续对话累积上下文,KV Cache 达到约 2039。
2. C++ 引擎进行 sliding window 修剪,旧缓存部分丢失。
3. 网页启用了“缓存修剪时自动结束”选项,所以会话被主动停止,不是崩溃,也不是录音达到 148 秒固定时间上限。
推荐处理:网页中关闭 Stop on KV pruning,保留 800ms Delay。如果显存足够,可 ctx_size=4096;但即使设置 4096,内部策略也可能在更小的 KV 长度触发滑动窗口。
代价:关闭自动停止只能避免因这一开关而主动结束;不代表 KV 不再被修剪,也不保证长时间对话永不失忆、永不出错。修剪后模型可能遗忘前文。长期稳定服务应进一步考虑周期性重建会话和摘要续聊逻辑。
12. 日常启动、停止与重新启动
12.1 以后每天只需启动这一条
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo
CUDA_VISIBLE_DEVICES=0 bash start_all.sh
不需要每次重新下载模型、重新创建 uv 环境或重新编译 CUDA。
12.2 启动前先检查是否已经在后台运行
curl -ks --max-time 3 https://localhost:8040/health || true
curl -s --max-time 3 http://localhost:22440/health || true
ss -lntp | grep -E ':8040|:22440|:19080' || true
如果 Gateway 与 Worker 仍处于 healthy,通常不需要重复启动。
12.3 正常停止(只针对本项目保存的 PID)
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo

for file in tmp/gateway.pid tmp/worker_*.pid; do
  [ -f "$file" ] || continue
  pid=$(cat "$file")
  [ -n "$pid" ] || continue
  # 防止 PID 已复用:只结束仍属于本项目 Gateway / Worker 的进程
  cmd=$(ps -p "$pid" -o args= 2>/dev/null || true)
  case "$cmd" in
    *gateway.py*|*worker.py*) kill "$pid" 2>/dev/null || true ;;
    *) echo "跳过 PID $pid(不属于当前 Gateway/Worker):$cmd" ;;
  esac
done
之后检查:
ss -lntp | grep -E ':8040|:22440|:19080' || true
ps -ef | grep -E '[l]lama-omni-server|[g]ateway.py|[w]orker.py'
如果 C++ 子进程因异常仍存活,先确认 ps -ef 中属于本项目的命令行与 PID,再对该 PID 单独 kill。不要在多项目共存的机器上随意执行无范围限制的 pkill -f。
12.4 修改 config.json 后
通常需要停止后再启动才能使 Worker 模型参数(例如 ctx_size)生效。对于网页 Session 开关,还要在浏览器重新开启一次会话,以确保设置应用到新会话。
13. 实际遇到过的问题与解决方法
序号 现象 根因/判断 实际解决或规避
1 GnuTLS recv error (-9)、curl 56、EOF、invalid index-pack GitHub Git 数据传输时 TLS 连接断开 --depth 1 --single-branch + HTTP/1.1;不行就 tar.gz 归档
2 CMake Could NOT find CURL 系统缺少 CURL 头文件和开发库 提前安装 libcurl4-openssl-dev;非必需时才考虑 LLAMA_CURL=OFF
3 llama-server / llama-omni-server 名称不同 分支、文档与 CMake 目标演进不同 检查源码真实目标和 Worker 启动程序,不要简单重命名
4 CUDA_VISIBLE_DEVICES=0 bash start_all.sh 打印成功后退出终端 脚本把服务放入 nohup 后台运行 正常行为;用 Gateway、Worker /health 验证
5 网页可打开但尚未验证模型 Gateway 健康不等于推理模型已加载 检查 Worker /health 的 model_loaded 和实际音频问答
6 AI 生成的中文回答断断续续 播放缓冲欠载(本次实测与此相符) 将 Delay 从 200 改为 800 ms,问题消失
7 聊几轮后自动退出 KV Cache sliding window 修剪;Stop on KV pruning 开启 网页关闭该开关;适度增大 ctx,并接受滑窗丢失旧记忆的代价
8 远程浏览器麦克风不能用 非安全上下文、证书、权限 HTTPS;本机 localhost 或 SSH 隧道;授权麦克风
9 CUDA OOM 显存不足、上下文过大、其它程序占 GPU Q4_K_M、单 Worker、关闭其它 GPU 程序、必要时 ctx_size=2048
10 WebUI 没声音 模型音频组件不全、TTS 错误、网页播放限制 检查 audio/tts/token2wav 文件、Worker 日志与浏览器 HTTPS
11 model_loaded: false / Worker 长时间 loading 模型路径错、文件缺失、C++ 服务未加载 查 tmp/worker_0.log、模型目录、GPU 显存与二进制
12 重新启动端口被占用 原后台 Worker/Gateway 未退出 先 /health,再用 PID 精准停止,避免重复启动


13.1 诊断命令合集
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo

# 服务状态
curl -ksS https://localhost:8040/health
curl -sS http://localhost:22440/health | python3 -m json.tool

# GPU 与显存
nvidia-smi
watch -n 1 nvidia-smi

# 端口 / 进程
ss -lntp | grep -E ':8040|:22440|:19080'
ps -ef | grep -E '[g]ateway.py|[w]orker.py|[l]lama-omni-server'

# 日志
tail -n 100 tmp/worker_0.log
tail -n 100 tmp/gateway.log
# 一边语音测试一边看:
tail -f tmp/worker_0.log
浏览器出现错误时,先保留 Worker 和 Gateway 日志,不要反复重装模型,绝大多数运行期问题无需重新下载 GB 级权重。
14. 性能监测与进一步优化
14.1 持续采集 GPU 指标
nvidia-smi \
  --query-gpu=timestamp,name,utilization.gpu,memory.used,memory.total,temperature.gpu,power.draw \
  --format=csv -l 1
建议分别测试:
- 半双工中文短句(基线正确性);
- 全双工中文长句(音频连续性);
- 5–10 分钟以上会话(滑动窗口与稳定性);
- 不同 Delay(800/1200 ms)下的首段延迟和 Gap 次数。
记录网页的 Infer、Ahead、Gap 次数与 TTFS,可以定位实时性能的主要瓶颈。如果 800 ms 播放流畅,建议维持该参数,不必为了形式上的低延迟而退回 200 ms。
14.2 ctx_size 的选择
设置 优点 缺点
2048 节约显存 更容易接近缓存限制;曾出现 2039 → 2003 修剪
4096 更合理的起点 比 2048 占更多 KV Cache 显存
8192 更大的上下文预算 12GB 显存下可能压力过大,且不保证滑窗策略变更


重点:ctx_size 不是“连续可聊天多少分钟”的直接换算,也不能关闭内部滑窗。真正的长期对话方案应在前端/Worker 做状态重建、摘要与续聊,不应只追求一个很大的上下文值。
14.3 不建议随意尝试的改法
- 不要把语言模型量化版本和音频组件混成不同模型发布版本。
- 不要直接修改 TTS 输出 WAV 的采样率以图“加速”,除非确认整个音频链都支持。
- 不要对未知 config.json 字段强行设置为 true/false 并假定有效。
- 不要把 4090 官方延迟基准当成 RTX 3060 的实测。
- 不要因脚本返回 Shell 就重复启动多个后台进程。
15. 备份、升级与安全建议
15.1 备份成功的配置与源码版本
cd ~/env/minicpm-o-4.5
cp MiniCPM-o-Demo/config.json \
  "MiniCPM-o-Demo/config.json.working.$(date +%Y%m%d)"

for d in llama.cpp-omni MiniCPM-o-Demo; do
  if [ -d "$d/.git" ]; then
    echo "===== $d ====="
    git -C "$d" branch --show-current
    git -C "$d" rev-parse HEAD
  fi
done
建议把实际显示的 commit hash 记录到此 README。已成功运行的版本可以长期冻结,不需要追求每天更新。若用 tar.gz 获得源码,则记录下载时间和对应仓库提交(若可获取)。
15.2 升级前的原则
1. 停服务并备份 config.json、必要的本地改动。
2. 单独升级 C++ 引擎或 Demo 时,先核对接口和可执行文件名称兼容性。
3. 模型仓库继续使用匹配的音频、TTS、Token2Wav 权重。
4. 升级成功后,重新验证 800 ms Delay 与 Stop on KV pruning 开关是否保留。
5. 升级失败时回退到之前记录的 commit 与工作配置。
15.3 网络与隐私
- 默认只通过 Ubuntu 本机 https://localhost:8040 或 SSH 隧道访问。
- /admin 和 /docs 不应直接暴露公网;公网使用需要鉴权、HTTPS 与防护。
- 对语音录音和临时 WAV 文件按需要清理与保护隐私。
- curl -k 只建议用于你自己知道是本地自签名证书的健康检查,不能当成通用互联网 TLS 校验策略。
16. 参考资料
- ModelScope 模型页面:https://modelscope.cn/models/OpenBMB/MiniCPM-o-4_5-gguf
- 官方 C++ 推理项目与显存/文件清单:https://github.com/OpenBMB/llama.cpp-omni
- 本次 C++ 分支:https://github.com/tc-mb/llama.cpp-omni/tree/feat/web-demo
- 本次 WebUI Demo 分支:https://github.com/OpenBMB/MiniCPM-o-Demo/tree/Comni
- Demo 中文说明:https://github.com/OpenBMB/MiniCPM-o-Demo/blob/Comni/README_zh.md
- Demo 配置模板:https://github.com/OpenBMB/MiniCPM-o-Demo/blob/Comni/config.example.json
- ModelScope 下载客户端:https://github.com/modelscope/modelscope_hub
- uv 文档:https://docs.astral.sh/uv/
- NVIDIA CUDA Linux 安装文档:https://docs.nvidia.com/cuda/cuda-installation-guide-linux/
附录 A:只想每天启动?最短操作卡
# 启动
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo
CUDA_VISIBLE_DEVICES=0 bash start_all.sh

# 验证(启动脚本返回 Shell 是正常的)
curl -ksS https://localhost:8040/health
curl -sS http://localhost:22440/health | python3 -m json.tool
浏览器打开 https://localhost:8040/audio_duplex,Delay 设为 800 ms,关闭 Stop on KV pruning(重新开始会话后测试)。
附录 B:故障发生后优先提供的排障信息
# 1. 版本与 GPU
nvidia-smi
nvcc --version

# 2. 当前配置的关键值(避免贴出不必要的隐私数据)
cd ~/env/minicpm-o-4.5/MiniCPM-o-Demo
.venv/base/bin/python - <<'PY'
import json
c=json.load(open('config.json'))
print('backend:', c.get('backend'))
for k in ('llamacpp_root', 'model_dir', 'llm_model', 'ctx_size', 'n_gpu_layers'):
    print(k, c.get('cpp_backend', {}).get(k))
print('delay:', c.get('audio', {}).get('playback_delay_ms'))
PY

# 3. 服务状态与错误日志
curl -ksS https://localhost:8040/health
curl -sS http://localhost:22440/health
tail -n 80 tmp/worker_0.log
tail -n 80 tmp/gateway.log
说明:此手册基于实际已成功部署的会话与 2026-10-17 可查的项目文档编写。并未在当前执行环境中重新完整克隆、编译和运行你的 Ubuntu 机器;以后仓库分支更新时,仍应以当前检出文件与本机日志为准。

评论

此博客中的热门博文

通过命令行在Github上发布项目的新版本

利用GitHub免费的静态页面托管空间发布网页

本地部署OpenAvatarChat实时交互数字人系统