dsh-tool-budget
会话级「工具预算」:决定这一轮对话里,模型能看到哪些工具。
用「方案 + 三档级别」代替逐个勾选一百多个工具,并给出切换工具表的成本估算、每个工具真实被调用的次数,以及基于本会话表现的调整建议。
衍生自 suqing114/dsh-tool-switch 0.3.0(MIT)。本仓库保留了它的核心能力(按会话遮罩工具、调用次数扫描),在其上重做了方案体系、三档级别、成本估算与本会话学习。上游变更可按需合并。
它解决什么
模型每一步都会看到完整的工具清单。清单越长:
- 每次请求的提示词越大(工具定义常驻在系统提示里);
- 模型选错工具、把能力用错场景的概率越高。
关掉当前任务用不到的工具,同时保留「它存在但暂时别用」的中间档,比全开或全关都更划算。
代价是:改工具表会让前缀缓存失效一次。本插件把这次重付量化出来,让你在「省下的」与「重付的」之间做决定。
安装
# 本地目录(开发时)
dsh plugin add link:C:/path/to/dsh-tool-budget
# 或从 npm(发布后)
dsh plugin add dsh-tool-budget
装好后输入框下方会出现「工具预算」胶囊;点开就是面板。
面板分区
自上而下:当前状态(常驻)→ 成本估算(常驻,默认展开)→ 模式 → 方案 → 工具列表 → 学习。
- 常驻区(标题 + 当前状态 + 成本)在滚动时固定,其余分区向下滚动;
- 每个分区都能折叠,折叠状态只存在内存里,不影响任何数据;
- 工具列表默认全部收起,组头显示
开/降/关三枚计数胶囊。
三档级别
| 级别 | 对模型可见 | 能否调用 | 用途 |
|---|---|---|---|
normal |
是 | 是 | 正常 |
warn |
是 | 否(guard 拒绝并说明原因) |
想让它知道有这个能力,但现在不该用 |
hidden |
否 | 否(从 schema、PTC 绑定与执行集合一起移除) | 彻底不出现 |
两条硬规则:
- 核心三件套永不可关:
tool_budget、present、ask_user_question。关掉它们会导致面板无法打开或结果无法交付。 - 受保护工具可关但需确认:
read/write/edit/grep/glob/pwsh/ops_*等文件与命令类工具。它们被误关的代价最高,所以要求二次确认。
模式
| 模式 | 面板行为 | 模型侧常驻开销 |
|---|---|---|
auto |
模型自己调用 tool_budget 恢复被关的工具 |
200 token |
ask |
模型停下来告诉你缺什么能力,由你决定是否恢复(默认) | 20 token |
off |
插件完全不生效:不遮罩、不注入工具,面板只做预览 | 0 |
off 下仍可勾选、仍可看统计,但改动不会落盘、方案不能应用——切回 ask 才生效。
方案(方案 = 场景包 = 学习包,同一件事)
一组「哪些组/插件应该是 normal、哪些是 hidden」的规则。三种来源:
- 预设:
全部保留、只聊天、代码 + 文件、查资料 + 网页、图像 + 设计、办公文档。 它们是规则(按功能组 + 插件前缀声明),不是固定名单,所以随实机安装的插件自动展开。 - 用户保存:把当前状态存成自己的方案,可改名、可删除;通过工具列表调整后会提示「已改动 N 处」,保存即写回该方案。
- 学习候选:从历史会话里聚类得到的方案。只读,必须先「采用」才变成普通方案(之后可改名、可调整)。
操作方式:
- 勾选一个或多个方案 → 点「应用这组」→ 按并集生效(包取并集;若包含「全部保留」则回到全开);
- 应用会清空精细调整(工具/分组/插件级的手动设置)并指向该方案;
- 「存为方案」会查重(同一组级别组合已存在时提示),可选择强制保存。
自动操作一览(触发条件与依据)
| 自动行为 | 触发条件 | 依据/实现 |
|---|---|---|
| 切换工具表 | 级别集合或模式变化 | syncSession 计算 allow/warn 两个集合,与上次 signature 不同才重建 restrict/guard;相同选择不重复安装 |
| 计一次脏数据 | 当前 levels 与当前方案基线不一致 | dirtyOf:有方案按方案基线,无方案以「全部保留」为基线 |
| 前缀缓存重付估算 | 勾选与当前选择不同 | pendingSwitch;repay = (context − toolBlock) × missFactor,只算一次 |
| 内置方案按当前工具表展开 | 每次读取状态 | 内置方案是规则,resolveLevels 实时展开,不需要人工维护 |
| 记录内置方案变化 | 工具名集合的签名变化 | catalogSignature(工具名排序后 sha1 前 12 位)与快照比较,变化写入 lastChange |
| 切换工作区后刷新学习 | state.workspace 与 learning.workspace 均非空且不同 |
面板打开时触发一次,每个工作区每次面板生命周期只触发一次 |
| 学习进度可见 | 开始学习后 | scan 每 8 个文件让出事件循环、每 40 个写一次进度;前端 1.2s 轮询 |
| ask 模式提醒 | 模型调用被 guard 拒绝 | 拒绝原因写进工具结果;本会话拦下次数用于学习建议 |
不会自动做的事:不会自动改级别、不会自动应用方案、不会自动关闭工具、不会把统计写进提示词。
成本怎么算
三个输入:
- 隐藏工具的字符数:被 hidden 的工具的 description + 参数签名总字符数;
- 当前上下文:会话日志里
usage行的input + cacheRead取最大值; - 历史平均每轮:同一批
usage行的均值。
四个公式:
saved = 隐藏工具字符数 ÷ charsPerToken # 每轮省下的 token
repay = (context − toolBlock) × missFactor # 切换后前缀缓存失效,重付一次
net = saved − 常驻开销 # 每轮净收益
projected= 历史平均每轮 − saved + 常驻开销 # 切换后预计每轮消耗
阈值 = 历史平均每轮 × thresholdMultiplier # 超过即标红:这次重付不划算
常驻开销固定为:auto 200、ask 20、off 0。这两个数字不开放修改,它们是写进提示词的固定文案长度近似值。
五个可改参数(面板「参数」里展开):
| 参数 | 默认 | 含义 |
|---|---|---|
charsPerToken |
3.6 | 多少个字符算一个 token(中英混排的经验值) |
missFactor |
1 | 重付系数;保守估计可调大到 1.5 |
thresholdMultiplier |
2 | 红色阈值 = 平均每轮 × 该倍数 |
priceInput |
2 | 每百万非缓存输入 token 的价格(展示用) |
priceCache |
0.2 | 每百万缓存命中 token 的价格(展示用) |
误差来源:字符/token 比例随语言与内容波动;实际缓存命中率受服务端策略影响;context 取的是历史最大值而非你此刻的真实上下文。
学习
历史学习(面板「开始学习」):
- 扫描
~/.dsh/sessions/<工作区>/<会话>/session.v4.jsonl.zstd,只看当前工作区,按修改时间取最近 400 个(默认); - 读每个会话实际调用过的工具,映射到功能组;
- 对组集合做贪心 Jaccard 聚类(阈值 0.5),簇至少包含 4 个会话才产出方案;
- 覆盖率(这些组在簇内会话中同时出现的比例)低于 0.6 丢弃;最多 6 组;取前 3 个簇;
- 置信度 = 该簇内「同时出现」的会话占比。
学习是手动的:不会因为对话变多自动重算;新对话要再点一次「开始学习」才会算进去。
本会话学习(面板「本轮调整建议」):
- 对话轮数达到阈值(默认 3,可改 1–20)后开始给建议;
- 规则一(恢复):本会话里被 guard 拦下过、当前又是 hidden 的组 → 建议恢复;
- 规则二(休眠):30 天调用为 0、且组内没有受保护工具、当前不是 hidden → 建议休眠;
- 每条都可单独执行,执行后可「↺ 撤销」。
调用次数
三个口径:本会话 / 近 30 天 / 全局。数据来源是会话日志里的 tool/call 记录,按文件 size + mtime 缓存,只解析变化过的文件。
工具行显示该口径下的调用次数,未调用显示「未用」;组头显示该组总次数;工具栏有「未用」与「已关闭」两个互斥筛选。
统计只进面板,不进提示词——否则每次数字变化都会破坏前缀缓存,还会把「次数」变成模型的决策依据。
数据文件
~/.dsh-tool-budget/:
budget.json:全局偏好(模式、语言、计数口径、学习阈值、成本参数)、保存的方案、每个会话的级别与所指方案、内置方案快照(builtins);usage-cache.json:每个会话日志的调用次数与天数桶;learning.json:上一次聚合出的学习候选与状态。
接口
HTTP(仅回环):
| 路由 | 方法 | 用途 |
|---|---|---|
/tool-budget/state |
GET/POST | 读取面板状态 / 执行操作(级别、方案、改名、保存、采用…) |
/tool-budget/usage |
GET | 调用次数(三口径) |
/tool-budget/cost |
GET/POST | 成本估算;POST 传 plans 预览切换结果 |
/tool-budget/learning |
GET/POST | 学习状态 / start、clear、status |
/tool-budget/preferences |
POST | 语言、模式、视图、口径等偏好 |
工具:tool_budget,动作 list/on/off/warn/reset/profile/pack/cost。
命令:/budget(list、reset、all on、all off、on|off|warn <target>)。
边界与已知限制
- 只在会话级生效:没有全局默认;每个会话各自记级别。
- agent 作用域注册的工具关不掉:它们不在
restrict的作用范围内,面板标「会话固定」。 - 切换必有一次重付:省 token 与破缓存的权衡是本质,不是缺陷;面板把它算给你看。
- off 模式不落盘:只能预览,避免「以为关了其实没关」。
- 统计依赖会话日志:日志未落盘的当前轮不会立刻计入。
- 只有本工作区的学习:不会混扫其他项目的会话。
开发与测试
node test/test-model.mjs # 级别解析、方案、成本公式、聚类、插件分类、字典完整性
node test/test-usage.mjs # 日志解帧、次数统计、缓存增量
DSH_APP=path/to/react-test/package.json node test/test-panel.mjs # jsdom 挂载面板
test-panel.mjs 需要一份带 react/react-dom 的目录(DSH_APP 指向它的 package.json),以及 jsdom。
许可
MIT。见 LICENSE;血缘声明见 package.json 的 derivedFrom 字段。
No comments yet. Be the first to write one.