dsh-result-budget:给工具结果按模型上下文窗口设限

前言

在 DeepSeek Harness 上跑本地小模型时,一个 cat 或 read 就可能塞满上下文:read 的默认上限是 2000 行 / 50 KB,bash 是 16000 字符。对 128k 的云端模型无所谓,对 4k–32k 的本地模型,一次调用就能把窗口占满。而自动 compaction 只在对话已经接近窗口时才触发,挡不住单个超长结果。dsh-result-budget 就是用来在这条通路上加一道按窗口计算的预算。

下面是这个插件的定位、机制、安装方式和注意事项。

这是什么

dsh-result-budget 是 DeepSeek Harness 插件,由 Wildchiken 维护,分类是「模型推理」。它的用途是让每个工具结果的大小贴合当前模型的上下文窗口,使本地和小窗口模型不会被单个超长输出淹没。预算随模型切换而变化,不是为某一个具体模型调好的固定数字。

插件只改变模型看到的内容,会话日志里仍然保留工具的真实输出,事后仍然可以查看。它的写入方式与宿主自带的 tool-result pruner 用的是同一对原语:先按 compaction/prune 的 shadow 价格计算,再以 tool/result 替换节点表面。这依赖 dsh-token-meter,它属于基础 bundle。

为什么需要

官方 dsh 用固定数值限制工具输出。对小窗口本地模型来说,问题主要有三点:

1、50 KB 的 read 大约等于 13k token,一个 8k 窗口的模型调用一次就满了。
2、自动 compaction 只在对话已经接近窗口时才运行,无法阻止单个结果把窗口填满。
3、小模型在长上下文里退化很快,即使不溢出,无关输出也会拉低质量和速度。

工作机制

在每一步之前,插件对从上一步以来到达的结果做处理:

budget = max(ratio × (contextWindow − reservedOutput), minTokens)   # 如果设置了 maxTokens,则被其封顶

contextWindow 与预留输出的取值方式和官方 dsh-compaction-basic 一致:通过 llm.resolveModelInfo 取会话路由到的 provider/model;预留输出取请求的 maxTokens,没有则取模型默认值。

超出预算的文本保留开头 75% 和结尾 25%,并在中间插入一行提示,告诉模型怎样查看剩余部分,例如 shell 工具用 grep/head/tail。默认参数下,不同窗口的单结果预算大致是:

窗口(预留输出) 单结果预算
4k(1k) 约 460 token
8k(2k) 约 920 token
32k(4k) 约 4300 token
128k(8k) 约 18400 token(工具自身上限通常先生效)
未知 2000 token

read 的处理不同:它从开头保留完整行,并给出准确的 offset 继续读取。分页文件中间挖洞会被静默跳过,所以不留尾部。如果连一行都放不下,提示会指向 bash 而不是同样的 offset。

token 估算按文本类型区分:每个数字按一个 token 计,标点和中日韩字符逐个计数,字母按单词长度计。宿主使用的固定 4 字符/token 在数字和哈希上偏差最高达 4 倍。这里的权重是在三个本地模型报告的 token 数上拟合的,又在未参与拟合的文件上验证:平均误差 6%,固定比例是 25%。

图片等非文本块直接透传。插件首次见到会话之前的历史不做处理,provider 的 prompt cache 因此得以保留。如果模型没有声明 contextWindow 或查询失败,则套用 fallbackTokens。

安装与启用

按 profile 安装:

dsh plugin --profile <name> add "github:Wildchiken/dsh-result-budget"

作为 bundle,它会作用于该 profile 里的所有 agent。

如果只想让插件覆盖某一个 agent preset,可以跳过 bundle,在 preset 的 plugins 里列出它,此时它只覆盖该 preset 的 agent:

- insert:
    - id: preset-local
      name: '@deepseek-ai/dsh-agent-preset'
      config:
        id: local
        name: Local
        plugins:
          # ...该 preset 自带的工具...
          - id: result-budget
            name: dsh-result-budget
            config:
              ratio: 0.15

也可以从自己的插件里组合它:

import { installResultBudget } from 'dsh-result-budget'

export function apply(ctx) {
  ctx.inject(['llm'], (ctx) => installResultBudget(ctx, { ratio: 0.1 }))
}

配置项

Key 默认值 含义
ratio 0.15 单个结果可占用可用窗口的最大比例,取值 (0, 1]
minTokens 384 预算下限
maxTokens null 可选预算上限;默认不设,避免大窗口模型丢内容
fallbackTokens 2000 窗口未知时的预算
headShare 0.75 保留文本中开头所占的比例,其余为结尾;read 不使用
exclude [] 跳过的工具名,允许 * 通配,例如 ["mcp_*"]

配置不合法时(未知 key、ratio 越界、非正整数、minTokens > maxTokens)会在加载时报错,而不是静默回退到默认值。

与其他组件的关系

  • tool-result-pruner 只在 compaction 触发时裁剪历史结果;这个插件在结果进入对话时就限制。可以两者同时使用。
  • spill-policy 在基础 bundle 里,固定上限 12500 token,会把完整结果存到模型可读的文件里,并跳过 read。它先运行,这个插件保留的文本结尾正好是 spill 的提示所在位置。结果落在这个预算与 spill 上限之间时不会生成文件。
  • Per-tool caps(readLimit、maxOutputChars)可以保持默认值,这个插件在它们之后运行。
  • 相关项目 argszero/dsh-tool-output-budget 更早出现,同样在结果到达时限定单个结果并保留日志,但它的预算是固定的字符数。想要所有模型用同一个数字可选它;想要预算跟随模型窗口则选这个插件。

效果与局限

README 给出了一组在 Spark X2.6 4B(LM Studio)上通过 headless runner 跑 6 个大量工具输出任务的对比,测试版本 v0.2.1,原始数据在 bench/ 目录:

窗口 插件关 插件开 触达上下文上限的次数(关/开)
8k 7 / 12 12 / 12 4 / 0
16k 9 / 12 11 / 12 1 / 1(插件关另有 2 次超时)
32k 11 / 12 4 / 6 1 / 0
  • 8k 和 16k:按任务配对后,有 7 次只在启用插件时通过,没有一次只在关闭时通过(p ≈ 0.016)。平均耗时也更短(8k 时 48 秒对比 69 秒,16k 时 57 秒对比 108 秒)。
  • 32k:可能反而有害。两次失败都是本来能放下的结果被裁掉了——一个 read 在模型需要的行之前被截断,一个 grep 的关键行落在被删掉的中间部分。32k 的样本很小(启用插件只有 6 次运行)。在 32k 及以上窗口,可以考虑调高 ratio 或不启用插件。
  • 只测了一个模型,任务也是特意选了大量输出的场景,所以反映的是它在哪里有用,而不是普遍性。

其他已知局限:

  • 预算用的是估算而非模型的 tokenizer,只在三个本地模型上拟合,其他模型上可能有差异;对会合并数字的模型来说在数字和哈希上偏高,这类结果会被裁得比实际需要的更早。
  • 被省略的内容模型无法直接读到,除非 spill-policy 存过文件。模型要么重新获取,要么按 shell 工具提示的方式收窄输出重跑,后者意味着带副作用的命令会执行第二次。
  • 小模型可能忽略提示。测试中一个本地 4B 模型跳过了建议的 offset,改用 grep。
  • 默认值只在一个本地模型上验证过。

另外,宿主模型客户端 pi-ai 本身也会限制输出:它把最大输出设为 window − estimated input − 4096,至少为 1。在 8k 窗口下,上下文超过大约 4k token 后模型只剩一个 token,回合会以 max-tokens 结束。这也是上表中插件关闭时大多数失败的原因。

适用场景与结论

适合在本地或端侧跑小窗口模型、且会收到大量工具输出的 DSH 场景。插件以安装时的 dsh 进程权限运行,安装前应当检查其源码与许可证(本插件为 MIT 许可)。

它的价值在于把「固定上限」换成「跟随当前模型窗口的预算」,让小窗口模型不至于被单个结果冲垮,同时保留完整日志。代价是估算存在偏差、被裁内容需要重新获取,且在 32k 以上窗口默认参数可能裁掉本来够用的结果。

插件目录页:https://www.skillhub.cn/plugins/Wildchiken/dsh-result-budget

源码与文档:https://github.com/Wildchiken/dsh-result-budget

需要说明的是,SkillHub 是独立社区站点,与 DeepSeek / 幻方没有官方从属关系。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye