Skip to content
dsh.fish
Bundle

deepseek-visual-plugin

DeepSeek Harness 视觉理解插件:把用户消息与工具结果中的图片翻译成文字描述,交给纯文本任务模型(如 DeepSeek)。

Source
zhangzhimou78-code
stars
1 stars
License
MIT
Updated
Updated 14 days ago

Readme

# deepseek-visual-plugin

DeepSeek Harness 视觉理解插件:把用户消息与工具结果中的图片翻译成文字描述,交给纯文本任务模型(如 DeepSeek)。**多模态模型(原生支持 image 输入)自动放行,不经过翻译。**

DeepSeek Harness 的插件是 Cordis 插件(TypeScript/ESM)。本插件按原生协议实现:拦截含图片的消息,自动判断当前模型是否原生支持 image:

- **纯文本模型**:调用视觉模型生成详细描述,再把图片块替换为描述文本。
- **多模态模型**:图片块原样进入模型请求,插件不介入。

替换发生在内容写入会话日志之前,模型请求与日志始终一致。

## 安装

本插件以单文件 ESM 插件形式部署到 Harness 家目录,通过 home 级补丁启用,对**所有 profile(web / headless 及未来新建的 profile)**生效:

**Windows(PowerShell)**

```powershell
# 1. 部署插件代码(与已在运行的安装共享 $DSH_HOME/profiles/node_modules 解析回退)
$dest = "$env:USERPROFILE\.dsh\profiles\node_modules\deepseek-visual-plugin"
New-Item -ItemType Directory -Path $dest -Force | Out-Null
Copy-Item index.js, package.json, cordis.patch.yml -Destination $dest -Force

# 2. 在 $DSH_HOME/cordis.patch.yml 中加入(不存在则创建;该文件被每个 profile 加载并被 HMR 监听):
# - insert:
#     - id: deepseek-visual
#       name: deepseek-visual-plugin
#       config:
#         model: <视觉模型名>
#         baseUrl: <OpenAI 兼容端点>
#         apiKeyEnv: <凭证引用名,如 DOUBAO_API_KEY>
```

**Linux / macOS(Bash / Zsh)**

```bash
# 1. 部署插件代码(与已在运行的安装共享 $DSH_HOME/profiles/node_modules 解析回退)
dest="$HOME/.dsh/profiles/node_modules/deepseek-visual-plugin"
mkdir -p "$dest"
cp index.js package.json cordis.patch.yml "$dest"

# 2. 在 $DSH_HOME/cordis.patch.yml 中加入(不存在则创建;该文件被每个 profile 加载并被 HMR 监听):
# - insert:
#     - id: deepseek-visual
#       name: deepseek-visual-plugin
#       config:
#         model: <视觉模型名>
#         baseUrl: <OpenAI 兼容端点>
#         apiKeyEnv: <凭证引用名,如 DOUBAO_API_KEY>
```

正在运行的 `dsh web` 会通过 home 补丁热更新自动挂载;若未生效,重启 `dsh web` 即可。**修改插件源码后必须重启 `dsh web`**:web 组合禁用了模块级 HMR,配置热更新不会重新加载已变更的插件模块。修改后重新执行第 1 步复制即可生效。

也可以作为常规 bundle 安装进单个 profile:

```sh
dsh plugin --profile web add C:\path\to\deepseek-visual-plugin
```

## 配置

`cordis.patch.yml` 已用默认值挂载该行。可调参数:

| 字段 | 默认值 | 说明 |
|---|---|---|
| `model` | `qwen3.7-plus` | 视觉模型名(OpenAI 兼容端点上的模型 ID) |
| `baseUrl` | DashScope 兼容端点 | 留空时回退 `QWEN_BASE_URL` / `DASHSCOPE_BASE_URL` / `OPENAI_BASE_URL` |
| `apiKey` | 空 | API Key 的**显式覆盖**(可选,不推荐明文写进配置) |
| `apiKeyEnv` | 空 | 凭证引用名(如 `DOUBAO_API_KEY`),通过 dsh 的 credentials 服务(`~/.dsh/.credentials.yaml`)解析 |
| `imagePrompt` | 内置中文提示词 | 图片描述提示词 |
| `timeoutMs` | `60000` | 单次视觉请求超时 |

**API Key 的解析优先级**:`config.apiKey`(显式覆盖)→ `config.apiKeyEnv`(credentials 服务解析 `~/.dsh/.credentials.yaml`)→ 环境变量回退(`QWEN_API_KEY` / `DASHSCOPE_API_KEY` / `OPENAI_API_KEY`)。

推荐做法:把 key 存进 `~/.dsh/.credentials.yaml`,配置里只写 `apiKeyEnv` 引用,避免明文密钥落在配置文件里:

```yaml
# ~/.dsh/.credentials.yaml
DOUBAO_API_KEY: <你的 key>
```

```yaml
# cordis.patch.yml
- insert:
    - id: deepseek-visual
      name: deepseek-visual-plugin
      config:
        model: doubao-seed-2-0-mini-260428
        baseUrl: https://ark.cn-beijing.volces.com/api/v3
        apiKeyEnv: DOUBAO_API_KEY
```

在 profile 的 `cordis.patch.yml` 中按行 id 覆盖配置(必须重述全部键)。未配置任何 key 时插件仍会加载:含图片的消息会被占位文本替换(提示无法解析),并给出一次日志警告;纯文本对话不受影响。

## 效果示例

以下截图来自真实运行中的 DeepSeek Harness。纯文本模型通过本插件"看懂"图片——多模态模型自动放行,纯文本模型触发翻译。

**1. 视觉模型把 Windows 开始菜单截图翻译成详细描述**

![视觉模型描述 Windows 开始菜单](docs/screenshots/01-vision-windows-start.png)

**2. 纯文本模型基于描述给出结构化回答**

![纯文本模型基于描述的结构化回答](docs/screenshots/02-text-response-windows-start.png)

**3. 多类 UI 截图都能稳定翻译**

插件会自动识别当前模型是否原生支持 image:多模态模型直接放行,纯文本模型触发翻译。例如下面的 DSH 侧边栏与模型下拉菜单截图都能被准确描述:

![视觉模型描述 DSH 侧边栏](docs/screenshots/03-vision-dsh-sidebar.png)
![模型推理下拉菜单截图](docs/screenshots/04-thinking-dropdown.png)
![模型对下拉菜单截图的最终回答](docs/screenshots/05-response-dropdown.png)

## 行为说明

- **自动识别模型能力**:插件查询当前模型是否原生支持 image。纯文本模型(如 DeepSeek chat-completions 适配器)触发翻译;多模态模型(如 GPT-4o、Claude、Qwen-VL 等原生支持 image 的模型)直接放行。
- **模型判断依据是「当前实际模型」,而非 agent 创建时的 seed 模型**:`agent.options` 是 agent 创建时固定的初始模型,不随用户在 UI 切换模型而更新;真实请求的模型由 `modelSelection` 在 `system-prompt/assemble` 阶段快照到 `assembly.variables.provider/model`。插件监听该事件缓存每个 agent 的「当前实际模型」,`agent/pre-step` 与 `tools/post-execute` 据此判断,缓存缺失时才回退到 `agent.options`。
- 覆盖两处图片入口:`agent/pre-step`(Web UI 粘贴/拖拽图片、客户端消息)与 `tools/post-execute`(`read_image` 等工具结果)。
- **图片准入**:插件包装 `ctx.llm.resolveModelInfo` / `listModels`,为**所有** provider 声明 `['text','image']`,使 Web 上传、`selectModel` 切换、`read_image` 等能力闸门放行;对于纯文本模型,图片随后在 `agent/pre-step` 被翻译成文字,实际请求不会携带图片块;对于多模态模型,图片块原样进入请求。卸载插件时声明自动恢复。
- 单张图片解析失败只替换为占位文本,不会中断会话。
- 原始图片仍保存在附件存储中;纯文本模型的会话历史中显示的是文字描述而非图片,多模态模型的会话历史中保留原始图片。
- DSH 的消息格式目前只有图片块(无视频块),视频抽帧逻辑未移植。
- `verify.mjs` 是本插件的功能自检(模拟 llm/attachments/credentials/fetch,不依赖真实 Harness)。先 `npm install` 安装 devDependencies,再运行 `npm test`(等价 `node verify.mjs`)确认。

## 开发与自检

```bash
npm install   # 安装 devDependencies(@deepseek-ai/schemastery),用于本地跑自检
npm test      # 等价于 node verify.mjs,运行功能自检
```

`verify.mjs` 模拟了 `ctx.llm` / `ctx.attachments` / `ctx.credentials` / `fetch`,在无需真实 Harness 的情况下驱动 `apply()`,验证:图片准入 patch、纯文本模型翻译、多模态模型放行、`system-prompt/assemble` 模型快照、无图快路径、失败占位、卸载恢复等。

## 卸载

**Windows(PowerShell)**

```powershell
Remove-Item -Recurse -Force "$env:USERPROFILE\.dsh\profiles\node_modules\deepseek-visual-plugin"
# 并从 $DSH_HOME/cordis.patch.yml 中删除 deepseek-visual 行
```

**Linux / macOS(Bash / Zsh)**

```bash
rm -rf "$HOME/.dsh/profiles/node_modules/deepseek-visual-plugin"
# 并从 $DSH_HOME/cordis.patch.yml 中删除 deepseek-visual 行
```

若改用 bundle 方式安装过,另行 `dsh plugin --profile <name> remove deepseek-visual-plugin`。

Install

dsh plugin --profile web add github:zhangzhimou78-code/deepseek-visual-plugin

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source