额度耗尽时自动切换到下一个可用模型厂商
30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/5 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add mufasa007/dsh-llm-failover该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · model
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 26 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🟢 扫描:未发现敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-llm给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 配额耗尽自动回退
- 多路由重试
- 流式请求瀑布切换
为 DeepSeek Harness 做配额感知的模型回退:某条模型路由配额耗尽时,自动在下一个路由上重试(llm/stream 瀑布流)。
README
由 DeepSeek 最新模型翻译生成dsh-llm-failover
面向 DeepSeek Harness(dsh)的大模型厂商自动故障转移插件。
当某家厂商不可用时——额度耗尽、账户被封禁、密钥失效、服务宕机、网络异常——本插件会把请求透明地改发到优先级列表中的下一个可用厂商。不需要模型做任何决策,上层 agent 循环也完全感知不到这次失败。
优先级:Claude ──▶ Kimi ──▶ DeepSeek │ │ │ 额度/封禁/ 额度/封禁/ 按量付费宕机 宕机 保底
插件不限定厂商:任何注册在 ctx.llm 上的路由都可以参与。
为什么需要它
dsh 没有内建的模型故障转移。以下是逐条核对随应用分发的包之后确认走不通的路径:
| 看起来可行的路径 | 为什么不行 |
| @deepseek-ai/dsh-llm-retry | 只在同一个 provider/model 上重跑。默认可重试码是 EMPTY_RESPONSE、RATE_LIMIT、SERVER、TIMEOUT、TRANSPORT —— 不含 QUOTA,而且它从不切换厂商。 |
| retryPolicy: { mode: 'always' } | 无限重试同一个模型;账号已停用时只会一直空转。
展开完整文档(README 剩余 1 节)
dsh-llm-failover
面向 DeepSeek Harness(dsh)的大模型厂商自动故障转移插件。
当某家厂商不可用时——额度耗尽、账户被封禁、密钥失效、服务宕机、网络异常——本插件会把请求透明地改发到优先级列表中的下一个可用厂商。不需要模型做任何决策,上层 agent 循环也完全感知不到这次失败。
优先级:Claude ──▶ Kimi ──▶ DeepSeek │ │ │ 额度/封禁/ 额度/封禁/ 按量付费宕机 宕机 保底
插件不限定厂商:任何注册在 ctx.llm 上的路由都可以参与。
为什么需要它
dsh 没有内建的模型故障转移。以下是逐条核对随应用分发的包之后确认走不通的路径:
| 看起来可行的路径 | 为什么不行 |
| @deepseek-ai/dsh-llm-retry | 只在同一个 provider/model 上重跑。默认可重试码是 EMPTY_RESPONSE、RATE_LIMIT、SERVER、TIMEOUT、TRANSPORT —— 不含 QUOTA,而且它从不切换厂商。 |
| retryPolicy: { mode: 'always' } | 无限重试同一个模型;账号已停用时只会一直空转。 |
| 修改 agent-default-model 或 --patch | 对已恢复的会话无效:selectionFor() 优先读会话自己请求头里记录的模型。 |
| 用 spawn_teammate 指定模型 | 工具 schema 没有 model 参数;teammate 继承 Lead 的路由 —— startContinuable 调用时根本没传 agentOptions。 |
| Anthropic 的 allowedFallbackModels | 是服务端对拒绝回复的兜底,与可用性无关。 |
唯一可用的钩子是 llm/stream 瀑布。
工作原理
LlmRuntime.stream(options)
└─ ctx.waterfall(this, "llm/stream", options, () => this.adapterStream(options))
↑ 适配器在这里才被选中,位于瀑布之后
四条关键事实(均已对照 @deepseek-ai/dsh-llm 源码核实):
1. dispatch() 不做监听器类型过滤 —— 任何 ctx.on("llm/stream", fn) 都参与瀑布。
2. 监听器签名是 (options, next),this 才是 LlmRuntime。cordis 会把 waterfall 的第一个参数从参数列表中 shift 出去、用于 bind 监听器 —— 所以必须用 function 而不是箭头函数,才能通过 this 拿到运行时。
3. 适配器选择发生在瀑布之后(adapterStream 内部的 this.registration(options.provider)),因此改写 options.provider / options.model 能够真正改变请求去向。
4. next() 是状态化推进器 —— 每调用一次就 shift 下一个监听器 —— 因此只能调用一次。所以故障转移重试是带着深度标记重新进入 llm.stream(),而不是再调一次 next()。
故障分类
| 类别 | 错误码 | 行为 |
| 确定性故障 | QUOTA、AUTH、INVALID_CREDENTIAL,以及措辞匹配 | 立即熔断并继续向后走。AUTH / INVALID_CREDENTIAL 属于账户级,会熔断整个厂商;QUOTA 只熔断该路由——不同模型的额度池相互独立。 |
| 瞬时故障 | RATE_LIMIT、SERVER、TIMEOUT、TRANSPORT、EMPTY_RESPONSE,以及无法识别者 | 计数;连续达到 failureThreshold 才熔断,因此一次抖动不会把你从某家厂商上赶走。 |
| 调用方问题 | INVALID_REQUEST、CONTEXT_WINDOW_EXCEEDED、ABORTED、UNKNOWN_MODEL、NO_ADAPTER | 既不切换也不熔断——换厂商修不好一个畸形的请求。原样透传。 |
熔断与恢复
每个路由(provider/model)与每个厂商各持有健康状态。已熔断的路由会被跳过,改用下一个候选;重复失败时冷却时间翻倍,上限由 maxCooldownMs 决定。
恢复采用半开策略且不产生任何额外请求:冷却时间一过,该路由重新变为可用,于是下一次真实请求就会重试它。成功即彻底清除状态并重置退避;失败则以更长的冷却重新熔断。若你在低流量场景下也想刷新厂商模型列表,可开启 probe.enabled。
内容安全
切换只发生在产出任何可见内容之前。若某家厂商在回答中途失败,已产出的部分与错误会原样透传——把两个模型的半截回复拼起来会得到自相矛盾的答案。
环境要求
- DeepSeek Harness,且插件能访问到 @deepseek-ai/dsh-llm(任何暴露 llm/stream 瀑布与 QUOTA_EXCEEDED_CODE 的较新版本)。
- 已在桌面端随附的 dsh-llm 0.1.5-rc.3 与 cordis 上验证。
安装
插件必须位于 profile 的 node_modules 内,否则无法解析同级的 @deepseek-ai/dsh-llm。
cp -R ./dsh-llm-failover "$DSH_HOME/profiles/node_modules/dsh-llm-failover"
cd "$DSH_HOME/profiles"
node -e "import('dsh-llm-failover').then(m => console.log(m.name, m.inject))"
→ llm-failover [ 'llm' ]
然后追加到 profile 的用户补丁层($DSH_HOME/profiles/<profile>/cordis.patch.yml):
⚠️ 新增插件必须用 insert: 形式。 写成 - id: <新id> 会被当作对已有条目的覆盖,报错 entry "<id>" not found。
- insert:
- id: llm-failover
name: dsh-llm-failover
config:
priority:
- provider: anthropic
model: claude-sonnet-5
- provider: kimi-coding
model: k3
- provider: deepseek-account
model: deepseek-flash
重启应用 —— cordis.patch.yml 在 profile 加载时读取。
设置页面
加载后,插件会在 设置 → 侧栏「插件」→ 本插件 下注册自己的配置页,编辑三个最常调的旋钮:
| 控件 | 对应设置 |
| 厂商优先级 | 逗号分隔,越靠前优先级越高:anthropic/claude-sonnet-5, kimi-coding/k3, deepseek-account/deepseek-flash。只写厂商名时使用该厂商公告的首个模型。 |
| 瞬时故障切换阈值 | failureThreshold。 |
| 冷却时长(分钟) | cooldownMs,界面上以分钟呈现。 |
保存的值进入设置文档,作为组合配置之上的用户层,插件实时读取 —— 无需重启。其余字段(chains、错误码列表、措辞、maxCooldownMs、probe)仍属于组合层。
接线方式(便于二次开发):
- .volatile() 是插件页出现的前提。 dsh-settings 逐条目调用 volatileForm(条目 schema),只保留带 volatile 标记的字段;一个都没有的条目会被整体丢弃(if (form === void 0) return [])。标记 volatile 同时把字段变成实时访问器,所以插件用 config.priority.get() 读取。
- 设置命名空间自动等于 loader 条目 id(ns: entry.options.id),无需任何注册调用;installSection 只存在于较旧的 dsh 构建里。
- 浏览器半侧(./client)通过 ctx.configForms.whileServed(["llm-failover"], …) 注册进插件页的 plugins.item slot;没装本插件的部署看不到这个页面。
- 包在 package.json 中声明 dsh.client —— 这是客户端模块系统把 ./client 送到浏览器的前提。
- 保存经由 profile 补丁编辑器写回:它会跳过 insert: 行,改为追加一条顶层 config 行。若配置来自 --patch 命令行叠加层,则页面无法编辑,宿主会以 "overridden by a home patch or command-line overlay" 拒绝。
配置
| 字段 | 默认值 | 含义 |
| priority | [] | 有序的厂商路由。失败时,按顺序尝试该厂商之后的路由;若失败厂商不在列表中,则使用整条列表。 |
| chains | [] | 按厂商(或按确切模型)覆盖。精确的 provider+model 条目优先,否则用第一个仅按 provider 匹配的条目。优先于 priority。 |
| fatalCodes | [] | 额外立即熔断的错误码。QUOTA、AUTH、INVALID_CREDENTIAL 始终包含。 |
| transientCodes | [] | 额外计入阈值的错误码。 |
| patterns | [] | 额外的正则字符串,匹配失败信息;命中即立即熔断。 |
| failureThreshold | 2 | 瞬时故障连续多少次后熔断。 |
| cooldownMs | 300000 | 首次熔断的冷却时间(5 分钟)。重复失败时翻倍。 |
| maxCooldownMs | 3600000 | 冷却上限(1 小时)。 |
| probe.enabled | false | 定时刷新厂商模型列表。 |
| probe.intervalMs | 600000 | 刷新间隔。 |
priority 条目可以省略 model,此时插件使用该厂商自己公告的首个模型(经 ctx.llm.listModels 解析)。它绝不会把当前请求的模型名套到别的厂商上;暂时解析不到的条目会被跳过,而不是瞎猜。
内置措辞
有些真实世界的说法永远到不了正确的错误码:pi-ai 的 classifyPiAiError() 会先判 isQuotaExceededError、后判 429 | rate limit,而 isQuotaExceededError 要求 usage limit 紧跟 exceeded|exhausted|reached:
| 厂商返回的措辞 | dsh 能否识别 | 归一后的码 |
| usage limit exceeded | 能 | QUOTA |
| insufficient quota | 能 | QUOTA |
| You have reached your usage limit for Claude. | 不能 | RATE_LIMIT |
| Your limit will reset at … | 不能 | 其它 |
| Your account has been suspended. | 不能 | 其它 |
因此插件自带补充措辞并自行匹配:
/usage[\s_-]limit/i
/reached your [^.]{0,40}limit/i
/limit will reset/i
/weekly limit|monthly limit/i
/account[^.]{0,30}(?:banned|suspended|disabled|deactivated)/i
/(?:banned|suspended)[^.]{0,20}(?:account|user|key)/i
/(?:insufficient|no)\s_-/i
可用 patterns 追加自己的。
测试
测试套件通过真实的 cordis 瀑布驱动插件、使用真实的 dsh-llm 辅助函数,只伪造 llm 服务,并用可拨动的时钟验证冷却与恢复:
cd "$DSH_HOME/profiles" && node path/to/test.mjs
必须在 profile 目录下运行,@deepseek-ai/cordis 与插件本身才能被解析到。
十个用例:确定性故障转移、熔断后跳过、冷却后半开恢复、瞬时故障按阈值熔断、调用方问题不介入、已产出内容后不切换、候选全部耗尽、账户级故障覆盖同厂商所有模型、封禁措辞识别、请求方不在优先级列表内。
局限
- 只在产出可见内容之前切换(刻意如此,见上文)。
- 熔断状态存于内存:应用重启即清空。仍在故障中的厂商会被重试一次并再次熔断。
- 健康状态按路由与厂商判定,但没有跨进程协调。
- 拦截每一次 llm/stream,包括 workflow 子代理与 teammate。这通常是想要的效果——它们都不该因为某家厂商宕机就整体失败——但会增加日志量。
- 非 DeepSeek 官方项目。它依赖 dsh 的内部包,升级后可能失效。
- 代码注释为中文;同时提供英文与中文 README。
许可证
MIT —— 见 LICENSE。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
mufasa007/dsh-llm-failover
额度耗尽时自动切换到下一个可用模型厂商
相关插件 · 模型接入
API 中继安全审计toby-bridges/api-relay-audit
面向 AI API 中转与 LLM 代理的本地安全审计。
★ 897已汉化DSH
69.4
免费搜索插件DDDMUC/dsh-free-search
DeepSeek Harness 免费搜索插件 —— 无需 API key,零成本,多引擎可切换。 一个给…
★ 761已汉化DSH
68.7
免费联网搜索liustack/modsearch
在官方 App 里模型能联网,切到 API 就不能了。ModSearch 把联网补回来:网页搜索、X…
★ 863已汉化DSH
68.5
OpenCode 免费模型FishBottle7/opencode2dsh
在 DSHDeepSeek Harness里原生使用 OpenCode Zen 的免费匿名模型。
★ 379已汉化DSH
67.8
AI 模型网关tingly-dev/tingly-box
Tingly Box Web UI 演示
★ 373已汉化DSH
67.4
WorkBuddy 账号池XDTrees/dsh-xdpool
把你能白嫖的模型额度接进 DSH 同一个池:WorkBuddy 多账号自动容错、十三家扫码登录、76…
★ 359已汉化DSH
67.1