dsh-image-vision

August 17, 2026 · View on GitHub

让 DeepSeek Harness 的纯文本主模型无缝读懂图片 —— 不修改任何宿主代码, 纯插件实现(“一切皆插件”)。

English docs: README.md

支持两种部署:源码运行(clone 仓库跑 pnpm dsh web)与正式安装版 (npm i -g @deepseek-ai/dsh)。两者都通过 dsh plugin 管理,@deepseek-ai/* 依赖由 DSH 宿主提供。

  • 对话里直接贴图/拖图:主模型是纯文本模型(如 DeepSeek V4 Flash 走 pi-ai 路由)也能接收图片,插件会用你配置的视觉模型把图片转录成文字 再交给主模型,主模型只看到纯文本。
  • 飞书/苍穹文档图片lark_read_doc 等工具返回的 <image token=.../> 会自动下载并通过视觉模型识别,结果作为工具结果注入对话。
  • describe_image 模型工具:读取本地图片文件并返回文字描述。
  • 不限 OCR:支持对人物、风景、表格、图表等做完整语义描述。

视觉模型可选 ModelScope 社区免费 API(如 Qwen/Qwen3-VL-8B-Instruct) 或 硅基流动(如 Qwen/Qwen3-VL-32B-Instruct),按你的 settings 配置 自动发现。


工作原理(为什么不用改核心代码)

API 代理在“图片上传 / 切换模型”时会调用 llm.resolveModelInfo(...),检查 当前模型的 inputModalities 是否包含 image,不包含就拒绝 (MODEL_DOES_NOT_SUPPORT_IMAGES)。DSH 是“一切皆插件”,所以本插件:

  1. 包装 ctx.llm.resolveModelInfo:当目标模型本来没有 image 输入、且 插件已配置视觉路由时,返回结果里补上 image,让准入闸门放行图片。
  2. 监听 agent/pre-step:图片进入消息流后、真正发模型请求之前,调用 视觉模型把每个图片块转录成文字,并替换回消息 —— 主模型实际收到的仍是 纯文本,永远不会把图片发给它。

以上都通过 DSH 官方提供的事件/服务扩展点完成,不改任何 packages/ 核心 文件,因此可以直接复制到别的机器或开源公用。


环境要求

  • DeepSeek Harness(开发预览版 0.1.0-rc.6 环境的源码运行或安装版均可)
  • Node.js ≥ 22.19
  • 已配置一个可用的视觉模型 provider(见下文配置)

安装

方式一:从 GitHub 安装(推荐)

npx @deepseek-ai/dsh plugin --profile web add github:VeryInt/dsh-image-vision

dsh plugin --profile web add github:VeryInt/dsh-image-vision

方式二:本地路径安装(开发/验证)

克隆下来或直接用本地目录:

git clone https://github.com/VeryInt/dsh-image-vision.git /path/to/dsh-image-vision
npx @deepseek-ai/dsh plugin --profile web add /path/to/dsh-image-vision

上面的 <profile> 换成你实际用的 profile(webheadless 等)。 若 pnpm 拦截 GitHub 依赖的 prepare/构建脚本,按它打印的提示在 <profile>/pnpm-workspace.yamlallowBuilds 里放行,再重试。

安装后重启 Harness。插件会出现在 设置 → 插件 列表。

PHP 版本注意:如果你们直接从仓库源码跑 pnpm dsh web(tsx 模式), bundle 里的 @deepseek-ai/* 依赖会通过仓库的 tsconfig.base.json paths 软解析到 packages/*/src,与当前已验证的行为一致。


配置视觉模型

图片识别需要一个视觉模型 provider。在 DSH 的 Models 设置页(或 ~/.dsh/settings.yaml)配置一个 OpenAI 兼容的视觉端点,并且给它的模型 条目声明 input: [text, image](Models 页面不显示该字段,需改配置文件)。

示例 settings.yaml

llm-pi-ai:
  providers:
    modelscope:
      displayName: ModelScope
      apiKeyEnv: MODELSCOPE_API_KEY
      api: openai-completions
      baseURL: https://api-inference.modelscope.cn/v1
      models:
        - id: Qwen/Qwen3-VL-8B-Instruct
          name: Qwen3-VL-8B
          input: [ text, image ]
    siliconflow:
      displayName: 硅基流动
      apiKeyEnv: SILICONFLOW_API_KEY
      api: openai-completions
      baseURL: https://api.siliconflow.cn/v1
      models:
        - id: Qwen/Qwen3-VL-32B-Instruct
          name: Qwen3-VL-32B-Instruct
          input: [ text, image ]

然后在 ~/.credentials.yaml 或环境变量里填对应 API Key:

# ModelScope 社区版:https://modelscope.cn 控制台申请
MODELSCOPE_API_KEY=ms-xxxxxx
# 硅基流动:https://cloud.siliconflow.cn 控制台申请
SILICONFLOW_API_KEY=sk-xxxxxx

注意:Qwen/Qwen3.5-27B 这类文本模型即使声明了图片也不真正接受图 片(实测返回空),必须用 VL 后缀的视觉模型。

插件自身的视觉路由配置

插件的 cordis.patch.yml 里有两项:

- insert:
    - id: dsh-image-vision
      name: dsh-image-vision
      config:
        provider: siliconflow      # 视觉 provider 路由(留空 = 自动发现)
        model: Qwen/Qwen3-VL-32B-Instruct   # 视觉模型 id(留空 = 自动发现)
        # prompt: 请完整描述这张图片的内容,包括其中的文字、人物、物体、场景、表格、图表等细节。
        # maxImagesPerMessage: 4
        # feishuImages: true
        # maxFeishuImages: 5

规则:

  • provider 和 model 都填:用这张视觉路由(优先级最高)。
  • provider/model 都留空:自动扫描所有已配置 provider,取第一个声明了 input: [text, image] 的模型(这是最常见的用法)。
  • 换模型 = 改这里 + 确认目标模型在 settings.yaml 已声明 input: [text, image]

验证

重启后:

  1. 对话里贴图:直接拖一张图或粘贴图片到输入框发给主模型,主模型应能 描述出图片内容(变成 [图片内容] …文本)。
  2. 飞书文档读图:让 agent 读一份含图片的飞书/苍穹文档,工具结果里 会出现 [飞书图片 <token>] … 的描述。
  3. describe_image 工具:在对话里让模型用 describe_image 读一个本地 图片路径。

如果图片识别失败,回复里会出现 [图片内容识别失败:…][飞书图片 … 识别失败:…],可根据错误信息定位(多为网络抖动或模型配置缺失)。


配置项

字段默认说明
provider视觉模型 provider 路由;空则自动发现
model视觉模型 id;空则自动发现
prompt(完整描述)发给视觉模型的描述指令
maxImagesPerMessage4单次消息最多桥接的图片数,超出会报错
feishuImagestrue是否自动识别飞书 <image token>
maxFeishuImages5单条工具结果最多识别的飞书图片数

许可证

MIT


致谢

实现思路参考了社区插件 oil-oil/dsh-vision 的 bundle 打包与桥接设计;本仓库采用纯 JS ESM 免构建结构,聚焦对接 settings.yaml 视觉模型与 agent/pre-step 转录,适合源码 / 安装版通用。