nlqh7
dsh-vision-router
给 DeepSeek Harness 纯文本模型加视觉:聊天框拖图自动分流给用户配置的视觉模型转文字,v4 不切换模型即可识图。 Vision for text-only DSH models: routes chat-box images to a user-configured vision model and returns text descriptions, deepseek-v4-pro reads images without switching.
- Stars
- 1
- Language
- TypeScript
- Created
- Aug 16, 2026
- Updated
- Aug 16, 2026
Introduction
@deepseek-ai/dsh-vision-router
English | 中文
让纯文本主模型(如 deepseek-v4-pro)在聊天框接收图片:图片在前置步骤被路由到用户配置的视觉模型转成文字描述,再回填给主模型。主模型全程只看到文字,无需切换模型。
工作原理
插件做三件事:
- 能力声明改写 — 把主模型的
inputModalities报告为['text', 'image'],使前端放行聊天框图片。通过替换ctx.llm.resolveModelInfo实现(cordis 无方法装饰 API,采用 monkey-patch 并在插件卸载时恢复原方法,避免 HMR 泄漏)。 - 自动发现视觉模型 — 扫描
ctx.llm.listProviders()与listModels(provider),找到第一个inputModalities含image的模型作为视觉模型;也可用visionProvider/visionModel显式指定。发现结果按llm/adapters-updated失效重扫。 - pre-step 分流转文字 — 监听
agent/pre-step,扫描进入步骤的消息里的ImageBlock,对每张图构造一条[{type:'image', attachment}, {type:'text', text: 描述指令}]的 user 消息经ctx.llm.stream()发给视觉模型,把返回文字作为【图片内容】…文本块替换原图片块。视觉模型适配器(pi-ai)负责读附件字节与 base64 序列化,插件零视觉 API 代码。
配置
interface Config {
/** 主模型 provider 路由,默认 `deepseek-official`。 */
provider?: string
/** 主模型 id,默认 `deepseek-v4-pro`。 */
model?: string
/** 优先视觉 provider;省略则自动发现。 */
visionProvider?: string
/** 优先视觉模型 id;省略则自动发现。 */
visionModel?: string
/** 发给视觉模型的描述指令。 */
imagePrompt?: string
/** 每次视觉调用的输出 token 上限,默认 1024。 */
maxTokens?: number
}
挂载
插件加载前,用户需在 DSH「设置 → 模型 → 添加自定义提供方」里配置一个 OpenAI 兼容视觉模型,并给该模型声明 input: [text, image](见 DSH 官方文档《配置模型》「图片输入」一节)。插件不内置任何视觉 provider 的地址或密钥。
安装
# 方式一:从 GitHub 仓库安装
dsh plugin --profile web add "github:<owner>/dsh-vision-router"
# 方式二:npm 安装后手动挂载
npm i @deepseek-ai/dsh-vision-router
挂载(cordis.patch.yml)
- insert:
- id: vision-router
name: '@deepseek-ai/dsh-vision-router'
config:
provider: deepseek-official
model: deepseek-v4-pro
装好并重启后,用纯文本主模型在聊天框拖图,图片会自动转成文字描述。
Model Experience
主模型请求(图片被替换)
What the model sees
主模型收到的消息里,每个 ImageBlock 被替换成一个文本块。视觉调用成功时文本为 【图片内容】 前缀 + 描述正文;未配置视觉模型时为 [图片:未配置视觉模型,无法识别];视觉调用失败或返回空文本时为 [图片:识别失败]。
Token effect
每张图贡献一次替换文本,长度由视觉模型描述决定;图片字节从不进入主模型上下文。每张不同的图各触发一次视觉调用,其 token 计费发生在视觉模型侧,与主模型请求分离。
KV Cache effect
替换发生在 agent/pre-step,先于主模型请求,因此主模型请求的前缀稳定(图片被替换成确定性文本后按普通文本参与前缀)。视觉调用是独立请求,不影响主模型前缀复用。
视觉模型请求(辅助调用)
What the model sees
视觉模型收到一条用户消息,含图片引用块与描述指令文本。指令默认要求输出纯描述、不加前缀标题。
Token effect
每次辅助调用为一条带图消息;输出上限由 maxTokens(默认 1024)约束。
KV Cache effect
独立请求;与主模型请求前缀无关,不共享、不失效主模型缓存。
Known Limitations and Deferred Work
- 前端硬拦截仍按主模型能力判断 — 插件改写的是
resolveModelInfo的返回值,所以需要该调用路径真正经过ctx.llm.resolveModelInfo(前端发送图片前的检查与主请求都走这里)。若某个未来前端改走别的能力查询,图片仍会被拦。 - 图片不进主模型上下文 — 图片块留在会话日志里(界面渲染缩略图),但发给主模型的请求被替换成文字描述,所以主模型永远拿不到原图字节;若后续主模型自身支持视觉、需要原图,需停用本插件或调整
provider/model。 - 视觉调用缓存在插件生命周期内 — 同一
attachmentId只调用一次视觉模型(进程内缓存 + in-flight 去重);跨会话重启后缓存清空,相同图片会重新描述。 - 发现依赖
llm/adapters-updated— 视觉模型在会话中途新增时,下一个请求会重扫;但已缓存的失败发现不会主动重试,除非拓扑变化或新会话。