dsh-tool-search
Hermes-style tool search & slimming: progressive disclosure, semantic search, describe, and call long-tail tools on demand while core tools stay eager.
Install
dsh plugin --profile web add dsh-tool-search
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
dsh-tool-search






DeepSeek Harness(DSH)的工具搜索与瘦身插件:Hermes 风格渐进式披露。当工具目录变大(挂了多个 MCP 服务或插件工具)时,每个工具的 JSON schema 都会在每一轮注入模型上下文——大量 token 花在本次任务根本用不到的工具上。本插件把长尾工具折叠到三个桥接工具后面,让模型通过配置的 rerank 模型按需搜索、加载和调用。
- 核心工具永远直通——文件/终端/必备工具始终直接可见。
- 桥接工具——
tool_search/tool_describe/tool_call替代被折叠的 schema。 - 分级披露——目录越大,模型可见清单自动越精简。
- 对话式配置——随包技能
tool-slimmer-setup通过对话帮你分组,并引导配置 rerank 模型。 - 全局或按项目——分组/匹配器存在
~/.dsh/dsh-tool-search.json(全局)或<workspace>/.dsh/dsh-tool-search.json(按项目),由你选择。
安装
dsh plugin --profile web add dsh-tool-search
工作原理
灵感来自 Hermes Agent 的 Tool Search。每一轮,插件的 system-prompt/assemble 监听器计算档位并替换模型可见工具:
档位 · 条件 · 模型看到
0 · 目录很小 / 无可折叠工具 · 全量直通,桥不出现
1 · 分组清单塞得进预算 · 桥 + ## 组 名称/描述清单
2 · 只有纯名称塞得进 · 桥 + 纯名称清单
3 · 纯名称也超预算 · 桥 + 每组一行摘要(组名: 数量)
预算 = min(thresholdPct% × 上下文窗口, listingMaxTokens),每轮重算。清单挂在 runtime context 上,不会被 complete prompt 组合丢弃。
动态注入:搜索、查看或调用某个延迟工具后,该工具会进入会话的可见集(LRU 上限 maxWarmTools),完整 schema 注入后续轮次的上下文——模型按需把工具拉进上下文,而不是永远堆着全部工具。
tool_call 执行时,插件以真实工具名走 ctx.tools.execute——审批、守卫、会话事件全部对着底层工具,永远不是桥本身。tool_search 用配置的 rerank 模型排序;未配置 matcher 或 rerank 失败时降级为关键词匹配(精确名 > 名字词 > 描述词),永不报错。
对话式配置
对你的 agent 说:
帮我配置 dsh-tool-search 的工具分组
tool-slimmer-setup 技能会读取目录、提出分组方案、与你确认、询问配置全局还是按项目,并引导你配置 rerank 匹配器(tool_search 和预加载的前置条件)。
配置
静态调优放在 profile 的 cordis.patch.yml(改后需重启):
- id: tool-search
config:
enabled: auto # auto | on | off
thresholdPct: 5 # 清单预算占上下文窗口的百分比
listingMaxTokens: 4000
configScope: auto # user | project | auto(存在项目文件时优先)
core: [todo_write] # 额外永远直通的工具
maxWarmTools: 8 # 动态注入工具的 LRU 上限
工具分组、匹配器和预加载放在运行时文件(用户级为 ~/.dsh/dsh-tool-search.json):
{
"version": 1,
"scope": "user",
"groups": [
{ "name": "git", "tools": ["git_status", "git_diff"] },
{ "name": "mcp-github", "prefixes": ["mcp_github_"] }
],
"matcher": {
"endpoint": "https://dashscope.aliyuncs.com/compatible-mode/v1/rerank",
"apiKey": "sk-...",
"model": "qwen3-reranker",
"topN": 20
},
"preload": { "enabled": false, "topK": 5 },
"core": ["read_file", "write_file"]
}
groups:精确工具名和/或名称前缀;工具归入第一个命中的组。matcher:OpenAI 兼容的/v1/rerank端点——唯一的匹配器类型。未配置时tool_search返回引导提示。preload:可选;启用(需配 matcher)后,会话首轮会用任务描述语义预加载 top-K 命中工具进 eager 集。- 文件按 mtime 热重载,下一轮生效。
桥接工具
工具 · 作用
tool_search(query, limit?) · 搜索延迟目录(rerank,关键词兜底),返回排序后的 {name, description, group} 匹配;命中工具注入可见上下文
tool_describe(name) · 加载单个延迟工具的完整 schema;该工具注入可见上下文
tool_call(name, arguments) · 以真实工具名调用延迟工具;审批/守卫/事件都走真实工具;该工具注入可见上下文
设计要点与坑
- 瘦身只改写模型可见表面(
system-prompt/assemble),注册表保持完整,延迟工具仍可执行。 - 桥、两个配置工具和
skill永远 eager,不会被自己延迟。 - PTC(
run_code)作用域保留传输工具,不保留声明。 这类作用域的线上工具表已被dsh-tools折叠成只剩run_code,所有声明挪进tools:sdk提示词段——那正是要瘦身的 token 所在。插件因此不改工具表(改写会把run_code从提示词里抹掉),而是重渲染该段:只声明 eager 核心加桥工具,并把延迟目录以run_code版表头注入运行时上下文。段所用的生成器从段文本自身判定(interface ToolArgsMap= TypeScript,TypedDict= Python);无法识别的文本整段放行,绝不用错语言重写。both模式下run_code保持 eager(桥也拒绝按名调用它)并同样重写声明;native 会话不受影响。 - dsh 0.2.1-rc.3 挪动了两个接缝。 PTC 渲染器搬到
@deepseek-ai/dsh-tool-executor-ptc,@deepseek-ai/dsh-tools不再导出它们,因此改为运行时动态导入:新包优先、dsh-tools兜底;两个都不在的宿主按"关闭声明重写"加载,而不是让整个依赖图导入失败。该版本还只把sections/contexts/variables交给瀑布、工具表由宿主在之后追加,所以没有自带工具表的装配会原样返回:这类宿主上本插件提供声明重写与目录注入,工具表瘦身只对更早版本生效。 到 0.2.1-rc.4 / 0.2.2-alpha.2 / 0.2.2-rc.1 这条分工彻底化:原生 schema 归宿主的工具执行器所有,步骤的ResolvedToolSet(context.toolSet)会传进每一处目录与声明查询,未准入该步骤的工具不会被披露。0.2.2-rc.1 没有改动本插件用到的任何接缝,因此 v0.1.10 只是清单升级。 - 关键词匹配只作为兜底:rerank 是首选排序,未配置 matcher 或 rerank 失败时降级(精确名 > 名字词 > 描述词),搜索永不报错。
- 完整架构见 [DESIGN.md](DESIGN.md)。
链接
许可证
MIT
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::10,最后更新 2026-11-05