Files
val-blog/skills/vision/SKILL.md
T

5.0 KiB
Raw Blame History

name, description, metadata
name description metadata
vision Agent 识图工具 - Gemini 2.5 Flash Lite(首选)或本地 Qwen2.5-VL(降级)分析图像内容
author version tags trigger trigger_priority
Val 2.3.0
vision
image
multimodal
gemini
local-model
automatic high

Vision 识图技能

目标

当 agent 收到图片消息时,自动调用视觉模型识别图片内容,并将描述纳入对话上下文,让 agent 能够"看见"图片。

触发条件(自动)

agent 在以下任一情况必须自动触发本技能,优先于内置 image 工具:

  • 用户通过任何渠道(Telegram、微信、QQ 等)发送的图片消息
  • 消息中包含图片附件(<qqmedia> 标签、image_url、文件附件等)
  • 用户直接要求 agent 看图
  • agent 需要理解图片内容才能继续对话

自动执行流程:

  1. 检测到消息中有图片 → 优先使用本技能(走 Gemini curl 流程)
  2. 不要依赖内置 image 工具,除非 Gemini curl 流程失败
  3. 识图结果作为辅助信息写入对话上下文,让 agent 能基于图片内容回复用户

引擎策略

按优先级顺序:

  1. Gemini 2.5 Flash Lite(首选)— 快(1-3 秒),准确,可用性高,通过环境变量 GEMINI_API_KEY 调用
  2. Gemini 2.5 Flash(二选)— 更高精度,但免费层有时 503,仅在 Lite 失败时降级尝试
  3. 本地 Qwen2.5-VL(最终降级)— 纯本地,但 CPU 推理非常慢(10-90 秒),仅在前两者都不可用时回退

调用方式

第一步:定位图片文件

图片文件存放在 /Users/guchen/.openclaw/media/inbound/ 目录下,文件名通过消息中的 UUID 标识获取。

例如消息中的 media 路径或 filename 中包含 UUID,对应的文件路径为 /Users/guchen/.openclaw/media/inbound/{UUID}.jpg

如果图片以 URL 形式传入,先下载到临时文件:

curl -sL -x http://127.0.0.1:7897 -o /tmp/vision_input.jpg "{图片URL}"

第二步:Gemini API(首选,通过 exec + curl

# 加载 GEMINI_API_KEY(注意:~/.zshrc 里 export 的值带双引号,
# 用 eval 展开确保去掉外层引号,否则 API 调用会报 key invalid
eval "$(grep '^export GEMINI_API_KEY=' ~/.zshrc 2>/dev/null)"
export HTTPS_PROXY=http://127.0.0.1:7897
VISION_B64=$(base64 -i /tmp/vision_input.jpg | tr -d '\n')
# 或者从 inbound 目录读取
VISION_B64=$(base64 -i /Users/guchen/.openclaw/media/inbound/{UUID}.jpg | tr -d '\n')

# 用 python3 构建 JSON 避免 shell 转义问题
curl -s --max-time 30 -x http://127.0.0.1:7897 \
  "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:generateContent?key=***" \
  -H "Content-Type: application/json" \
  -d "$(python3 -c "
import json
b64 = '''$VISION_B64'''
payload = {
    'contents': [{
        'parts': [
            {'text': '请用中文详细描述这张图片的内容'},
            {'inline_data': {'mime_type': 'image/jpeg', 'data': b64}}
        ]
    }]
}
print(json.dumps(payload))
")"

从响应中提取:.candidates[0].content.parts[0].text

如果 gemini-2.5-flash-lite 失败(429/503),尝试降级到 gemini-2.5-flash

  • 将 URL 中的 gemini-2.5-flash-lite 替换为 gemini-2.5-flash

第三步:降级到本地 Qwen API

如果 Gemini 调用失败(超时、API key 未设置、网络不通、额度用完等),降级到本地模型:

VISION_B64=$(base64 -i /tmp/vision_input.jpg | tr -d '\n')
curl -s --max-time 120 http://127.0.0.1:8081/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "guff",
    "messages": [
      {
        "role": "user",
        "content": [
          {"type": "text", "text": "请用中文详细描述这张图片的内容"},
          {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,"'$VISION_B64'"}}
        ]
      }
    ],
    "max_tokens": 500
  }' 2>&1

从响应中提取:.choices[0].message.content

第四步:纳入上下文

将识图得到的文字描述以辅助信息形式写入对话上下文,格式参考:

[Vision: 图片描述内容...]

然后根据图片内容回复用户。

速度参考

引擎 延迟 备注
Gemini 2.5 Flash Lite 1-3 秒 首选,可用性高
Gemini 2.5 Flash 1-3 秒 二选,精度更高但有时 503
本地 Qwen2.5-VL 10-90 秒 CPU 推理,无网络依赖

注意事项

  • 每次识图调用串行处理,不要并发多张图片
  • 图片大小建议不超过 5MB,过大的图片应先压缩
  • 识别结果不一定 100% 准确,在回复中适当表达不确定性
  • 如果 Gemini 和本地模型都不可用,给出友好提示而非报错
  • API key 存放于 ~/.zshrc 中的 GEMINI_API_KEY 环境变量
  • 密钥加载必须用 eval "$(grep '^export GEMINI_API_KEY=' ~/.zshrc)" 而不是 source ~/.zshrc,因为后者引入的变量值可能因 shell 引号上下文不一致而出错
  • 代理地址:127.0.0.1:7897