给 DeepSeek Harness 加上识图能力:从踩坑到发布开源插件的完整实践
摘要:DeepSeek 官方开源智能体框架 DeepSeek Harness 的默认模型是纯文本的,上传图片直接报"当前模型不支持"。本文记录完整解决方案:给 adapter 打 4 行补丁放行上传,再开发一个 vision 工具插件把识图"外包"给百炼视觉大模型,最后开源发布并跑通 CI。文末附真实踩坑清单。
项目地址:github.com/sjakdhasdh/…(MIT,欢迎 Star ⭐)
一、背景:文本模型的"眼盲"问题
DeepSeek Harness 是 DeepSeek 官方的 AI 智能体框架,底层用 Cordis 插件系统,提供 Web UI 让你和 Agent 对话,让它读写文件、执行命令、调用工具。
但默认模型(如 deepseek-v4-flash)是纯文本模型,上传图片时 Web UI 直接报错:
当前模型不支持图片,请切换支持图片的模型
用户发来的图片,Agent 完全"看不见"。这是硬伤。
二、核心思路:把识图外包给视觉大模型
既然模型没有原生识图能力,就让别的模型替它看:
用户发图片 → Agent 收到图片路径/URL
→ 调用 vision 工具
→ 转发给视觉大模型(阿里云百炼 qwen3.7-flash,OpenAI 兼容接口)
→ 拿到文字描述 → 回答用户
deepseek-v4-flash 虽然"看不见"图片,但能"读到"图片的文字描述——识图能力间接到手。
三、第一步:放行图片上传(4 行补丁)
3.1 拦截逻辑在哪
在 dsh-host-apiproxy 的 prompt 处理器里:
if (modelInfo.inputModalities !== void 0 && !modelInfo.inputModalities.includes("image")) {
// 拒绝:MODEL_DOES_NOT_SUPPORT_IMAGES
}
3.2 根因:adapter 硬编码纯文本
DeepSeek 官方 adapter(dsh-llm-deepseek)把所有模型硬编码为纯文本:
inputModalities: ["text"] // ← 拦截的根源
模型目录 schema 没有能力字段,配置层无解,只能打补丁。改动 4 处:
| # | 位置 | 改动 |
|---|---|---|
| 1 | modelInfo() | ["text"] → ["text", "image"](放行上传校验) |
| 2 | resolveModel() 回退分支 | 同上 |
| 3 | assertTextOnly() | 不再抛 UNSUPPORTED_CONTENT |
| 4 | flattenText() | 图片块渲染成标记 [图片附件: sha256:...] |
上传的图片以内容寻址方式存储:
~/.dsh/attachments/v1/objects/<sha256前2位>/<sha256>
⚠️ 注意:补丁在
node_modules里,重装依赖后会丢失。恢复步骤见项目内 PATCHES.md。
四、第二步:开发 vision 插件
用社区脚手架 create-dsh-plugin(几秒生成插件模板):
npx create-dsh-plugin dsh-vision -t tool --tool-name vision -y
4.1 核心逻辑
// 本地图片 → base64 data URL;URL 直接透传
async function toImageUrl(image: string): Promise<string> {
if (/^https?:///i.test(image)) return image
const resolved = resolve(image)
const data = await readFile(resolved)
return `data:image/jpeg;base64,${data.toString('base64')}`
}
// 调百炼 OpenAI 兼容接口
await fetch(`${baseURL}chat/completions`, {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
model,
messages: [{
role: 'user',
content: [
{ type: 'image_url', image_url: { url: imageUrl } },
{ type: 'text', text: prompt },
],
}],
}),
})
4.2 配置:三级优先级
插件 config > 环境变量 > 默认值,不写死任何 Key:
# profile 的 cordis.patch.yml
- id: dsh-vision
config:
apiKey: sk-xxx # 或环境变量 DASHSCOPE_API_KEY
model: qwen3.7-flash-2026-07-15
baseURL: https://dashscope.aliyuncs.com/compatible-mode/v1
4.3 安装
pnpm install && pnpm run build
dsh plugin --profile web add ./dsh-vision
重启后新建会话,模型工具列表里就会出现 vision 工具。
五、真实踩坑清单(都很痛)
- 路径含空格:
dsh plugin add转发给 pnpm 时把空格当分隔符。解法:用 8.3 短路径。 - schemastery 的
z.infer在verbatimModuleSyntax下不可用:改用普通 TS interface。 - PowerShell 5.1 读 UTF-8 脚本乱码:中文脚本要用 pwsh 7 跑。
- System.Drawing 的 GIF 编码器环境损坏:画 PNG 帧 + ffmpeg 合成。
- git 推送卡死:Git Credential Manager 无交互环境挂起;最终用认证头直推。
- 推送 workflow 文件被拒:OAuth token 缺
workflowscope,gh auth refresh -s workflow补授权。
六、效果实测
发送测试图(红圆 + 蓝矩形 + "Vision Test 123"),模型准确描述:
"左侧红色圆形,右侧蓝色矩形,下方黑色文字 Vision Test 123"
完整链路:上传放行 → 内容寻址存储 → 附件标记 → vision 工具 → 百炼识图 → 中文回答,全自动。
七、开源发布
- 仓库:github.com/sjakdhasdh/…(MIT)
- README 中英双语 + 演示 GIF
- GitHub Actions CI(typecheck + build,徽章绿色 ✅)
- 官方仓库 Discussion:#876
DeepSeek Harness 生态还在早期(0.1.0-rc),第一个识图插件这个生态位很有价值。欢迎 Star、Issue、PR!
如果你也在玩 DeepSeek Harness,欢迎留言交流。代码都在仓库里,拿去改、拿去发 PR。