文章目录
思考

我给 DeepSeek Harness 写了个开源插件:dsh-vision-plugin

我给 DeepSeek Harness 写了个开源插件:dsh-vision-plugin

给 DeepSeek Harness 的纯文本模型装上「眼睛」——图片先由视觉模型转写成文字,主模型照常回答。

dsh-vision-plugin:给 DeepSeek Harness 的纯文本模型装上「眼睛」

从一次「它看不见」说起

在用 DeepSeek Harness(DSH)聊天时,一个反复出现的场景让人头疼:deepseek-v4 系列是纯文本模型,你可以在对话框里粘贴截图、照片,但模型看不到它们。粘贴一张报错截图,得到的回复往往是「我无法查看图片」。

其实解决思路很直接:找一个看得见的模型当「翻译官」。图片先交给视觉模型(qwen3.7-plus、kimi-k3 等)转写成文字描述,再把描述交给主模型——纯文本模型就「看得见」了。

于是我把这个思路做成了开源插件:dsh-vision-plugin(MIT 协议,已发布到 npm)。

三个能力

  1. 粘贴图片直接问 —— 对话框粘贴或拖入图片,任意文本模型都能回答图片内容,不需要任何特殊指令。
  2. vision_analyze 工具 —— 模型可以主动调用它分析本地图片文件,还能指定问题(「图中表格第三行数据是多少?」)和具体视觉模型。
  3. 设置页配置视觉模型 —— DSH 设置面板新增「视觉模型」页:选择默认视觉模型、查看当前路由,中英双语、跟随界面语言。

效果是这样的:

你:这是什么?                          (粘贴了一张 Clash Verge Logo)

助手:这是 Clash Verge 的标志(Logo)。左侧是一个黑色的猫头剪影,
     右侧是文字 "Clash Verge"。它是一款基于 Clash 内核的图形化
     代理客户端软件……

图片由视觉模型自动转写,主模型看到的是文字描述,回答和读图效果一样自然。

在 DSH 中粘贴图片提问,纯文本模型也能看图作答

快速开始

永久安装只需要三步,之后每次 dsh 启动都会自动载入。

① 一条命令安装。 插件已发布到 npm,dsh plugin 会装好包并自动把它注册进 profile 的 bundles:

dsh plugin --profile web add dsh-vision-plugin

② 给文本模型声明图片能力。 宿主在消息进入会话前会检查当前模型的输入能力,需要在 ~/.dsh/settings.yaml 里给文本模型声明(文件热加载,不用重启):

llm-pi-ai:
  providers:
    opencode-go:
      apiKeyEnv: OPENCODE_GO_API_KEY
      modelOverrides:
        deepseek-v4-flash:
          input: [text, image]
        deepseek-v4-pro:
          input: [text, image]
        # 其他可能切换到的文本模型同理;原生视觉模型无需声明

③ 重启 dsh,粘贴图片开聊。 验证方法:设置面板出现「视觉模型」页、工具列表里有 vision_analyze

它是怎么工作的

仓库根目录就是一个 dsh bundle 包,由三部分组成:

  • lib/index.js —— 宿主半部(组合插件行 vision):注册 vision_analyze 工具、llm/stream 转写瀑布,以及 /vision/api/state/vision/api/model 两个 JSON 接口;
  • lib/client.js —— 浏览器半部:「视觉模型」设置页,由 web shell 提供;
  • cordis.patch.yml —— loader 补丁行,负责把 bundle 挂载进 dsh 启动流程。

dsh-vision-plugin 的 bundle 包结构

核心逻辑都在 lib/engine.js 里——共享引擎,单一事实源:工具、瀑布、路由发现、缓存与超时全部集中在这里,而且刻意保持零 import(因为 pnpm 不会为 link: 方式安装的 profile 插件安装依赖)。

工作流程:图片进入会话 → llm/stream 监听器判断目标模型——原生视觉模型(白名单)直接看原图;文本模型则先由视觉模型转写成文字再派发。转写请求带 Symbol 标记防止递归,结果按「图片 + 问题」缓存(TTL + FIFO 上限,并发时同一张图共享一次在途调用,不会重复请求)。

一张图片的旅程:视觉模型转写瀑布

可靠性设计

视觉模型调用是外部依赖,出错不能打断对话:

  • 输出了一部分就保留一部分;
  • 完全失败就换备用模型再试一次;
  • 调用挂起超过两分钟会被掐断并视为失败,从而触发备用模型重试;
  • 还不行就告诉模型「图片暂时不可用」,对话照常继续。

视觉模型的选择优先级:工具显式参数(model/provider)> 设置页配置 > 自动选择。自动选择会遍历所有已配置的 provider,找到第一个带视觉模型的路由——即使你没有配置某个特定 provider 也能用。同一张图、同一个问题有缓存,多轮追问不会重复计费。

工程实践

  • 一致性检查npm run check 校验版本号在各处同步、lib/engine.js 保持零 import;
  • 测试套件npm test 覆盖路由发现、override 优先级、缓存/去重、超时、瀑布、工具六类场景;
  • 可调常量:全部集中在 lib/engine.js 顶部——兜底模型、原生视觉白名单、自动选择顺序、视觉调用挂起超时、转写缓存 TTL 与上限、模型目录缓存 TTL。

开源地址

项目以 MIT 协议开源,欢迎 star、提 issue、贡献代码:

GitHub:https://github.com/Xin-Zhang-IceMan/dsh-vision-plugin

从「模型看不见图片」这个小痛点出发,到设计 bundle 结构、写引擎、补测试、发 npm 包,整个过程收获很多。如果你也在用 DeepSeek Harness,希望这个插件能帮上忙。

Discussion

评论 · 0

无需登录也可以参与讨论

还没有评论,来开启这场讨论吧。

留下评论