在 Claude Code / Codex / Pi 里用 DeepSeek,怎么让它看见图?

在 Claude Code / Codex / Pi 里用 DeepSeek,怎么让它看见图?

DeepSeek 写代码很香,接进 Claude Code、Codex、Pi 也越来越常见。但有一件事会反复踩坑:官方 API 是纯文本的。你把报错截图、UI 稿、接口文档拍照丢进去,模型要么直接说看不见,要么根据文件名瞎编。

我后来做了个很小的 skill:glm-vision。思路不复杂------看图的事交给智谱 GLM,推理和写代码还是 DeepSeek 。仓库在这里:voidman2017/glm-vision

这篇文章把问题和做法讲清楚:为什么官方看不了图、skill 的架构怎么拆、怎么装、边界在哪。

问题不在 agent,在模型接口

Claude、GPT、Gemini 本身就能吃 image 块。DeepSeek V4 Flash / Pro 的托管 API 文档里,输入类型是 text。coding agent 不管多聪明,发出去的请求里只要带上图片,上游就会拒,或者在进模型之前把图丢掉。

所以会出现一种很割裂的体验:

  • 用 Claude 时,@screenshot.png 就能对界面评头论足
  • 切到 DeepSeek 后,同一张图变成「我无法查看图片」

社区里另一条路是视觉代理:本地拦请求,把图转成文字再转发给 DeepSeek。那条路能做到「粘贴即看」,但要改 base_url、常驻端口,还可能和你已经在跑的 Claude 反代叠在一起。我想先要一个更轻的东西:

  • 不改 DeepSeek 的鉴权和线路
  • 不装额外 Python 依赖
  • Claude Code、Codex、Pi、OpenCode 都能用
  • 智谱 Flash 视觉模型免费,先把日常截图跑通

于是就只剩 skill + 一条命令。

它到底做了什么

agent 看见图片路径时,不要自己「看」,而是跑:

bash 复制代码
python3 scripts/see.py shot.png -q "这是什么界面?读出报错和关键按钮。"

see.py 把本地图编成 data:image/...;base64,...,打到智谱的 OpenAI 兼容接口 /chat/completions,把 stdout 里的描述交回 DeepSeek。DeepSeek 再决定怎么改代码、怎么回你。

整条链路可以画成:

flowchart TD A[&#34;你 @ 了一张图&#34;] --> B[&#34;SKILL.md 约束 agent<br/>先跑 see.py,禁止脑补像素&#34;] B --> C[see.py] C --> C1[&#34;读取 ~/.config/glm-vision/env&#34;] C1 --> C2[&#34;同一模型重试<br/>429 / 1305 / 5xx&#34;] C2 --> C3[&#34;再换队列里的下一个模型&#34;] C3 --> D[GLM 输出文字描述] D --> E[&#34;DeepSeek 继续写代码 / 解释报错&#34;]

有两个角色,不要混:

flowchart LR subgraph eye[眼睛] G[智谱 GLM-4.6V-Flash 等] end subgraph brain[大脑] D[DeepSeek] end G -->|文字描述| D D -->|改代码 / 解释报错| U[你]
角色 谁来当 干什么
眼睛 智谱 GLM-4.6V-Flash 等 读图、OCR、说界面上有什么
大脑 DeepSeek 根据文字描述推理、改代码、给方案

这不是原生多模态。DeepSeek 拿到的是「别人看过之后的笔记」,不是视觉 token。好处是主模型不用换;代价是描述漏了的细节,后面补不回来。所以 -q 要把当前任务写进去,而不是笼统的「描述这张图」。

架构上就三块

仓库很小,刻意保持三块分离。

flowchart TB subgraph skill[给 agent] S[SKILL.md] end subgraph cli[真正发请求] P[scripts/see.py] end subgraph cfg[不进 git] E[&#34;~/.config/glm-vision/env&#34;] end S -->|约束:先跑脚本,禁止脑补| P E -->|API Key / 模型队列 / 重试| P P -->|image_url + 描述| G[智谱 /chat/completions]

一次完整调用的时序:

sequenceDiagram actor User as 你 participant Agent as DeepSeek Agent participant Skill as SKILL.md participant See as see.py participant GLM as 智谱 GLM User->>Agent: @error.png 这是什么报错? Agent->>Skill: 匹配识图场景 Skill-->>Agent: 必须先跑 see.py Agent->>See: see.py error.png -q 用户原话 See->>See: 读 env,转 data URL loop 同一模型重试 See->>GLM: chat/completions + image_url alt 429 / 1305 / 5xx 且还有次数 GLM-->>See: 限流 else 成功 GLM-->>See: 文字描述 end end alt 仍失败且队列未空 See->>GLM: 换下一个模型再试 GLM-->>See: 文字描述 end See-->>Agent: stdout 描述 Agent-->>User: 基于描述解释并改代码

1. SKILL.md:给 agent 看的说明书

它不负责发 HTTP。它只规定:

  • 什么时候必须调用脚本(@ 图、路径是 png/jpg、用户说识图/看截图)
  • 命令怎么写,-q 怎么带上用户原话
  • 脚本已经会重试和降级,禁止 再包一层 sleep && retry
  • stdout 当事实,stderr 里的 info: / warn: 只说明用了哪个模型
  • 没有文件路径就请用户先保存,不要假装看见了剪贴板

人看的安装说明放在 README.md,不塞进 skill 包,避免每次识图都把装机步骤灌进上下文。

2. scripts/see.py:真正干活的 CLI

只有 Python 标准库:urllibbase64argparse。不需要 pip install openai

它做几件具体的事:

  • 把本地 PNG / JPEG / GIF / WebP 转成 data URL(上限 5MB)
  • 按 OpenAI 的 image_url 格式发给 VISION_BASE_URL/chat/completions
  • VISION_LANG 给视觉模型加一句「请用中文/英文回答」,和系统环境变量 LANG 分开,免得 macOS 的 en_US.UTF-8 把配置冲掉
  • 同一模型先重试,再换下一个

默认队列:

flowchart LR A[glm-4.6v-flash] --> B[glm-4.1v-thinking-flash] --> C[glm-4v-flash]

glm-4.6v-flash 官方标免费,也支持本地 base64,所以放队首。老的 glm-4v-flash 有过「不支持 base64」的记录,只能吃公网 URL,所以放队尾;一旦遇到的是格式错误而不是限流,脚本不会继续降级,避免把同一个坏请求打遍所有模型。

重试策略也很直白:

flowchart TD S[&#34;对当前模型发起请求&#34;] --> R{成功?} R -->|是| OK[输出描述] R -->|否| T{可重试?<br/>429 / 1305 / 5xx} T -->|是且未达次数| W[&#34;等待 2s / 4s / 8s&#34;] --> S T -->|是但次数用尽| N{还有下一个模型?} T -->|否 格式/鉴权等| X[停止降级并报错] N -->|是| M[换下一个模型] --> S N -->|否| X

每个模型最多 1 + VISION_RETRIES 次;等待按 VISION_RETRY_DELAY 翻倍。可重试:HTTP 429 / 500 / 502 / 503 / 504,以及智谱 1302、1305。

免费 Flash 高峰期很容易 429。如果失败一次就换模型,主模型几乎用不上;如果只死磕一个模型,又会卡死整轮对话。所以是「先礼貌地再问两遍,再换人」。

3. ~/.config/glm-vision/env:密钥单独放

Key 不进 git。agent 和脚本读同一份配置:

bash 复制代码
VISION_API_KEY=你的智谱key
VISION_BASE_URL=https://open.bigmodel.cn/api/paas/v4
VISION_MODELS=glm-4.6v-flash,glm-4.1v-thinking-flash,glm-4v-flash
VISION_RETRIES=2
VISION_RETRY_DELAY=2
VISION_LANG=zh

查找顺序:

flowchart TD A{&#34;$VISION_ENV_FILE 有值且文件存在?&#34;} -->|是| U[用该文件] A -->|否| B{&#34;~/.config/glm-vision/env 存在?&#34;} B -->|是| U2[用这份 env] B -->|否| C{&#34;~/.config/agent-vision-toolkit/env 存在?&#34;} C -->|是| U3[兼容 toolkit 的 env] C -->|否| E[缺少 VISION_API_KEY]

进程里的环境变量优先于文件。

怎么用

最佳推荐:AI时代自然是魔法打败魔法。直接提供仓库地址给AI,让它帮忙执行安装。当然也可以执行手动安装

安装

先克隆,再链到你正在用的 agent(不必四个都装):

bash 复制代码
git clone https://github.com/voidman2017/glm-vision.git
cd glm-vision

ln -sfn "$(pwd)" ~/.claude/skills/glm-vision
ln -sfn "$(pwd)" ~/.codex/skills/glm-vision
ln -sfn "$(pwd)" ~/.pi/agent/skills/glm-vision

对应目录:

Agent Skills 目录
Claude Code ~/.claude/skills/glm-vision
Codex ~/.codex/skills/glm-vision
Pi ~/.pi/agent/skills/glm-vision
OpenCode ~/.config/opencode/skills/glm-vision

Windows 可以用目录 Junction。不想软链就 cp -R。装完重启 agent,很多 CLI 只在启动时扫 skill。

然后配 Key:

bash 复制代码
mkdir -p ~/.config/glm-vision
cp assets/env.example ~/.config/glm-vision/env
chmod 600 ~/.config/glm-vision/env
# 填上 VISION_API_KEY,国内使用建议 VISION_LANG=zh

智谱开放平台实名后就能调 Flash 视觉模型,不必先充值。

先在终端验一下

bash 复制代码
python3 scripts/see.py --help
python3 scripts/see.py ~/Desktop/error.png -q "读出报错全文和底部按钮"

成功时 stderr 类似 info: using model glm-4.6v-flash,stdout 才是给 DeepSeek 看的描述。

常用参数:

bash 复制代码
# OCR,按阅读顺序抄文字
python3 scripts/see.py dialog.png --ocr

# 对比两张图
python3 scripts/see.py before.png after.png -q "布局和文案有什么差异?"

# 这次指定队列,或加大重试
python3 scripts/see.py shot.png --model glm-4.1v-thinking-flash
python3 scripts/see.py shot.png --retries 3 --retry-delay 2

在 agent 里怎么用

切到 DeepSeek,然后:

text 复制代码
@error.png 这个报错是什么意思?相关代码在哪?

skill 生效时,模型会先跑 see.py,再基于描述回答。如果你只是把图粘进输入框、没有任何路径,skill 帮不上 ------像素根本没落到磁盘。先保存,再 @

和「视觉代理」怎么选

glm-vision 本地视觉代理(如 agent-vision-toolkit)
粘贴即看 否,要有路径 能做
要不要改 DeepSeek 的 base_url 不用 通常要改,还可能叠一层本地端口
安装量 skill + 一份 env 代理进程、开机自启、和现有反代协调
适合 日常 @ 截图、OCR、对比 UI 三端无缝粘图、内置 view_image

我自己日常用 skill 就够了。已经有 Codex / Claude 反代、又特别依赖粘贴的人,再上代理更合适。两套可以共用同一份 VISION_* 配置。

几个踩过的坑

免费模型会限流。 智谱 1305「当前访问量过大」很常见。所以脚本默认同一模型试 3 次,再换 glm-4.1v-thinking-flash。三个 Flash 一起挤的时候,把付费 glm-4.6v 加到 VISION_MODELS 队尾当保底即可。

老 Flash 不一定吃 base64。 coding agent 里的图几乎都是本地文件,没有公网 URL。队首一定要用支持 data URL 的模型。

这是有损压缩。 GLM 漏读的一行小字,DeepSeek 无法「再看一眼」,除非你让脚本带着更具体的 -q 再跑一次。把用户原话传进去,比「请详细描述」有用得多。

skill 不是魔法。 它改变的是 agent 的行为约束,不是模型的输入模态。没有路径,就没有图。

小结

DeepSeek 官方暂时不提供识图 API。与其等接口,不如把「看」和「想」拆开:GLM 看图,DeepSeek 写代码。glm-vision 把这件事收成一个可安装的 skill,一条不依赖第三方包的命令,加上重试和降级,让 Claude Code / Codex / Pi 里的 DeepSeek 至少能认真对待一张截图。

仓库:github.com/voidman2017...

MIT,欢迎star,提 issue 和 PR。

相关推荐
Bigger22 分钟前
谁动了我的 URL?——记一次微前端"灵异 Bug"的排查实录
前端·ai编程·vue-router
用户5619035069331 小时前
多环境 API 怎么管理?dev/test/prod 一套规范
ai编程
lifallen1 小时前
长任务怎样选择遗忘:clearing、compaction 与 memory
人工智能·学习·ai·ai编程
却尘2 小时前
Agent Framework(2):差旅助手是怎样跑完一次 `RunAsync` 的
aigc·ai编程
chengliu05083 小时前
Crayfish 与 WorkBuddy 容器版:桌面 Agent、容器运行时,以及相对 RPA 的真实优势
ai编程
plainGeekDev3 小时前
软件工程术语库·前端·移动·AI·管理篇
aigc·ai编程·claude
花椒技术3 小时前
客服Agent:一个已交付 Agent 的工程实现拆解
agent·ai编程·产品
_codeOH4 小时前
Agent 记忆系统设计实战:让 AI 拥有长期记忆的工程方案
人工智能·ai编程
赫媒派4 小时前
OpenAI Recurrent Depth:3个安全隐患
安全·openai·ai编程
咸鱼老弟4 小时前
用 Cursor Rules / CLAUDE.md 把团队规范"固化"进 AI 编程工作流
ai编程