GenericAgent Vision API SOP 实战指南:截图驱动 GUI 自动化中视觉模型的最小化调用规范
2026/9/14 19:23:37 网站建设 项目流程

GenericAgent Vision API SOP 实战指南:截图驱动 GUI 自动化中视觉模型的最小化调用规范

【免费下载链接】GenericAgentSelf-evolving agent: grows skill tree from 3.3K-line seed, achieving full system control with 6x less token consumption项目地址: https://gitcode.com/GitHub_Trending/pc/GenericAgent

导读

memory/vision_sop.md是 GenericAgent 项目中视觉模型(VLM)调用的标准操作规程(SOP),它定义了三个核心问题:什么时候才能用 vision API、怎么安全高效地调用ask_vision、以及没有现成vision_api.py时如何从模板初始化视觉能力。本指南以该 SOP 为骨架,结合仓库内memory/vision_api.template.pymemory/ljqCtrl.pymemory/ocr_utils.pymemory/computer_use.md的源码级细节,帮助你掌握一条"窗口枚举 → 局部截图 → 本地 OCR → 最后才上 vision"的省 token、高可靠的 GUI 自动化链路,并能在任何环境(Claude / OpenAI 兼容 / ModelScope)下快速接通视觉能力。

一、三条前置规则:Vision 是"最后手段"而非首选

vision_sop.md开篇即强调三条"必须遵守"的硬性规则,它们决定了整个 GUI 自动化的资源使用策略:

  1. 先枚举窗口:调用 vision 前必须先用pygetwindow枚举窗口标题,确认目标窗口存在且已激活到前台。窗口不存在就不截图——这避免了对不存在或后台窗口做无意义的视觉分析。
  2. 禁止全屏截图:必须先利用ljqCtrl截取窗口区域。能截局部(如标题栏)就不截整窗口,能截窗口就绝不全屏。全屏截图在任何场景下都不允许。这既是出于 token 成本控制,也是因为全屏图包含大量无关像素,会稀释 VLM 对目标区域的注意力。
  3. 能不用 vision 就不用:如果窗口标题或本地 OCR(ocr_utils.py)能获取所需信息,就不要调用 vision API,省 token 且更可靠。Vision 是最后手段。

这条规则链并非孤立设计,它与仓库中memory/computer_use.md定义的"探测/定位四工具优先级"完全一致:

优先级工具定位限制
0win32gui窗口枚举始终先行,确定目标窗口、前台状态、客户区原点仅定位窗口,不进控件
1Python UIA(控件树)首选探测与免坐标点击游戏禁用;一旦对该窗口无效则弃用
2ui_detect.py+ljqCtrl截图视觉检测控件,返回 bbox + OCR 文本bbox 为截图内坐标,需转屏幕物理坐标
3vision (VLM)仅语义理解、确认界面状态、辅助判断目标不可信其坐标

从源码结构看,vision 处于优先级链条的最末端,其定位是"语义理解与状态确认",而不是坐标定位工具——这正是 SOP 要求"能不用就不用"的根本原因。

二、快速用法:ask_vision单函数入口

当确需调用视觉能力时,SOP 给出了最小可用调用方式:

from vision_api import ask_vision result = ask_vision(image, prompt="描述图片内容", timeout=60, max_pixels=1_440_000) # image: 文件路径(str/Path) 或 PIL Image # backend: 'claude'(默认) | 'openai' | 'modelscope' # 返回 str:成功为模型回复,失败为 'Error: ...'

对照memory/vision_api.template.pyask_vision的完整签名(第 25 行),可以对每个参数做更精确的说明:

  • image_input:接受文件路径(str/Path)或 PILImage对象。模板实现里会先做类型检查,其他类型直接抛出TypeError并返回Error: 图片处理失败 - ...
  • prompt:默认值为"详细描述这张图片的内容"。建议按任务写具体指令,因为该 prompt 会原样拼入多模态消息。
  • timeout:请求超时秒数,默认 60。模板对requests.exceptions.Timeout单独捕获,返回Error: 请求超时 (>{timeout}s)
  • max_pixels:图片像素上限,默认1_440_000(约 1200×1200)。超过该值时模板会自动等比缩放,这是控制 token 消耗的关键参数。
  • backend:后端选择,'claude'(默认)、'openai''modelscope'三选一,分别路由到_call_claude/_call_openai_compat/_call_openai_compat(modelscope 配置)

返回值统一为str:成功返回模型回复文本;任何失败(图片处理异常、超时、网络错误、配置缺失、响应解析失败)都以"Error: ..."前缀返回,方便调用方在 GUI 自动化脚本中直接判断成败,而无需 try/except 包裹。

三、没有vision_api.py?从模板初始化视觉能力

SOP 给出了一套"自举"式的初始化流程,适用于任何全新环境(例如新部署的机器或新克隆的仓库):

  1. 复制模板memory/vision_api.template.pymemory/vision_api.py
  2. 只改头部"用户配置区":去mykey.py里扫描变量名(⚠️ 只看名字,禁止输出 apikey 值),尝试找能用配置名填入CLAUDE_CONFIG_KEY/OPENAI_CONFIG_KEYDEFAULT_BACKEND选后端,并测试。
  3. 保底方案:没有可用 config 时,去 ModelScope 申请 token 填入MODELSCOPE_API_KEY

3.1 配置区字段逐一说明

模板第 5~16 行的"用户配置区"是唯一需要修改的地方:

CLAUDE_CONFIG_KEY = 'claude_config141' # mykey.py 中 Claude 配置的变量名 OPENAI_CONFIG_KEY = 'oai_config1' # mykey.py 中 OpenAI 配置的变量名 MODELSCOPE_API_KEY = '' # 直接填你的 ModelScope token DEFAULT_BACKEND = 'claude' # 默认后端: 'claude' / 'openai' / 'modelscope'

模板注释中明确提示:mykey.py中的配置变量名不固定(可能形如xxx_config = {"apibase": ..., "apikey": ..., "model": ..., "proxy": None}),因此 SOP 强调"只打印变量名/字段名/model/apibase 域名路径/HTTP 状态码/错误类型,禁止打印完整 dict 和 apikey/token"——这是安全红线。

仓库中的mykey_template.py给出了典型配置的结构佐证:apikey必填且前缀决定鉴权方式(如sk-ant-*x-api-key头,其它sk-*cr_*amp_*走 Bearer),apibase必填且遵循自动拼接规则,model必填([1m]后缀触发 1m 上下文 beta)。这意味着vision_api.py中读取的cfg['apibase'] / cfg['apikey'] / cfg['model'] / cfg.get('proxy')与项目主 LLM 配置体系是同一套凭据源,无需为视觉能力单独申请密钥。

3.2 ModelScope 保底通道

mykey.py中没有任何可用配置时,模板提供了开箱即用的保底后端(第 18~19 行):

MODELSCOPE_API_BASE = 'https://api-inference.modelscope.cn' MODELSCOPE_MODEL = 'Qwen/Qwen3-VL-235B-A22B-Instruct'

只需在MODELSCOPE_API_KEY填入从 ModelScope 申请的 token,并把DEFAULT_BACKEND设为'modelscope'即可工作,模型为 Qwen3-VL 系列视觉大模型。

四、源码级原理:一次ask_vision调用内部发生了什么

4.1 图片预处理管线(_prepare_image

所有后端共用同一条预处理管线(memory/vision_api.template.py第 55~78 行),这也是max_pixels参数的实际作用点:

  1. 加载:PILImage对象直接使用;str/PathImage.open打开;其他类型抛TypeError
  2. 等比缩放:若w * h > max_pixels,按scale = (max_pixels / (w * h)) ** 0.5计算缩放比,用LANCZOS重采样,并打印📐 缩放: 原尺寸 → 新尺寸日志。这是将任意分辨率截图收敛到 token 可控范围的关键。
  3. 通道归一化RGBA/LA/P模式统一转 RGB,以白底合成透明通道,避免后续 JPEG 编码报错或出现黑底。
  4. JPEG 编码quality=80, optimize=True压缩后 base64 编码,打印📦 Base64: xx.xKB便于估算请求体积。

4.2 三个后端的请求差异

Claude 后端(_call_claude:POST 到cfg['apibase'] + '/v1/messages',请求体使用 Anthropic Messages 格式,图片以{'type': 'image', 'source': {'type': 'base64', 'media_type': 'image/jpeg', 'data': b64}}放在content数组首位、prompt 文本在后;鉴权头为x-api-key+anthropic-version: 2023-06-01,返回解析resp.json()['content'][0]['text']。模板注释特别提示:不同的中转 apibase 可能已含/v1或路径不同,需按实际状态码和响应结构修正 endpoint

OpenAI 兼容后端(_call_openai_compat:POST 到apibase.rstrip('/') + '/v1/chat/completions',请求体为标准 Chat Completions 多模态格式——content数组里文本在前、图片 URL 使用data:image/jpeg;base64,前缀的 data URI;鉴权头为Authorization: Bearer <apikey>proxy参数会透传给requestsproxies{'https': proxy, 'http': proxy}),用于中转代理场景。ModelScope 后端复用同一函数,只是换成了MODELSCOPE_API_BASE / MODELSCOPE_API_KEY / MODELSCOPE_MODEL三个常量。

4.3 统一的错误返回协议

模板对四类异常做了归一化处理,调用方只需判断返回值是否以"Error:"开头:

  • 图片处理失败:Error: 图片处理失败 - <异常类型>: <详情>
  • 超时:Error: 请求超时 (>{timeout}s)
  • 网络错误:Error: API请求失败 - <异常类型>: <详情>
  • 配置缺失 / 响应解析失败(KeyError/ValueError):Error: 响应解析失败 - <详情>

另有兜底分支:未知 backend 返回Error: 未知backend '<name>',可选: claude, openai, modelscope

五、与截图链路协同:vision 之前应该做什么

SOP 的"禁止全屏截图"规则与ljqCtrl的窗口截图能力强绑定。参考memory/ljqCtrl_sop.md,vision 的输入图片应来自以下链路:

  1. 激活并定位窗口ljqCtrl.Activate(hwnd)memory/ljqCtrl.py第 85 行)先把目标窗口置于前台,这是截图的先决条件。
  2. 窗口级截图ljqCtrl.GrabWindow(hwnd_or_name)(第 102 行)前台截图返回 PIL Image,直接可作为ask_vision的输入;GrabWindowBg(hwnd_or_name, timeout=5)(第 112 行)则是 Win10+ 的 WGC 后台截图。
  3. 必要时先试本地 OCRmemory/ocr_utils.py基于rapidocr-onnxruntime(约 1 秒/次,中英文准确率高、带 bbox),提供ocr_image/ocr_screen/ocr_window三个入口。其中ocr_window(hwnd)使用PrintWindowAPI,支持远程桌面(RDP)断开后ImageGrab截图全黑的情况。只要 OCR 能给出文本信息(如按钮文字、弹窗内容),就完全没有必要调用 vision。

computer_use.md的节奏建议看,完整流程是:进入新界面先只探测不操作(枚举窗口 + UIA + ljqCtrl 截图 + ui_detect),读完实际输出再决定下一步;仅当ui_detect的视觉检测与 OCR 都不足以判断界面语义时,才把截图交给ask_vision做"语义理解、确认界面状态、辅助判断目标"。此外要牢记:vision 返回的文本不可用于坐标定位——如果确实需要点击,必须回到ui_detectbbox +ClientToScreen(hwnd, (0,0)) / ljqCtrl.dpi_scale的物理坐标转换链路(详见 ljqCtrl 使用与坐标转换 SOP)。

六、macOS 平台的对应适配

SOP 针对 Windows 主链路给出,但仓库为 macOS 提供了完整的镜像实现(memory/maclijqCtrl.py),vision 的调用方式完全不变,只是截图来源替换为:

  • 控制层:import macljqCtrl as ljqCtrl(API 镜像,Quartz/screencapture 实现);
  • 窗口枚举:ListWindows()返回 id/app/title/bbox/pid;
  • 区域截图:GrabWindow(window_id)ScreenCapAt(x, y, radius)(物理坐标);
  • 权限:首次使用需授予"辅助功能"权限,可用AXIsProcessTrusted()检测。

在这些平台上,ask_vision(image, ...)依然接收 PIL Image 或文件路径,ljqCtrl.GrabWindow的返回可直接传入,无需改动 vision 侧代码——这正是"vision 只关心拿到什么图,不关心图从哪来"的设计价值。

七、实践清单与常见误区

标准调用流程(推荐顺序)

# 1. 枚举窗口,确认目标存在且在前台 # (pygetwindow 枚举标题 → ljqCtrl.Activate(hwnd)) # 2. 窗口级截图,绝不全屏 # img = ljqCtrl.GrabWindow(hwnd) # 或 ljqCtrl.GrabWindowBg(hwnd) # 3. 优先本地 OCR,能拿到文本就不用 vision # from ocr_utils import ocr_image # info = ocr_image(img) # if not info['text']: # # 4. 兜底才调 vision # result = ask_vision(img, prompt="描述图片内容", timeout=60, max_pixels=1_440_000) # if result.startswith('Error:'): # # 按 Error 前缀分流:超时重试、配置修正、换 backend

常见误区

  • ❌ 直接把全屏ImageGrab.grab()结果传给ask_vision——违反"禁止全屏截图"规则;
  • ❌ 对不存在的窗口/未激活窗口截图再送 vision——应先枚举并激活;
  • ❌ 把 vision 返回的内容当作坐标依据点击——vision 只负责语义理解,点击坐标必须走ui_detect+ 物理坐标转换;
  • ❌ 在日志中打印完整 config dict 或 apikey——SOP 与模板均明确禁止,只允许打印变量名/字段名/model/域名/状态码;
  • ❌ 忽略max_pixels缩放——大图不仅费 token,还可能因超出模型输入上限而报错。

八、总结

vision_sop.md的本质是一份"成本与可靠性优先"的视觉调用规范:通过"先枚举窗口、只截窗口、能本地 OCR 就不上 VLM"三条规则,把 vision API 的使用压缩到最少必要次数;再通过ask_vision的统一入口和三个后端(Claude / OpenAI 兼容 / ModelScope 保底)的透明切换,保证任何环境下都能以最低成本获得视觉理解能力。配合memory/vision_api.template.py的自举初始化流程、memory/ljqCtrl_sop.md的截图链路和memory/ocr_utils.py的本地 OCR,这套 SOP 构成了 GenericAgent 桌面自动化体系中"最后一公里"的语义确认环节——准确、省 token、且可审计。

延伸阅读:GUI 操作的整体节奏与工具优先级见 computer_use.md;窗口截图与 DPI 物理坐标换算见 ljqCtrl_sop.md;视觉能力模板实现见 vision_api.template.py;本地 OCR 能力见 ocr_utils.py。

【免费下载链接】GenericAgentSelf-evolving agent: grows skill tree from 3.3K-line seed, achieving full system control with 6x less token consumption项目地址: https://gitcode.com/GitHub_Trending/pc/GenericAgent

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询