dsh-qwen-vision
   
> English: README.en.md
给 DeepSeek Harness 的 Web GUI 装上"眼睛"。 本插件整合 Qwen-MM-Plugins 的云端视觉模型,让没有 原生视觉能力的模型在 Agent 工作流层面获得完整的图片/音视频理解能力。
✨ 功能
1. Qwen 视觉 MCP 工具 —— 为 agent 注册 mcp__qwen-mm-plugins-api__vision_chat、ocr、 grounding、omni_asr、omni_av_caption、transcribe_audio、segmentation 等工具。 2. 聊天框直接粘贴图片 —— 在输入框 Ctrl+V 图片:自动上传到 POST /qwen-vision/paste, 保存到 $DSH_HOME/qwen-vision-paste/,并把文件路径插入光标处,无需手打路径。 3. qwen-image-vision 技能 —— 每个会话自动学会把四种来源的图片路由到视觉工具: 粘贴的图、拖拽进聊天框的附件、Windows 剪贴板截图、用户给的本地路径/URL。 4. 零依赖、免构建 —— 纯 JavaScript 产物,没有 prepare 脚本,git 安装无需 allowBuilds 授权。
🚀 快速开始
0. 最省事:让 DSH 自己装
DSH 本身就是一个能操作终端的 agent —— 直接把仓库地址发到对话框,让它自己完成安装:
> 帮我安装插件 https://github.com/Asanagl/dsh-qwen-vision,装完提醒我重启 dsh web,并告诉我验证步骤
DSH 会自己执行 dsh plugin --profile web add、检查 uv/git 依赖,并引导你配置 DashScope Key。
1. 安装
dsh plugin --profile web add github:Asanagl/dsh-qwen-vision安装后重启 profile:
dsh --profile web> 建议锁定版本:dsh plugin --profile web add github:Asanagl/dsh-qwen-vision#v0.1.1
2. 配置 DashScope API Key
DSH 启动 MCP 子进程前会过滤凭据类环境变量,因此 key 必须写入 Qwen-MM-Plugins 的共享配置文件 (视觉、OCR、ASR 等云端能力需要;本地 core 文件读取不需要):
mkdir -p ~/.qwen-mm-plugins
printf 'DASHSCOPE_API_KEY=sk-...\n' > ~/.qwen-mm-plugins/config也可以运行 Qwen-MM-Plugins 安装器的 Configure 步骤完成配置。 Key 在 阿里云百炼 申请。
3. 使用
| 你的操作 | Agent 的反应 |
|---|---|
| 截图后 Ctrl+V 到输入框,直接提问 | 读取插入的路径,调用 vision_chat |
| 不粘贴,直接说"看下我刚截的图" | 直接读取 Windows 剪贴板图片 |
| 把图片拖进聊天框,说"看下我发的图" | 到附件库取最新一张并识别 |
| 把图片路径/URL 发给它 | 直接识别 |
🏗 工作原理
┌─────────────────────────── DeepSeek Harness (web profile) ───────────────────────────┐
│ │
│ cordis.patch.yml (bundle 层) │
│ ├── mcp-qwen-mm-plugins-api ── stdio ──▶ uvx qwen-mm-plugins[api] ──▶ DashScope │
│ │ (Qwen VL / Omni 云端模型) │
│ └── qwen-vision (本包,双面插件) │
│ ├─ Node 半 (index.js) │
│ │ ├─ POST /qwen-vision/paste → $DSH_HOME/qwen-vision-paste/*.png │
│ │ └─ ctx.skills.register('qwen-image-vision') │
│ └─ 浏览器半 (client.js, window.__ModuleLoader__) │
│ └─ 拦截输入框 paste 事件 → 上传 → 光标处插入路径 │
└───────────────────────────────────────────────────────────────────────────────────────┘- 组合包层(
cordis.patch.yml):插入@deepseek-ai/dsh-mcp-client行注册 Qwen-MM-Plugins
的 stdio MCP server,以及本包自身的插件行。
- Node 半(
index.js):通过ctx.inject(['webServer'])/ctx.inject(['skills'])声明服务依赖——
服务就绪后再激活、服务卸载时自动清理,服务缺失时保持未激活而不会阻塞启动。 在 ctx.webServer 注册粘贴接收路由(25MB 上限,同名同构图片格式), 在 ctx.skills 注册 qwen-image-vision 技能;两项注册失败都只告警、绝不拖垮 DSH 启动。
- 浏览器半(
client.js):零依赖 client 模块,通过window.__ModuleLoader__.load
注册工厂,捕获阶段拦截输入框的图片粘贴事件。
📋 环境要求
- DeepSeek Harness 0.1.0-rc.6+(已在 rc.6 验证)
- PATH 中有 uv(提供
uvx)和git - DashScope API Key(云端视觉能力)
- 音视频能力(
omni_*/transcribe_audio)需要 ffmpeg
🔧 常用配置
Qwen-MM-Plugins 的运行时配置都写在 ~/.qwen-mm-plugins/config(KEY=VALUE 行,环境变量优先)。 常用项:
| 变量 | 默认 | 用途 |
|---|---|---|
DASHSCOPE_API_KEY | — | 云端视觉/OCR/ASR 等(必配) |
DASHSCOPE_BASE_URL | DashScope 兼容地址 | 覆盖 OpenAI 兼容端点 |
QWEN_MM_API_VL_MODEL | qwen3.7-plus | vision_chat / OCR / grounding 默认模型 |
QWEN_MM_API_OMNI_MODEL | qwen3.5-omni-plus | Omni 音视频理解默认模型 |
完整目录见 Qwen-MM-Plugins 配置参考。
❓ 常见问题
装了之后工具没出现? MCP 行在 profile 启动时加载。重启 dsh --profile web 并新建会话后再看工具列表。
Windows 上能用吗? 能。本插件为 MCP 子进程设置了 PYTHONUTF8=1,规避中文 Windows 的 GBK 控制台编码崩溃; uvx 走原生 Windows 的 uv。上游 Qwen-MM-Plugins 官方仅在 WSL2 验证,原生 Windows 属社区路径。
MCP 工具调用失败怎么排查? 手动跑一次系统检查:
uvx --from "qwen-mm-plugins[api] @ git+https://github.com/QwenLM/Qwen-MM-Plugins.git@qwen-mm-plugins-api-v1.0.2" \
qwen-mm-plugins-api --check-system要花钱吗? vision_chat / ocr / omni_* 等走 DashScope 云端,按量计费;费用在百炼控制台查看。 粘贴接收、路径插入、技能本身都在本地,不产生费用。
如何卸载?
dsh plugin --profile web remove dsh-qwen-vision已保存的粘贴图片在 $DSH_HOME/qwen-vision-paste/,可自行删除。
⚠️ 已知限制
- DSH 0.1.0-rc.6 会把 MCP 返回的 image/audio/resource 块渲染为
content discarded;
文本结果(看图回答、OCR、语音转写)完全可用,依赖媒体回传的流程尚不完整。
- 粘贴只支持图片;非图片文件请继续用拖拽或路径。
- 25MB 单图上限(超大图会弹 toast 跳过)。
🔄 更新
dsh plugin --profile web add github:Asanagl/dsh-qwen-vision#v0.1.1插件随 Qwen-MM-Plugins 的不可变 tag(qwen-mm-plugins-api-v1.0.2)固定,升级视觉后端 = 在 cordis.patch.yml 中改 args 里的 tag 并重启。
🧯 事故记录:2026-08-15 启动失败
最初版本在 apply() 里同步 ctx.get('skills'),但服务未就绪时返回 undefined; 随后在 readFile(...).then() 的异步回调里调用 skills.register(),外层 try/catch 捕获不到这个 Promise 回调中的异常:
> npx @deepseek-ai/dsh web
dsh: fatal load failure: TypeError: Cannot read properties of undefined (reading 'register')
at file:///C:/Users/Asanagi/code/dsh-qwen-vision/index.js:103:16修复要点(同时适用于所有 DSH 插件):
1. 服务依赖一律用 ctx.inject(['service'], callback) 声明,让 Cordis 等待服务就绪并在 服务变化时卸载/重跑;不要同步 ctx.get('service') 后立即使用。 2. inject 回调可以是 async;把最终返回的函数(disposer)return 出去用于卸载清理。 3. 异步代码的错误必须在同一条 Promise 链里 catch,不能留给外层同步 try/catch。 4. 可选功能(路由、技能)注册失败只 logger.warn,绝不把整个 DSH 拖成 fatal load failure。 5. 改动后跑 npm test(含负向用例),再重启 dsh web 做启动回归。
📄 许可证
MIT。Qwen-MM-Plugins 为 Apache-2.0,在运行时拉取,未随包分发。