前言¶
DeepSeek Harness(dsh)的核心理念是「一切皆插件」:模型、工具、会话、沙箱和界面都可以换。官方仓库是 deepseek-ai/deepseek-harness。日常驱动它的,往往是 DeepSeek、稠密 Qwen、Llama、Mistral 这类纯文本模型。
把截图贴进对话时,会撞上两堵墙。第一堵在发送前:dsh 按路由声明的模态检查附件,文本模型会被直接拒绝,并点出模型名。第二堵更麻烦:如果在文本路由上硬写 input: [text, image],附件能发出去,但上游会在回合中途返回 400 "not a multimodal model"——此时用户消息已经落盘,会话会反复重试一个永远成功不了的请求。
只加一个「看图工具」也解不开第一扇门:模型要先看见图片,才会决定去调工具,而那正是 dsh 拒绝的请求。社区维护者 tonyd2wild 因此做了 DeepSeek-Harness-Vision-Tools:文本模型继续当大脑,视觉模型只负责看,图片字节不到大脑上下文里。本文按插件目录页、GitHub README、examples/dsh.md 和仓库源码核对后整理。
这是什么¶
DeepSeek-Harness-Vision-Tools 是一款会话与消息类社区插件,由 tonyd2wild 维护,许可证 MIT。目录页与 GitHub 均标注 10 stars;目录收录日期为 2026-08-10,仓库最近推送时间为 2026-08-13。插件包名是 dsh-plugin-vision,package.json 中的版本为 0.1.0。
README 开头写明:这是非官方社区项目,与 DeepSeek AI 无隶属、无背书、非其维护。问题请开到本仓库,不要报到 DeepSeek。社区插件目录 deepseek-harness-plugin.com 是独立站点,也不是 DeepSeek / 幻方的官方应用商店。
它解决的问题可以缩成一句:任意文本模型搭配任意视觉模型,给 dsh 两条进图通道。
| 入口 | 机制 | 谁触发 |
|---|---|---|
| 聊天里附上的图片 | 视觉代理 shim/vision_shim.py |
自动拦截,模型到达前改写 |
| 磁盘上的图片文件 | analyze_image 工具 plugin/vision/ |
智能体按需调用 |
两条通道互补,不是主备关系。工具接不住聊天附件:附件必须先到模型,模型才会去调工具。代理也捡不起智能体还没放进消息的磁盘文件。图片只发给视觉模型;大脑看到的是 [Image: ...] 这类文字。
核心功能¶
大脑和眼睛分开,两端都由你选¶
仓库刻意不写死模型。维护者自己的 DeepSeek 构建和硬件组合别人很难复用,所以配方只留两个槽位:
| 槽位 | 放什么 | 建议 |
|---|---|---|
| 大脑(文本) | dsh 已经在跑的任意 OpenAI 兼容文本模型 |
沿用现有模型 |
| 眼睛(视觉) | 代理和/或工具去调的本地 VLM | 按 fast / detailed 分档 |
同一套眼睛可以服务两扇门。工具按调用选择后端;代理通过 --vision-model 指定一个:
| 角色 | 适用 | 仓库举例 |
|---|---|---|
fast(默认) |
颜色、版面、粗内容 | 约 0.8B 的小 VLM,如 Qwen3.5-0.8B |
detailed |
小字、细部、偏 OCR 的工作 | 更大的 VLM,如约 27B 的 Qwen2.5-VL / Qwen3-VL |
MODELS.md 给出的 fast 默认是 Qwen3.5-0.8B:Apple Silicon 走 MLX(mlx-community/Qwen3.5-0.8B-MLX-8bit),Windows / Linux / NVIDIA 走 llama.cpp(GGUF + mmproj)。活体占用大约 Mac 统一内存 2–3 GB,或 PC 约 2 GB 显存。不一定两档都开,先跑 fast 即可。
Ollama 目前还不能加载 Qwen3.5 的独立 mmproj,默认 fast 模型不能走 Ollama。若坚持用 Ollama 一行命令,仓库建议改 Moondream 或 Qwen2.5-VL,再把后端指到 http://127.0.0.1:11434/v1/chat/completions。
视觉代理:聊天附件在到达大脑前变成文字¶
代理是一个只依赖 Python 标准库的本地 HTTP 服务,对外说 OpenAI API,夹在 dsh 和文本上游之间:
POST /v1/chat/completions:把每条消息里的image_url块换成{"type":"text","text":"[Image: ...]"};若整条消息都变成文本,再收成普通字符串(有的服务器对 block 数组更挑剔)。GET /v1/models以及其他 GET 原样转发,方便dsh做模型发现。- 流式响应按字节转发。
dsh每个回合都在流式输出,缓冲会卡住界面。 - 视觉失败时降级,不抛死:块变成
[Image: (image could not be analyzed: ...)],回合仍能结束。 - 请求体上限 64 MB,因为图片是 base64 内联的。
dsh 的模型路由要指向代理,并声明 input: [text, image]。这句话对代理为真,对文本大脑为假。路由描述的是它正在对话的对象。
analyze_image:磁盘文件由智能体决定何时看¶
plugin/vision/index.js 用 @deepseek-ai/dsh-tools 的 defineTool() 注册模型可见工具。参数来自源码:
| 参数 | 是否必填 | 含义 |
|---|---|---|
path |
是 | 要分析的图片路径 |
backend |
否 | fast 或 detailed(以挂载时实际配置为准) |
prompt |
否 | 问视觉模型的问题,默认 "Describe this image in detail." |
工具把文件读成 base64,POST 到对应后端的 /v1/chat/completions,把返回的纯文本写进工具结果。未知后端会抛错并列出合法名称,没有静默回退,避免把 detailed 打成 fast 却看不出来。
读文件优先走 ctx.fs(遵守工作区边界和审批策略)。若退化到 readFileSync,会绕过沙箱,模型理论上能通过这个工具读盘上任意文件。仓库要求:只在受信任、有人值守的机器上依赖这条回退,无人值守前先把门闩上。
安装与启用¶
插件目录页给出的安装命令如下,在 DeepSeek Harness 终端执行:
dsh plugin add github:tonyd2wild/DeepSeek-Harness-Vision-Tools
目录页同时写了可复现写法:把 commit 哈希接到仓库名后面。
dsh plugin add github:tonyd2wild/DeepSeek-Harness-Vision-Tools#commit
插件以当前 dsh 进程的权限运行,安装时可能执行代码。安装前应检查源代码仓库和许可证。
这个仓库不是「只丢一个 JS 插件」那么简单:代理是独立 Python 进程,工具在 plugin/vision/。要两扇门都工作,需要按 README 把眼睛服务、代理和工具分别拉起来。前置条件(README「What you need」):
- 已有
dsh在跑的文本模型(任意 OpenAI 兼容端点) - 一台本地 VLM;最小的
fast档大约还要 2–3 GB 余量 - Python 3.8+(代理只用标准库,零第三方依赖)
pnpm(dsh plugin会调它;只装工具时需要)- 视觉运行时:Mac 用 MLX(
mlx-vlm),Windows / PC 用 llama.cpp(或 Ollama 跑回退模型)
快速起步:
git clone https://github.com/tonyd2wild/DeepSeek-Harness-Vision-Tools
cd DeepSeek-Harness-Vision-Tools
cp .env.example .env # 把端点改成你自己的主机
./setup.sh # 拉起本地视觉服务(RUN_PROXY=1 时连代理一起起)
门 1,代理(聊天附件):
python3 shim/vision_shim.py --port 8900 \
--upstream http://127.0.0.1:8000 \
--vision-url http://YOUR_FAST_VISION_HOST:8081/v1/chat/completions \
--vision-model your-fast-vlm
环境变量与 CLI 一一对应,CLI 优先:SHIM_PORT / --port,VISION_TARGET / --upstream,EYES_URL / --vision-url,EYES_MODEL / --vision-model。健康检查:
curl http://127.0.0.1:8900/health
门 2,工具(磁盘文件)。先把插件拷到稳定路径,并按仓库「陷阱 2」改 package.json 里 @deepseek-ai/dsh-tools 的 link:,指向当前 Harness 自带的那一份,不要装 npm 上的旧包(文档写的是 npm 上的 0.0.1-rc.1 比 Harness 自带的 0.1.0-rc.6 更老,而且会去引一个从未发布的包):
cp -r plugin/vision ~/.dsh/plugins/vision
dsh plugin --profile <p> add link:~/.dsh/plugins/vision
<p> 换成实际 profile,例如 web 或 headless。插件从 profile 目录解析,不要丢进安装目录的 node_modules,否则所有 profile 启动都会 ERR_MODULE_NOT_FOUND。每个要用的 profile 都要加一次。
典型用法¶
把一条 dsh 路由指到代理¶
模型路由写在 $DSH_HOME/settings.yaml 的 pi-ai 提供方块里。baseURL 指向代理,并声明图文输入。下面是 examples/dsh.md 的占位配置,主机和模型 id 换成你的:
llm-pi-ai:
providers:
vision-proxy:
displayName: Your Text Model (via vision proxy)
apiKeyEnv: YOUR_PLACEHOLDER_KEY_ENV
api: openai-completions
baseURL: http://127.0.0.1:8900/v1
models:
- id: your-text-model-id
contextWindow: 262144
maxTokens: 32768
input: [text, image]
无密钥的上游也要填 apiKeyEnv,指向任意非空环境变量。省略的话 pi-ai 会去做环境发现,找不到就报 PI_AI_ERROR: No API key。
再留一条直连上游、不声明 input 的后备路由,代理挂了还能继续干活:
text-only-direct:
displayName: Your Text Model (direct, no vision)
apiKeyEnv: YOUR_PLACEHOLDER_KEY_ENV
api: openai-completions
baseURL: http://127.0.0.1:8000/v1
models:
- id: your-text-model-id
contextWindow: 262144
maxTokens: 32768
模型路由热加载,不用重启。保存后在模型选择器里选代理那条,附上一张图即可。
给 analyze_image 配两个后端¶
在插件配置块或环境变量里写:
export VISION_FAST_URL=http://YOUR_FAST_VISION_HOST:8081/v1/chat/completions
export VISION_FAST_MODEL=your-fast-vlm
export VISION_DETAILED_URL=http://YOUR_DETAILED_VISION_HOST:8010/v1/chat/completions
export VISION_DETAILED_MODEL=your-detailed-vlm
智能体调用形态是 analyze_image(path, backend, prompt)。例如对截图或票据覆盖提示词:prompt: "List every object and any visible text."。
Web 表面上,面向模型的工具行在宿主层是关掉的,要靠 agent preset 才能看见。不要去改随安装分发的 standard preset,升级会被覆盖。建一个新 id 的用户 preset(例如 standard-vision),组合 web 和 analyze_image。用户 preset 不能复用已分发的 id,否则会被静默遮住。然后在 settings.yaml 里设默认(热加载):
agent-presets:
default: standard-vision
Preset 第一次开会话才挂载。看干净启动日志不能证明工具在;要开一场真实会话。
告诉智能体:它并没有变成多模态模型¶
dsh 会把 $DSH_HOME/AGENTS.md 读进每场会话。代理生效后,模型常会推断自己被切到了视觉路由。仓库提供了一段可粘贴说明,核心是:你仍是原来的文本模型;图已经被代理或工具写成了 [Image: ...];请说「描述表明……」,不要说「我能看见……」。
仓库给出的端到端核对方法¶
文本模型拿到图片块时,会编一段看起来合理的描述,读起来像成功。仓库用模型猜不到的纯色图做过观察:
- 非流式:纯绿 → “The image is a solid, bright green.”
- 流式:纯蓝 → “a solid, uniform field of deep, saturated blue”(5 个 chunk,干净的
[DONE]) - 同一套文本模型,直接塞图片会返回
400 "is not a multimodal model",用来证明字来自代理的视觉腿,不是大脑
复现方式:生成几张纯色 PNG,聊天里附一张问颜色(代理路径),或让 analyze_image 指向文件(工具路径),核对描述是否对得上。
适用场景与注意事项¶
适合:希望保住现在这颗文本大脑,又要让 dsh 对截图、照片、摄像头帧有情境感知的人。仓库原话是:它附加能力,不接管部署;代理是独立进程,随时可杀;工具只是多一个智能体可以调用的能力。
不适合当成原生多模态。仓库「Honest limits」写得很直:
- 描述是有损的。细部、精确空间关系和小物体可能丢。版面推理请换更大的
detailed模型。 - 小 VLM 读图中文字弱。
fast用体积换精度。OCR 重的工作把代理或工具指到更大的 VLM,并接受额外内存和延迟。 - 大脑推理的是字,不是像素。多数智能体工作(屏幕上有什么、照片里是什么、读一条报错)够用;关键 OCR 或细粒度视觉推理不够。
input: [text, image]是声明,不是检查。只对真正收图的端点声明:代理,或真正的 VLM。写在纯文本模型上,会在消息落盘后中途 400。
另外几条来自 examples/dsh.md 的坑:
- llama.cpp 路径必须带
--mmproj(视觉投影器)。backends/pc_llamacpp.sh会自动传。漏了的话 llama.cpp 会静默按纯文本跑,描述全是空话。这是最常见的「进程在跑但看不见」。 - Windows 绝对路径在 preset 里可用,在 profile patch 里会把
C:当成 URL scheme,报ERR_UNSUPPORTED_ESM_URL_SCHEME。两边都用裸包名更稳。 - 改
settings.yaml(模型路由、默认 preset)不用重启;改 preset 的agent.cordis.yml也不用,下场会话按文件时间戳换代;改插件index.js要重启(ESM 按进程缓存);代理本身只重启代理进程,dsh不受影响。
若文本大脑跑在 DGX Spark 上,仓库认为 fast 视觉模型大约 2–3 GB,通常可以和大脑放在同一台机器,把 --vision-url 指到 127.0.0.1。Spark 上报的「空闲」内存会高估 CUDA 实际可用量(GPU 与 CPU 共用一块池);小 fast 多半放得下,大 detailed VLM 未必。先确认服务起来再依赖。
持久化方面:代理可用 autostart/ 里的 Windows 登录脚本(.vbs)或 Linux systemd user unit;工具靠上面的用户 preset。两者独立。
小结¶
DeepSeek-Harness-Vision-Tools 做的不是把 dsh 换成多模态模型,而是在聊天附件和磁盘文件两条入口上,把「看」交给本地视觉模型,把「想」留给原来的文本模型。目录页安装命令是 dsh plugin add github:tonyd2wild/DeepSeek-Harness-Vision-Tools;真要两扇门都通,还要按 README 起视觉服务、代理,并按 profile 用 link: 挂上 plugin/vision。
安装前请阅读源码和 MIT 许可证。插件以当前 dsh 进程权限运行。问题请开到本仓库,不要报到 DeepSeek。
- 插件目录:https://deepseek-harness-plugin.com/zh-CN/plugins/deepseek-harness-vision-tools/
- GitHub:https://github.com/tonyd2wild/DeepSeek-Harness-Vision-Tools
- 集成说明:仓库内
examples/dsh.md - DeepSeek Harness 官方仓库:https://github.com/deepseek-ai/deepseek-harness