按当前任务只暴露必要工具,减少上下文开销
30.6/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/11/2 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add qwq1223211/dsh-minimal-router该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
一个 DSH 包,三个模块:阶段路由、熔断器、缓存探测。
README
由 DeepSeek 最新模型翻译生成极简路由(dsh-minimal-router)· v1.19.5 · 小白版说明
一句话:让 AI 一次只看见它当前需要的工具,看不见的就不花钱。
30 秒看懂
三条命令:
1. 装(挑一条能用的)
dsh plugin --profile desktop add github:qwq1223211/dsh-minimal-router
或者跟 AI 说:帮我安装这个插件:https://github.com/qwq1223211/dsh-minimal-router
2. 重载:设置 → 插件 → 把「极简路由器」关掉再打开 (link 安装不热更新,这步必须做)
3. 验证:让 AI 调一次 route_status
装完到底变了什么(纯净新会话,同一台机器、同一个模型):
| | 装之前 | 装之后 | |
| 每轮发给模型的工具 | 165 | 66 | −99 个 |
| 工具声明字节 | 131,694 | 43,238 | −67.2% |
| 每轮 promptTokens | 47,885 | 25,688 | −46.4% |
| 缓存命中率 | — | 99.16% | |
还有一行数字,是这个插件存在的理由——本机探针的真实记录:
{
"tools": 172, "toolsChars": 138711,
展开完整文档(README 剩余 1 节)
极简路由(dsh-minimal-router)· v1.19.5 · 小白版说明
一句话:让 AI 一次只看见它当前需要的工具,看不见的就不花钱。
30 秒看懂
三条命令:
1. 装(挑一条能用的)
dsh plugin --profile desktop add github:qwq1223211/dsh-minimal-router
或者跟 AI 说:帮我安装这个插件:https://github.com/qwq1223211/dsh-minimal-router
2. 重载:设置 → 插件 → 把「极简路由器」关掉再打开 (link 安装不热更新,这步必须做)
3. 验证:让 AI 调一次 route_status
装完到底变了什么(纯净新会话,同一台机器、同一个模型):
| | 装之前 | 装之后 | |
| 每轮发给模型的工具 | 165 | 66 | −99 个 |
| 工具声明字节 | 131,694 | 43,238 | −67.2% |
| 每轮 promptTokens | 47,885 | 25,688 | −46.4% |
| 缓存命中率 | — | 99.16% | |
还有一行数字,是这个插件存在的理由——本机探针的真实记录:
{
"tools": 172, "toolsChars": 138711,
"inputTokens": 563654, "cacheReadTokens": 5504,
"promptTokens": 569158, "hitRate": 0.0097
}
hitRate: 0.97% 的意思是:整段上下文按全价重算了一遍。 插件里所有设计(安全闸门、迟滞、冷却、成本闸门)都是为了让这种行少出现。
这条记录就是我在长会话里重载插件产生的——也就是文档反复强调"别在长会话里装/改插件"的原因。
它不做什么(装之前请先看):不缩系统提示(那才是大头)、省下的多是缓存价 token(账单可能几乎不动)、不能和另一个工具路由同时开。
unionEnabled (multi-domain union) is @experimental and off by default; see [docs/LIMITS.md.
安装(两种方式,任选一个)
方式 1 · 在 DSH 里直接喊话(推荐,小白用这个)
打开 DSH,对 AI 说这一句:
帮我安装这个插件:https://github.com/qwq1223211/dsh-minimal-router
⚠️ 装完必须做这一步,否则等于没装:设置 → 插件 → 把「极简路由器」关掉,再打开。
(link 安装不会热更新,不做这一步跑的还是旧代码——你会以为"装了没效果"。)
方式 2 · 终端极客版
dsh plugin --profile desktop add github:qwq1223211/dsh-minimal-router
这条命令本质是把参数转发给 profile 目录里的 pnpm,但 DSH 还会顺手做两件事:把它加进该 profile 的 dsh.profile.bundles,并初始化 profile(如果不存在)。
这一点已实测(v1.12.0,全新 profile):装完 node_modules/@local/dsh-minimal-router 里是 34 个文件的真实目录(不是 link),profile 的 package.json 里自动出现了 "@local/dsh-minimal-router": "github:..." 和 bundles 条目。
所以正常情况下不需要再手动启用一次;装完直接「设置 → 插件 → 关掉再打开」。
装不上?用本地目录兜底(这条一定能成)
git clone https://github.com/qwq1223211/dsh-minimal-router.git
然后把你 clone 下来的那个文件夹的绝对路径发给 AI:
用 plugin_manager install_bundle 安装这个目录:C:\你\clone\到的\路径\dsh-minimal-router
这条路绕开了所有网络、registry、包名解析问题——它做的事情就是把一个本地文件夹挂进 DSH。
如果方式 1、方式 2 都失败,用这个。
装完怎么确认成功
对 AI 说:调 route_status
能看到一段 JSON(里面有 stages、tagCounts、modelGuard)就说明装好了、且在运行。
运行时数据放在 ~/.dsh/minimal-router/(探针历史、你的 custom_stages.json),不在插件目录里面——因为真实依赖安装时,插件目录会被升级替换掉。
一、我为什么要装这个?
DSH 默认会把所有插件的工具说明一次性塞给模型。装了几十个插件之后,模型每一轮都要先"读一遍"上百个工具的说明书——哪怕这一轮只是在聊天。
三组实测数字(同一台机器、同一个模型)
① 工具:165 → 66
| | 装之前(auto) | 装之后(core 阶段) |
| 发给模型的工具数 | 165 个 | 66 个(−60%) |
| 工具说明的字节数 | 131,694 | 43,238(−67.2%) |
| 每轮 promptTokens(纯净新会话实测) | 47,885 | 25,688(−46.4%) |
| 缓存命中率 | 91.4%(第 2 步) | 99.16% |
| 切换阶段的一次性代价(小会话) | — | 约 3 千 token |
| 切换阶段的一次性代价(50 万 token 的大会话) | — | 51 万 token 全价 ⚠️ |
这组数字来自一个全新的、干净的会话(只有一个系统提示、没有历史包袱),是这套方案能达到的真实上限。
切换一次,聊一轮就赚回来(约 10 倍)。
② 系统提示:159,334 → 17,685
这个是我踩过的最大一个坑:
| 情况 | 系统提示字节 | 说明 |
| 一个聊了很久的旧会话 | 159,334 | 系统提示被追加了 9 份(每改一次记忆/装一次插件就 +1 份 17,685) |
| 一个干净的新会话 | 17,685 | 只有 1 份 |
结论:开新会话省下的,比这个插件省下的还多。 这两件事要一起做。
③ 缓存命中:冷启动 0% → 第二步 91% → 稳定 99%+
| 第几步 | promptTokens | 命中率 |
| 新会话第 1 步(冷启动) | 43,864 | 0% |
| 新会话第 2 步 | 47,885 | 91.42% |
| 稳定后 | — | 99%+ |
冷启动必然是 0%,这是物理规律,不用在意。 看趋势,别看第一次。
老实说一句:省下来的 token 里大部分是"缓存命中"的便宜 token,所以账单上的数字不会像字节数那么夸张。但它是持续省的,而且顺带解决了"模型看着一堆工具发呆、乱选工具"的问题。
二、装一次,得到三个模块、十一个工具
一个包,一次安装,一次重载。 你不用分三次装三个插件——因为每装一次插件就要重载一次,而每次重载都可能触发一次全量前缀重建(实测最贵的一次 51 万 token)。
| 模块 | 工具 | 作用 |
| 路由(主角) | route_stage route_status route_reset route_init route_use route_hint route_activity | 分阶段、物理砍工具、切阶段、看它干了什么 |
| 熔断 | guard_status guard_reset | 连续 3 次工具失败就中断,防止死循环烧钱 |
| 探针 | cache_probe_report cache_probe_clear | 记录每次请求的真实 token 账单,用来验证省钱效果 |
不想用某一块? 一行配置关掉,不用拆包:
guardEnabled: false # 关掉熔断 probeEnabled: false # 关掉探针
强烈建议保留探针:没有它你没法验证到底省了多少,也没法发现"某次操作把缓存打爆了"。
想看"它到底做了什么"?用 route_activity
route_status 回答的是此刻是什么状态;route_activity 回答的是刚才发生了什么。
route_activity() # 最近 20 条
route_activity({ "limit": 50 }) # 最近 50 条
route_activity({ "kind": "deny" }) # 只看被拦下的调用
记七种事:switch(切阶段)、restrict(改工具表)、deny(拦调用)、block(闸门拦截)、grant(临时收窄)、reset(复位)、degrade(降级)。
返回长这样:
{
"summary": { "total": 12, "text": "最近共 12 条:切阶段 2 次 · 拦截调用 9 次 · 改工具表 1 次" },
"events": [
{ "t": 1730000000000, "kind": "deny", "by": "stage", "stage": "core", "tool": "unity_object_create" }
]
}
日志存在 ~/.dsh/minimal-router/activity.jsonl,只留最近 200 条,不会随时间无限长。
路由模块的四个工具
| 工具 | 干什么 |
| route_stage("core") | 切换当前任务阶段 |
| route_status() | 看现在是哪个阶段、砍掉了多少工具 |
| route_reset() | 一键复位,解除所有限制 |
最重要的一条:它们永远不会被拦截。 哪怕你被阶段规则卡住了,这三个工具也永远能用——这是刻意的"逃生门"设计。
三、它是怎么工作的(30 秒看懂)
1. 自动分类:它按工具名的前缀自动打标签,不需要你配置。
unity_object_create → 属于 unity 组 mcp__meshy__meshy_image_to_3d → 属于 meshy 组 read / write / pwsh → 属于 core(基础工具,永远在场)
2. 判断阶段:你说的话里出现"界面/按钮"→ 切到 unity-ui;出现"贴图/模型"→ 切到 art。
3. 物理瘦身:切到某个阶段后,不属于这个阶段的工具会被真的从请求里摘掉,不是只提示。
4. 粘住:切一次就一直是这个阶段,不会因为你说下一句话就失效(只有再命中别的关键词、或你手动复位,才会变)。
四、默认有 6 个阶段
| 阶段 | 允许的工具组 | 说这些话会自动切过去 |
| auto(默认) | 全部,不限制 | —— |
| core | 只有基础工具 | 通用、基础、core |
| unity-code | unity + 13 个 Unity 子系统 | 代码、脚本、编译、报错、unity |
| unity-ui | unity、ui、uikit、uiflow、dialogue、quest | 界面、按钮、布局、面板 |
| art | art、meshy、image、asset | 贴图、模型、素材、美术 |
| audio | audio | 音效、音乐 |
auto 是默认值,不砍任何工具,所以刚装完你不会感觉到任何限制。只有进入具体阶段才会开始瘦身。
顺便说一句:这张表之所以长这样,是因为作者自己就在做 Unity + AI 美术,不是因为它"只支持游戏开发"。你完全可以在 1 分钟之内把它换成 Python、数据分析、写文档、剪辑视频……任何东西(见下一节)。
五、我不是做 Unity 的,怎么改成我自己的领域?
最省事的办法:装内置示例。
route_init({ "preset": "python-data" })
它会直接写出可用的 custom_stages.json,然后重载插件就生效。内置 4 套:
| preset | 适合 |
| python-data | 写 Python / 数据处理 / 报表 |
| web-dev | 前后端 / 部署 / Git |
| writing | 写作、查资料、校对 |
| qq-chat | QQ 机器人(把 QQ 工具放行,其它场景再收) |
不带参数跑 route_init,则是"扫描你环境 + 生成模板"的另一条路(适合想从零定制的)。
更彻底的零配置:让模型自己决定这一轮要哪几组
连阶段都不用配。 内置工具 route_use 让模型(或你)按需收窄:
route_use({ "groups": ["unity"], "turns": 3 })
效果:只留 unity 组 + 基础工具,其余全部临时摘掉;3 轮后自动恢复,不用记着撤销。
想立刻放开就说 route_use({ "groups": [] })。
组名从哪来?看 route_status 的 tagCounts——它就是从你的工具名自动推出来的,不需要你提前定义任何阶段。
为什么不是"每轮调用一个小模型来判断"?
那等于每轮多一次请求:整段上下文的输入要按全价重发。
我们实测这个插件一轮省下的 token 里 99.9% 是缓存价,用一次全价请求去换这些便宜 token 是净亏。所以判断权交回给本来就在上下文里的模型自己——它已经知道自己在干什么,加一个工具让它表态,成本为零。
想自己验证"提示有没有用"?用 route_hint
route_hint({ "enabled": false }) # 只关掉当前会话的提示,其它会话不受影响
route_hint({ "enabled": true }) # 打开
route_hint() # 只查询
运行时生效,不用重载插件。提示本身的成本是每轮 50~126 token(占工具声明的 0.1%),所以"提示费钱"这件事在金额上不可能——值得验证的只有它的行为影响。
这正是它设计成"通用"的原因:阶段和标签都写在配置里,不用改代码。
步骤 1:看看你现在有哪些工具组
对 AI 说:
调 route_status 看看
返回里有一个 tagCounts,长这样:
{
"unity": 26, "asset": 6, "audio": 3,
"mcp": 1, "terminal": 6, "session": 5,
"read": 1, "cache": 2, "route": 3
}
每个数字就是"这个前缀下有几个工具"。
步骤 2:编一个你自己的阶段表
打开插件目录下的 cordis.patch.yml,把 stages 加进去(示例:一个做 Python 数据分析的人):
- insert:
- id: minimal-router
name: '@local/dsh-minimal-router'
config:
defaultStage: auto
enforceByRestrict: true
stages:
auto:
title: 自动
allow: []
keywords: []
core:
title: 通用
allow: []
keywords: ['聊天', '通用']
python:
title: 写 Python
allow: ['python', 'notebook', 'jupyter']
keywords: ['python', '脚本', 'pandas', '数据清洗']
data:
title: 数据分析
allow: ['sql', 'db', 'chart', 'plot']
keywords: ['报表', '图表', '数据库', 'sql']
writing:
title: 写文档
allow: ['office', 'docx', 'pptx', 'xlsx']
keywords: ['报告', '文档', 'ppt']
规则就三条:
- allow 里写工具名前缀(python_ 开头的工具就写 python),不用写全名
- keywords 里写你会说的话,中文英文都行
- 阶段表里前面的优先匹配,所以把更具体的放前面
stages 写成对象或数组都行(很多人会自然写成数组,现在两种都认):
{ "stages": [ { "stage": "chat", "allow": ["snowluma"] }, { "stage": "core", "allow": [] } ] }
⚠️ 如果你的工具一个都不属于内置阶段(Unity / 美术 / 音频)
内置阶段表认领的标签(unity/ui/art/meshy/image/audio/asset…)在你这里可能一个都不存在。
那样 deny 列表永远是空的,表现就是"装了但一个 token 都没省",而且不报任何错。
route_status 会直接告诉你:
"stageTableUnused": true,
"stageTableHint": "内置阶段表认领的标签在你这里一个都不存在……"
两种解法:
1. 跑 route_init,按生成的模板把你自己的标签写进某个阶段(推荐)
2. 给阶段加 strict: true —— 这一条会让它连"没被任何阶段认领的标签"也一起拒绝:
{
"defaultStage": "chat",
"stages": {
"auto": { "allow": ["snowluma", "snowluma-host"] },
"chat": { "allow": ["snowluma", "snowluma-host"], "strict": true },
"core": { "allow": [] }
}
}
strict 默认 false。不写它就是"未分类一律放行",绝不会误杀;写了它就是"只留我列的"。
改完在「设置 → 插件」里把这行关掉再打开,立即生效。
为什么不怕"新装的插件没被分类"?因为有个保护规则:没被任何阶段认领的标签,永远放行。
你新装一个 foobar 插件,它的标签 foobar 没人认领 → 任何阶段都能用 → 绝不会因为它没分类就把你拦死。等你确认要管它了,再把 foobar 写进某个阶段的 allow。
五之二、⚠️ 降级保护(开源版的生命线)
这个插件的省钱效果依赖模型的一个能力:系统提示的变更可以追加到历史尾部,而不是重写头部。
不是所有模型都支持。已知情况:
| 模型 | 支持 | 结果 |
| deepseek-flash | ✅ in-history | 全功能 |
| deepseek-v4-pro | ❌ 只有 leading-only | 自动降级 |
| 其它任何没见过的模型 | ? | 自动降级(不确定就不冒险) |
为什么必须降级: 如果模型不支持,系统提示每变一次就要重写整个前缀 → 每一步的缓存全部失效 → 400K/步 全价 × 几十步,账单直接失控。
降级后会发生什么:
| 功能 | 安全模型 | 降级时 |
| 尾部路由提示 | ✅ 开 | ❌ 一个字都不注入 |
| 物理瘦身(restrict) | ✅ 开 | ❌ 强制关闭 |
| 越界拦截 | ✅ 开 | ✅ 保留(不碰 prompt,零成本) |
| 死循环体检 | ✅ 开 | ✅ 保留 |
同时控制台会打一个醒目的警告框(同一个模型只打一次,不刷屏):
╔════════════════════════════════════════════════════════════════╗
║ ⚠ dsh-minimal-router 已自动降级 ║ ║ ║ ║ 当前模型:deepseek-account / deepseek-v4-pro ║ ║ 原因:模型 deepseek-v4-pro 的 systemPromptUpdate 是 ║ ║ "leading-only"(不是 in-history),系统提示一变就会重写前缀 ║ ║ ║ ║ 已关闭:尾部路由提示、物理瘦身(restrict) ║ ║ 仍保留:越界拦截、死循环体检(这两项不碰 prompt,零缓存成本) ║ ║ ║ ║ 确实知道风险还想开:config 里设 unsafeForce: true ║ ╚════════════════════════════════════════════════════════════════╝
我用的不是 DeepSeek,怎么办?
两个开关,任选其一:
1) 精确放行:只信任你确认过的模型名(推荐)写纯模型 ID 就行;带 provider 前缀(bailian/xxx)、大小写不同也能认(内部会归一化)
trustedModels: ['my-flash', 'qwen-coder-plus']
2) 一刀切:全部强行开启(自担风险) unsafeForce: true
trustedModels 是"你的断言",不是插件的实测。 命中白名单时插件会专门提醒一句。
启用后请聊 3 轮再看 cache_probe_report:如果 prefixChanges 开始涨、hitRate 掉到很低,说明这条路由并不支持 in-history —— 立刻把它从白名单里删掉。
配置写在哪个文件:插件读的是包内那份 <包目录>/cordis.patch.yml,不是 profile 的。
改完必须重载插件(设置 → 插件 → 关掉再打开)才生效。
版本要求是怎么判的(从 DSH 源码里挖出来的)
package.json 里写的是 engines.dsh: ">=0.2.1-rc.4"。DSH 的真实逻辑是:
range.trim() !== "" && semver.satisfies(runtimeVersion, range, { includePrerelease: true })
| 事实 | 说明 |
| 是 semver 范围,不是精确值 | 网上说"必须版本号一模一样"的说法是错的 |
| 带 includePrerelease: true | 预发布版本也会匹配,不用纠结 -rc.N |
| 空字符串 = 不满足 → 直接拦装 | 千万别把 engines.dsh 改成 "" |
被拦时 DSH 会给出 incompatible-version 并列出未满足的包;插件管理器另有 set_version_exemption 可按精确运行时版本豁免(自担风险)。
怎么知道自己的模型支不支持? 换上去跑两步,然后用 dsh-cache-probe 看 hitRate:
- 一直 99%+ → 支持,可以加进 trustedModels
- 每步都掉到很低 → 不支持,别加
五之三、🛡 安全闸门(超长会话的刹车)
在很长的会话里切阶段,代价不是"省一点",而是把整个前缀按全价重算一遍。实测:
| 会话大小 | 切一次阶段的代价 |
| 5 万 token | 约 3 千 token(便宜,随便切) |
| 50 万 token | 约 51 万 token 全价(一次 1000 倍) |
所以插件内置了闸门:当上一次请求的上下文超过 contextGuardThreshold(默认 100,000 token)时,切阶段会被拒绝,并告诉你原因和三条出路(开新会话 / 用 force:true / 别切)。
闸门拦两条路,缺一条都等于没装:
1. route_stage 工具显式切换
2. 关键词自动切换(agent/inbox/claimed)—— 这个是我实测漏掉、后来补上的。漏网的后果是:用户在 78 万 token 的会话里随口说一句"切到 core 阶段",直接触发 51.4 万 token 全量重建。
我们拦不住的事:DSH 的插件热重载(那是插件管理器的行为)。所以长会话里别装插件、别改插件,要动就开新会话。
成本闸门:先算"几轮能回本",再决定切不切
从 615 条真实探针记录里挖出 60 次前缀变化,结论很反直觉:
| 类型 | 次数 | 这次未命中的比例 |
| 便宜档 | 35 | 上下文的 0.2% ~ 1.2% |
| 灾难档 | 11 | 上下文的 98% ~ 99% |
而且看不出和"改了多少字节"有关:改 98,778 字节可能只花 708 token;改 481 字节可能花掉 581,830 token。
便宜是运气,贵是风险。 所以成本一律按最坏情况估(整段上下文全价),然后算:
回本轮数 = 最坏成本 ÷ 每轮省下的 token(被摘掉的字节 × 0.3)
回本超过 3 轮就不自动切(switchPaybackTurns)。显式命令不受这条限制——你亲口要求的不该被经济账拦住。
想让工具表"只增不减"?开累积披露
accumulateDisclosure: true
一旦某组工具在本会话里露过面,之后就不再收回。好处是每次切换的差异更小、前缀缓存更稳;代价是瘦身效果会随会话变长而衰减。所以默认关闭,由你显式打开。route_reset 会清空累积状态。
一个必须知道的边界
这个插件只管"事前削减",不管"事后压缩"。 长会话真正的大头是历史消息,请交给 dsh-command-context-trim(/trim)或 compaction 类插件。一个会话里两者配合的顺序是:先 /trim 削历史 → 再切阶段,这样全价重建的基数更小。
与其它插件的共存边界(重要)
| 情况 | 说明 |
| 别的插件也在 tools/pre-execute 上做决定 | 安全。本插件对放行的工具一律 next() 往下传,不会盖掉别人的拒绝;只有它自己要拦时才短路 |
| 装了自动压缩 / /trim 类插件 | 建议搭配。压缩时不要同时切阶段:压缩本身要复用前缀,再动工具表会让它白干 |
| 装了另一个工具路由器(如 loadout 类) | 不要同时开。两个都在收窄工具面时,行为不可预测——关掉其中一个 |
| 装了 QQ / 消息类插件的门禁 | 只要那个门禁也在 pre-execute 上按同样规则 next(),就能共存;如果你发现消息发不出去,先把本插件 enforceStage 关掉二分排查 |
一句话:本插件永远站在"少拦一次"这边——算不清就放行、缺服务就降级、出异常就 next()。
五之四、🧠 三个"更聪明"的能力(v1.16)
三个都不发额外请求、不调模型,所以不会多花你一分钱上下文。
1. 语义打分路由(默认开)
关键词没命中时,用本地字符统计再猜一次。
| 你说的话 | 免关键词也能认出 |
| 帮我把那个按钮挪一下 | unity-ui |
| 跑一下编译看看哪里报错 | unity-code |
| 给我加个背景音乐 | audio |
| 今天天气怎么样 | 不切(返回 null) |
规则很简单:领先第二名不到 25% 就不猜。猜错也不会立刻切——它和关键词走同一条闸门链(上下文闸门 → 成本闸门 → 迟滞)。
intentRouting: true # 关掉就退回纯关键词 intentMinScore: 2.0 # 分数门槛,调高更保守 intentMinMargin: 0.25 # 领先幅度,调高更保守
2. 空转工具画像(默认开)
记录每个工具真正被调用过几次,写在 ~/.dsh/minimal-router/tool-usage.json。
调 route_status,里面多了一段:
"toolUsage": {
"unusedTools": 62,
"unusedRatio": 0.45,
"unusedGroups": [{ "tag": "unity", "unused": 12, "total": 26 }],
"advice": "有 62 个工具自安装以来一次都没被调用过;对应的插件可以考虑卸载" }
它只给建议,不会替你卸插件——卸载是不可逆的跨项目操作。
usageTracking: true
3. 自适应阶段(默认关)
从最近 20 次真实调用里学:某组占 60% 以上、且至少 6 次,才在 auto 阶段提议切换。
adaptiveStage: false # 默认关;想试就打开 adaptiveWindow: 20 # 看最近多少次调用 adaptiveMinCalls: 6 # 至少命中这么多次 adaptiveMinShare: 0.6 # 且要占到 60%
为什么默认关:它会自动改工具表,而切一次可能要付整段前缀的重建成本(实测最贵 51.4 万 token)。打开了也仍然要过成本闸门和迟滞,一次命中不会切。
三个能力在 route_status 里怎么查
| 字段 | 含义 |
| lastIntent | 最近一次语义判定(猜不准就是 null) |
| toolUsage | 空转工具画像 |
| adaptiveStage / lastAdaptive | 自适应开关和最近一次信号 |
v1.16 起共 312 项测试(新增 intent 11、usage 6、adaptive 7)。
五之五、🧠 三件"主动的聪明"(v1.18)
前面三个能力是"被动响应";这三个会自己判断。
1. 智能开关:只在划算的时候瘦身(默认开)
切阶段前先算一笔账:
重建成本(≈ 当前上下文全价)÷ 每轮收益(被摘掉那部分工具声明的 token)= 回本轮数
- 回本 ≤ 3 轮 → 照常物理瘦身
- 回本 > 3 轮(典型:50 万 token 的会话)→ 只提示、不瘦身
因为在这种会话里切一次要付 50 万全价,却只省 2.6 万/轮 —— 19 轮才回本,白折腾。
autoRestrictPolicy: true # 关掉就恢复"只要切了就瘦"
显式 route_stage 不受影响:你自己要求的,照办。
2. 主动建议:不确定的时候,说一句而不是沉默
语义分没到"敢切"的门槛、但明显有感时,不切阶段,只在尾部提示里加一行:
Tip: looks like art; if so, route_use(["art"],3).
把决定权交回模型,零额外请求,仍然受 200 字硬上限约束。
3. 拦截回收统计:拦得对不对,有数了
被拦之后 2 分钟内,模型换了个工具继续干 → 记一次"自己恢复"。
route_status.denyRecovery 给出:
{ "denied": 12, "recovered": 9, "rate": 0.75, "note": "拦截后多数能自己换路,阈值合适" }
恢复率低(比如 0.25)说明:拦截太严、或者提示文案太模糊。
4. 本机调参脚本
node scripts/tune.mjs --days 7
读 ~/.dsh/minimal-router/ 下的活动日志和工具画像,直接给建议:拦截是不是太多、有多少工具从没用过、成本闸门是不是经常拦。数据不出本机。
六、三个铁血规则(不是配置项,改不了)
| 规则 | 说明 |
| 死循环体检 | 写文件前本地扫描代码。发现 while(true) / for(;;) / do{}while(true) 且循环体里没有 break/return/throw → 直接拒绝写入,并告诉你在第几行。正常代码、注释里的、字符串里的、grep "while(true)" 都不会被误杀 |
| 越界拦截 | 在 core 阶段调 meshy_ 会被拦,并明确告诉你 请立即调用 route_stage("art") |
| 逃生门 | route_ / guard_* 永远放行,任何情况都不会把你锁死 |
七、自带监控(不用额外装)
这个包里自带探针,会记录每次请求的真实账单:
toolsChars : 43,238 ← 工具声明占多少字节 promptTokens : 25,688 ← 这次请求一共多少 token cacheReadTokens: 25,472 ← 其中命中缓存的 hitRate : 99.16% ← 命中率 prefixSig : 9515b76a ← 前缀指纹(变了就说明缓存要重建)
对 AI 说「调 cache_probe_report」就能看到。没有这个数字,你永远不知道自己省了多少。
只看当前会话:scope: "session"
默认报告是全部历史的平均值,对"我现在这个会话花了多少"没什么帮助。加上作用域:
调 cache_probe_report({"scope": "session"})
返回里会多出 session(会话指纹,只存哈希,不存原始 id)、sessionTotal,以及只统计这个会话的 summary。
实测一次:session: "8c144bfe"、sessionTotal: 1、lastHitRate: 0.0097。
那一次恰好是重载插件后的第一个请求 —— 命中率 0.97% 就是"一次全价重建"的样子。
这也是为什么文档一直强调:长会话里别装/改插件。
八、常见问题
Q:会不会把我卡住? 不会。三个逃生门工具永远可用;最坏情况下在「设置 → 插件」里关掉这个插件,限制立刻全部消失(不用重启)。
Q:会不会改我的文件? 不会。它只做两件事:往上下文尾部加一行不超过 200 字的提示;在工具执行前做检查和拦截。
Q:为什么我的模型换成别的会不一样? deepseek-flash 支持"系统提示追加到历史"这种机制,所以尾插几乎不破坏缓存。换成不支持它的模型时,这个插件会自动降级并大声警告(见下方"降级保护")。
Q:promptTokens 怎么还是几十万? 那是你的对话历史,不是工具。开关插件前后对比 toolsChars 才说明问题。历史长了就会被压缩(compaction),那是另一个话题。
Q:为什么不能全自动适配所有领域?非要我跑一次 route_init? 因为插件秉持 "绝不误杀" 的安全原则。
在你不指定新领域的情况下,它不敢瞎猜你新装的工具是干什么用的——万一猜错,你就被拦在半路上,那比不省 token 惨得多。所以对没被任何阶段认领的工具,它的默认动作只有一个:全部放行。这样一来安全了,但也就达不到瘦身效果了。
route_init 是一个 "智能扫描仪":它会把你环境里所有还没分类的工具扫出来,连"这个组有几个工具""有没有被某个阶段认领"一起告诉你,并生成一份模板。你只需要花 1 分钟确认一下(改改名字、写两句你平时说的话),以后它就全自动为你省钱了。
一句话:不是它不想全自动,是"全自动乱猜"会让你付出更贵的代价。 1 分钟确认,换的是以后永远不会被误杀、又一直省钱。
九、装在哪 / 怎么卸载
- 插件目录:C:\Users\Leo\Documents\deepseek-harness\default-workspace\dsh-minimal-router
- 安装:让 AI 执行 plugin_manager install_bundle,目标填上面这个目录
- 卸载:设置 → 插件 → 移除
- 改完代码必须关掉再打开一次(link 安装不会热更新)
十、附:作者实测的完整账本
| 项目 | 数值 |
| 工具数 165 → 66 | −99 个 |
| 工具声明 131,694 → 43,238 字节 | −67.2% |
| 每轮 promptTokens 47,885 → 25,688(纯净新会话) | −46.4% |
| 切换阶段的一次性代价(小会话) | 约 3,205 token |
| 切换阶段的一次性代价(50 万 token 的大会话) | 约 512,000 token 全价 ⚠️ |
| 缓存命中率 | 99.16% ~ 99.9% |
| 自测 | 277 项(router 177 + guard 21 + probe 31 + fuzz 12 + instrument 28 + install-elsewhere 8),三平台全绿 |
| 覆盖率 | 90.32% 行覆盖(3649/4040,Node 内置 V8 coverage,零依赖) |预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
qwq1223211/dsh-minimal-router
按当前任务只暴露必要工具,减少上下文开销
相关插件 · 其他
模型破甲清洗HunYiSage/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 16,993已汉化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,269已汉化DSH
70.8
这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。