前言¶
在 DSH 里切到视觉模型后,若会话历史里已经堆了很多截图或附件,请求有时会在上游网关处直接被拒:错误里常见「单请求最多 N 张图片」一类说明。适配器 dsh-llm-pi-ai 默认按 base64 体积(maxRequestImageBytes,常见默认 20 MiB)做预算,并不按张数限流,因此可能出现「总字节仍在预算内、但图片张数已超过网关硬上限」的情况。官方 dsh-compaction-image-offload 主要识别 IMAGE_OFFLOAD_REQUIRED,对这种 INVALID_REQUEST 类张数错误往往帮不上忙,会话会逐步卡死——再发「继续」也每步失败。
下面介绍社区插件 dsh-image-count-guard(维护者 MacilyDots,分类:工作流):在网关按图片张数拒绝请求时,把最旧的图片卸载为占位文本并重试,复用官方 image/offload 投影,尽量恢复已卡死的视觉模型会话。
这是什么¶
dsh-image-count-guard 是 DeepSeek Harness 的兜底型工作流插件(npm 包名 dsh-image-count-guard,当前资料中版本 0.1.0,MIT 许可证)。它挂在 agent/request-error 瀑布流上:当失败信息匹配「图片张数上限」类英文表述时,统计当前面上尚未 omitted 的图片出现次数,按模型请求顺序选出最旧的一批写入 image/offload 决策,并返回 { kind: 'retry' } 重试该步(不消耗 provider 的重试预算)。
与官方卸载插件的分工如下(资料原文表格):
| 情况 | 由谁处理 |
|---|---|
适配器因字节预算自行拒绝(IMAGE_OFFLOAD_REQUIRED) |
官方 dsh-compaction-image-offload |
上游网关因图片张数拒绝(如 INVALID_REQUEST 等) |
本插件 |
两者写入同一类 image/offload 事件,语义与占位、回放、token 与 KV cache 行为与官方卸载一致;本插件不依赖官方 handler 的注册顺序,只要求 image/offload 投影已注册。
它要解决的具体问题¶
资料中以 OpenCode Go 为例:网关单请求硬上限为 20 张图片。而 dsh-llm-pi-ai 仅按 base64 字节预算时,可能出现:
- 会话历史里图片不断累积(资料实测一例:36 张,原始约 11.79 MiB,base64 约 15.72 MiB);
- 切换到视觉模型(如
opencode-go/deepseek-v4.1-flash)后,15.72 MiB 仍低于 20 MiB 默认预算,适配器认为可发送,将全部 36 张 inline 发出; - 网关返回
400 INVALID_REQUEST:a request may include at most 20 images; - 官方 image-offload 不识别该错误 → 步骤失败;
- 此后该会话每一步都会失败,会话完全卡死。
本插件则在匹配到张数限制文案后,卸载 max(1, total - (limit - safetyMargin)) 个最旧出现位置(total 为当前未 omitted 的图片出现次数),每次重试至少 omit 一处,因此恢复过程会终止:要么请求通过,要么无图可卸、原失败仍为终态(不会无限重试)。
错误文案匹配需同时包含 image 与数量短语,资料列举的模式包括:at most N images、maximum of N images、no more than N images、up to N images、too many images 等。
安装与启用¶
安装方式来自仓库 README:在插件源码目录下执行 PowerShell 安装脚本(脚本会手工改 profile 三处:dependencies、dsh.profile.bundles、pnpm-lock.yaml,并复制一份 node_modules 副本且不运行 pnpm install;修改前备份到 .backup\<timestamp>\,仅保留最近 5 份)。DSH 主目录取自 $env:DSH_HOME,否则为 ~\.dsh。
安装后必须重启 DSH。
# 在插件源码目录执行
pwsh -File .\install.ps1 # 安装到 desktop profile(默认)
pwsh -File .\install.ps1 -Profile web # 安装到指定 profile
卸载:
pwsh -File .\install.ps1 -Uninstall
说明:本插件以当前 DSH 进程权限运行;安装前请自行查看 GitHub 源码 与 LICENSE,确认符合你的环境与合规要求。DeepSeek Harness 生态强调「一切皆插件」;社区目录站点(如 SkillHub)与 DeepSeek / 幻方无官方从属关系,本文不以「官方应用商店」口吻描述安装来源。
安装结束时,install.ps1 会打印四项静态检查:deps / bundles / node_modules / lock。
可选配置¶
默认无需配置。若需覆盖,在 profile 的 cordis.patch.yml 中按 id 写入:
- id: image-count-guard
config:
defaultImageLimit: 20 # 错误文案未给出数字时假设的上限
safetyMargin: 2 # 卸载后保留的余量,避免再加一张又失败
maxOffloadPerRetry: 80 # 单次重试最多 omit 的图片出现次数
典型用法与验证¶
恢复已卡死的会话(联调验证)
- 安装插件并重启 DSH;
- 打开此前因图片张数超限而卡死的会话,发送「continue」;
- 插件生效时,会话应记录
image/offload事件,下一步请求成功。
离线单元测试
在插件目录执行:
node --test test/guard.test.mjs
资料说明共 11 个用例,覆盖匹配、选择、收敛轮次上界、无副作用边界等。
可选装配检查
将插件挂到临时 profile 后运行 --dump-config,输出中应包含 # == dsh-image-count-guard 与 - id: image-count-guard,退出码 0。
诊断:会话内图片统计
PowerShell 示例(路径按你的 DSH 会话目录调整):
# 单会话:张数、已 omit 数、原始字节、base64 估计、平均图大小
node tools\session-image-report.mjs `
"$env:USERPROFILE\.dsh\sessions\<workspace>\session-<id>\session.v4.jsonl.zstd"
# 扫描最近会话,按图片张数排序
node tools\session-image-report.mjs "$env:USERPROFILE\.dsh\sessions" --limit 20
资料中两例会话说明「仅字节预算无法对齐张数上限」:session-c312057f 为 36 张、base64 约 15.72 MiB(低于 20 MiB 默认预算仍会因 20 张上限被拒);session-b15b99cb 为 25 张、base64 仅约 1.52 MiB。这正是需要按张数处理、而非只靠 maxRequestImageBytes 的场景。
适用场景与注意¶
适合谁
- 长期使用视觉模型、会话里截图/附件较多的 DSH 用户;
- 上游网关对单请求图片张数有硬上限,而本地适配器仍按体积预算放行的情况;
- 已安装或计划安装官方
dsh-compaction-image-offload(需其注册的image/offload投影);若官方插件被禁用、投影未注册,本插件在append失败时会捕获并将失败交回下游,无副作用。
已知限制(资料原文)
- 卸载不可撤销:被 omit 的图片之后以占位文本呈现(含只读附件路径),与官方
image/offload一致;若需再看图,需让模型再次调用read_image。 - 错误文案须为英文且同时含
image与数量短语;新网关措辞出现时,需在src/index.js的LIMIT_PATTERNS中增补条目。 - 修改
src/index.js后须重新运行install.ps1同步 node_modules 副本,否则 DSH 仍加载旧代码。
链接¶
- 社区目录页:https://www.skillhub.cn/plugins/MacilyDots/dsh-image-count-guard
- 源码与说明:https://github.com/MacilyDots/dsh-image-count-guard
当网关因图片张数拒绝请求、官方字节卸载又无法识别错误码时,dsh-image-count-guard 用同一套 image/offload 语义卸最旧图片并重试,是工作流里专门补「张数上限」这一环的兜底插件;安装以 README 中的 install.ps1 为准,改配置走 cordis.patch.yml,联调与诊断可按上文命令复现。