dsh-plugin-image-tools:给 DSH Web GUI 补上图片能力的三个工具

前言

用 DeepSeek Harness(DSH)的 Web GUI 做智能体,有三个和图片有关的场景一直不好处理:

1、模型想让你在几个候选里挑一张图(比如给小说选封面),但选项卡里放不了图,模型只能把路径打印出来让你自己开文件;
2、模型生成了图,想在回复正文里图文混排,同样没有通道;
3、你往聊天里发一张图,文本-only 的模型适配器直接报 UNSUPPORTED_CONTENT,回合中断。

dsh-plugin-image-tools 就是针对这三个场景的 DSH 插件:图片选择卡、回复内嵌图片、盲模型收图,三个工具各管一摊,全部零 token 本地渲染,纯插件实现,不改核心包。

这是什么

dsh-plugin-image-tools 由 Pasumao 维护,MIT 许可证,运行平台为 Web GUI(package.jsondsh.client.platformweb),当前版本 0.6.6。

为什么做成插件而不是改核心:浏览器端消费 question/requested 帧时用 zod schema 严格解析,选项对象上的未知字段会被剥离;助手消息 content 由模型文本生成,也没有携带结构化图片块的通道。图片没法直接塞进 option / content 字段。插件的解法是:服务端把图片字节归一化进内存注册表,用自定义 web 路由直接供字节;客户端部分在 conversation.composer slot 链注册条目,负责渲染和增强。

代码与文档由 AI 辅助生成,均经人工审查与实机验证(npm run smoke)。

安装与启用

npm 安装(推荐):

dsh plugin --profile web add dsh-plugin-image-tools

或从 GitHub 源安装:

dsh plugin --profile web add github:Pasumao/dsh-plugin-image-tools

装完重启 dsh(launcher),再刷新浏览器页面。包自带 cordis.patch.yml 挂载行,经 dsh.profile.bundles 自动应用,不需要手动改配置。插件不读取环境变量、不需要 API Key / token、不写配置文件,装好即用。纯文字问题不带图片时自动放行给原生 UI,互不影响。

三个工具

三个工具的图片来源统一支持三种形态:本地路径(相对会话工作区或绝对路径)、http(s) URL(服务端拉取后转存)、base64 data URI。单张上限 20 MiB,仅支持 PNG / JPEG / WebP / GIF(按魔数校验,声明不符会报错)。

ask_user_choice:在选项里挑图

模型传入 questions 数组,每个选项可带一张图(path / url / data 三选一),纯图片、纯文字、图文选项可在同一题混排。支持多题分页、单选/多选、自定义答案、跳过;label 末尾写 (Recommended)(推荐) 会显示推荐标注。缩略图点击弹出 Lightbox 大图,Esc / 点遮罩 / 关闭按钮退出。选择卡由 Web GUI 渲染,答案协议与原生一致:

{
  "questions": [
    {
      "id": "cover",
      "question": "选一张封面图",
      "header": "封面选择",
      "options": [
        { "label": "深海鲸鱼 (Recommended)", "image": { "path": "novel/assets/covers/whale.png" } },
        { "label": "星空", "image": { "url": "https://example.com/stars.png" } },
        { "label": "手绘风",
          "image": { "data": "data:image/png;base64,iVBORw0KGgo..." } },
        { "label": "都不选,我自己说", "description": "选这个可以在下方输入自定义答案" }
      ],
      "multi_select": false
    }
  ]
}
// 返回{ "answers": [ { "id": "cover", "selected": ["深海鲸鱼 (Recommended)"] } ] }

show_images:在回复正文里展示图

调用时传 images 数组(一次 1~9 张,每张可带 caption),工具返回绝对 URL 的 markdown 图片片段,模型把片段原样逐行粘贴进回复正文,图片就随文字显示:

// 调用 show_images
{
  "images": [
    { "image": { "path": "novel/assets/covers/whale.png" }, "caption": "深海鲸鱼封面" },
    { "image": { "url": "https://example.com/stars.png" }, "caption": "星空" }
  ]
}
// 返回:{ "markdown": ["![深海鲸鱼封面](http://127.0.0.1:3080/dsh-plugin-image-tools/show/<id>/0)", "![星空](http://127.0.0.1:3080/dsh-plugin-image-tools/show/<id>/1)"] }

客户端插件会对这类图片做渐进增强:圆角样式、悬停显示说明、点击放大、加载失败降级。

save_received_images:盲模型收图存成文件

用户往聊天里发图时,插件注册的 agent/pre-step 监听器把进入 LLM 步骤的消息里的 image 块重写为 dshimg:<attachmentId> 文本占位符,文本-only 适配器不再因图片块报 UNSUPPORTED_CONTENT,回合照常运行;用户气泡里由客户端增强器把占位符替换为可放大的图片回显。

模型看到占位符后调用 save_received_images,把图片按 attachmentId 保存为工作区文件,默认目录 received/;文件名优先用附件自带的安全文件名,否则按 image-<n>-<时间戳>.<ext> 生成。之后就能用文件/命令工具对图片做分析(尺寸、像素、哈希等)。

限制与注意

  • 图片字节仅存进程内存:选择卡图片随问题回答/取消立即释放;内嵌图片与附件回显依赖 30 分钟 TTL 清理。
  • 图片路由 URL 是内容寻址的,响应头下发 Cache-Control: private, max-age=2592000, immutable(30 天浏览器缓存);服务端清理后刷新页面仍可命中本地缓存。
  • 图片路由为同源普通 HTTP 路由(与 GUI 同信任级别),未加额外鉴权。
  • 内嵌图片的 markdown URL 是绝对地址,若 GUI 经反向代理或换端口访问,历史消息里的图片地址可能失效。
  • 兼容性:实测于 DSH 0.1.2-rc.1(0.6.5 起适配该版选择卡新协议,0.6.6 起测试自带 react/react-dom),依赖客户端服务 slots / locale
  • 插件以当前 dsh 进程权限运行,安装前建议自行查看源码与许可证(MIT)。

结尾

dsh-plugin-image-tools 用三个工具覆盖了 Web GUI 里「选图、看图、发图」三件事,零 token 本地渲染,不改核心包,也不需要配置。如果你在 DSH 上做涉及图片的工作流(封面挑选、出图展示、给文本模型传图分析),可以直接装来试。

  • 社区插件目录(独立站点,与 DeepSeek / 幻方无官方从属关系):https://www.skillhub.cn/plugins/Pasumao/dsh-plugin-image-tools
  • GitHub 仓库:https://github.com/Pasumao/dsh-plugin-image-tools
羽毛球分组比赛记分
小程序二维码

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

小夜