← 返回列表
✓ 可直接安装
Vision model for DeepSeek Harness | DeepSeek Harness…
自动检查通过:npm 包已发布且 engines 声明满足基线(声明 Node >=20.18);该结论来自程序自动检查,未经人工实机验证。 · 最近上游提交 2026/9/11 · 已提供中文文档
Vision model for DeepSeek Harness | DeepSeek Harness 外置视觉模型插件
综合分
36.9
GitHub 分
36.9
用户评分
—
★ Stars
8
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add dsh-tool-visionnpm 包 dsh-tool-vision 已校验归属本仓库,走 npm 安装最省事
数据截至 2026/9/17(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查✓ 自动检查通过
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-tool-vision @ 0.9.0
✓Node 引擎要求 >=20.18 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/18 02:18:03
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/dsh-settings@deepseek-ai/dsh-tools用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
dsh-tool-vision
GitHub: Scorp1o117/dsh-tool-vision · npm: dsh-tool-vision · English
Enhancement Suite npm
属于 DeepSeek Harness Enhancement Suite —— Vision · Soul/Persona · 长期记忆 · 插件市场。
给 DeepSeek Harness 外接视觉模型的插件。
DSH 0.1.1 已为 DeepSeek 视觉模型目录加入原生图片输入。本插件继续提供独立的 OpenAI 兼容视觉端点、像素级图片工具、截图,以及文本模型图片桥。Harness 的每次模型请求都严格从会话日志推导(llm/stream 请求必须与持久化推导一致,否则 agent-loop invariant 会报 log-reconstruction desync),因此图片桥仍在可持久重建的路径内完成转换:
1. inspect_image 工具 —— 把图片(本地文件或 http(s) URL)发给任意支持 image_url 内容块的 OpenAI 兼容 /chat/completions 端点,把视觉模型的文字回答带回对话。
2. 图片桥(v0.2.1) —— 粘贴的图片在进入持久化日志之前就被转换成 inspect_image 指引文本,拦截点是 agent/pre-step waterfall(这是 harness 唯一允许插件替换"进入某一步的消息"的缝;替换后的消息会成为持久化的 user/message 日志,所以请求重建 invariant 天然满足)。旧版本已经写进日志的图片消息,会在该会话下一次 pre-step 时用 surface replace 惰性修复。只有 multimodalModels 白名单内的模型直收图片块;不参考模型的 inputModalities 声明——因为很多配置为了通过 prompt 准入检查,会给纯文本模型声明 input: [text, image](那只是声明,不代表上游真的能吃 image_url)。
- 除 dsh SDK 外零依赖 —— 兼容任意端点:OpenAI GPT-4o、Qwen-VL(DashScope)、GLM-4V(智谱)、Moonshot、Gemini 兼容端点、本地 Ollama 等。
- 注册在全局工具层:进程内所有 Agent 都能调用 inspect_image。
- Web UI 设置栏(v0.3.0):设置 → 视觉模型 编辑 tool-vision 命名空间(API 地址、只写密钥、模型、桥接选项),写入 settings.yaml,改动即时生效无需重启。API 密钥存放在 settings.yaml 而非 profile patch;插件按包名挂载(name: 'dsh-tool-vision')以便 web 端发现客户端 bundle。
安装
在 profile patch($DSH_HOME/profiles//cordis.patch.yml)里挂载:
- insert:
- id: tool-vision
name: 'dsh-tool-vision' # 前置:在 profile 里 pnpm add dsh-tool-vision
config:
baseURL: 'https://api.openai.com/v1'
apiKeyEnv: 'VISION_API_KEY'
model: 'gpt-4o-mini'
不装 npm 包、直接加载本地路径:
- id: tool-vision
name: './plugins/dsh-tool-vision/index.js'
配置
| 字段 | 默认值 | 含义 |
|---|---|---|
| enabled | true | 总开关(v0.8.0)。关闭后插件不注册任何东西:inspect_image、14 个 vision_ 工具、图片桥、预览路由、图片能力声明统统下线;设置栏本身保留,所以随时能再打开。热生效,无需重启 dsh |
| baseURL | https://api.openai.com/v1 | OpenAI 兼容 API 基地址 |
| apiKey | '' | API 密钥(优先于环境变量) |
| apiKeyEnv | VISION_API_KEY | 存放密钥的环境变量名 |
| model | gpt-4o-mini | 视觉模型 id |
| maxTokens | 1024 | 视觉调用最大输出 token |
| timeoutMs | 60000 | 单次请求超时 |
| maxImageBytes | 10MB | 本地图片大小上限 |
| description | 默认描述 | 工具描述(模型可见) |
| bridgeTextOnly | true | 把粘贴图片转成文本指引(发给看不懂图片的模型时) |
| bridgeExportDir | 临时目录 | 桥接图片导出目录(os.tmpdir()/dsh-vision-bridge) |
| multimodalModels | [] | 模型名单(逗号分隔)。每项按「完整 id / 末段裸 id / provider/id」三种写法匹配,大小写不敏感,支持 ? 通配(如 vl、deepseek/)。含义由下面的模式决定 |
| multimodalListMode | whitelist | 名单模式(v0.9.0):whitelist 名单内模型直收图片块(旧行为);blacklist 名单内模型强制走桥接(用来纠正"声明支持图片但实际不支持"的模型);off 忽略名单。未知值一律回退 whitelist |
| autoDetectMultimodal | true | 自动识别(v0.9.0):按当前路由自己声明的 inputModalities 判定,再与名单合成(白名单取并集、黑名单取差集)。默认开启=识别到纯文本就交给桥接、识别到多模态就等同白名单成员直发图片;声明永远读"包装前"的真值,不会被 bridgeAutoImage 的假声明污染。设为 false 可退回"只认名单"的纯手工行为 |
| probeResults | {} | 实测结果(v0.9.0):"provider/model" → "yes"/"no",由 vision_probe_model 工具写入,不要手改。实测优先级高于声明(真实请求 > 自称),但低于 multimodalModels(人的明确意图有最终话语权) |
| bridgePreview | true | 桥接图片内联预览:用户气泡内显示缩略图,点击放大 |
| bridgePreviewScanIntervalMs | 2000 | 预览兜底扫描间隔(毫秒);0 关闭兜底 |
| bridgePreviewHideHint | true | 图片加载成功后隐藏桥接提示文本(失败时保留,安全降级) |
| bridgeAutoImage | true | 桥接开启时向宿主准入检查报告所有模型都支持图片输入,纯文本模型也能直接粘贴图片,无需手动改 provider 配置 |
| sendSessionHeader | true | 给视觉请求发送稳定的会话标识头。OpenCode Go 等网关要求每请求带 x-opencode-session(一个对话一个稳定 ID),缺失的请求在 2026-09-06 起可能报错 |
| sessionHeaderName | x-opencode-session | 承载会话 ID 的头名 |
| sessionId | '' | 固定会话 ID(后台/无 dsh 会话调用时用);留空则自动:优先取当前 dsh 会话 ID,否则用进程级稳定随机 ID |
图片桥配置
1. (一般不需要)只有关闭 bridgeAutoImage 时才需要手动给模型声明图片输入(pi-ai 风格),让 harness 放行图片消息:
llm-pi-ai:
providers:
your-provider:
models:
- id: deepseek-v4-flash
input: [text, image]
2. 在插件配置里列出真正多模态的模型,让它们直收图片块(名单模式见下一节):
- id: tool-vision
name: 'dsh-tool-vision'
config:
multimodalListMode: whitelist # 默认,名单内直发图片
multimodalModels: ['mimo-v2.5', 'grok-4.5']
之后在文本模型下贴图,转录里会留下一条指引:
[User sent an image, exported to: . Inspect it with the inspect_image tool...]
(该消息不再以像素图形式渲染),Agent 会调用视觉端点查看并把结果带回对话。
为什么不用 llm/stream?harness 会冻结每个请求,且 agent-loop invariant 会拒绝任何与会话日志推导不一致的请求;这个 cordis 版本的 waterfall next() 也无法替换请求参数。agent/pre-step 才是受支持的缝:它的决策消息会成为持久化日志,invariant 天然成立。
密钥解析顺序:config.apiKey → process.env[apiKeyEnv] → process.env.OPENAI_API_KEY。
桥接图片预览(v0.4.0)
纯文本模型下,被桥接的图片在对话里只显示一段 [User sent an image...] 文本指引。开启 bridgePreview(默认开)后,浏览器端会在展示层把指引渲染成气泡内缩略图:
- 缩略图 + 灯箱:点击缩略图全屏放大,点击任意处或按 Esc 关闭;
- 即时 + 兜底:新消息由 MutationObserver 即时处理,历史消息由周期兜底扫描补齐(间隔见 bridgePreviewScanIntervalMs);
- 隐藏提示文本(P2):bridgePreviewHideHint 开启时,图片加载成功后桥接文本自动隐藏,气泡只留图片;加载失败则保留文本(安全降级,绝不出现"既无图又无字");
- 识别机制:桥接文本带不可见前缀标记(\u200b[bridge]),客户端据此精确识别桥接块——用户正常发言中出现"exported to:"字样不会被误伤;
- 纯展示层红线:不修改持久化消息、不修改转录、不修改模型侧文本、不碰 inspect_image 调用链。
预览图片由同源回环路由 /plugins/dsh-tool-vision/image 提供,只读桥接导出目录、仅本机 Host、仅图片扩展名、单文件 ≤ 20MB、防目录穿越。
工具:inspect_image
| 参数 | 必填 | 含义 |
|---|---|---|
| path | ✅ | 图片路径(绝对路径,或相对当前工作区)或 http(s) URL |
| question | – | 可选的具体问题 |
| detail | – | auto / low / high 分辨率提示 |
示例端点(baseURL):
- OpenAI:https://api.openai.com/v1 —— gpt-4o、gpt-4o-mini
- 阿里云 DashScope(Qwen-VL):https://dashscope.aliyuncs.com/compatible-mode/v1 —— qwen-vl-plus、qwen-vl-max
- 智谱(GLM-4V):https://open.bigmodel.cn/api/paas/v4 —— glm-4v-flash(免费档)、glm-4v-plus
- Moonshot(Kimi):https://api.moonshot.cn/v1 —— moonshot-v1-8k-vision-preview
- Ollama 本地:http://localhost:11434/v1 —— llama3.2-vision(无需密钥)
像素级视觉工具(v0.6.0,移植自 dsh-vision-router)
14 个 vision_ 工具由同一个 inspect_image 配置的端点驱动
(baseURL/apiKey/model)——无 provider 链、无本地模型、零新增配置:
| 工具 | 用途 |
|---|---|
| vision_describe | 看图问答 / 多图对比(可选结构化 JSON) |
| vision_ground | 定位目标,返回原图像素坐标框 |
| vision_detect | 枚举元素(按钮/输入框/图标…),带编号框 |
| vision_crop | 按像素区域裁剪出 PNG 产物 |
| vision_pixel_diff | 逐像素对比:差异比例、最差区域、热图、报告 |
| vision_colors | 主色量化,还原 UI 调色板 |
| vision_ocr | 逐字转写文字(只读字,不做场景识别) |
| vision_long_screenshot_ocr | 长截图分块转写为 Markdown |
| vision_trace | potrace 矢量化输出彩色 SVG(worker 线程,安全) |
| vision_extract_foreground | 纯色背景抠图 → 透明 PNG |
| vision_html_screenshot | 本地 HTML 无头渲染截图(禁网) |
| vision_screenshot | 桌面截屏(隐私门控:需在设置中开启 desktopScreenshot;Win: PowerShell / macOS: screencapture / Linux: import/scrot) |
| vision_present | 通过宿主附件库把生成的图片正式展示给用户 |
| vision_materialize | 把附件/本地图片落盘为工作区真实路径 |
质量与安全细节:
- 内容哈希缓存按 端点+模型+图片+问题 取键(切模型不吃旧答案,失败结果
不入缓存);
- 统一 4MP 降采样后再调用模型;超大输入 stat 预检直接拒绝(文件与
附件路径统一 20MB 上限);
- 限流/5xx 自动重试(感知 Retry-After 退避);端点内容安全拒绝明确
返回 VISION_CONTENT_FILTERED,不再误报后端不可用;
- 长截图 OCR 边界:120s 总预算、40 块上限、取消检查、首块失败即停;
- 路径 containment(相对输入禁止逃逸工作区);产物写入
/.dsh-tool-vision/。
依赖 sharp / potrace / puppeteer-core(声明为可选依赖:平台安装失败
不会阻断插件安装;缺失时懒加载降级并给出安装提示,不影响其他工具)。
vision_screenshot 属于隐私敏感能力,默认不注册——在 tool-vision 设置中
开启 desktopScreenshot: true 后才会注册桌面截屏工具。
v0.9.0:模型名单模式与自动识别
桥接要回答一个问题:当前这个模型能不能直接看图片? v0.9.0 把它拆成两个相互独立的输入。
base = autoDetectMultimodal ? (路由声明含 image) : 空集
off → direct = base 名单不参与
whitelist → direct = base ∪ 名单 名单只做"加"
blacklist → direct = base \ 名单 名单只做"减"
命中名单时以名单为准:名单是用户明确的意图,优先级高于模型自己的声明,所以永远能纠正误判。
黑名单绝不会退化成"未列出的一律直发":黑名单的基准是自动识别集;没开自动识别时基准是空集,未列出的模型照样走桥接。这是刻意设计的——否则一次误配就能把图片硬塞给纯文本端点。
匹配规则:mimo-v2.5、xiaomi/mimo-v2.5、commandcode/xiaomi/mimo-v2.5 指向同一个路由;* / ? 为通配符;大小写不敏感。v0.8.1 只做字符串全等,README 自己举的 mimo-v2.5 例子在 xiaomi/mimo-v2.5 这类路由上其实静默无效,v0.9.0 修好了(只会多放行,不会收回任何旧配置已经放行的模型)。
面板(设置 → 视觉模型):
- 名单字段下面是一份可直接勾选的模型清单:候选来自 dsh 已配置的模型(llm.listProviders() + llm.listModels()),按 provider 分组,标注哪些声明支持图片;勾选加入、取消勾选移出,上方输入框仍可手打通配符(两者共用同一份草稿,改完按「保存」生效,未保存时清单头部会标"未保存");
- 顶部常驻当前路由判定:provider / model、直发还是桥接、依据是什么(名单命中 / 自动识别 / 默认)。
为什么不只用 :原生 datalist 必须聚焦输入框并敲字才会弹出,v0.9.0 第一版因此看起来像"面板没反应"。现在清单常驻可见,datalist 只作打字辅助。
取消勾选移除的是命中的那条记录本身(名单里写 mimo-v2.5 命中了 xiaomi/mimo-v2.5,取消勾选就移除 mimo-v2.5,不会凭空虚增一个完整 id)。"哪条命中了"由服务端用与桥接同一套匹配器算出(payload 的 matchedEntries),客户端不复制规则,所以面板显示的状态永远不会和实际判定打架。
判定依据的读取路径(这是本版最容易做错的地方):autoDetectMultimodal 必须读 resolveModelInfo 被包装之前的真值,否则 bridgeAutoImage 给所有模型贴上的"支持图片"就成了自证。代码里由 unwrappedResolveModelInfo() 保证,并有专门的回归测试。
候选项由插件自己的回环路由提供:GET /plugins/dsh-tool-vision/models(仅本机 Host、只读、no-store),只返回 provider/model id 与声明能力,不含任何密钥或端点地址。它挂在插件主 fiber 而非总开关的子 fiber 上,所以插件关闭时面板依然可用。
⚠️ inputModalities 是声明,不是保证——profile 里常见"为了过准入检查而写 input: [text, image]"的纯文本模型。上游 dsh-llm-pi-ai 自己也把"未声明"一律当作纯文本,理由写在源码注释里:两种误判的代价不对等——少声明会在贴图前就拒绝并点名模型,多声明则会放行一张"上游中途拒收、而消息已经落盘"的图片。
所以自动识别是默认开启的,同时带三层兜底:① 某个路由首次因"仅凭自己的声明"被放行时,日志会打一条明确提示并点名怎么改;② 面板顶部常驻当前判定与依据;③ 把该模型写进 multimodalModels 并切到 blacklist 模式即可强制回到桥接。
测试
npm test # 服务端单测(不需要额外依赖)
npm run test:render # 面板渲染测试(需要 devDependencies)
npm run test:render 在 jsdom 里加载真实客户端 bundle、走真实注册路径(apply → slots.register → 组件),数据由真实的服务端路由处理器产出,最后断言真实 DOM 与真实的设置写入。
它单独成命令、不并入 npm test:它需要 react / react-dom / jsdom,而一个"依赖缺失就静默跳过"的 DOM 测试只会带来虚假的安全感。需要时先 npm i -D react@18 react-dom@18 jsdom。
它存在的理由很具体:v0.9.0 第一版把模型清单只渲染进原生 —— 服务端单测全绿,面板却看起来完全没反应。这类 bug 在 DOM 之下根本抓不到。
实测探测:vision_probe_model(v0.9.0)
前面所有判定都建立在"模型说自己能不能看图"之上。这个工具改为真的发一张图过去试,是插件里唯一的地面真相。
base = autoDetect ? 路由声明含 image : ∅
探测结果(若有)覆盖 base 实测 > 自称
名单命中(若有)覆盖一切 人的意图 > 实测
为什么一次请求不够(都是实测踩出来的):
- 会瞎猜:模型可能对橙色方块回答"blue"。所以探测跑两个不同颜色,两个都答对才算通过;
- 推理模型会返回空 content:思考预算不够时 max_tokens 全被烧光。默认给 2048,并回退读 reasoning_content;
- 必须要有对照组:先发一条纯文本请求确认"这条路本身是通的",否则一个 401/超时会被误读成"它不能看图"——那会把一条好端端的多模态路由永久推回桥接;
- 端点不报错 ≠ 能看图。真实网关实测:meituan/LongCat-2.0:free 收到图片请求返回 200,但回答是 "I can't see any image."。只有"端点主动拒绝图片部分"才是确定性的负面信号。
结论分三档:yes(对照组通过 + 两色全对)、no(端点拒绝图片,或答了但没读图)、unknown(网络/鉴权/协议问题——绝不当作能力结论)。
它怎么拿到主模型的端点与凭据(不新增任何配置):llm.listConfigurableProviders() 给出 provider 的 settings 命名空间与路径 → settings.get(ns) 读出 baseURL/apiKeyEnv/api → credentials.resolve(apiKeyEnv) 取出密钥(.value),与 dsh-llm-pi-ai 真实调用同一条路。只读,且端点与密钥绝不出现在探测结果里。
联动:探测结果写入 probeResults 并立即参与桥接判定——yes 直接放行图片、no 强制回到桥接,且与名单模式无关。(这比"自动往名单里写一笔"更正确:名单在 blacklist 模式下含义是反的,自动写入会得到完全相反的效果。)面板清单里每个模型带徽章:
- 已实测可看图 / 已实测不可看图(蓝 / 红)——实测优先展示;
- 没探测过的才回退显示声明的 声明支持图片;
- 顶部"依据"栏显示 实测(真实发图验证通过/未通过)。
未知协议的路由(如 openai-responses)会直接返回 unknown 并说明原因,而不是用 chat/completions 去猜一个自信的错误答案。
v0.8.0:总开关,以及保存修复
总开关。 enabled 字段加设置栏顶部的一键按钮(一键关闭 / 重新启用)。
注册本身就是绑定在「发起注册的 cordis fiber」上的副作用,所以插件把所有工具、
图片桥、预览路由和图片能力声明都放进一个子 fiber:关掉开关就是销毁这个子
fiber,15 个工具一并从模型侧消失。设置栏留在父 fiber 上,因此关掉之后还能再打开。
无需重启 dsh。
保存修复。 此前表单把 18 个字段作为并行 scope.set()/unset() 提交。每个
写入各自携带一个 revision 栅栏,而栅栏落后于宿主文档的写入会被 settings/conflict
拒绝——且被拒绝的写入仍然 resolve(scope 的契约是「完成写入与恢复读取后结算」,
不是「被拒就抛错」)。于是设置栏显示「已保存」,而编辑内容静默回退,看起来就是
「完全存不了」。
现在改为一次原子 mutate(),整批修改共用一个栅栏和一次持久化决策;写入结算后
再回读命名空间section做校验,只有确认生效才报「已保存」,否则弹出「写入未生效」并
重新载入表单。没有 mutate() 的旧宿主回退为串行写入(每个等前一个完成,revision
链条依然正确),绝不并行。
另外删掉了 3 处 if (typeof scope.load === "function") scope.load():SettingsScope 接口
从来没有 load()(完整 seam 只有 getSnapshot / subscribe / mutate / set / unset,读走的是
共享 describe 镜像,由宿主 settings/document-updated 驱动刷新)。这些守卫是照臆测 API 写的
死代码,读起来像"已经刷新过了",反而掩盖了缺失的写入校验。
限制
- 从 0.6.3 起最低支持 DSH 0.1.0-rc.7,已针对 0.1.0-rc.7、
0.1.0-rc.8 和 0.1.1-rc.1 测试。仍使用 DSH 0.1.0-rc.6 的用户请锁定
dsh-tool-vision@0.6.1;这是最后一个包含旧 settings 白名单兼容补丁的版本。
- 被桥接的图片以文本指引进入对话(转录而非像素)——文本模型无法做像素级上下文推理;视觉模型的描述通过 inspect_image 回传。
- 桥接是单向门:文本模型下贴的图会在 agent/pre-step 被写进持久化日志,之后切到多模态模型也不会还原成图片块(反方向——多模态切到文本模型——会由 repairLoggedImages 自动补上桥接)。
- 图片以 base64 传输;注意隐私与大小限制。
- 独立于 dsh-llm 的路由/重试体系;失败会向 Agent 返回明确错误。
License
MIT —— 桥接预览与整合:xing666173。像素级视觉工具移植自
dsh-vision-router(© ysr666,MIT),
在此致谢。扫码进群