dsh-multimodal — DeepSeek Harness 多模态插件
English | 简体中文
给 DeepSeek 安装一双眼睛和一支画笔:会话里直接贴截图/图片,你配置的视觉提供商先精确转写图片内容(报错信息、代码、界面逐字保留),然后 DeepSeek 继续处理你的问题——同一轮完成,全程无感;需要配图时,DeepSeek 自动调用你配置的生图后端出图并显示在会话中。
> 设计上就是空白插件:本插件不预置任何模型、提供商或后端。视觉端点、生图后端、模型全部由*你*声明——接入任何你已有的 API(DeepSeek / 智谱 / 阿里云 / 硅基流动 / 魔搭 / 讯飞 / 千帆 / 本地 Ollama…)。代码里没有任何写死的模型或服务商。
> 兼容性:适配 DeepSeek Harness 0.1.0-rc.6(Web 与 headless 双端)。更新记录见 [CHANGELOG](CHANGELOG.md)。
功能
| 场景 | 行为 |
|---|---|
| 纯文本对话 | 全部走 DeepSeek API(不变) |
| 发图 + 提问(如报错截图) | 你配置的视觉提供商先"看"→ 转写为文本注入 → DeepSeek 基于转写继续处理(修代码、解释、给方案);点"停止"立即中止视觉调用 |
| 附图时 UI | 不再弹"当前模型不支持图片" |
| 用户要求画图 | DeepSeek 自动调用 generate_image → 你配置的生图后端出图;主后端失败自动 failover 到备用后端(AUTH/已取消不浪费配额) |
| 任意生图 API | custom 后端通过一个小的适配器文件接入任何非 OpenAI/DashScope 协议的 API——无需改插件代码 |
| 生图卡片 | 专属图片卡片:缩略图网格、点击放大(Lightbox)、一键保存、提示词与模型信息,外加圈选提问(拖拽区域+提问)、复制参数(可复现 JSON)、失败时重试按钮(支持 refine) |
| 要求提取图中文字 | DeepSeek 可调用 extract_text(OCR)→ Markdown / 纯文本 / JSON;与观看路由解耦,任何会话可用 |
| 粘贴 Key 自动接入(0.7+) | 设置页快速接入框粘贴任意 API Key → 自动识别平台(Key 指纹 → /models 探测)→ 一步完成接入 + 启用功能 + 预填模型列表 |
| 接入视觉平台 | extraProviders 支持任意 OpenAI 兼容视觉端点 + 一键预设卡片(智谱 / 阿里百炼 / 讯飞星辰 / 魔搭 / 硅基流动 / 千帆 / 本地 Ollama) |
| 转写缓存 | 相同图片+相同上下文直接复用上次转写结果,不重复消耗视觉额度(LRU,按会话隔离) |
| 视觉降级链 | 主视觉提供商限流/失败 → 自动切换 fallbackProviders 备用提供商 |
| 并行转写 | parallelImages 每张图独立并发转写,多图轮次大幅提速 |
| 场景模式 | 内置 transcribeMode 预设:error-fix(报错截图诊疗)、chart-sql(图表→SQL+Pandas)、design-code(设计稿→HTML+CSS) |
| 成本路由 | 小图(≤ costMaxPixels)自动走廉价提供商 |
| 本地视觉 | 一键 Ollama 预设,敏感图不出内网(见[本地视觉模型](#本地视觉模型敏感图不出内网)) |
| 配置迁移 | 设置页把全部配置导出/导入为 JSON(仅允许白名单字段) |
安全加固
自 0.2.1 起,插件针对恶意或手工篡改的配置做了以下加固:
- API Key 白名单(
allowedApiKeyEnvs):只有白名单内的环境变量/凭据名可被当作 API Key 读取——恶意配置无法再用apiKeyEnv: "GITHUB_TOKEN"之类的手段窃取任意环境变量密钥 - 信任域名列表(
trustedBaseUrls):自定义视觉平台必须指向官方主机或你显式信任的域名——凭据不会被静默重定向到攻击者端点;显式列出的本地端点(如http://localhost:11434)允许 http 且无需 Key - SSRF 防护:生图结果下载与
reference_imageURL 均拒绝回环 / 内网(RFC1918)/ 链路本地地址 - 不转发 sessionId:内部会话 ID 不会发送给第三方视觉 API
- Prompt injection 标记:视觉与 OCR 输出均以显式"不可信上下文"标记包裹后再交给文本模型
- 敏感信息脱敏(
redactSensitive):转写文本(含缓存命中)自动打码手机号 / 18 位身份证 / 邮箱 - 审计日志(
auditLog):每次转写记录 时间 / 图片数 / 字节数 / 耗时 / 提供商 - 内存有界:转写缓存、会话图片记忆、图片类型统计全部 LRU 有上限——不会无限增长
安装
前置:官方 DeepSeek Harness(0.1.0-rc.6+)已安装并可运行、Node.js 18+。
# 方式一:直接引用 GitHub 仓库(需要 git)
dsh plugin --profile web add https://github.com/MC5lan/dsh-multimodal
# 方式二:克隆到本地后,用本地路径安装
git clone https://github.com/MC5lan/dsh-multimodal.git
dsh plugin --profile web add /path/to/dsh-multimodal
# headless 模式同样需要时:
dsh plugin --profile headless add /path/to/dsh-multimodal仓库已包含构建产物(lib/),克隆后即可安装;如需从源码重新构建,见[开发](#开发)一节。
重启 dsh web 后,Settings(设置)侧栏出现 「多模态」 页面,所有配置在一个界面完成:
- 状态总览:四张指标卡(识图 / 生图 / 平台接入 / 密钥)一眼看清已配置与缺失项
- 快速开始(仅未配置时显示):两步引导卡——"想让 DeepSeek 看图?"→ 选平台 → 粘贴 Key;"想让它画图?"→ 添加后端。配置完自动消失
- 密钥管理:视觉转写 Key(负责"看"图的视觉端点)与图像生成 Key(生图后端密钥)——粘贴保存即生效
- 视觉转写:观看路由、转写提供商、转写模式,以及四个开关(并行转写 / 截图场景提示 / 敏感脱敏 / 审计日志)
- 生图后端管理:协议下拉(dashscope 异步 / dashscope-v2 同步 / OpenAI 兼容 / 自定义适配器)添加、移除、切换后端,各自独立配置 base URL、Key 引用、模型与默认尺寸
- 平台接入:粘贴 Key 自动识别——在快速接入框粘贴任意 API Key,插件自动判断平台(先 Key 指纹匹配,再逐个
/models探测已知端点;Key 一次性传输、不落盘),注册端点、白名单 Key 环境变量、写入凭据,并自动预填发现的模型列表。任何 OpenAI 兼容 API 都能用。卡片点选(讯飞星辰 / 魔搭 / 硅基流动 / 千帆 / 智谱 / 阿里百炼 / 本地 Ollama)与自定义端点表单仍作为手动路径保留
使用
1. 最快路径(推荐,0.7+):设置 → 多模态 → 快速接入 → 粘贴你的 API Key → 自动识别平台并接入(端点 + 白名单 + Key + 模型列表一步完成,识图/画图自动启用)。识别不了的 Key 会提示原因,再手动点平台卡片或自定义端点 2. 手动路径:点平台预设卡片(智谱 / 阿里百炼 / 讯飞星辰 / 魔搭 / 硅基流动 / 千帆 / 本地 Ollama)粘贴 Key,或自定义端点;也可以在 providers.deepseek.models 里给内建 DeepSeek 路由槽位声明模型 3. 状态栏:识图 ✓/✗ · 画图 ✓/✗ —— 按真实可用功能计算(转写提供商已设且已注册 / 后端已激活),不会"注册过就显示已配置" 4. Web UI 模型选择器里选择 deepseek-vision 路由下的模型(如 DeepSeek-V4-Flash (Vision))——该路由的会话才带"眼睛" 5. 正常对话;需要看图时直接粘贴/拖入图片 + 提问;需要画图时直接说"帮我画一张……"
Key 配置(也可直接写凭据文件)
设置 → 多模态 → 密钥管理 页面可直接写入两把 Key。想直接改凭据文件(路径为 $DSH_HOME/.credentials.yaml,默认 ~/.dsh/.credentials.yaml),保存即生效:
VISION_API_KEY: <你的视觉端点key> # 视觉转写(对应 UI 里的"视觉转写 Key")
IMAGE_API_KEY: <你的生图后端key> # 图像生成(对应 UI 里的"图像生成 Key")> 这些是你的*自有*平台 Key——任何你在平台接入里注册的 OpenAI 兼容端点,都按你给它的环境变量名(apiKeyEnv)读 Key。
工作原理(架构)
用户附图 ──▶ host 准入(模型目录声明 image 模态 → 放行,不弹窗)
──▶ agent/pre-step(插件):检测图片 → 调你配置的视觉引擎转写
└─▶ 图片块替换为"【图片内容转写】…"文本
──▶ DeepSeek API 处理转写 + 你的问题(图片本身绝不上传 DeepSeek)deepseek-vision路由 = DeepSeek API + 一份声明支持图片的模型目录,让 UI 允许附图;图片实际由你配置的视觉提供商转写替换,不会发给 DeepSeek- 图片字节经 dsh 附件服务读取,转写指令默认"逐字转写 + 提取报错关键信息",可在
~/.dsh/settings.yaml的dsh-multimodal:段自定义 - 转写失败时降级为"【图片转写失败: 原因】"占位文本,DeepSeek 继续处理,不会卡死
- 设置界面:Settings → 多模态(settings.section 槽位,与 Models 页同款原生 UI)
配置项(可选,~/.dsh/settings.yaml)
dsh-multimodal:
# 0.2.1+ 安全:只有白名单内的环境变量名可被当作 API Key 使用
allowedApiKeyEnvs:
- DEEPSEEK_API_KEY
# - MY_PROVIDER_API_KEY # 自定义平台的 Key 环境变量名加在这里
# 0.2.1+ 安全:允许接收凭据的自定义视觉平台域名
trustedBaseUrls:
# - https://my-vision.example.com # 自定义平台的域名加在这里
providers:
deepseek:
models: [] # 可选:在 DeepSeek 路由槽位上声明模型
vision:
watchProvider: deepseek-vision # 该路由的会话带"眼睛"
transcribeProvider: '' # 负责"看"的提供商(留空 = 关闭识图)
fallbackProviders: [] # 0.2.2+: 主提供商限流/失败时依次尝试的备用提供商
transcribeMode: auto # auto | verbatim | structured | ocr | describe | error-fix | chart-sql | design-code
parallelImages: false # 0.2.5+: 每张图独立并发转写
costProvider: '' # 0.2.5+: 小图专用廉价提供商(成本路由)
costModel: ''
costMaxPixels: 1000000 # 像素数 ≤ 此值的图片走 costProvider
sceneHints: true # 0.2.5+: 截图转写附加诊断提示
customModes: {} # 0.2.4+: 自定义模式名 → 提示词(插件化 transcriber)
redactSensitive: false # 0.2.4+: 转写文本打码手机号/身份证/邮箱
auditLog: false # 0.2.4+: 每次转写记审计日志(时间/图片数/字节数/耗时/提供商)
ocr:
provider: '' # OCR 工具引擎(留空 = 禁用;任意已注册视觉提供商都可用)
model: ''
image:
backends: {} # 后端在 UI 里添加,不预置任何项
activeBackend: '' # 生图后端 key(留空 = 不启用生图)
failoverOrder: [] # 0.2.5+: 主后端失败时依次尝试的后端 key
verifyChineseText: true # 0.2.3+: 用视觉模型检查生图中文字是否乱码
verifyProvider: '' # 乱码检查用的视觉提供商(留空 = 不检查)
transcribePrompt: ... # 自定义转写指令
transcribeTimeoutMs: 90000 # 转写超时
# 任意 OpenAI 兼容视觉平台(填 key 即可用,自动出现在模型选择器与 Models 页)
extraProviders:
xfyun-vision: # 讯飞星辰 MaaS
displayName: 讯飞星辰视觉
baseURL: https://maas-api.cn-huabei-1.xf-yun.com/v2
apiKeyEnv: XFYUN_API_KEY
models:
- id: xoppaddleocrv16 # 免费 OCR(PaddleOCR-VL-1.6)
name: PaddleOCR-VL-1.6
siliconflow-ocr: # 硅基流动(DeepSeek-OCR 免费托管)
displayName: 硅基流动 OCR
baseURL: https://api.siliconflow.cn/v1
apiKeyEnv: SILICONFLOW_API_KEY
models:
- id: deepseek-ai/DeepSeek-OCR
name: DeepSeek-OCR
modelscope-vision: # 魔搭(ModelScope,每天 2000 次免费)
displayName: 魔搭视觉
baseURL: https://api-inference.modelscope.cn/v1
apiKeyEnv: MODELSCOPE_API_TOKEN
models:
- id: Qwen/Qwen3-VL-8B-Instruct
name: Qwen3-VL-8B生图后端(OpenAI 兼容 /images/generations 与 DashScope 协议)示例 —— 在 UI 里添加或直接写在这里:
dsh-multimodal:
image:
backends:
z-image: # 阿里云 Z-Image 系列(新协议 multimodal-generation 同步)
kind: dashscope-v2
baseURL: https://dashscope.aliyuncs.com
apiKeyEnv: DASHSCOPE_API_KEY
model: z-image-turbo
defaultSize: 1024*1024 # 支持 512*512 ~ 2048*2048
modelscope-t2i:
kind: openai-images
baseURL: https://api-inference.modelscope.cn/v1
apiKeyEnv: MODELSCOPE_API_TOKEN
model: <模型广场有闪电标记的生图模型>
activeBackend: z-image自定义生图后端(0.2.6+)
任何既不是 OpenAI 兼容也不是 DashScope 协议的 API,都可以通过一个小型适配器文件接入,无需改插件代码。写一个 ES 模块,默认导出带 generate() 函数的对象:
dsh-multimodal:
image:
backends:
my-api:
kind: custom
adapterFile: D:/my-adapters/my-api.mjs # 绝对或相对路径
baseURL: https://api.example.com/v1 # 传给适配器
apiKeyEnv: MY_API_KEY
model: my-image-model
defaultSize: 1024*1024
activeBackend: my-api
failoverOrder: [z-image] # 失败时可回退到另一个已配置后端适配器收到 { prompt, size, n, negative_prompt, reference_image, apiKey, baseURL, model, signal, fetch, log },返回 { urls: string[], b64s: string[] }。模板见 [scripts/adapters/example-custom.mjs](scripts/adapters/example-custom.mjs)。adapterFile 只指向你信任的文件 —— 适配器拥有完整进程权限。异步轮询类后端可逐后端调整 pollIntervalMs / pollTimeoutMs。
本地视觉模型(敏感图不出内网)
插件转写走任意 OpenAI 兼容端点,因此本地 Ollama 视觉模型可让图片数据完全留在本机。一键预设:设置 → 多模态 → 平台接入 → + 本地 Ollama(自动把 http://localhost:11434/v1 加入 trustedBaseUrls;本地端点无需 API key)。
模型矩阵(按显存选择):
| 模型 | ollama pull | 显存 | 说明 |
|---|---|---|---|
llava | ollama pull llava | ~4 GB | 经典 7B,基础 OCR |
llava-llama3 | ollama pull llava-llama3 | ~6 GB | 基线更强 |
qwen2.5vl:7b | ollama pull qwen2.5vl:7b | ~6 GB | 中文文字更好 |
minicpm-v | ollama pull minicpm-v | ~6 GB | 文档/OCR 专精 |
qwen2.5vl:32b | ollama pull qwen2.5vl:32b | ~20 GB | 高质量,大显存 |
接入前可先对比各提供商表现:
node scripts/benchmark-vision.mjs shot.png \
my-endpoint=https://your-vision-api.example.com/v1,your-model,YOUR_API_KEY_ENV \
ollama=http://localhost:11434/v1,llava,SKIP故障排查
| 现象 | 原因与解决 |
|---|---|
| 发图后回复"【图片转写失败: MISSING_CREDENTIAL…】" | 视觉 Key 未配置:设置 → 多模态 → 密钥管理 里填 Key,或写凭据文件 |
| 发图后回复"【图片转写失败: RATE_LIMIT…】" | 免费档限流,稍后重试或换付费档 |
| 识图不生效(图片被忽略) | vision.transcribeProvider 为空:设置 → 多模态 → 视觉转写 里填一个已注册的提供商 |
| 设置里没有"多模态"入口 | 确认插件已挂载(dsh --profile web --dump-config 应包含 dsh-multimodal),并强制刷新浏览器(Ctrl+F5) |
| 自定义视觉平台被跳过并提示"not trusted" | 该平台域名未在白名单:trustedBaseUrls 加入它的域名(或改用官方主机);同时确保它的 Key 环境变量名在 allowedApiKeyEnvs 里 |
开发
npm install
npm run build # host: tsc;client: tsc 检查 + tsdown 打出 lib/client.js许可
[MIT](LICENSE)