VRAM Switcher:在 DeepSeek Harness 上协调 12 GB 卡上的 LLM、IndexTTS 与 ComfyUI

前言

在 DeepSeek Harness(DSH)里接本地人设 LLM、IndexTTS 语音和 ComfyUI 自拍/改图时,常见瓶颈不是「能不能跑」,而是 12 GB 显存装不下三个常驻服务。Windows 上进程不会立刻退出,而是把显存换页到内存——链路仍通,但扩散步速、预填 token 速度会差几个数量级。通用 GPU 调度器往往通过改 base URL、加代理或轮询 nvidia-smi 来仲裁;本地 AI 陪伴更关心的是 语音合成何时真正结束、一批 ComfyUI 队列何时跑空,边界在宿主事件和 flag 协议上,而不是 HTTP 网关。

下面介绍社区插件 VRAM Switcher(仓库 xiaoxiao150/vram-switcher,维护者 xiaoxiao150)。它在 AstrBot / DSH 宿主边界上,按 profile 对你列出的进程做停/起顺序,让三类 workload 在同一张卡上轮流独占,且 不换客户端、不加代理、不读 nvidia-smi。

这是什么

VRAM Switcher 是面向 本地 AI 情感陪伴 的 GPU 协调器:人设对话(本地 LLM)、IndexTTS 语音、ComfyUI 图像在同一张约 12 GB 的卡上轮流用卡。分类上属于 模型推理 相关插件;GitHub 约 28 stars,当前 npm/插件包版本 2.0.4,许可证 MIT。

同一套 Python 核心 vram_switcher 同时服务 AstrBot(Python 插件)、DSH(原生 Cordis 插件 dsh-vram-switcher + 长驻 daemon.py)以及可选 MCP stdio。DSH 侧通过 Cordis 注册工具,由 Python daemon 复用与 AstrBot 相同的 Orchestrator、profile 解析与 coordinator.lock 跨进程锁。

核心功能

显存争用与状态机

在 README 给出的典型 12 GB 占用估算中:llama-server(示例为 Qwen3.6-35B-A3B MoE)约 4.9 GB,IndexTTS webui 约 2.3–5.3 GB,ComfyUI 约 6–7 GB,再加桌面与宿主约 2 GB——任意两个图像/语音/LLM 服务与桌面叠加就容易触发换页。插件在任务前停掉不需要的服务、拉起需要的;结束后再恢复,例如:

LLM 常驻,显存 4.9 GB / 12 GB
        │
        ├── "/aimg 一只猫" ──► 停 LLM ──► 起 ComfyUI ──► 出图 ──► 等队列跑空
        │                              (腾出 ~6 GB)             停 ComfyUI
        │                                                        拉起 LLM
        └── 语音请求 ──────► 停 LLM ──► 确保 TTS 在线 ──► 合成 ──► 拉起 LLM

维护者在其机器上记录过换页前后的对比:s2mel 从约 0.12 s/步 恶化到 30 s/步,预填从约 1300 tok/s 掉到 0.2 tok/s;协调后的目标是回到「轮流独占」下的正常速度。

就绪与边界

  • ComfyUI:等待 8188 端口 listen,而不是进程刚启动;恢复 LLM 前轮询 /queue,等一批图跑空再停图像服务。
  • IndexTTS:无 unload API 时通过 进程级互斥;TTS 插件写 tts_busy.flag / 读 tts_ready.flag,调度器在真正停完 LLM 后再写 ready,避免 TTS 抢跑导致再次换页。
  • 进程范围:只动 profile 里配置的进程名、命令行过滤与可选端口白名单,没有「杀掉所有 python」类逻辑。

DSH 原生工具

dsh-plugin.json(manifest v0.15)声明的 in-process 工具命名空间前缀为 vram_:

工具 作用
vram_status 查看 LLM/TTS/image 状态、profile、租约与任务
vram_acquire 获取 GPU 租约;mode=image 或 mode=tts
vram_release 释放租约,停 disposable 服务并恢复 LLM

vram_acquire 可能停本地 LLM 并冷启动 ComfyUI/TTS,耗时可达数分钟;租约默认 900 秒,可通过 lease_seconds 延长,直到 vram_release 或超时。

加载架构简述:

DSH Cordis -> dsh-plugin/index.js -> ctx.tools.register(...)
                              └─ Python daemon.py -> vram_switcher.Orchestrator

package.json 要求 DSH >=0.2.0-rc.2 || >=0.2.1-rc.0,并通过 dsh.bundle.patch 注入 cordis.patch.yml。

与通用调度器的定位

若只需 llama.cpp / vLLM 换模型并让客户端改 base URL,更适合 llama-swap 等通用方案。VRAM Switcher 刻意不做 多卡仲裁、游戏/VM、nvidia-smi 轮询、provider 自动切换;它多做的是 AstrBot 事件钩子、DSH Cordis 工具、IndexTTS flag 协议,以及在陪伴回合内串行文字 → 语音 → 生图。

安装与启用

插件以 当前 DSH 进程权限 运行:manifest 声明子进程 spawn(按 profile 启动 TTS/ComfyUI 与 Python coordinator)与读用户选择的 profile/日志。安装前请阅读仓库源码与 MIT 许可证,确认 profile 中的路径与停启命令符合你的环境。

1、生成 profile(与宿主无关)

在已获取源码的目录中运行 configure.py,自动探测正在运行的 llama-server、TTS webui、ComfyUI,不会启动或停止任何进程:

python configure.py --root D:/AI        # 只预览加 --dry-run

会生成 profile.local.json,并打印 [detected] / [missing] / [port] 等信息。未探测到的服务可设为 enabled: false;也可从 profile.example.json 手工复制修改。路径支持 ${PLUGIN_DIR}、${DATA_DIR} 等变量。

2、安装 DSH 插件

官方 README「在市场里安装」一节给出的 DSH 源码/CLI 安装方式为:

# DSH(包名 dsh-vram-switcher)
dsh plugin --profile web add github:xiaoxiao150/vram-switcher

社区目录 SkillHub - vram-switcher 与 DSH 插件市场(收录流程见仓库 dsh/README.md)也可用于发现该包;SkillHub 说明安装由 DeepSeek Harness 读取后端安装计划后执行,与上述 GitHub 源一致。目录站为社区站点,与 DeepSeek / 幻方无官方从属关系。

3、指向同一 profile 与 dataDir

在 profile 的 cordis.patch.yml 覆盖中配置(示例见仓库 dsh/cordis.patch.example.yml):

  • profilePath:上一步生成的 profile.local.json 绝对路径
  • dataDir:与 AstrBot 共用时必须一致,否则 coordinator.lock 无法串行
  • pythonPath:Python 3.10+(需 psutil,或使用 DSH 自带 Python 并在 Windows 上走 tasklist/PowerShell 回退)
  • leaseSeconds:可选,默认 900

若 DSH 与 AstrBot 同时跑 GPU 任务,锁只是安全网,不能替代「同一时刻只让一个宿主切卡」的操作习惯。

注意:若当前 DSH 轮次正在用 profile 里 llm 指向的同一本地 LLM,不要调用 vram_acquire,否则会停掉正在生成回复的模型;协调轮次应使用远端 provider,或把 GPU 任务交给 AstrBot。

典型用法

Cordis 工具(智能体 / 工作流)

生图类工具可在调用 ComfyUI 前 vram_acquire(mode=image),出图并确认队列结束后 vram_release。TTS 侧仍建议配合 IndexTTS 插件的 busy/ready flag;仅 HTTP 边界无法替代「合成结束」语义。

嵌入自有服务(Python 核心)

不绑 AstrBot/DSH 时,可直接使用 VramService(README 示例):

from vram_switcher import load_config
from vram_switcher.service import VramService

cfg = load_config({"profile_path": "profile.local.json"}, plugin_dir=".", data_dir="./data")
service = VramService(cfg)
await service.start()
await service.acquire("image", reason="selfie")   # 停 LLM、起 ComfyUI
# ... 出图 ...
await service.release("selfie")                   # 停 ComfyUI、恢复 LLM

语音链路仍应实现 tts_busy.flag / tts_ready.flag 协议,细节见仓库 docs/indextts.md。

适用场景与注意

更适合:在 DSH(或 AstrBot)上跑本地 AI 陪伴,单卡约 12 GB,需要 IndexTTS + ComfyUI + 本地 LLM 在同一回合内切换,且不想改端口或加代理。

GPU 路径:调度器本身不依赖 CUDA/nvidia-smi;N 卡 Windows 为 README 中的生产验证路径。AMD / Linux 需按 docs/gpu-support.md 调整 ready.type、超时与进程匹配。

已知限制(仓库 README):Windows 优先;不显式读显存数值;TTS 需 busy/ready 协议;默认 ComfyUI 队列为 /queue;默认不做 provider 切换。可选 mcp_server.py 勿与原生 Cordis 插件同时加载,避免重复管理同一组服务。

夜间静默:profile 支持默认 23:00–07:00 不重新拉起本地 LLM(可在 profile 中调整)。

结尾

VRAM Switcher 把「12 GB 上 LLM、IndexTTS、ComfyUI 互抢显存导致换页变慢」收敛成 profile 驱动的停/起顺序 + 就绪/队列/flag 边界,并在 DSH 上以原生 Cordis 工具暴露租约。配置生成、IndexTTS 与 GPU 矩阵见 GitHub 文档。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜