一个不依赖第三方 npm 包的 DSH(DeepSeek Harness)插件,让只支持文本的模型也能“看懂”图片。
它通过 DSH 的 ctx.llm 服务调用视觉模型,不会把图片塞给当前文本模型,也不会要求切换主模型:
- 允许当前文本模型接收图片附件:
advertiseImage会让 DSH 的图片准入与 Web UI 认为当前模型支持图片,避免出现“当前模型不支持图片,请切换模型”。 - 自动识别用户附加的图片:在
agent/pre-step阶段发现用户消息里的ImageBlock,用视觉模型生成文字描述,并作为插件上下文追加到同一步。主文本模型实际不会收到图片,适配器会把它投影成占位文本,因此不会报UNSUPPORTED_CONTENT。 - 自动识别工具返回的图片:
tools/post-execute会处理read_image等工具结果里的图片,把视觉描述追加到工具结果中。 - 提供
describe_image工具:模型可以读取本地 PNG/JPEG/WebP/GIF 文件,调用视觉模型后返回文字描述/OCR 结果。它与内置read_image不冲突;内置工具需要当前模型支持图片输入,本工具专门补足文本模型场景。
默认使用 DeepSeek 官方适配器内的视觉模型:
provider: deepseek-official
model: deepseek-v4-flash-vision-exp
因此通常直接复用 DSH 已经配置好的 DEEPSEEK_API_KEY,无需另配 OpenAI Key。
包内已经提供 package.json 的 dsh.bundle.patch 和 cordis.patch.yml,可以直接被 dsh plugin 安装:
# 从 npm 安装
dsh plugin --profile web add dsh-image-reader
# 或从 GitHub 安装
dsh plugin --profile web add github:wang90/dsh-image-reader
# 或安装本地 checkout
dsh plugin --profile web add ./dsh-image-reader安装后重启 DSH Web。
把下面一行加入 $DSH_HOME/profiles/web/cordis.patch.yml(路径按实际 clone 位置调整):
- insert:
- id: image-reader
name: '/absolute/path/to/dsh-image-reader/image-reader.mjs'
config:
advertiseImage: true
describeToolImages: truepatchReload: live 的 profile 会在保存 patch 后热加载插件;普通启动则重启 DSH Web 后生效。
直接在 Web UI 里附加图片并发送。主模型收到请求前,插件会:
- 找到消息中的图片附件;
- 调用
deepseek-v4-flash-vision-exp识别; - 把识别结果作为一条
plugin来源的上下文插入用户消息之后; - 主模型继续按原来的文本模型运行。
原始图片仍保存在会话历史中;以后切换到支持视觉的模型时仍然可以直接查看原图。
模型可以调用:
{
"file_path": "/path/to/image.png",
"prompt": "只看左上角的报错信息,逐字转录"
}返回:
{
"text": "视觉模型给出的描述/OCR 结果",
"model": "deepseek-official/deepseek-v4-flash-vision-exp",
"path": "...",
"mediaType": "image/png",
"bytes": 12345,
"width": 800,
"height": 600
}相对路径按当前会话工作区解析,并使用 ctx.fs,因此仍受文件系统 sandbox 约束。
在 patch 的插件行里可加 config:
- insert:
- id: image-reader
name: '/absolute/path/to/dsh-image-reader/image-reader.mjs'
config:
provider: deepseek-official
model: deepseek-v4-flash-vision-exp
auto: true
tool: true
cache: true
skipVisionModel: true
advertiseImage: true
describeToolImages: true
maxImagesPerStep: 8
maxOutputTokens: 2048
timeoutMs: 120000
maxDescriptionChars: 12000
maxToolImageBytes: 20971520
reasoningEffort: 'off'
prompt: |
请仔细识别并描述这张图片……全部字段都有默认值;只在需要时覆盖即可。
| 字段 | 默认值 | 说明 |
|---|---|---|
provider |
deepseek-official |
调用视觉模型的 DSH provider |
model |
deepseek-v4-flash-vision-exp |
必须是声明了 image input modality 的模型 |
auto |
true |
是否自动识别用户附加图片 |
tool |
true |
是否注册 describe_image 工具 |
cache |
true |
同一附件同一提示词是否复用识别结果 |
skipVisionModel |
true |
如果当前主模型真实能力本身支持图片,则跳过自动识别,避免重复处理 |
advertiseImage |
true |
让 DSH 认为当前文本模型也接受图片,从而允许 Web UI/API 提交图片;实际图片会由本插件转成文字描述 |
describeToolImages |
true |
自动识别工具结果里的图片,例如内置 read_image 返回的图片会追加文字描述 |
maxImagesPerStep |
8 |
单步最多自动识别几张图片 |
maxOutputTokens |
2048 |
视觉模型输出 token 上限 |
timeoutMs |
120000 |
单次视觉调用超时 |
maxDescriptionChars |
12000 |
注入上下文的单图描述长度上限 |
maxToolImageBytes |
20971520 |
describe_image 读取的原始文件大小上限,同时受附件服务限制 |
reasoningEffort |
off |
辅助视觉调用的推理档位,off 可降低成本与延迟 |
prompt |
内置中文识别提示词 | 视觉模型提示词 |
也支持环境变量:DSH_IMAGE_READER_PROVIDER、DSH_IMAGE_READER_MODEL、DSH_IMAGE_READER_AUTO 等,名称可由字段名推导。
- 视觉调用失败时,自动路径不会中断当前 turn,而是把失败信息作为插件上下文注入,让主模型可以如实告诉用户。
describe_image工具失败时,按普通工具错误返回。- 如果
provider/model配错,错误信息会包含视觉调用的失败原因,便于在 DSH 模型设置中修正。
- 自动路径直接复用附件服务中已经持久化的图片,不会把 base64 写进会话日志。
describe_image读取文件后会调用ctx.attachments.saveImage做持久化,然后调用视觉模型。附件服务本身只接受 PNG/JPEG/WebP/GIF,并执行尺寸/字节校验。- 文件读取通过
ctx.fs,遵守当前会话的文件系统策略。