dsh-visionary

by zhuiyueya

视觉与多模态github收录于 08-23

在图片抵达 LLM 前透明地转成 OCR 文本 + 视觉模型描述——让 DeepSeek API 终于能「看见」聊天图片

A DeepSeek Harness plugin that transparently turns chat images into OCR text + vision-model descriptions before they reach the LLM — so DeepSeek API can finally see…

安装

dsh plugin --profile web add github:zhuiyueya/dsh-visionary

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

安装与环境配置指引、插件开发教程见 DSH 中文社区文档 ↗

安装即在你的机器上以你的权限运行第三方代码——它可读写文件、使用凭据、访问网络,DSH 的工具审批不会为插件代码加沙箱。「检测到 manifest」仅代表发现 dsh.bundle / dsh.plugin 清单,不构成兼容性或安全审查;安装前请审阅源码,不熟悉的插件先在不含密钥的环境试用。

README

目录

👁️ dsh-visionary

给纯文本的 DeepSeek 模型装上眼睛。

一个 DeepSeek Harness 插件:在图片到达模型之前,透明地把聊天中的图片转换成 OCR 精确文字 + 视觉模型结构化描述 —— 从此 DeepSeek API 也能看懂截图、文档、照片和图表。

License: MIT DSH Node UI 配置

English · 简体中文


✨ 为什么需要它

DeepSeek API 是纯文本模型。在对话里粘贴一张图片,Harness 会直接拒绝(UNSUPPORTED_CONTENT)——截图看不了、文档看不了、照片看不了。

dsh-visionary 恰好守在被拒绝的那道边界上,在适配器看到图片之前把请求改写:每个图片块变成一个结构化文本块(精确 OCR 转写 + 详细的视觉模型描述)。用户侧的聊天记录保留原图,只有模型侧的请求被转换。

⚡ 特性

  • 🔌 透明、框架级 —— 挂在所有 LLM 调用的唯一汇合点(streamWithRegistration)上;web、headless、子代理全部生效
  • 🖥️ 在「设置 → 模型」页配置 —— 预置 6 个视觉提供商(GLM-4V、Qwen-VL、硅基流动、OpenRouter、Gemini、Ollama),像添加 DeepSeek 一样点几下即可,零配置文件
  • 🔁 多后端回退链 —— 按 免费 → 付费 → 本地 Ollama 依次尝试,谁先成功用谁;失败原因聚合,绝不中断对话
  • 🔤 OCR + VLM 混合 —— 截图/文档走本地精确 OCR;自然图片走结构化 VLM 描述(并附上 OCR 文本互为印证)
  • 🧠 能力感知 —— 目标模型声明支持图片输入时原样放行,零开销
  • 🗃️ 双层缓存 —— 会话级(vision/describe 事件)+ 全局 KV(~/.dsh/storages):同一张图跨轮次、跨会话都只转换一次
  • 🛡️ 防刷屏护栏 —— 每条描述 maxChars 硬截断、单请求图片预算、超大图送 VLM 前自动缩小
  • 💪 失败不阻塞 —— 转换失败变成明确的占位文本,模型会如实告知用户;可选严格模式直接报错

🔧 工作原理

flowchart LR
    U[用户粘贴图片] --> S[附件存储<br/>字节 + 元数据]
    S --> M[用户消息<br/>含 image block]
    M --> B{dsh-visionary<br/>守在 LLM 边界}
    B -->|模型支持图片| P[原样放行]
    B -->|纯文本模型| T[转换每个图片块]
    T --> C{命中缓存?}
    C -->|是| F[复用转换文本]
    C -->|否| O[OCR - 本地 tesseract / HTTP 服务]
    O --> V[VLM 回退链<br/>GLM-4V → Qwen-VL → Ollama...]
    V --> F
    F --> R[纯文本模型作答<br/>如同亲眼所见]
  • 拦截点:LlmRuntime.streamWithRegistration —— llm.stream() 与 prepareCall().stream() 的共同出口
  • 模型侧 / 用户侧分离:会话日志保留原图(界面不变),仅模型请求被改写
  • 图片 → 文本格式:
[用户上传的图片 <attachmentId>, 1024x768, image/png]
── OCR 识别文本 ──
<图中精确文字>
── 视觉模型描述(glm-4v-flash)──
<结构化描述>

🚀 快速开始

# 1. 安装插件到 profile
dsh plugin --profile web add dsh-visionary

# 2. 在 ~/.dsh/profiles/web/cordis.patch.yml 激活
- insert:
    - id: visionary
      name: dsh-visionary

重启 dsh web 即生效 —— 发截图零配置可用(内置 tesseract OCR)。想获得完整效果,再加一个视觉模型:

🖥️ 在设置页「模型」里配置视觉模型

打开 设置 → 模型,与配置 DeepSeek 的操作完全一致:

  1. 点击 添加模型,从目录里选一个:

    目录项 默认端点 说明
    GLM-4V-Flash(智谱,免费) https://open.bigmodel.cn/api/paas/v4 免费、中文强,首选
    Qwen-VL(阿里云百炼) https://dashscope.aliyuncs.com/compatible-mode/v1 中文效果顶级
    Qwen2.5-VL(硅基流动) https://api.siliconflow.cn/v1 注册送额度
    OpenRouter 视觉模型(含 :free) https://openrouter.ai/api/v1 一个 key 多模型
    Gemini 视觉模型(Google) https://generativelanguage.googleapis.com/v1beta/openai 免费层额度大
    Ollama 本地视觉模型 http://localhost:11434/v1 离线、隐私、无需 key
  2. 粘贴 API key(存入 DSH 凭据库,可直接点 获取模型 自动探测模型列表)。

  3. 确认 baseURL 与模型 id,保存。完成——全程不碰 YAML。

配置了多个视觉模型时,自动按目录顺序组成有序回退链(目录顺序 = 优先级);已配置的模型随时可在页面编辑/删除。任何提供商路由下声明了 image 输入模态的模型都会被自动纳入。

OCR 调优、模式、缓存属于 vision: 命名空间的高级配置——默认值已开箱即用。

🧭 模式与回退链

模式 行为 适用场景
auto(默认) 先 OCR;OCR 达到 ocr.minChars 字数视为"文本图"→ 仅 OCR。否则 VLM 描述(附 OCR 上下文互证) 一切
ocr 仅 OCR 截图、文档、代码、表格
vlm 仅视觉模型 照片、自然图片、示意图
both OCR 和 VLM 都要(VLM 纠正/补充 OCR) 需要语义理解的文档

每张图的回退顺序:设置页配置的提供商 → vlm.backends —— 逐个尝试直到成功;超时/API 错误自动换下一个;全部失败变成可见占位符(严格模式则报错)。

⚙️ 高级配置

全部可选,写在 settings.yaml 的 vision: 段(热更新):

vision:
  mode: auto            # auto | ocr | vlm | both
  ocr:
    engine: auto        # auto(http→rapid-json→tesseract) | tesseract | http | rapid-json | none
    languages: [chi_sim, eng]   # tesseract 语言包
    minChars: 20        # auto 模式:OCR 达到该字数视为"文本图",不再调 VLM
    # http: { url: "http://127.0.0.1:8000/ocr" }   # 自托管 PaddleOCR/RapidOCR 服务
    # binaryPath: "/path/to/RapidOCR-json"         # Windows/Linux 高精度 OCR
  vlm:
    enabled: true
    maxChars: 2000       # 每条描述硬上限(提示词约束 + 输出截断双保险)
    maxPixels: 1500000   # 超过该像素数先等比缩小再送 VLM(需 sharp)
    prompt: |            # 默认中文明细描述提示词,可自由覆盖
      请以中文详细描述这张图片……
    backends:            # 传统有序回退链(设置页配置的提供商优先)
      - name: local-ollama
        baseUrl: http://localhost:11434/v1
        model: qwen2.5vl
  skipVisionModels: true         # 目标模型支持图片时原样放行
  cache: { session: true, global: true, maxAgeMs: 2592000000 }
  concurrency: 4                 # 单请求图片并行转换数
  maxImagesPerRequest: 10        # 单请求图片预算(超出用省略标记)
  placeholderOnError: true       # false = 转换失败直接让 LLM 请求报错

OCR 引擎

引擎 说明
tesseract 内置,纯 JS + WASM,零原生依赖;语言包自动下载(设 langPath 可完全离线)
http 对接任意自托管 OCR 服务(PaddleOCR/RapidOCR FastAPI、Dify OCR 节点)—— 中文精度最佳路径;POST {"image":"data:…"} 期望 {"text":"…"}
rapid-json RapidOCR-json 二进制(Windows/Linux,中文高精度)
none 关闭 OCR(纯 VLM 模式)

API key 解析

apiKey(字面量)→ apiKeyEnv 环境变量 → DSH 凭据服务。本地服务(Ollama)允许无 key;云端无 key 会 401 并自动回退到下一个后端。

🗃️ 缓存

  • 会话层:会话日志里的 vision/describe 事件 —— 同一会话内同一张图跨轮次零重复调用
  • 全局层:~/.dsh/storages 的 KV 单元 —— 新会话里遇到同一张图也不会重新转换
  • 缓存键对转换配置做指纹(模式、OCR 引擎、后端端点/模型、提示词、各项上限),更换模型后旧缓存自动失效

❓ 常见问题

用户还能看到自己的图片吗? 能。聊天记录保留原图,只有模型侧的请求携带文本。

会花钱吗? OCR 本地免费;默认 VLM(GLM-4V-Flash)官方免费;回退链(免费 → 付费 → 本地 Ollama)由你掌控。

图片会发给第三方吗? 只有当你配置了云端 VLM 才会。mode: ocr(或本地 Ollama)时一切都在本机完成。

为什么不用工具式方案? 工具式插件依赖模型记得去调工具(通常还要写硬规则兜底)。本插件是推式:转换发生在适配器之前、无条件执行——模型连"看不了"的选项都没有。

一条消息多张图? 并行转换(受 concurrency 限制)、缓存、预算封顶。

🧪 开发

git clone git@github.com:zhuiyueya/dsh-visionary.git
cd dsh-visionary && npm install

# 端到端测试(真实 tesseract OCR + mock VLM 服务 + 转换断言)
node test/e2e.mjs          # 20/20 PASS

# 真实 DeepSeek API 集成验证(在 profile 目录运行,见脚本头注释)

📌 Topics

Recommended GitHub tags for discoverability:

deepseek-harness  dsh-plugin  vision-bridge  image-understanding
multimodal  ocr  vlm  text-only-llm  llm-plugin  glm-4v  qwen-vl  ollama

📜 许可证

MIT

🙏 致谢

架构参考了 OpenClaw 的媒体理解(推式预处理)、opencode 的图片规范化、block/goose 的本地推理模态门控,以及 vision-bridge-mcp 的回退链——融汇成一个 DeepSeek Harness 原生插件。

原始 README: https://github.com/zhuiyueya/dsh-visionary/blob/main/README.zh-CN.md ↗