现象
本机 RTX 5070 Ti Laptop(12227 MiB)。VoxCPM2 已加载时,通过 UI/接口切到 IndexTTS 2.5 或
2.0,直接 503 INSUFFICIENT_VRAM,且不会自动卸载旧引擎:
[IndexTTS2] VRAM 检查: 需要 9.00GB, 可用 5.53GB
[IndexTTS2] VRAM 检查: 需要 8.25GB, 可用 5.53GB
判别实验:不是硬件不够,是编排缺一步
同一台机器、同一批权重,每轮先显式 unload 再 load,6/6 全成功:
| 轮 |
引擎 |
卸载后可用 |
加载结果 |
耗时 |
加载后 nvidia-smi |
| R1 |
voxcpm2 |
9800 MiB |
2xx |
24s |
9090 MiB |
| R1 |
indextts2 |
9660 MiB |
2xx |
31s |
10098 MiB |
| R1 |
indextts20 |
9674 MiB |
2xx |
27s |
10448 MiB |
| R2 |
voxcpm2 |
9630 MiB |
2xx |
28s |
9062 MiB |
| R2 |
indextts2 |
9705 MiB |
2xx |
27s |
10058 MiB |
| R2 |
indextts20 |
9683 MiB |
2xx |
27s |
10357 MiB |
卸载前后回落:基线 2290 → 全部卸载后 2507 MiB(spread 217 MiB,无泄漏)。
所以 IndexTTS 2.5(需 9.00GB)装得下,前提是旧引擎先释放。
根因(三段证据)
- 日志里只有
[IndexTTS2] VRAM 检查(model_manager_core/load.py:538),没有
[引擎切换] VRAM 检查 那行 → 切换路径没走到。
model_manager_core/switch.py:189-198 是 M-R1 修复:预检把「卸载当前引擎可释放的显存」
计入可用量,注释明说否则「永远走不到『先卸载再加载』的路径」。但 routes/model.py
的 load 端点对 voxcpm2 / indextts2 / indextts20 各自直接调专用加载器,只有
generic 新式引擎才走 switch_engine → 三个真实引擎全部绕过该记账。
model_manager_core/load.py 内没有任何 unload_model 调用(grep 无匹配)→
专用加载器既不先卸载,预检又是「当前空闲 vs 需求」的裸比较。
历史上这里曾把两个引擎一起压进显存导致 OOM(load.py:543-546 注释记着
「实测 12.10GB 落在 11.94GB 卡上」),当时改成了硬失败 —— 补丁止住了 OOM,
但没补「切换先卸载」,于是症状从崩溃变成永远 503。
期望
12GB 级显卡上,从 UI 切换引擎应当可用(卸载旧引擎 → 等回收 → 预检带可回收记账 → 加载),
而不是要求用户重启服务。三条候选路径:
- A. 让
routes/model.py 的 load 端点在「已有其他引擎加载」时统一走 switch_engine
(最贴近 M-R1 原意,但要确认三个专用加载器的副作用);
- B. 在专用加载器进入预检前先
unload_model() + 等待释放(switch.py 已有
_wait_vram_freed,可复用);
- C. 至少把
load.py 的裸比较换成 switch.py 同款的带记账版本,并在报错里提示
「当前有 X 引擎驻留,卸载后可释放约 Y GB」。
环境
- 分支
main @ 6046bfa(v2.2.2 工作树),入口 start_portable.py
- 模型:
model/VoxCPM2 4.6GB、model/IndexTTS-2.5、model/IndexTTS-2.0
- 验收脚本报出的
persona_count=6,音色均在本地
发现于 2026-09-20 真推理验收(DOD 第 9 项显存回落实测)。
现象
本机 RTX 5070 Ti Laptop(12227 MiB)。VoxCPM2 已加载时,通过 UI/接口切到 IndexTTS 2.5 或
2.0,直接 503 INSUFFICIENT_VRAM,且不会自动卸载旧引擎:
判别实验:不是硬件不够,是编排缺一步
同一台机器、同一批权重,每轮先显式 unload 再 load,6/6 全成功:
卸载前后回落:基线 2290 → 全部卸载后 2507 MiB(spread 217 MiB,无泄漏)。
所以 IndexTTS 2.5(需 9.00GB)装得下,前提是旧引擎先释放。
根因(三段证据)
[IndexTTS2] VRAM 检查(model_manager_core/load.py:538),没有[引擎切换] VRAM 检查那行 → 切换路径没走到。model_manager_core/switch.py:189-198是 M-R1 修复:预检把「卸载当前引擎可释放的显存」计入可用量,注释明说否则「永远走不到『先卸载再加载』的路径」。但
routes/model.py的 load 端点对
voxcpm2/indextts2/indextts20各自直接调专用加载器,只有generic 新式引擎才走
switch_engine→ 三个真实引擎全部绕过该记账。model_manager_core/load.py内没有任何unload_model调用(grep 无匹配)→专用加载器既不先卸载,预检又是「当前空闲 vs 需求」的裸比较。
历史上这里曾把两个引擎一起压进显存导致 OOM(
load.py:543-546注释记着「实测 12.10GB 落在 11.94GB 卡上」),当时改成了硬失败 —— 补丁止住了 OOM,
但没补「切换先卸载」,于是症状从崩溃变成永远 503。
期望
12GB 级显卡上,从 UI 切换引擎应当可用(卸载旧引擎 → 等回收 → 预检带可回收记账 → 加载),
而不是要求用户重启服务。三条候选路径:
routes/model.py的 load 端点在「已有其他引擎加载」时统一走switch_engine(最贴近 M-R1 原意,但要确认三个专用加载器的副作用);
unload_model()+ 等待释放(switch.py已有_wait_vram_freed,可复用);load.py的裸比较换成 switch.py 同款的带记账版本,并在报错里提示「当前有 X 引擎驻留,卸载后可释放约 Y GB」。
环境
main@6046bfa(v2.2.2 工作树),入口start_portable.pymodel/VoxCPM24.6GB、model/IndexTTS-2.5、model/IndexTTS-2.0persona_count=6,音色均在本地发现于 2026-09-20 真推理验收(DOD 第 9 项显存回落实测)。