前言
在上一篇中,我们揭秘了 UFO 的“火眼金睛”:它通过 Set-of-Marks (SoM) 技术,把屏幕上的每个按钮都标记上了 ID。
当 GPT-4V 看着满屏的红框说:“我觉得应该点击 5号 按钮”时,UFO 的大脑工作就结束了,轮到**“四肢” (Execution Layer)** 登场了。
-
它是瞬间把鼠标“瞬移”过去的吗?
-
它是怎么输入文字的?
-
如果点歪了怎么办?
今天这一篇,我们深入 ufo/automator 模块,拆解 Action Execution 的全过程,带你掌握 Windows 自动化控制的核心代码。
🦾 第一步:指令翻译 (从文本到动作)
GPT-4V 返回给 UFO 的通常是一段 JSON 格式的字符串,比如:
JSON
{
"thought": "I need to save the file.",
"control_label": "5",
"action": "click"
}
UFO 的控制器首先要把这个“文本指令”翻译成 Python 的函数调用。这部分逻辑通常在 AppAgent 的响应解析部分。
关键流程:
-
提取 ID:拿到
control_label: "5"。 -
查表:回到我们在上一篇建立的
control_map(ID 到控件对象的映射表)。 -
锁定对象:找到 ID 为 5 的那个
pywinauto控件对象。
🖱️ 第二步:鼠标点击的玄学 (click vs click_input)
这是新手最容易踩坑的地方。在 ufo/automator/ui_control/controller.py (或类似文件) 中,你会发现 UFO 并没有使用普通的点击方法。
源码核心逻辑:
Python
# 伪代码:UFO 的点击逻辑封装
def execution_click(element):
# 1. 确保控件可见并置顶
element.set_focus()
# 2. 高亮一下(为了让用户知道我要点这里了,视觉反馈)
highlight_element(element)
# 3. 核心点击操作
# 注意:这里用的是 click_input() 而不是 click()
element.click_input(coords=(x, y))
这里的门道 (必考题):
pywinauto 提供了两种点击方式,UFO 为什么选 click_input?
-
click()(消息级):直接给窗口发一个 Windows Message (WM_CLICK)。-
优点:快,鼠标光标不需要移动,可以在后台运行。
-
缺点:很多现代 UI(如 WPF, UWP, Electron)根本不理会这种假消息,点击经常无效。
-
-
click_input()(硬件模拟级):-
原理:真实的移动鼠标光标到指定坐标,按下物理左键,再松开。
-
优点:兼容性无敌,和真人操作一模一样。
-
缺点:会独占你的鼠标,操作期间你不能动。
-
UFO 为了保证在各种软件里都能跑通,果断选择了模拟真实硬件的 click_input()。
⌨️ 第三步:键盘输入的艺术
除了点击,UFO 还需要打字。这在源码中对应 type 动作。
Python
def execution_type(element, text):
# 1. 先点一下输入框,确保焦点在里面
element.click_input()
# 2. 输入文字
# with_spaces=True 保证空格不会被吞掉
element.type_keys(text, with_spaces=True)
特殊按键处理:
你可能会在源码里看到类似 {ENTER} 或 ^a (Ctrl+A) 的字符串。这是 pywinauto 的特殊语法。
UFO 在这里做了一层封装,允许 GPT 输出 "Press Enter",然后内部转化为 type_keys("{ENTER}"),从而实现回车、删除、复制粘贴等操作。
🛡️ 第四步:安全与高亮 (Visual Feedback)
UFO 有一个非常贴心的设计:在点击之前,会在屏幕上画一个框或圆圈,闪烁一下。
这不仅仅是为了酷炫,更是一种 Safety Check (安全机制)。
代码位于 ufo/automator/ui_control/screenshot.py 的绘图工具中。
源码逻辑:
-
获取目标控件的
RECT(矩形范围)。 -
在执行
click_input之前,调用GDI或PyQt绘制一个半透明的红色矩形覆盖在目标上。 -
time.sleep(0.5)暂停半秒。 -
清除矩形,执行点击。
为什么这么做?
-
调试:如果你发现红框画歪了,说明上一轮的坐标识别有问题。
-
介入:如果你发现 UFO 要点击“删除文件”,这半秒的延迟给了你惊呼和拔电源的机会(笑)。
🚧 异常处理:如果不动了怎么办?
源码分析不仅要看正常流程,还要看它怎么处理“翻车”。
在 controller.py 中,通常包裹着大量的 try...except 块:
Python
try:
control.click_input()
except ElementNotFoundError:
# 控件找不到了?可能是界面刷新了
print("Error: Element not found, triggering re-observation...")
# 触发重新截图,重新识别流程
return "FAIL_RETRY"
except Exception as e:
# 其他未知错误
print(f"Unknown error: {e}")
UFO 引入了自我修正机制:如果动作执行失败,它不会直接报错退出,而是会将“执行失败”作为反馈传回给 GPT-4V。
GPT-4V 收到反馈后,往往会说:“哦,可能是菜单没展开,那我先点一下菜单,再点按钮。”
📝 总结与实战建议
通过分析 UFO 的动作执行源码,我们学到了 Windows 自动化的三个黄金法则:
-
模拟真实:尽量使用
click_input()模拟物理硬件,而不是发消息,以获得最大兼容性。 -
状态确认:操作前必须
set_focus(),操作后最好检查结果。 -
视觉反馈:给用户展示机器人的“意图”(高亮),是提升 AI Agent 体验的关键。
实战作业:
打开你的 UFO 源码,找到 controller.py,尝试修改一下 type_keys 的速度(pywinauto.timings),看看能不能让 UFO 打字快得像黑客帝国一样!
下期预告:
现在 UFO 能看能动了,但它怎么记得住之前的操作?如果任务很长(比如“把所有未读邮件整理到Excel”),它怎么规划步骤?
下期文章:《UFO 源码实战 (4):拆解 prompter 模块,看微软如何调教 GPT-4V 》,我们将深入 AI 的大脑皮层!
点赞是免费的,但知识是无价的。我们下期见! 🤖

973

被折叠的 条评论
为什么被折叠?



