模型故障切换 guangxiangwu6-cmd/dsh-llm-failover
DeepSeek 客户端模型报错时自动切换健康模型,任务不中断
27.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/11/1 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/guangxiangwu6-cmd/dsh-llm-failover.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 7 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件
查看扫描证据(共 1 处,展示前 1 条)
- 读取本地文件lib/index.js:14
const manifest = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 模型报错自动切换
- 任务不中断
- 冷却自动恢复
DeepSeek Harness 模型自动故障转移插件:重试阈值 -> 标记不可用 -> 无缝切到下一个健康模型 -> 冷却自动恢复。18 个模型池,19/19 测试通过,启动安全。
README
由 DeepSeek 最新模型翻译生成dsh-llm-failover
模型挂了,任务照跑。
DeepSeek Harness 的社区模型自动故障切换插件。服务商出现 429 / 5xx / 超时 / 网络错误 / SSE 中断时,自动切到健康模型继续执行,不让整个任务失败。
⚠️ DeepSeek Harness 社区插件,与 DeepSeek 无隶属关系,也未获其背书。
是什么,为什么
你在用 DeepSeek Harness 跑任务,当前模型突然挂了——429 限流、5xx 服务端错误、超时、网络断连、SSE 流中断。没有 failover 插件,整个任务直接失败,你得手动重试。
本插件在服务商层面实现自动故障转移:
Provider A (DeepSeek V4)
│
展开完整文档(README 剩余 1 节)
dsh-llm-failover
模型挂了,任务照跑。
DeepSeek Harness 的社区模型自动故障切换插件。服务商出现 429 / 5xx / 超时 / 网络错误 / SSE 中断时,自动切到健康模型继续执行,不让整个任务失败。
⚠️ DeepSeek Harness 社区插件,与 DeepSeek 无隶属关系,也未获其背书。
是什么,为什么
你在用 DeepSeek Harness 跑任务,当前模型突然挂了——429 限流、5xx 服务端错误、超时、网络断连、SSE 流中断。没有 failover 插件,整个任务直接失败,你得手动重试。
本插件在服务商层面实现自动故障转移:
Provider A (DeepSeek V4)
│
├── 5xx / Timeout / Transport / 短促 429 ──► 阈值(默认 5 次,抖动交给 retry 层吸收) │ │ │ ▼ │ A 停车(60s 起,连续停车翻倍) │ └── 配额用尽 / 用量窗口 / 上游公布长时间重置 ──► 墙:第一次就切 │ ▼ A 停车到上游说的重置时间 │ ┌────────────────────────────────────────┘ ▼ Switch to Provider B (next healthy model in priority pool) — 半开的不抢健康 provider │ ▼ Task continues seamlessly — same session, same context │ ▼ Cooldown expires → A 以「探针」身份入场,一次请求定生死 │ ├── 出活(assistant message 证明)→ 记录清空、惩罚归零 └── 又失败 → 立刻回停车(不用重攒阈值),冷却翻倍(封顶 maxCooldownSeconds)
「墙」不靠猜:上游公布的重置时间(providerRetryAfterMs、正文里的 resets at <ISO>、"retry again in N 单位")原样采用;账号级措辞("usage limit for your plan"、"insufficient credits"…)按无公布时间的墙处理;模糊说法(单独一句 "quota exceeded")不算墙。判定表与取舍见 docs/architecture.md。
功能
- 自动 Retry + Failover — 基于 agent loop 的两个公开 waterfall 扩展点,零修改核心循环
- 墙与抖动分开 — 配额/用量窗口这类"确定要等到重置"的失败第一次就切,并按上游公布的时间停车(上界 30 天);5xx、超时、传输、流中断、短促 429 仍走阈值
- half-open 探针 — 冷却到期不直接放行,而是放一次探针请求:成功才恢复,失败立刻回停车且冷却翻倍(封顶);上游公布的时间永远原样使用(信息不打折,只惩罚递增)
- 服务商健康管理 — 按服务商粒度跟踪连续失败次数、停车原因与累计停车次数
- 优先级池切换 — models 数组顺序即优先级;半开状态的服务商不抢占健康服务商
- 双通道恢复 — 冷却到期惰性入场探针 + assistant message 主动证明恢复(停车期内只要改道过,此后归属该服务商的"成功"一律拒收:歧义覆盖整段停车期,不只是切过去那一分钟,避免冷却被自己发起的切换绕过)
- 最大切换保护 — 单回合切换上限防止死循环
- 错误分类 — 7 种可恢复错误 + 多种永久错误,精确决定是否切换;每类一个开关
- 终止时说得清 — 所有服务商都停车时,日志给出最早恢复的是谁、还有多久,并附全服务商状态快照
- 两套本地测试 — node --test test/failover.test.mjs(35 项,node:test 风格)+ node test/smoke.test.mjs(49 项,纯离线、不需要 harness)
- 敏感信息日志脱敏 — URL 凭据 / Bearer token / key 参数自动掩码
- 会话安全设计 — 不写自定义事件类型,避免会话重载兼容问题
- 与 llm-retry 共存 — 阈值以下决策权归 llm-retry,达到阈值才由本插件接管;下游任何决定都原样尊重
安装
三步手工操作,不联网、不 npm install:
1. 复制插件到 Harness(排除 node_modules) $dst = "<DSH安装目录>\\resources\\app.asar.unpacked\\node_modules\\@deepseek-ai\\dsh-llm-failover" New-Item -ItemType Directory -Force -Path $dst | Out-Null Copy-Item "<本仓库目录>\\" $dst -Recurse -Force -Exclude node_modules
2. 把 patches/cordis.patch.snippet.yml 的内容追加到 DSH home 下的 profiles\\desktop\\cordis.patch.yml 末尾 DSH home 默认:Windows %USERPROFILE%\\.dsh / Linux·macOS ~/.dsh
3. 重启 DeepSeek Harness Desktop
启动日志出现 llm-failover: active (v<版本>; …) 即加载成功,括号里的版本号就是当前真正在跑的构建(读自部署目录的 package.json)。
完全可逆:删目录 + 删配置块 + 重启。
更省事的部署方式(推荐):不要拷进 harness 本体(升级会覆盖),而是放在 harness 之外的覆盖目录里,用 profile 的 link: 依赖指过去;改了代码用 node tools/sync-to-dsh.mjs --dest <覆盖目录> 同步(先备份再覆盖)。见 INSTALL.md。
快速配置
健康的时候插件不碰路由:请求仍然打在宿主自己选定的 provider 上。models 只决定故障时的备份选择顺序——当前 provider 不可用了,就取池里第一个健康的条目顶上。
- insert:
- id: llm-failover
name: '@deepseek-ai/dsh-llm-failover'
config:
enabled: true # 总开关 models: # 故障切换池(顺序 = 优先级)
- provider: deepseek-official
model: deepseek-v4-flash
- provider: my-siliconflow # llm-pi-ai settings 里的 profile 名 model: deepseek-ai/DeepSeek-V3 maxConsecutiveFailures: 5 # 「抖动」类失败:同一 provider 连续失败多少次后切换 cooldownSeconds: 60 # 抖动类的停车时长(必须 > 0) quotaCooldownSeconds: 14400 # 「墙」类(配额/用量窗口,且上游没给重置时间)的停车时长 maxCooldownSeconds: 86400 # 本地惩罚性退避的翻倍上限(上游公布的重置不受它截断) autoRecover: true # 冷却到期是否自动入场探针 maxSwitchesPerTurn: 8 # 单回合最大切换次数
未配置键取默认值;未知键不会导致报错,只记录警告后忽略。models 为空时插件保持惰性。
多账号:一个账号一个 provider profile
健康状态按 provider 粒度管理:同一 provider 下的多个模型、同一把 key 的多个账号,共享一套失败计数和停车状态。
- 因此同 provider 多账号不是独立故障域——账号 A 的配额用尽时,同一个 profile 下的账号 B 一起停。
- 想让两个账号轮流上,就把每个账号各配成一个独立的 llm-pi-ai profile,再把它们当成两个 provider 放进池里:
models:
- provider: deepseek-official # 账号 A(profile 1) model: deepseek-v4-flash
- provider: deepseek-official-b # 账号 B(profile 2,另一把 key) model: deepseek-v4-flash
当前版本没有宿主贯通的 accountKey/routeKey,所以做不到「同一个 profile 内多账号轮换」;上面这种 profile-per-account 是唯一能吃到 provider 级隔离的写法。
按类别切换开关
| 开关 | 默认 | 控制范围 |
| failoverOnRateLimit | ✅ true | HTTP 429 |
| failoverOnTimeout | ✅ true | 请求/连接/空闲超时 |
| failoverOnServerError | ✅ true | HTTP 5xx |
| failoverOnTransportError | ✅ true | 网络/代理链路异常 |
| failoverOnStreamInterrupted | ✅ true | SSE 流中断 |
| failoverOnEmptyResponse | ❌ false | 退化空补全 |
| failoverOnQuota | ✅ true | 配额/余额/用量窗口(第一次就切,停到上游说的重置时间) |
错误分类
| 错误 | 默认行为 | 原因 |
| RATE_LIMIT (429) | 切换(抖动走阈值;点明重置时间/账号级措辞的按墙立即切) | 限流可能是瞬时,也可能是计量窗口,用措辞区分 |
| SERVER (5xx) | 切换 | 服务端瞬时故障 |
| TIMEOUT | Failover | 请求/连接超时 |
| TRANSPORT | Failover | DNS、连接重置/拒绝、代理异常 |
| STREAM_CLOSED | Failover | SSE 流中途中断 |
| EMPTY_RESPONSE | Retry only | 可安全重复,不一定需要切模型 |
| QUOTA | Failover(墙:第一次就切,停到重置) | 配额是事实不是抖动;同 provider 重试必然再失败 |
| AUTH / INVALID_CREDENTIAL | Never failover | 凭证问题,切换无用 |
| INVALID_REQUEST / UNKNOWN_MODEL | Never failover | 请求本身有误 |
| CONTEXT_WINDOW_EXCEEDED | Never failover | 交给 compaction 处理 |
| ABORTED | Never failover | 用户主动取消 |
Architecture
agent/request-error (请求失败恢复点) —— 本插件是最外层
│
├── 永久错误 → 永不切换,让错误冒泡 │ ├── 「墙」(配额/用量窗口/长时间重置)→ 第一次就切:停车到重置时间 │ └── 「抖动」→ 计数 ├── 未达阈值 → 交给下游栈(通常是 llm-retry),任何下游决定都原样尊重 └── 达到阈值 → 停车(冷却翻倍,封顶)→ 切换到下一个健康目标
agent/request (每次构建请求时)
│
└── 目标 provider 处于停车期 → 自动改写到最优健康条目(健康 > 半开:半开的不抢占健康的) └── 改写时丢弃继承的 reasoningEffort(属于失败路由的每模型设置)
session/event (assistant/message)
└── 出活 = 证明恢复:清空该 provider 的记录与惩罚(冷却期内、且刚被改道过的"成功"判为歧义并拒收 —— 否则冷却会被自己发起的切换绕过)
恢复是双通道的:冷却到期后以探针身份惰性入场(一次请求定生死);任何 assistant 消息证明某 provider 成功出活时立即恢复。冷却中的 provider 不会被当作切换目标,除非所有 provider 都在停车;那时日志会给出最早恢复的那个是谁、还有多久。
详见 docs/architecture.md(状态机、判定表、与 retry 层的分工)。
Project Status
Release Candidate — 版本 0.2.0-rc.2
- ✅ 核心 failover 功能已实现并通过两套本地回归测试(node --test test/failover.test.mjs 35 项 + node test/smoke.test.mjs 49 项,合计 84 项,都不需要 harness 在场)
- ✅ 启动安全设计经真实加载器验证(见 INSTALL.md 的安装前冒烟彩排)
- ✅ 已安装进真实 DSH Desktop 环境(2026-08-27)
- ✅ 冷却保护(2026-09-21):切换后返回的"成功"证据若与插件自己发起的改道冲突,会被判为歧义并拒收,避免冷却被提前取消
- ✅ 墙/抖动分开 + half-open 探针(2026-09-25):配额与用量窗口第一次就切并按上游公布的重置时间停车;冷却到期改为放一次探针,探针失败立刻回停车且冷却翻倍封顶;终止日志给出最早恢复时间与全 provider 状态。判定表与取舍见 docs/architecture.md,借鉴来源见下
- ✅ rc.2 状态机修复(2026-10-27):已停车 provider 的迟到失败不再重复停车、不再延长冷却;歧义成功的拒收覆盖整段停车期(4h 墙与无限停车都绕不过去);同代 half-open 探针的迟到失败按探针失败处理,而不是从 1/5 重新计数;一次失败里的多个重置信号取最晚;上游公布的重置不再被 maxCooldownSeconds 截断;自回退等待尊重 Retry-After;长回合的切换预算不再被 TTL 清扫掉;autoRecover: false 的无限停车在终止日志里如实写 parked(indefinitely …)
- ✅ QA 彩排脚本 6 个(smoke / badconfig / disabled / doc-crosscheck / s0-session-compat / final-round)
- 🔄 当前生产配置:3 个目标 —— bailian/qwen3.8-flash、commandcode/deepseek/deepseek-v4.1-flash、deepseek-official/deepseek-flash(付费的 deepseek-official 排最后,只在其它目标都不可用时才切过去)
Intentionally descoped
- 会话内可见切换提示 — DSH 当前未暴露注册自定义会话事件类型的扩展点,插件侧不存在受支持的实现通道。详见 docs/session-compatibility.md。
- 自动推导备份模型 — 切换目标必须显式列在 models 里,不会从适配器目录自动推导。
- 旁路调用保护 — 直接消费 ctx.llm.stream() 的调用(标题生成、compaction 摘要)不在保护范围内。
- 终止错误的文案改写 — RequestErrorAction 只有 { kind: 'retry' } | undefined,改不了客户端看到的错误;有用的信息(最早恢复时间、各 provider 状态)写进宿主日志。
- 探针并发上限 — 本插件观察失败而不是代理调用,做不到 opossum 那种"半开只放一个并发探针";靠"探针失败立刻回停车 + 冷却递增"限制影响面。
- 健康状态持久化 — 重启后从头开始(乐观),第一次失败重新学习。
未来可能的扩展
- 若 DSH 提供事件词汇注册面或 ignorable 公开写入口,可重新评估恢复会话事件记录
- 若 RequestErrorAction 扩展出携带文案/原因的形状,把"最早何时恢复"放进用户可见的错误里
Prior art(借鉴来源)
这个插件的关键设计是照着现成实现改的,不重复造轮子;下面逐条记清借了什么、为什么不能直接当依赖。
| 来源 | 借了什么 | 为什么不能直接用 |
| LiteLLM Router | 429 类失败立刻进冷却,不等阈值;retry-after 作为最短等待;每类错误各自的失败阈值(allowed_fails_policy);所有部署都在冷却时把「最早恢复时间」说清楚;fallback 路径上的失败也要触发冷却(他们 issue #31876);以及「重试会相乘」的教训(他们把 provider SDK 自己的重试钉成 0) | 语言与形态不同(Python 服务 vs 宿主内插件);安装路径是文件拷贝,不能 npm install,所以只借设计 |
| opossum | half-open 语义:冷却到期先放探针,成功才恢复,失败立刻回打开;冷却递增 + 上限 | 插件不能引三方依赖(宿主 node_modules 由 harness 拥有);且它代理调用,我们只观察失败,探针并发上限做不到 |
| @mars-sea/dsh-commandcode-provider | 「点名了用量窗口才算窗口用尽」(issue #54)、「两个窗口都读、解禁取最晚」(issue #51 后续)、账号级措辞的标记列表、resets at <ISO> 记法 | 它管同一 provider 的多个账号(换密钥),本插件管多 provider 之间的切换(换路由),层次不同 |
| dsh-llm-retry(宿主自带) | 分工与字段:它消费 failure.providerRetryAfterMs 做同 provider 退避,本插件把它作为唯一的结构化重置信号;阈值以下决策权交给它 | 它不切 provider,本插件不抢它的活 |
| dsh-llm 的 isQuotaExceededError(宿主自带分类器) | 措辞 → QUOTA 的映射:本插件主路径直接吃这个 code,措辞列表只做兜底 | 宿主内部实现,插件只读 failure.code |
Security
本插件在设计上避免敏感信息泄露:
- URL 内嵌凭据掩码 — 日志中 URL 里的 key=、token= 参数自动替换为 **
- Bearer token 掩码 — Authorization header 中的 token 不会明文出现在日志
- 错误文本截断 — 错误信息截断至 200 字符,减少意外泄露窗口
- 不写会话事件 — 决策轨迹只存在于宿主日志,不追加任何会话事件
Troubleshooting
| Problem | Check |
| 插件没有加载 | 启动日志搜索 llm-failover,确认目录复制位置正确 |
| models 没有配置 | models 为空时插件仅日志提示,不执行切换 |
| provider 名称配置错误 | 插件不校验 provider 是否存在:写错的名字会被当作切换目标用,请求随后以该 provider 的解析/鉴权错误结束。逐字对照 llm-pi-ai settings 里的 profile 名 |
| 模型切换没有发生 | 检查 maxConsecutiveFailures 是否达到;检查 per-class 开关 |
| 为什么 AUTH 不切换 | 凭证问题切换无用,设计行为 |
| 为什么某些错误只 retry | 参考 Error Classification 表 |
| 为什么这次 429 立刻切了 | 那是「墙」:上游公布了 ≥60s 的重置时间,或正文带账号级措辞(如 usage limit for your plan)。日志里会写明来源(quota-code / message-marker / provider-retry-after / reset-stamp / retry-after-prose) |
| 刚切过去又被切回来 / provider 一直反复失败 | half-open 探针在工作:每次失败会翻倍延长停车(封顶 maxCooldownSeconds)。日志里找 parked ... after a failed probe |
| 所有 provider 都停了,怎么办 | 日志的 no healthy target left 会给出 Earliest recovery: "X" in …;等它,或往 models 里加一个 provider,或解决那个配额用尽的账号 |
| 为什么 session 中看不到 failover 消息 | 插件不写会话事件,见 docs/session-compatibility.md |
| 如何查看日志 | Host 日志面板过滤 llm-failover |
| 如何关闭插件 | config.enabled: false 或 patch 行块加 disabled: true |
详见 docs/troubleshooting.md。
Demo
License
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
guangxiangwu6-cmd/dsh-llm-failover
模型报错时自动切换健康模型,任务不中断
相关插件 · 其他
模型破甲清洗YuJunZhiXue/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 16,148已汉化DeepSeek 客户端
73
女娲蒸馏alchaincyf/nuwa-skill
输入名人名字,提炼其思维模型与决策方式供你调用
★ 37,308已汉化DSH
72
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 888已汉化DSH
71.6
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,266已汉化DSH
70.7