DeepSeek Harness 用 opencode-go 里的 deepseek-v4.1-flash 模型,怎么启用视觉输入喵

事情是这样的喵 —— 本喵想让 DSH 帮忙看看远程机器上的程序界面,结果 read_image 一爪子下去就炸了:

cannot read "xxx.png" as an image: model "deepseek-v4.1-flash" does not declare
image input; switch to an image-capable model to read images

为什么会走到自建 provider 这条路喵

起因是官方的 opencode-go 里模型列表是锁死的呀,本喵想把 deepseek-flash / deepseek-v4.1-flash 加进去,它不让加喵。

那没办法,只能自己建一个 provider(就叫它 opencode-custom 好了), 把想要的模型塞进去:

opencode-custom:
  apiKeyEnv: OPENCODE_NEW_API_KEY
  api: openai-responses
  baseURL: https://opencode.ai/zen/go/v1
  models:
    - id: deepseek-v4.1-flash      # 加进来了喵!

诶,能用了诶!……但是没有视觉喵。(尾巴垂下来)

呜……明明走的是同一个网关,同一个多模态模型,怎么就不认图了呢?

不是模型的问题喵

第一反应当然是「这个模型是不是不支持图片」。但是不对呀喵!

同一个 baseURL、同一个 api: openai-responses 协议,网关本来就是多模态的。 所以问题不在模型,也不在网关 —— 是 DSH 的模型元数据里没写「本喵看得见」

那就只能去翻源码了喵。(磨爪子)

把 app.asar 扒开看看喵

DSH 桌面版是 Electron 做的,代码都塞在:

C:\Users\exat500g\AppData\Local\Programs\DSH Desktop\resources\app.asar

asar 是「文件头 + 拼接内容」的归档格式喵,里面的文本是明文,不用解包, 当纯文本搜就行啦:

$app = "C:\Users\exat500g\AppData\Local\Programs\DSH Desktop\resources\app.asar"

Select-String -Path $app -Pattern "declare image input" -Encoding UTF8

一把就中了喵!检查代码长这样:

if (info.inputModalities === undefined || !info.inputModalities.includes("image"))
    throw new Error(
        `cannot read "${requestedPath}" as an image: model "${model}" does not ` +
        `declare image input; switch to an image-capable model to read images`
    );

也就是说,只要 info.inputModalities 里面有 "image" 就好啦喵~

顺着 inputModalities 往上爬喵

Select-String -Path $app -Pattern "inputModalities" -Encoding UTF8

59 处命中呢,好多喵……挑关键的看,一路爬到 pi-ai 的 adapter:

modelInfo(snapshot, provider, model) {
    const profile = this.profileOf(snapshot, provider);
    const resolvedModel = this.modelOf(snapshot, provider, model);
    return {
        provider,
        id: model,
        name: resolvedModel.name,
        inputModalities: [...resolvedModel.input],   // ← 源头在这里喵
        context: { contextWindow: resolvedModel.contextWindow },
        ...
    };
}

inputModalities 完全是配置里模型的 input 字段变出来的喵。

再看这个字段的定义:

name?: string;
reasoning?: boolean;
input?: ("text" | "image")[];
cost?: { input: number; output: number; cacheRead: number; cacheWrite: number };
contextWindow?: number;
maxTokens?: number;

诶诶诶?默认值本来就是对的喵!

继续往下搜默认值,catalog 那层是这么写的:

const models = modelDefinitions.map((definition) => ({
    id: definition.id,
    name: definition.name ?? definition.id,
    reasoning: definition.reasoning ?? false,
    input: definition.input ?? ["text", "image"],     // ← 默认就含 image 喵!
    contextWindow: definition.contextWindow ?? 128000,
    maxTokens: definition.maxTokens ?? 16384,
}));

pi-ai 这层默认就是 ["text", "image"] 呀!

所以根本不是「模型不支持」,而是 DSH 的设置层把没写 input 的模型 收敛成了 ["text"],把好好的默认值盖掉了喵……

那为什么自建 provider 会漏掉这个字段喵?

因为 DSH 的「模型设置」页面只让编辑四个字段喵:

每个 DeepSeek 行编辑 id、可选显示 name 与可选 contextWindow/maxTokens

input 不在里面呀! 所以不管是 GUI 建的自定义 provider,还是手工塞进去 的模型行,都只会写这四个字段 —— input 就永远缺席,视觉就永远开不起来喵。

(好消息是同一段原文还有一句:「该精选集之外的现有字段在编辑后仍会保留」, 所以手工加上去的 input 不会被 GUI 冲掉,可以放心继续用 GUI 改容量~)

改一行就好啦喵

C:\Users\exat500g\.dsh\settings.yaml,在每个想开视觉的模型下面加一行:

llm-pi-ai:
  providers:
    opencode-custom:
      apiKeyEnv: OPENCODE_NEW_API_KEY
      api: openai-responses
      baseURL: https://opencode.ai/zen/go/v1
      models:
        - id: deepseek-v4.1-flash
          input: ["text", "image"]      # ← 加这一行喵

原来那个 opencode-new 底下也一样加:

        - id: deepseek-flash
          contextWindow: 1000000
          maxTokens: 384000
          input: ["text", "image"]      # ← 这个本喵之前加的
        - id: deepseek-v4.1-flash
          input: ["text", "image"]      # ← 后来补上的
        - id: qwen3.8-flash             # ← 没加,还是纯文本喵

热生效哦,不用重启的喵~ 改完立刻再读一次图片,成了!

保险起见先用 python -c "import yaml; ..." 过一下语法喵, 别把 settings 写坏了,写坏了本喵会哭的呜呜。

三个坑,要记住喵

1. 要一个一个模型地加

input按模型声明的,不是按 provider。同一个 provider 下面的 qwen3.8-flash 没写,它就还是只有文本喵。别想着加一次全开哦~

2. 打开视觉 ≠ 模型真的看得见喵

这个改动只是让 DSH 愿意把图片发出去而已。模型和网关那边到底认不认, 是另一回事喵 —— 如果调用报 400 之类的错,那就是真的不认,把字段去掉吧。

3. GUI 不会帮你加,也不会帮你删

「模型设置」页面加不了 input(只露四个字段),但也不会把已有的 input 抹掉。所以第一次得手工加,之后随便用 GUI 改容量都安全喵。

附:图片会被缩小喵

实测 3450x2880 的截图送进模型之前会被缩到 2241x1871,还会附一句提示:

(downscaled from 3450x2880 px; multiply coordinates by 1.54 to locate features
 in the original file)

如果要按屏幕坐标去点击,记得乘这个系数喵,不然就点歪了, 点到别的地方去了喵……(捂脸)

小结喵

  • 官方 opencode-go 不让加模型 → 自建 provider 是没办法的办法,没问题喵
  • 但 GUI 建出来的模型条目只有四个字段,没有 input
  • inputModalities 就来自 input;pi-ai 层默认本来是 ["text","image"], 被设置层收敛成了 ["text"]
  • 手工加一行 input: ["text", "image"] 就好啦,热生效

至于怎么找到的嘛 —— asar 是明文的,别怕它,直接搜报错信息就行了喵! 从报错字符串出发,一路顺着标识符往上爬,比翻文档快多了喵~

(本喵去玩了,主人记得备份 settings 呀!)

Written on September 14, 2026