@everclear077/dsh-progressive-tools

toolsinstall failsnpmMIT

Cache-stable progressive tool discovery: a fixed tool_search and tool_dispatch surface on every request, in-memory catalog search, nested dispatch through the Harness pipeline, and a byte-stable native tool list across discovery.

下载量 / Downloads
930
测试时间 / Tested
2026-11-07
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add @everclear077/dsh-progressive-tools

Sandbox test results

StageResult
1 install✗
2 list—
3 mount—
4 boot—
First error
dsh: initialized profile web at /home/node/.dsh/profiles/web

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

DSH Progressive Tools

为 DeepSeek Harness 提供缓存稳定的渐进式工具发现。默认模式从真实首个请求

开始只发送固定的小工具面,完整目录保留在进程内,搜索到的工具仍通过 DSH

原有执行管线完成调用。

<p align="center">

<img src="docs/assets/overview.zh-CN.png" alt="DSH 渐进式工具,everclear077:缓存稳定发现、精简请求面、内存目录、原有管线分发" width="920">

</p>

[English](./README.md)

[文档导航](./docs/README.md) · [快速上手](./docs/getting-started.md) ·

[升级指南](./docs/migration.md) · [问题排查](./docs/troubleshooting.md)

解决的问题

每个可见工具的名称、描述和参数 schema 都会重复占用请求 token。如果后续

再动态改变工具列表,请求前缀也会变化,导致上下文缓存无法继续复用。

默认的 stable-proxy 模式同时保证:

  • 第一次请求就是精简工具面;
  • 搜索前后顶层工具定义和系统文本保持逐字节稳定。

<p align="center">

<img src="docs/assets/stable-proxy-flow.zh-CN.png" alt="stable-proxy 流程:完整注册表留在进程内存,拆成可搜索目录和冻结请求面;三条路径分别直达原有管线、搜索后分发,或被单调 guard 拒绝" width="920">

</p>

搜索只追加对话历史,不改变顶层 tools 数组。真实工具原有的审批、guard、

参数校验、超时、结果策略、延迟上下文和取消信号仍然生效。

实测影响

下表对比 关闭插件(每次请求都把已注册工具全部送上线,本 profile 为

71 个定义)和 当前默认开启(stable-proxy,文件系统工具常驻,

maxResults: 2,线上 9 个定义)。两组使用同一批 8 类任务、100 轮可对

比对话、同一本地 web profile。缓存读是宿主上报的已缓存请求前缀;未缓存

输入是其余仍需发送的 token。

结论先说清楚:日常读写和改文件时,未缓存输入几乎持平,缓存读大约少四

分之五,输出更少,平均耗时更短。多出来的未缓存输入,主要出现在目录浏览

和“证明某个名字不存在”的探测上。

总体 token、缓存与延迟(100 轮)

指标 · 关闭插件 · 开启插件 · 变化

每次请求可见工具数 · 71 · 9 · −87%

未缓存输入 token · 130,122 · 155,823 · +20%

输出 token · 28,532 · 24,418 · −14%

缓存读 token · 3,133,428 · 663,687 · −79%

合计(输入 + 输出 + 缓存读) · 3,292,082 · 843,928 · −74%

提示中的缓存占比(cache / (input + cache)) · 96.0% · 81.0% · −15 个百分点

平均延迟 · 45.2 s · 20.9 s · −54%

p50 延迟 · 31.7 s · 18.8 s · −41%

p90 延迟 · 85.4 s · 34.8 s · −59%

未缓存输入上升,是因为搜索结果(以及首轮 100 测里为证明名字不存在而发起

的搜索)会写入对话历史。缓存读下降,是因为稳定前缀不再携带大量用不到的

schema。计费通常把缓存读标得比新输入便宜;合计列是原始 token 量,不是某

家的价目。

只看日常工作(S1–S7,87 轮,不含假名字探测):

指标 · 关闭插件 · 开启插件 · 变化

未缓存输入 token · 120,753 · 121,105 · +0.3%

输出 token · 26,624 · 20,869 · −22%

缓存读 token · 2,927,348 · 573,831 · −80%

分场景 token

场景 · 轮次 · 输入(关) · 输入(开) · 输出(关) · 输出(开) · 缓存读(关) · 缓存读(开)

S1 心算、不用工具 · 12 · 1,892 · 8,325 · 532 · 364 · 196,852 · 36,231

S2 查看工作区 · 13 · 15,729 · 17,837 · 2,446 · 2,616 · 418,816 · 94,720

S3 新建并回读文件 · 12 · 17,022 · 17,584 · 2,521 · 2,347 · 603,136 · 122,880

S4 阅读 README.md · 13 · 15,841 · 15,594 · 2,600 · 1,567 · 518,912 · 83,200

S5 浏览隐藏目录 · 12 · 38,561 · 27,086 · 12,539 · 8,055 · 367,104 · 76,800

S6 多文件查看 · 13 · 19,695 · 21,036 · 4,832 · 4,768 · 435,712 · 83,200

S7 记住后续口令 · 12 · 12,013 · 13,643 · 1,154 · 1,152 · 386,816 · 76,800

S8 调用不存在的名字 · 13 · 9,369 · 34,718 · 1,908 · 3,549 · 206,080 · 89,856

合计 · 100 · 130,122 · 155,823 · 28,532 · 24,418 · 3,133,428 · 663,687

S1 的 9 工具前缀比 4 工具前缀贵一些,但缓存仍远小于 71 个原生 schema。

S2–S4、S6 不再搜索:read / write / glob / grep 已在稳定面上。S5

用 tool_search 的 status 代替宿主侧长时间摸索,所以更便宜。本表 S8

在插件侧仍以搜索为主;当前行为见后面的补测。

分场景延迟

场景 · 平均(关) · 平均(开) · 变化 · p50(关) · p50(开)

S1 心算、不用工具 · 11.3 s · 7.5 s · −34% · 9.6 s · 6.8 s

S2 查看工作区 · 69.8 s · 20.3 s · −71% · 63.6 s · 18.8 s

S3 新建并回读文件 · 79.4 s · 23.7 s · −70% · 67.0 s · 23.0 s

S4 阅读 README.md · 67.9 s · 15.6 s · −77% · 67.2 s · 16.6 s

S5 浏览隐藏目录 · 47.2 s · 31.8 s · −33% · 38.6 s · 30.6 s

S6 多文件查看 · 33.1 s · 25.6 s · −23% · 31.4 s · 25.0 s

S7 记住后续口令 · 29.7 s · 21.6 s · −27% · 22.9 s · 17.0 s

S8 调用不存在的名字 · 22.1 s · 21.0 s · −5% · 17.8 s · 20.9 s

全部 100 轮 · 45.2 s · 20.9 s · −54% · 31.7 s · 18.8 s

任务结果与前缀稳定性

检查项 · 关闭插件 · 开启插件

完成轮次 · 100 / 100 · 100 / 100

S1–S7 成功 · 87 / 87(100%) · 87 / 87(100%)

S8 未真正 调用 假工具 · 13 / 13 · 13 / 13

S8 在 100 轮里被打分器判成功 · 12 / 13(1 条部分) · 0 / 13(搜索参数里出现假名字即判失败)

本轮顶层工具列表保持稳定 · 100 / 100 · 100 / 100

调用了 tool_search 的轮次 · 0% · 24%(S5 全部,S8 的 12 / 13)

调用了 tool_dispatch 的轮次 · 不适用 · 0%

S1–S7 的任务质量没有回退。100 轮 S8 的打分过严:只要搜索 query 里出现假

名字就算失败,即使从未分发。在当前“不要只为证明某个名字不存在而去搜索”

(未命中的标识符查询返回空结果)之后,单独重测 13 轮 S8:

S8(缺失名字) · 100 轮插件侧 · 后来的 13 轮补测

搜索率 · 92% · 0%

未缓存输入 · 34,718 · 13,404(−61%)

输出 · 3,549 · 2,078(−41%)

平均延迟 · 21.0 s · 11.4 s(−45%)

热路径未缓存输入 · 搜了约 3,500 / 没搜 819 · 716

假工具被调用 · 0 · 0

打分器 成功 / 部分 / 失败 · 0 / 1 / 12 · 10 / 3 / 0

后 3 条部分成功仍是正确拒绝;打分正则没吃到 doesn't exist / can't 这类

写法。

为什么默认要把文件系统工具放到稳定面上

更早一轮 100 测使用 4 工具 前缀(tool_search、tool_dispatch、

skill、ask_user_question)且 maxResults: 5。文件任务要先搜索再分发,

未缓存输入相对关闭插件大约多 80%,主要就来自这里:

100 轮插件侧 · 4 工具前缀 · 当前 9 工具前缀 · 变化

未缓存输入 · 233,716 · 155,823 · −33%

输出 · 34,933 · 24,418 · −30%

缓存读 · 744,898 · 663,687 · −11%

平均延迟 · 31.9 s · 20.9 s · −35%

文件任务搜索 / 分发 · S2–S4、S6 为 100% / 100% · 0% / 0% · —

这是本机当前工具组合下的快照,不是对每个 profile 的承诺。原生目录越大,

缓存节省通常越大;如果任务总是要发现延迟工具,对话历史仍会吃搜索结果。

改 alwaysVisible 或已装插件集合之后应重新测量。

主要能力

  • 真实 AgentLoop 第一次请求即发送最小工具定义。
  • 搜索前后原生工具数组和 Code Mode SDK 保持稳定。
  • 返回精确工具名称、完整描述和参数 schema,不再激活整个工具族。
  • 工具族级发现:每条命中同时列出所属工具族的全部成员名,一次搜索即可

铺开一个插件的完整可分发工具面。

  • status 动作可浏览完整目录;可选 statusGrantsDiscovery 供受信任部署

一次性解锁全部名字。

  • 对话体量有界增长:搜索结果只记录本次新增的发现名单,恢复所需的累积

状态走呈现元数据,不占对话 token。

  • 确定性的 BM25 风格词法排序,覆盖工具名、描述、嵌套参数说明、枚举、

工具族元数据及多语言别名。

  • tool_dispatch 使用原始工具定义进行运行时参数校验和执行。
  • 单调 guard 阻止隐藏工具被直接调用,只允许分发器拥有的嵌套调用树进入。
  • 同时支持继承工具和 Agent 自有工具的渐进式隐藏。
  • 从顶层结果和 Code Mode 日志恢复已发现工具。
  • 可选 Skill 到工具族的发现联动。
  • 保留 dynamic 兼容模式,供必须动态暴露原生 schema 的场景使用。
  • Cordis effect 完整可逆,支持卸载和配置重载。

运行时兼容性

0.6.0 版本适配运行时 0.1.7-rc.2,核心 peer 依赖固定到该验证版本,

不承诺兼容旧运行时或后续预发布版本。安装时固定下面的 npm 版本,避免装到后续发布。

安装

从官方 npm 源把插件加入 Harness profile:

dsh plugin --profile web add npm:@everclear077/dsh-progressive-tools@0

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::2,最后更新 2026-09-25

Links

GitHub · Homepage · npm

Same category