- Home
- Plugins
- Models & Providers
- dsh-model-rotation
dsh-model-rotation
zhouxuan-yu/dsh-model-rotation
Model rotation for DeepSeek Harness: groups each provider's models by source, orders them by hand or by measured success rate and latency, stores model plus reasoning-effort presets, falls over to the next entry when a model hits its quota or is unavailable, resends the same step on the next model, and shows which model actually answered. Uses the models of whatever provider plugins are already installed (Antigravity accounts, Codex subscription, DeepSeek API keys); it does not provide model access itself.
Install
dsh plugin --profile web add github:zhouxuan-yu/dsh-model-rotationREADME
dsh-model-rotation
给 DeepSeek Harness 用的多来源模型轮询插件:把 Gemini / Claude / GPT / DeepSeek 排成一条链, 前一档额度用尽或报错就自动换下一档,并把这一步自动重发;还能随时看到「这次到底是哪个模型答的」。
TL;DR — 注册一个虚拟模型 rotation/auto。选中它,之后每次提问都按你排好的顺序挑模型:
失败自动降级、必要时整步重发,模型选择器 / 会话头 / 设置页三处都能看到实际用了谁。
| 模型选择器:置顶的「⚡ 自动轮询」 | 会话头:本次回答的模型 |
|---|---|
![]() | ![]() |

截图由插件真实组件离线渲染(数据为示例):composer 菜单 / 会话头徽章 / 设置页。
English (short)
dsh-model-rotation is a DeepSeek Harness plugin that turns
your LLM subscriptions into one ordered, self-healing model chain.
- One virtual model
rotation/auto— select it once and every turn uses your chain. - Grouped by source — agy account pool (Gemini / Claude / GPT-OSS), Codex subscription, DeepSeek API keys, built-in DeepSeek; filter models per group and pick one.
- Order it your way — manual order (
order/move/up/down) or automatic order by measured success rate & latency. - Quota-aware failover — hard failures (quota, auth, region
ELIGIBILITY) get a long cooldown; the next attempt simply uses the next model, and the whole step is re-sent automatically (autoResend). - Presets — bundle model + reasoning effort (e.g.
Gemini 3.8 high,Codex GPT-6.1-Sol high) and switch with one click. - See who answered — composer picker, session-header badge and the settings page all show the model that actually produced the reply.
Install (DSH desktop, local clone): node scripts/install.mjs → restart the app → Settings → 模型轮询.
给 DeepSeek Harness 用的有序多来源模型轮询 + 排序 + 预设插件。
- 一条可排序的链(默认就是「Gemini 3.8 high → Codex GPT-6.1 Sol high → xiao-DeepSeek Flash → 内置 DeepSeek Flash」), 前一档额度用尽 / 鉴权失败 / 报错时自动切下一档;
- 按来源分组:agy 账号池 / Codex 订阅 / 两家 DeepSeek API / 内置 DeepSeek 各自成组,
组内模型可筛选后再加进链(同名模型也不会混,比如 Codex 的
gpt-6.1-sol与 apixiao 的gpt-6.1-sol); - 手动排序:严格按你排的顺序走;
- 自动排序:按实测成功率 / 延迟动态调整尝试顺序;
- 预设:把「用哪些模型 + 各自思考强度」存成一组(
example/fast/coding/quality内置,也可自存), 一句话切换,适合按任务类型换档。
界面导览(设置 → 模型轮询)
打开 DSH 设置,左侧最下面一项就是 「模型轮询」。整页从上到下是:
| 区域 | 内容 |
|---|---|
| 三步上手 | 首次使用的引导卡:一句说明 + 四个一键按钮(推荐链 / 自动排序 / 探测全部 / 命令速查) |
| 顶部状态条 | 排序模式、预设、冷却中 N 档、上次回答:哪个模型(悬停看耗时与切换) |
| ① 排序方式 | 手动 / 自动;自动再选偏好(均衡 / 更快 / 更稳) |
| ② 轮询链 | 每一档的序号、↑↓、勾选启用、模型、思考强度、成功率与延迟、探测 / 删除 |
| ③ 添加候选 | 先选分组,再在组内按关键字筛选模型,选强度后加入链尾 |
| ④ 预设 | 下拉应用内置/自存预设;输入名字把当前链存成预设;删除自定义预设 |
| ⑤ 状态与维护 | 刷新、重置冷却与统计、恢复默认(两次确认)、尝试顺序说明、命令输出 |
页面每 5 秒自动刷新状态;所有按钮都等价于一条 /rotation 命令,所以命令和界面可以混用。
不确定从哪开始,就点引导卡里的 「一键:推荐链」——它会套用内置的 example 预设
(Gemini 3.8 Flash[high] → Codex GPT-6.1 Sol[high] → xiao-DeepSeek Flash → 内置 DeepSeek Flash)。
模型选择器:置顶的「⚡ 自动轮询」
composer 右下角的模型选择器(conversation.input.model 槽位)被本插件接管,菜单第一行固定是
「⚡ 自动轮询(Auto)」,点它就把当前会话切到 rotation/auto,也就是进入本插件的轮询模式 ——
之后每次调用都按设置里的链逐档尝试,前一档失败自动换下一档。
菜单里其余入口保持原样:
- 模型 › —— 按来源分组列出所有模型(
agy 账号池/Codex 订阅/DeepSeek API/GPT API/DeepSeek 内置/DeepSeek 账号池),模型数 > 4 时带搜索框; - 思考强度 › —— 当前模型支持的强度(各来源不一样:Gemini
low/medium/high、 Codexlow/medium/high/xhigh/max、内置 DeepSeekoff/low/high/max)。
当前是轮询模式时,选择器会显示品牌色的 ⚡ 自动轮询;选中普通模型则自动退出轮询模式(回到该模型直连)。
所有选择都走官方同一个 per-session ModelDirectory(directory.select),所以和官方选择器、
/model 命令的行为完全一致。
说明:官方槽位是 single 槽,插件用更低的 slot priority 遮蔽官方那一份来做整体替换 (single 槽的同 priority 注册会直接抛错)。若哪天官方改了这块结构导致接管失败, 插件只在控制台 warn,不影响
/rotation命令与设置页。
对话头上:本次回答到底用了哪个模型
轮询模式下「这次是谁答的」不再靠猜。会话头(标题右侧的 actions 区,conversation.session.header.actions 槽位)
会显示一个胶囊徽章,例如:
⚡ Codex GPT-6.1 Sol · high · 7.6s · ↻1
- 模型名:实际成功回答的那一档(不是链的第一档);
- 强度:本次实际生效的思考强度;
- 耗时:该档自身的延迟;
- ↻N:本次回答前有 N 档失败被切换掉了(没有切换则不显示);
- 悬停:完整说明,含分组、总耗时、前面每档失败的原因码,以及整段「尝试轨迹」
(
✅/❌ CODE [分组] provider/model 秒数)。
徽章显示「本会话最近一次轮询回答」,每 4 秒刷新一次;按会话分别保存(最多 100 个), 不会被另一会话、标题生成或上下文压缩覆盖。强度取真实委托参数,而不是仅取预设值。
直连的模型也认。 插件同时监听每一次模型调用(llm/stream),所以就算你在选择器里直接选了
Codex / GPT-6.1 Sol(没走轮询),徽章也会显示 ◆ deepseek-flash · low · 0.9s · 直连,
标题是「本会话最近一次回答(直连):provider/model」。标题生成、上下文压缩这类后台调用不参与,
不会把你的徽章改掉。
额度用尽 → 自动「再发一次」
适配器里的切换只对「还没吐出任何内容」的失败安全(已经输出一半再换模型会拼出两截答案)。
所以插件还接管了 agent 循环的失败回调(agent/request-error):
- 轮询模式下的某一步请求失败(额度用尽 / 鉴权失效 / 限流 / 5xx …,中断不算);
- 失败的那一档已经在适配器里进了冷却,于是直接让 agent 循环重跑这一步, 下一次自然落到链里的下一档模型 —— 效果等同于「自动再发一次你的消息,换成下一个模型回答」;
- 最多重发
maxAutoResends次(默认 2),用完就把错误交还给正常流程; - 链里所有档都在冷却时不做重发(避免无意义的空转)。
这一层不依赖模型选择器,rotation/auto 或 Model Rotation / Auto 都一样生效。
v0.6.1 真机修复
另一个插件的模型选择器 installDirectorySlots 使用 priority -10,遮住了先前 -1 的 Auto 选择器。
本版改为 -20,回归测试包含与 -10 的竞争检查。会话头仍用独立 list 槽追加,不遮挡其它功能。
诊断:接管失败时不再静默
浏览器 console 的错误进不了 host 日志,所以插件自带一条极小的诊断通道:
- client 端在关键节点上报(
apply/ 座位注册成功或失败 / 座位渲染崩溃 / 兜底按钮点击), 写入POST /plugins/model-rotation/client-report; - host 端把它写进
<状态目录>/client-report.jsonl(保留最近 40 条), 同时并入GET /plugins/model-rotation/state的clientReports; - 座位渲染一旦崩溃,
SeatBoundary会兜底成一个「⚡ 自动轮询」按钮(点击仍能切到轮询模式), 并把错误栈上报 —— 这样即使官方改结构导致接管失败,也不会把你的模型选择器弄没。
排查时:_probe_rotation_live.mjs 直接打印运行中的 state / clientReports,或看
%APPDATA%\dsh-desktop\harness\state\dsh-model-rotation\client-report.jsonl。
图形界面:在设置里配置(推荐)
插件带了 client 上半,会在 设置 → 模型轮询 里加一整页可视化面板(settings.section 槽位,排在「插件」后面):
- 排序方式:手动 / 自动一键切,自动模式还能选偏好(均衡 / 速度优先 / 稳定优先);
- 轮询链:每档一行 —— 分组徽章、↑/↓ 上下移、启用勾选、直接下拉换模型、下拉改思考强度、
删除、单档探测;行内实时显示
成功 87% · 1200ms或冷却 12m(QUOTA); - 添加候选:先选分组(agy / Codex / 两家 DeepSeek API / 内置 DeepSeek), 再用关键字筛选组内模型,选模型 → 选思考强度 → 添加;
- 预设:下拉应用内置/自定义预设,输入 id 把当前链存成新预设,一键删除;
- 状态与维护:调用/切换次数、当前尝试顺序、探测全部、端到端测试、重置冷却、恢复默认。
面板 5 秒轮询一次 GET /plugins/model-rotation/state,所有改动走
POST /plugins/model-rotation/command(内部就是 /rotation 的子命令),所以 GUI 和命令行为完全一致。
改完立刻落盘,不用重启。
它是怎么工作的
插件注册一个虚拟 provider(默认 id rotation),下面只有一个模型 auto。
它不接任何 API,只是分发器:
- 会话里选中
rotation/auto后,每次模型调用都进本插件的stream(); stream()按当前顺序把请求原样委托给真实 provider(ctx.llm.stream);- 还没向会话吐出内容之前失败 → 换下一档;已经输出过内容再失败只能报错(否则会话消息错乱);
- 用户主动中止(abort)不算失败,不切换、不冷却;
- 所有候选都在冷却时 fail-open:仍按顺序试一遍,不会把请求直接打死。
被跳过的候选进冷却表:额度 / 鉴权 / 地区资格(ELIGIBILITY) 类 15 分钟,其它 30 秒。
冷却会跟状态一起落盘,DSH 重启后仍然跳过——不会每次重启都先去白等一次 Gemini 的
「账号/地区不适用」(实测那一档要 10~30 秒才失败)。
排序方式、当前链、自定义预设、仍然有效的冷却都会落盘(默认 <DSH_HOME>/state/dsh-model-rotation/state.json)。
失败的处理建议会一起显示:/rotation status 里冷却行带失败码,/rotation probe 失败行
下面多一行 ↳ 说明(例如「该账号/地区不适用,可换 agy 账号或代理,或把这一档停用」)。
排序
手动排序(默认)
sortMode: manual:严格按链顺序尝试,第 1 档不行才用第 2 档。
/rotation order 2,1,3 # 按序号重排(只写要前置的几档也行)
/rotation move 3 1 # 把 #3 移到 #1
/rotation up 2 # 上移一档
/rotation down 2 # 下移一档
自动排序
sortMode: auto:给每档记健康度(成功率 EWMA、首字延迟 EWMA、连续失败数),每次调用按偏好重排:
autoPrefer | 打分 | 适合 |
|---|---|---|
speed | 0.2×成功率 + 0.8×速度 | 聊天、轻任务 |
balanced(默认) | 0.5×成功率 + 0.5×速度 | 日常 |
reliability | 0.85×成功率 + 0.15×速度 | 长任务、工具调用 |
/rotation sort auto # 用当前 autoPrefer
/rotation sort auto speed # 切自动 + 速度优先
/rotation sort manual # 切回手动
自动排序只调「尝试顺序」,不删档;冷却中的档永远排到最后。
手动改链
/rotation groups # 按来源列分组:每组有多少模型、哪些已在链里
/rotation models # 同上,外加每个模型支持的思考强度
/rotation set 3 apixiao/gpt-6-sol high # 把 #3 换成这个模型,思考强度 high
/rotation effort 3 inherit # 强度沿用会话(inherit)/ none / low / medium / high / xhigh
/rotation add openai-codex/gpt-6-astra high # 在链尾追加一档(provider 就是分组)
/rotation remove 4 # 删掉 #4(至少保留一档)
/rotation disable 4 # 临时停用 #4
/rotation enable 4
同一个 provider 可以被多档引用;group 字段可覆盖显示分组(用于把多个同源 provider 合并成一组)。
预设(模型 + 思考强度打包)
内置四个预设:
| 预设 | 链 |
|---|---|
example | Gemini 3.8 Flash [high] → Codex GPT-6.1 Sol [high] → xiao-DeepSeek Flash → 内置 DeepSeek Flash(= 默认链) |
fast | Gemini 3.8 Flash [low] → GPT-OSS 120B → GPT-6 Luna → xiao-DeepSeek Flash → 内置 DeepSeek Flash |
coding | Claude Sonnet 4.6 → Codex GPT-6.1 Sol [high] → GPT-6 Sol → DeepSeek V4 Pro [high] → 内置 DeepSeek Flash |
quality | Claude Opus 4.6 Thinking → Codex GPT-6.1 Sol [high] → GPT-6.1 Sol(API) → DeepSeek V4 Pro [high] → 内置 DeepSeek Flash |
/rotation preset # 列出全部预设
/rotation preset use coding # 切到预设
/rotation preset use chain # 退出预设,回到手动链
/rotation preset save mine 我的链 # 把当前链(含强度)存成自定义预设
/rotation preset delete mine
状态与自查
/rotation # 链 / 排序模式 / 冷却 / 每档成功率与延迟
/rotation groups # 按来源列分组(每组模型数 + 链里引用了哪些)
/rotation probe # 逐个直连探测(✅/❌ + 失败码 + 耗时)
/rotation probe 2 # 只探 #2
/rotation probe group openai-codex # 只探某个分组
/rotation test # 端到端走一遍虚拟 provider,验证切换逻辑
/rotation reset # 清冷却 + 健康度统计
/rotation reset-all # 恢复配置默认(清掉命令改过的链 / 排序 / 自定义预设)
/rotation help
agent 侧另有工具 rotation_probe:mode = status | probe | test | models。
配置
改配置有三种入口(等价,改的是同一份运行时状态):
- 设置 → 模型轮询:可视化面板(排序、增删改、强度、预设、状态)。
- 命令:
/rotation下的sort/order/set/effort/preset等子命令。 - 设置 → 插件:
dsh-model-rotation的 schema 表单,改的是插件配置(Config,静态默认值),适合改quotaCooldownMs、contextWindow这类不常变的键;链与排序请优先用第 1、2 种(它们写状态文件,不会被 schema 默认值覆盖)。
schema 表单里的键:
| 键 | 默认值 | 说明 |
|---|---|---|
enabled | true | 总开关 |
virtualProviderId | rotation | 虚拟 provider id |
virtualModelId | auto | 虚拟模型 id |
displayName | Model Rotation | 选择器里显示的名字 |
sortMode | manual | manual / auto |
autoPrefer | balanced | 自动排序偏好:speed / balanced / reliability |
autoAssumeLatencyMs | 1500 | 还没测过延迟时的假设值 |
chain | 见下 | 有序链,{ provider, model, label?, enabled?, reasoningEffort? } |
presets | 内置 3 组 | 预设数组 { id, label, chain } |
activePreset | 空 | 启用哪个预设(留空=用 chain) |
quotaCooldownMs | 900000 | 额度 / 鉴权类失败冷却 |
errorCooldownMs | 30000 | 其它失败冷却 |
passReasoningEffort | true | 是否把会话强度透传给候选 |
contextWindow | 1048576 | 对外声明上下文 |
maxTokens | 0 | 对外声明最大输出(0=不声明) |
logSwitches | true | 切换 / 失败打日志 |
autoResend | true | 额度用尽等失败后自动用下一档重发这一步(等同「再发一次消息」) |
maxAutoResends | 2 | 同一步最多自动重发几次 |
stateFile | <DSH_HOME>/state/dsh-model-rotation/state.json | 排序/链/预设的持久化位置 |
reasoningEffort 语义:留空 = 沿用会话(inherit);none = 强制不带强度;其它值 = 覆盖为指定强度。
默认链(= 内置预设 example,与本机现有 provider 配置对齐):
antigravity/gemini-3.8-flash [high] agy 账号池:Gemini 3.8 Flash
openai-codex/gpt-6.1-sol [high] Codex 订阅:GPT-6.1 Sol
xiao-deepseek/deepseek-flash DeepSeek API:DeepSeek Flash
deepseek-official/deepseek-flash 内置 DeepSeek:DeepSeek Flash(兜底)
分组来自 provider id(也是「来源」的天然边界):
| 分组 | provider id | 说明 |
|---|---|---|
| agy 账号池 | antigravity | dsh-agy-link 插件,账号池内部自己再做轮换 |
| Codex 订阅 | openai-codex | dsh-codex-subscription 插件(ChatGPT 订阅) |
| DeepSeek API | xiao-deepseek | llm-pi-ai 里配的一家 DeepSeek 兼容 API |
| GPT API | apixiao | llm-pi-ai 里配的 GPT 兼容 API |
| DeepSeek 内置 | deepseek-official | DSH 自带的官方 DeepSeek 账号 |
| DeepSeek 账号池 | deepseek-account | llm-deepseek-account 插件的 API Key 账号池(没登录时模型列表为空) |
模型清单来自各 provider 的实时目录(
ctx.llm.listModels),思考强度来自resolveModelInfo, 不同来源支持的强度并不相同(例如内置 DeepSeek 是off/low/high/max,Codex 是low/medium/high/xhigh/max), 面板里的强度下拉会按真实支持项显示。
让它生效
三种方式,任选:
- 模型选择器第一行「⚡ 自动轮询(Auto)」(最快,只影响那个会话);
- 在模型选择器里选
Model Rotation / Auto(同上,分组里的官方名字); - 设为全局默认:把 profile 里
agent-default-model的 config 改成- id: agent-default-model name: "@deepseek-ai/dsh-agent-default-model" config: provider: rotation model: auto
安装
已发布到 npm:https://www.npmjs.com/package/dsh-model-rotation(npm i -g dsh-model-rotation 可取到包,但本机 DSH 仍需下面的 generation 通道才会真正加载)。
不能用 dsh plugin --profile web add <目录>:那条命令只是 pnpm 的薄包装,
不维护 dsh.profile.bundles,装进去不会被加载。用桌面端的「generation」安装通道(仓库自带脚本):
cd C:\Users\ZhouXuan\Documents\deepseek-harness\default-workspace\dsh-model-rotation
$env:ELECTRON_RUN_AS_NODE='1'
& "D:\DSH\DSH Desktop\DSH Desktop.exe" ".\scripts\install.mjs"
脚本做的事:从 app.asar 加载 dsh-desktop-market-installer,用
installGeneration({sourceDirectory}) 把本目录打成 profiles/.generations/live/<id>,
写进 .generations/desired.json,再由 publishInstalledGeneration 投影成
profiles/web/node_modules/dsh-model-rotation 链接 + dependencies + dsh.profile.bundles 条目。
装完必须重启 DSH 桌面端才会加载(Cordis 启动时挂插件,运行中不热加载)。
- 升级:改完代码重跑
scripts/install.mjs(装成新 generation 并切换链接),再重启。 - 卸载:
& "D:\DSH\DSH Desktop\DSH Desktop.exe" ".\scripts\uninstall.mjs",然后重启。 - 验收:重启后模型选择器第一行出现「⚡ 自动轮询(Auto)」、点它会话切到
rotation/auto;/rotation status;/rotation groups(应看到 4~6 个来源分组);/rotation probe(逐档实测,含 Codex 与内置 DeepSeek);/rotation test。
维护性:不写死容易变的地方
- 分组名不写死:
agy 账号池/Codex 订阅这类名字只是别名,运行时优先用 provider 自己上报的名字 (ctx.llm.listProviders()),取不到才退回别名、再退回 provider id。以后你换插件、加新的 API provider, 甚至插件改版把名字改了,分组都会自动跟着显示,不用改代码。 - 排序不写死:模型分组顺序、模型清单、思考强度集合全部来自目录(
listProviders/listModels/resolveModelInfo),没有内置任何厂家或型号表参与逻辑;fast/coding/quality预设只是模板, 随时可以preset save覆盖或reset-all丢掉。 - 界面不写死 DOM:模型选择器是「接官方数据、只替换入口组件」的方式实现的(拿到同一个 per-session
模型目录),官方改版时如果接不上会自动退回官方选择器,同时上报一条
client-report,不会白屏。
已知限制
- 冷却不区分「同一 provider 的不同账号」——账号级轮询由
dsh-agy-link自己做 (它内部有 account pool + sticky 指针),本插件负责「跨 provider 的降级链」。 - Gemini 在账号/地区不适用时会返回
ELIGIBILITY:本插件会把它按 15 分钟冷却处理, 但这一次请求仍要等它 10~30 秒失败后才切到下一档;要么换 agy 账号/代理,要么把这档停用。 - 已经开始输出内容后不能中途换模型,只能报错。
- 不会自动改写
agent-default-model,需要手动选或改配置。 - 自动排序的延迟只用首字时间(TTFT)衡量,不含长输出耗时。
Related plugins
dsh-our-free-model
ebony-vinyl/dsh-our-free-model
dsh-routing-suite
yjh051108/dsh-routing-suite
dsh-workbuddy-connect
corrinehu/dsh-workbuddy-connect
dsh-connect-workbuddy
dingminhua/dsh-connect-workbuddy

