前言¶
做智能体开发的人,多半会遇到同一类问题:免费的模型平台有几个,各自额度不同,收尾时间也不同。跑在某个平台时中间触发额度上限,整个任务就断了,前面的上下文都白跑。手工盯着换平台、换模型,能解决但不可持续,尤其当平台会增减、模型名在不同渠道叫法不一致时。
puppy-bai/dsh-quota-takeover 处理的就是这件事:在 Our Free Model(下称 OFM)之上加一层「接力」逻辑——平台额度不够按你设定的顺序换下一个,某个平台没有你要的模型就跳过,全都没有就换下一档模型再遍历一遍,任务因额度中断时自动切到新平台并往中断的会话里发一条「继续」。维护者是 puppy-bai,分类是模型推理。
本文只依据插件 README 与 package.json 中已有的内容介绍,不涉及未公开功能。
它解决什么问题¶
OFM 负责把多个平台的账号、模型和剩余额度聚合起来。它的短板是顺序固定:一个平台额度用完后,接力不会自动发生。本插件把「平台顺序 × 模型档」编译成一条有序候选链,写回 OFM 的 combo(auto:main),由 OFM 的 fallback 策略逐项尝试。
也就是说,插件本身不直接调用模型,它做的是编译计划和写回计划。
核心能力¶
下面按需求逐条列出已实现的行为,来源是 README 的「它做什么」表。
- 额度耗尽换下一个平台:把「平台顺序 × 模型档」编译成候选链,写回 OFM 的 combo(
auto:main)。 - 模型不存在则跳过:每个模型档有别名表,平台模型清单匹配不到记为
missing并跳过。别名匹配先精确比较,再去-free/-preview/eac:前缀小写比较,最后按 id 最后一段比较——聚合渠道的siliconflow/deepseek-ai/DeepSeek-V3能被DeepSeek-V3命中。 - 全部换完还没有就换档重遍历:遍历形状为
tier-major(档优先),先全平台找第 1 档,再全平台找第 2 档。 - 兜底:
finalResort.fallbackModels(如groq/llama-3.3-70b)非空时编译兜底链;为空则进入「等待恢复」。 - 中断续跑:监听
llm/stream的错误终点,分类为额度/限流后写冷却、重编译计划、向该会话agent.followup(一条「继续」消息)。 - 平台表自动维护:平台来源有三处——channel-pack 账号池、OFM 聚合渠道
/providers、catalog 里的新通道(如subscription:magpie/siliconflow/…)。每轮同步重新读。连续platformPolicy.pruneAfterMisses(默认 3)轮读不到的平台从顺序里清掉;pruneZeroAccounts(默认开)会把账号数为 0 的渠道隐藏,之后补上账号会自动回来;也可以在设置页每行手动删除平台,写进hiddenPlatforms和excludePlatforms,底部「已隐藏 N 个」点 ↺ 可放回。
为什么是两个半身¶
OFM 的 API 挂在 harness 的信任围栏后,插件进程内的 fetch 一律返回 401(README 提到实测,详见设计文档 §12.1)。所以读账号/额度、写 combos 这两件事只能由浏览器侧代劳,host 侧负责编译计划。
浏览器(带 DSH 认证 cookie) 插件 host 进程
│ ① GET /api/our-free-model/combos │
│ ① GET /api/our-free-model/subscriptions │
│ ② POST /api/quota-takeover/snapshot ────▶│ 编译计划(平台顺序 × 模型档 × 额度 × 冷却)
│ ③ GET /api/quota-takeover/pending ◀──────│ 待写回的 combos
│ ④ POST /api/our-free-model/combos │ (只有浏览器有写权限)
│ ⑤ POST /api/quota-takeover/applied ─────▶│ 记录已写回
续跑不受这个限制影响,因为它是进程内 agent.followup(),不经过 HTTP。
安装与启用¶
前提:先装好 Our Free Model。没有 OFM 时,本插件只剩续跑能力,没有可接力的平台。
从市场装(发布后可用):
DSH → Plugins → Discover 里搜 quota-takeover
手动装(开发或未发布时),README 给出的命令如下:
cd ~/.dsh/profiles/desktop
npm i /path/to/dsh-quota-takeover-0.1.1.tgz # 或把源码目录拷到 node_modules/dsh-quota-takeover
# 然后在 package.json 的 dsh.profile.bundles 数组里追加 "dsh-quota-takeover"
# 被 bundles 引用的包,其自带 cordis.patch.yml 自动生效;
# 别再往 cordis.patch.yml 手写同名条目,否则报 duplicate loader entry id
装完要完全退出 DeepSeek Harness 再打开。host 半身只在进程启动时 apply 一次,刷新页面只重载浏览器半身。
三个检查点:
| 检查点 | 期望 |
|---|---|
| 设置 → 「额度接力」 | 页面出现,且没有红色「宿主半身没有加载」告警 |
| 平台顺序 / 模型档 | 列出 channel-pack 里启用的平台与它们的真实模型 |
~/.dsh/quota-takeover/journal.jsonl |
有 api-mounted;发生过失败时有 failure / resume |
运行期数据放在 ~/.dsh/quota-takeover/{config,plan,bench,resume,platforms}.json 和 journal.jsonl。
配置¶
配置文件是 ~/.dsh/quota-takeover/config.json,也可以由设置页「额度接力」写入。README 提供的样例:
{
"enabled": true,
"platformOrder": ["trae", "minimax", "zcode", "loomy", "raccoon", "gemini"],
"platformPolicy": {
"unknownTail": true,
"excludePlatforms": [],
"pruneMissing": true, // 读不到的渠道自动从顺序里清掉
"pruneAfterMisses": 3, // 连续缺席几轮才清(防一次探测失败误删)
"pruneZeroAccounts": true // 0 账号的空渠道自动隐藏(有账号后自动回来)
},
"modelTiers": [
{ "id": "deepseek-flash", "label": "DeepSeek V4.1 Flash", "pinned": true,
"aliases": ["deepseek-v4.1-flash", "deepseek-v4-flash-0731", "deepseek-flash"] },
{ "id": "glm-flash", "label": "GLM 5.3 Flash", "aliases": ["glm-5.3-flash"] }
],
"traversal": { "order": "tier-major", "maxChainLength": 16, "optimisticOnUnknown": true },
"finalResort": { "fallbackModels": [], "retryAfterMinutes": 10 },
"resume": { "enabled": true, "onlyQuotaLike": true, "maxPerSession": 5, "requireCandidateChange": true }
}
几个容易踩的点:
platformOrder没列出的平台排在后面(受platformPolicy.unknownTail控制)。pruneMissing/pruneAfterMisses决定撤掉的渠道何时被清理,缺席次数记在platforms.json。一轮读不到任何平台时整轮跳过,README 解释这是为了区分中继故障和渠道被删。optimisticOnUnknown:平台模型清单未知时先把格子放进链,真没有会让 OFM 的 combo 自然失败并前进——未知不等于不存在。resume.requireCandidateChange是核心防呆:候选链没变化就不重复注入「继续」,避免握着同一个额度耗尽的平台反复触发。
HTTP API¶
以下接口在浏览器侧使用,需要带 DSH 认证 cookie:
| 方法 | 路径 | 作用 |
|---|---|---|
| GET | /api/quota-takeover/status |
计划 + 桥状态 + 配置 |
| POST | /api/quota-takeover/compile |
手动重编译 |
| POST | /api/quota-takeover/snapshot |
浏览器推账号/额度/模型快照 |
| GET | /api/quota-takeover/pending |
取待写回的 combos |
| POST | /api/quota-takeover/applied |
回报写回成功 |
| GET | /api/quota-takeover/bridge |
中继健康状况 |
| POST | /api/quota-takeover/config |
改配置(合并后重编译) |
| POST | /api/quota-takeover/bench/clear |
清空冷却表 |
开发者自测¶
README 里给的几条命令,适合改完代码后自己跑一遍:
node --test tests/*.test.js # 单测(编译器 / 分类器 / 续跑状态机,README 写 32 个)
node probes/smoke-host.mjs # 假 ctx 装载 host 半身,跑通中继闭环
node probes/plan-preview.mjs # 用本地 state.json 预演一次编译
node probes/ofm-probe.mjs <gui 地址> # 探针:OFM API 可达性(预期 401)
已知限制¶
按 README「已知限制」一节列出:
- 写回依赖 GUI 打开。浏览器关掉时链停在旧计划上;候选里已带 resolved 模型 id,旧链仍能跑。
- 默认不直接改 OFM 的
settings.json(除显式writeBack.mode: "file")。OFM 把设置常驻内存,改盘不热生效且会被下次保存覆盖。 - 续跑只在「额度/限流」类失败上生效(
onlyQuotaLike);用户主动 abort 绝不续跑。 llm/stream目前只观察不改道(探针 4 未验),改道能力留作 M2。
适用场景与注意¶
适合已经在用 OFM 聚合多个免费或低价平台的开发者:想把平台增减、模型档顺序和额度中断后的续跑交给插件维护,而不是手改 combo。平台多、模型名在各渠道写法参差、经常碰到额度用完时,这层接力能明显减少人工介入。
需要注意:
- 插件以当前 dsh 进程的权限运行,安装前应检查源码与许可证(README 的 license 字段写的是 MIT)。
- 它是 OFM 之上的一层,前提是 OFM 已正确配置并启用了 channel-pack 等渠道;没有 OFM 时只剩续跑能力。
- 写回依赖浏览器半身,长期运行的环境里 GUI 不能随便关。
结尾¶
dsh-quota-takeover 的价值在于把「额度耗尽 → 换平台 / 换模型档 → 继续跑」这条链路自动化,并且用 resume.requireCandidateChange 等配置把误续跑控制住。如果你的需求正好在 OFM 的射程之外,可以先看插件目录页和源码再决定:
- 目录页:https://www.skillhub.cn/plugins/puppy-bai/dsh-quota-takeover
- GitHub:https://github.com/puppy-bai/dsh-quota-takeover
目录站是独立站点,与 DeepSeek / 幻方无官方从属关系。