dsh-image-guard:DeepSeek Harness 图片预算管理插件

DeepSeek Harness (DSH) 的理念是“一切皆插件”。在多模态会话中,客户端通常按字节或像素计算图片预算,而上游模型(如 vLLM)往往按张数限制输入(--limit-mm-per-prompt.image)。字节预算无法阻止因图片过多导致的 400 错误,且 DSH 的 compact 压缩会重发相同的历史记录,导致重复失败。dsh-image-guard 旨在解决这一问题。

核心功能

该插件运行在 DSH 的 fetch 链路首层,主要处理“请求发送前”和“错误重试”两个阶段。

  • 保留最新 N 张,其余替换为标记:插件会保留最新的 keepRecent 张图片,其余图片被替换为可识别的标记(包含文件名、路径或指纹)。被裁剪的图片不会无声丢失,模型或 agent 需要时可再次获取。
  • 解析上游上限:当上游因图片数量返回 HTTP 400 时,插件会从错误消息 At most N image(s) 中解析上限 N,并按 N−1 张重试;解析到上限后,同进程内后续请求将直接按 N−1 张发送,不再触发 400。
  • 节省视觉 token:每张被裁剪的图片净省约 930 token(实测上限 972 − 标记开销约 40)。设置页实时显示累计节省量。
  • 不修改会话历史:仅修改即将发出的请求体(使用 structuredClone 的副本),前缀缓存保持有效,关闭插件即恢复原有行为。
  • 始终保持在 fetch 链首:插件拦截 globalThis.fetch 的赋值,配合 200ms 看门狗与链上探针兜底,确保它始终位于 dsh-net-proxy 之前,避免代理模式下的绕过问题。

安装与启用

本插件目前尚未发布到 npm,也未被任何插件市场目录收录,无法在 DSH Desktop 的 GUI 插件市场中搜索到。需手动安装。

命令行 profile

dsh plugin --profile <name> add github:mafeis/dsh-image-guard

注意:desktop profile 由 Electron 持有,启动器拒绝对其执行插件管理请求。

DSH Desktop 手动安装

DSH Desktop 加载名为 desktop 的 profile,位于 ~/.dsh/profiles/desktop/。需手动编辑 manifest 并安装依赖。

  1. 编辑 ~/.dsh/profiles/desktop/package.json,在 dependencies 中加入:
    "dsh-image-guard": "github:mafeis/dsh-image-guard"
  1. 在同一文件的 dsh.profile.bundles 数组中追加 "dsh-image-guard"(该字段不存在则在 dsh 字段下新建):
    "dsh": {
      "profile": {
        "bundles": ["dsh-image-guard"]
      }
    }
  1. 安装依赖后重启 DSH Desktop:
    cd ~/.dsh/profiles/desktop && pnpm install --prefer-offline --ignore-scripts

配置与调试

配置文件位于 ~/.dsh/image-guard.json,修改后支持热更新,也可在设置页或通过 /_dsh/image-guard 路由修改。

常用配置项

字段 默认值 说明
enabled true 总开关,关闭后完全透传
keepRecent 12 保留最新的图片张数,其余替换为标记
maxRetries 3 400 后的降级重试次数
learnLimit true 是否从 400 响应中解析上游上限
dryRun false 仅观察,不修改任何请求
markerLang 空 标记语言,留空跟随宿主界面语言,zh / en 为固定值
placeholder 空 标记模板,留空则使用生效语言的默认模板
pathMode basename full / relative / basename / none,决定路径显示方式
tokensPerImage 972 估算节省量所用的单张图片视觉 token 数
verbose true 是否输出日志

调试步骤

  1. 先观察再启用:在设置页打开 dryRun,此时仅记录将被裁剪的图片,不修改任何请求。
  2. 检查链路接入:设置 → 图片守卫 → 诊断。应显示守卫已接入 fetch 链,且链上探针计数持续增加。
  3. 查看状态:~/.dsh/image-guard-status.json 中的 chatPosts 开始增长。

标记机制

被裁剪的图片会被替换为标记。根据图片来源不同,标记内容不同:

  • 有路径(默认):[图片已省略 #1 · 01-race-start.png · 需要时按文件名在工作区内搜索后读取]
  • 仅有附件元数据:[图片已省略 #1 · 01-race-start.png · 内联图片 sha256:bf23bcd3 (image/png 1280x720 618 KiB) · 无原文件路径,已无法取回]
  • 远端 URL:[图片已省略 #1 · race.png · https://…/race.png · 需要时可重新访问该地址]

已知限制

  • 仅控制张数:不压缩、不缩放图片;字节预算不在处理范围。
  • 首次 400:上限只能从 400 响应中获知,首次请求仍会出现一次 400。
  • 仅针对历史图片:最新 N 张按原样发送(含字节)。
  • 内联图片无法恢复:已内联且无路径的图片无法取回,标记会明确说明。
  • 依赖当前形态:依赖 DSH 当前的请求形态,形态不匹配的请求会透传。

结语

dsh-image-guard 通过拦截请求链路,解决了 DSH 客户端按字节预算而上游按张数限制导致的多模态会话中断问题。通过解析错误并动态调整图片数量,实现了会话的连续性。

目录页:dsh-image-guard
GitHub:mafeis/dsh-image-guard

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

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

小夜