基于Qwen3-4B与OpenClaw的AI智能体UI自动化测试实践
1. 项目概述:当大模型“长出”了手和眼
最近在折腾一个挺有意思的玩意儿,叫OpenClaw。简单来说,你可以把它理解为一个给大语言模型(LLM)装上的“机械臂”和“眼睛”。光有大模型聪明的大脑还不够,我们得让它能“看到”屏幕,并且能“动手”去点击、输入、拖拽,完成一系列真实的UI操作。这听起来是不是有点像科幻电影里的场景?其实,这就是我们常说的“AI智能体”或“AI自动化”的核心能力之一。
我这次的项目,就是尝试用Qwen3-4B这个轻量级但能力不俗的开源大模型作为“大脑”,驱动OpenClaw和nanobot这套组合工具,去完成一个完整的UI自动化测试流程。Qwen3-4B负责理解任务、分析界面、生成操作指令;OpenClaw作为执行器,负责将指令转化为对操作系统和应用程序的实际控制;而nanobot则扮演了“眼睛”的角色,负责捕捉屏幕信息,为大脑提供“视觉”输入。这个组合的目标很明确:验证一个基于大模型的、能理解自然语言指令的UI自动化测试方案是否可行、稳定,以及它的边界在哪里。
这不仅仅是又一个自动化测试脚本。传统的自动化测试,无论是基于Selenium、Playwright还是Appium,都需要测试工程师编写精确的定位符(如XPath、CSS Selector)和预设的操作流程。脚本是“死”的,界面稍有变动,脚本就可能失效。而我们尝试的这条路,是让AI根据对当前屏幕内容的理解,动态地决定下一步该做什么。比如,你只需要告诉它“帮我在这个电商网站搜索‘无线鼠标’并加入购物车”,它就能自己找到搜索框、输入关键词、点击搜索按钮、浏览结果、选择商品、点击加入购物车。这背后,是视觉理解、自然语言处理和精准控制的结合。
2. 核心组件深度解析:大脑、眼睛与手
要玩转这个项目,首先得把三个核心组件吃透:作为“大脑”的Qwen3-4B模型,作为“眼睛”的nanobot,以及作为“手”的OpenClaw。它们各自承担着不同的职责,协同工作才能完成复杂的任务。
2.1 “大脑”:Qwen3-4B模型的选择与部署
为什么是Qwen3-4B?在众多开源模型中,我选择它主要基于几个考量。首先,4B(40亿)参数规模是一个甜点区:它比一些70B、130B的巨无霸模型轻量得多,对硬件要求友好(消费级显卡甚至CPU都能跑),推理速度也快;同时,经过充分的指令微调后,其在理解任务、遵循指令、进行简单推理方面的能力,对于UI自动化这种相对结构化的任务来说,已经足够用了。其次,Qwen系列模型对中文的支持非常好,这对于处理中文界面的自动化测试是个巨大优势。最后,它的开源协议友好,社区活跃,遇到问题容易找到解决方案。
部署Qwen3-4B,我强烈推荐使用Ollama。Ollama极大地简化了本地大模型的部署和管理。你不需要去手动处理复杂的Python环境、模型下载和加载。只需要一条命令:
ollama run qwen2.5:4bOllama会自动下载模型,并启动一个本地的API服务。默认情况下,它会监听11434端口。你可以通过简单的HTTP请求与它交互。对于我们的项目,我们需要的是模型能够接收包含系统提示词(System Prompt)和用户消息(User Message)的对话,并返回结构化的操作指令。因此,在系统提示词中,我们需要精心设计,告诉模型它现在是一个UI自动化助手,需要根据给定的屏幕描述(来自nanobot)和用户任务,输出下一步的精确操作,比如CLICK [x, y]、TYPE [text]、SCROLL [direction]等。
注意:Qwen3-4B的“视觉”能力(VL版本)是另一个话题。我们这里讨论的是纯文本模型。视觉模型可以直接处理图像,但通常需要更大的算力和更复杂的集成。在我们的架构里,视觉信息由nanobot处理成文本描述,再喂给文本模型,这是一种折中但实用的方案。
2.2 “眼睛”:nanobot的视觉感知与信息提取
nanobot在这里的核心任务是把“看到”的屏幕内容,转换成“大脑”能理解的文本描述。它并不是简单截图,而是需要做屏幕内容的结构化分析。
一种常见的做法是使用基于计算机视觉的OCR(光学字符识别)和UI元素检测技术。例如,可以结合PaddleOCR、Tesseract等OCR引擎来识别屏幕上的所有文字及其位置,同时使用目标检测模型(比如训练好的按钮、输入框、链接检测器)来识别常见的UI控件。nanobot将这些信息整合成一个结构化的文本描述,可能类似于:
屏幕内容描述: - 位于顶部中央的文本框,内容为空,标签为“搜索框”。 - 位于文本框右侧的按钮,文本为“搜索”。 - 下方是一个商品列表区域,包含3个商品项。 - 商品1:名称“罗技无线鼠标”,价格“199元”,其下方有一个按钮文本为“加入购物车”。 - 商品2:名称“雷柏机械键盘”,价格“299元”。 - 商品3:名称“苹果妙控板”,价格“899元”。 当前焦点:无。这个描述需要尽可能准确、简洁且包含空间和语义信息。描述的粒度是一个需要权衡的问题:太细会使得提示词过长,影响模型推理效率和成本;太粗又可能导致模型无法精确定位。在实践中,我通常会过滤掉一些不相关的背景元素,只保留可交互的控件和关键信息文本。
nanobot的实现可以是一个独立的Python服务,定期捕获屏幕(或指定应用窗口),运行分析流水线,并通过API将描述提供给OpenClaw或直接给Qwen模型。对于Web自动化,也可以考虑直接使用浏览器开发者工具提供的可访问性树(Accessibility Tree),这比纯视觉分析更精确,但仅限于浏览器环境。
2.3 “手”:OpenClaw的精准控制与执行
OpenClaw是最终的“执行者”。它接收来自Qwen模型的指令,并将其转化为操作系统级别的输入事件。这通常通过模拟键盘和鼠标操作来实现。
在Python中,我们可以使用pyautogui、pynput或ctypes调用Windows API / Linux Xlib来实现。一个健壮的OpenClaw模块需要具备以下能力:
- 坐标映射与点击:根据指令中的坐标
[x, y]执行点击。这里的关键是坐标系的统一。nanobot分析的坐标是基于屏幕截图的,而pyautogui.click()使用的坐标是基于整个屏幕的。必须确保坐标系转换正确。对于相对点击(如点击某个识别出的元素),需要将元素在截图中的相对坐标,加上截图时窗口在屏幕上的绝对偏移量。 - 文本输入:模拟键盘输入文本。需要注意输入法的状态,最好在输入前将输入法切换到英文状态,并使用
pyautogui.typewrite()逐字符输入,对于复杂内容,有时复制粘贴更可靠。 - 滚动与快捷键:模拟鼠标滚轮滚动和系统快捷键(如Ctrl+C, Ctrl+V)。
- 等待与容错:操作之间需要加入合理的等待时间(
time.sleep),因为UI响应需要时间。更重要的是容错机制,比如点击后检查预期变化是否发生,如果没有,则触发重试或上报错误。
OpenClaw的指令集需要和Qwen模型的输出约定好。一个简单的协议可以是JSON格式:
{ "action": "click", "params": {"x": 500, "y": 300} }或者更简单的行文本格式:ACTION [param1, param2, ...]。协议的设计要兼顾模型的输出能力和解析的简便性。
3. 系统集成与工作流搭建
把大脑、眼睛和手连接起来,形成一个闭环的工作流,是整个项目的工程核心。这个流程必须是异步、可观测且具备一定鲁棒性的。
3.1 核心循环流程设计
我设计的主体工作流是一个“感知-思考-行动”的循环:
- 初始化与任务输入:用户通过命令行或API提交一个自然语言任务,例如“在Chrome中打开百度,搜索‘今日天气’”。
- 首次感知:nanobot启动,捕获当前屏幕(假设是桌面),生成初始描述
S0。 - 思考决策:将系统提示词、当前屏幕描述
S0和用户任务拼接,发送给Qwen3-4B模型。系统提示词类似于:你是一个UI自动化助手。你将收到当前的屏幕描述和用户任务。请根据描述,决定下一步最合适的操作。你只能输出以下格式的指令:CLICK [x, y](点击坐标);TYPE [text](输入文本);PRESS [key](按下单个键,如ENTER);SCROLL [up|down](滚动);WAIT [seconds](等待);DONE(任务完成)。坐标(x,y)是屏幕上的绝对像素坐标。请确保你的操作基于屏幕描述中的元素信息。
- 解析与执行:OpenClaw模块解析模型返回的文本,提取出动作指令和参数。例如,模型返回
CLICK [100, 200],OpenClaw就执行点击(100, 200)的操作。 - 等待与再次感知:执行操作后,等待一个短暂的时间(如1-2秒)让UI稳定。然后nanobot再次捕获屏幕,生成新的描述
S1。 - 循环判断:将新的屏幕描述
S1和剩余任务(或上下文)再次送入模型,获取下一个动作。如此循环,直到模型输出DONE,或循环超过最大步数,或检测到错误状态(如找不到关键元素)。
这个循环的关键在于,每一次“思考”都是基于最新的屏幕状态。这赋予了系统处理动态界面和意外弹窗的能力。
3.2 关键配置与参数调优
要让这个系统稳定运行,一堆参数需要仔细调校:
- Ollama API参数:调用Qwen模型时的
temperature设置很关键。对于自动化任务,我们需要模型输出确定性的、格式严格的指令,因此temperature应该设得很低,比如0.1或0.2,以减少随机性。max_tokens也要限制,防止模型“胡说八道”生成过长内容。 - nanobot采样频率与延迟:每次操作后等待多久再截图?太短了界面还没更新,太长了影响效率。通常1-2秒是个合理的起点。对于网络请求多的页面,可能需要更长。
- OpenClaw操作延迟:
pyautogui的默认操作速度非常快,快到有些应用程序反应不过来。必须在每次点击、输入前后加入pyautogui.PAUSE = 0.5这样的全局暂停,或者在每个操作间手动time.sleep(0.5)。 - 错误处理与重试:模型可能输出无法解析的指令,或者指令坐标超出屏幕范围。OpenClaw需要捕获这些异常,并反馈给主循环。主循环可以尝试让模型基于相同的屏幕描述重新决策(也许上次是“分心”了),或者记录错误并中止任务。
- 系统提示词工程:这是影响模型行为最直接的因素。提示词需要明确任务边界、输出格式,并包含一些例子(Few-shot Learning)。例如,可以在提示词里加入:
示例1: 屏幕描述:有一个写着“用户名”的输入框。 任务:输入“testuser”。 输出:TYPE [testuser]
示例2: 屏幕描述:有一个“提交”按钮。 任务:点击提交按钮。 输出:CLICK [按钮的中心坐标]
3.3 工程实现示例:一个简单的命令行工具
下面是一个高度简化的、概念性的代码框架,展示了如何将各个部分串联起来:
import time import requests import json import pyautogui from nanobot import ScreenAnalyzer # 假设的nanobot模块 from openclaw import ActionExecutor # 假设的openclaw模块 class AITestAgent: def __init__(self, ollama_url="http://localhost:11434/api/generate"): self.ollama_url = ollama_url self.analyzer = ScreenAnalyzer() self.executor = ActionExecutor() self.system_prompt = """你是一个UI自动化助手...(完整的提示词)""" def get_model_decision(self, screen_description, user_task): """请求模型给出下一步动作""" prompt = f"{self.system_prompt}\n当前屏幕:{screen_description}\n任务:{user_task}\n下一步动作:" payload = { "model": "qwen2.5:4b", "prompt": prompt, "stream": False, "options": {"temperature": 0.1, "num_predict": 50} } try: response = requests.post(self.ollama_url, json=payload, timeout=30) response.raise_for_status() result = response.json() return result['response'].strip() except Exception as e: print(f"调用模型失败:{e}") return "ERROR" def parse_and_execute(self, decision): """解析并执行模型指令""" if decision == "DONE": return True, "任务完成" if decision.startswith("CLICK"): # 解析坐标,例如 CLICK [100, 200] import re match = re.search(r'\[(\d+),\s*(\d+)\]', decision) if match: x, y = int(match.group(1)), int(match.group(2)) self.executor.click(x, y) return False, f"点击了({x}, {y})" elif decision.startswith("TYPE"): # 解析文本 text = decision[5:].strip(' []') self.executor.type(text) return False, f"输入了{text}" # ... 解析其他指令 else: print(f"无法解析的指令:{decision}") return False, "指令解析错误" def run(self, user_task, max_steps=50): """主运行循环""" for step in range(max_steps): print(f"\n--- 步骤 {step+1} ---") # 1. 感知 print("正在分析屏幕...") description = self.analyzer.capture_and_describe() # 2. 思考 print("正在询问模型决策...") decision = self.get_model_decision(description, user_task) print(f"模型决策:{decision}") # 3. 行动与判断 is_done, msg = self.parse_and_execute(decision) print(f"执行结果:{msg}") if is_done: print("任务成功完成!") break if "ERROR" in decision: print("遇到错误,终止任务。") break # 操作后等待 time.sleep(1.5) else: print(f"达到最大步数 {max_steps},任务未完成。") if __name__ == "__main__": agent = AITestAgent() agent.run("在记事本中输入‘Hello, AI Agent!’并保存")4. 实战验证:典型UI自动化测试场景剖析
理论说得再多,不如实际跑一跑。我设计了几个复杂度递增的测试场景,来验证这套系统的能力边界。
4.1 场景一:简单的桌面应用操作(记事本)
任务:打开Windows记事本,输入一段文字,并保存为指定文件名的文本文件。
过程与挑战:
- 启动应用:初始屏幕是桌面。模型需要输出
PRESS [win]打开开始菜单,然后TYPE [notepad],再PRESS [enter]。这里第一个挑战是,模型是否知道用Win键打开开始菜单?这依赖于提示词中的知识。实践中,我发现在提示词中加入“要打开应用,可以按Win键打开开始菜单,然后输入应用名”这样的引导非常有效。 - 定位输入区域:记事本打开后,nanobot的描述可能是“一个空白窗口,标题为‘无标题 - 记事本’,内部有一个可编辑的文本区域”。模型需要理解“可编辑的文本区域”就是输入焦点,直接输出
TYPE [Hello, AI Agent!]。这里TYPE指令不需要坐标,因为焦点已在。 - 触发保存:这是难点。保存需要点击“文件”菜单,再点击“保存”。nanobot的描述需要能识别出菜单栏项。如果描述是“顶部有菜单栏,包含‘文件(F)’、‘编辑(E)’等”,模型需要输出
CLICK [文件菜单的坐标]。点击后,会出现保存对话框,这是一个新的界面状态,需要nanobot再次捕获和描述。 - 在对话框中操作:保存对话框里,有“文件名”输入框、“保存”按钮等。模型需要根据描述,依次执行
CLICK [文件名输入框]->TYPE [test_ai]->CLICK [保存按钮]。
心得:对于这类标准桌面应用,系统的成功率较高。关键在于nanobot能否稳定识别出菜单、按钮、输入框等控件。如果使用更高级的UI自动化框架(如pywinauto或Microsoft UI Automation)来辅助nanobot获取更精确的控件树,而非纯视觉分析,成功率会大幅提升。
4.2 场景二:Web页面交互(电商搜索)
任务:在浏览器中打开某电商网站首页,搜索“蓝牙耳机”,并点击第一个商品进入详情页。
过程与挑战:
- 浏览器导航:首先需要打开浏览器(可能已打开)。如果浏览器未打开,流程同记事本。如果已打开,模型需要将焦点切换到浏览器地址栏。这需要nanobot的描述能区分不同窗口和其内部的地址栏组件。指令可能是
CLICK [地址栏坐标]->TYPE [www.jd.com]->PRESS [enter]。 - 识别搜索框:电商首页元素繁多。nanobot的描述必须足够清晰,能指出“顶部有一个较大的搜索输入框,旁边有‘搜索’按钮”。模型才能输出正确的
CLICK [搜索框坐标]->TYPE [蓝牙耳机]->CLICK [搜索按钮坐标]。 - 列表页操作:搜索结果是动态加载的列表。nanobot需要描述出“商品列表区域,包含多个商品卡片,第一个卡片标题包含‘XX蓝牙耳机’,价格是‘199元’,下方有‘查看详情’按钮”。模型需要理解“第一个”这个概念,并输出点击其“查看详情”按钮的指令。
- 动态内容与等待:从点击搜索到结果加载完成,有网络延迟。必须在
CLICK [搜索按钮]后,主动插入一个WAIT [3]指令,或者我们的主循环在每次操作后固定等待足够时间,让nanobot捕获到加载完成后的新页面。
心得:Web自动化对nanobot的视觉分析能力要求更高,因为页面布局多样、元素密集。直接使用浏览器开发者工具通过CDP(Chrome DevTools Protocol)获取DOM和可访问性树信息,比纯视觉OCR更可靠。可以将OpenClaw与Playwright或Selenium结合,用它们来获取精确的元素定位信息,然后由OpenClaw执行“物理”点击(如果需要绕过反爬)。这实际上是混合模式。
4.3 场景三:异常处理与鲁棒性测试
任务:执行一个多步骤任务,期间人为制造干扰,如意外弹窗、元素加载慢、模型输出错误指令。
测试与观察:
- 意外弹窗:在任务中途,手动弹出一个系统通知。nanobot会将其描述为“屏幕中央出现一个小窗口,显示‘系统更新可用’,有关闭按钮”。一个优秀的模型应该能判断这个弹窗与主任务无关,并输出
CLICK [关闭按钮坐标]来消除干扰,然后继续主任务。如果提示词中未包含处理干扰的指引,模型可能会困惑。 - 元素加载慢:模型指令点击一个按钮,但网络原因按钮还没出现。OpenClaw执行点击时可能点在了错误位置,或者点击无效。我们的系统需要超时和重试机制。例如,执行点击后,等待2秒,然后nanobot再次检查预期的新界面(如下一个页面)是否出现。如果未出现,则可以将相同的屏幕描述和任务再次发给模型,相当于问“你现在还是看到这个界面,任务还没完成,下一步该怎么做?”模型可能会尝试其他操作,比如滚动页面寻找目标,或输出
WAIT。 - 模型“幻觉”:模型有时会输出无法执行的指令,比如
CLICK [1500, -50](坐标超出屏幕),或者OPEN [music](动作不在指令集内)。OpenClaw的解析器必须能检测这些错误,并抛出一个“指令错误”信号。主循环收到这个信号后,不应简单地重试同一指令,而是应该将当前的屏幕描述连同“上一步指令执行失败”的信息,一起重新提交给模型,让它“反思”并给出新指令。
5. 优势、局限与未来优化方向
经过一系列测试,这套基于Qwen3-4B+OpenClaw+nanobot的方案,其优势和短板都非常明显。
5.1 核心优势与价值
- 自然语言驱动:最大的魅力在于,测试用例可以用人类语言来描述,无需编写和维护复杂的定位符脚本。这降低了自动化测试的入门门槛,也让测试意图的表达更直接。
- 动态适应能力:由于每一步决策都基于实时屏幕分析,理论上它能处理一些界面变化。比如按钮位置变了,但文本没变,nanobot能重新找到它,模型就能再次点击它。这比硬编码XPath的脚本更健壮。
- 处理非预期状态:如前所述,对于意外弹窗等干扰,系统有潜力去识别并处理,这是传统脚本难以做到的。
- 快速原型验证:对于探索性测试或快速验证一个想法,你只需要用语言描述,就能看到AI去执行,非常高效。
5.2 当前主要局限与挑战
- 成本与速度:每一“步”都需要调用大模型和视觉分析,耗时远高于传统脚本。Qwen3-4B在本地推理,一步可能也需要1-3秒,复杂任务几十步下来就是分钟级,不适合对速度要求高的回归测试。
- 可靠性问题:
- 视觉识别误差:nanobot的OCR和元素识别不可能100%准确,尤其在界面复杂、字体奇特、背景干扰多的情况下。识别错误会导致描述错误,进而导致模型决策错误。
- 模型决策不确定性:即使温度设低,模型仍有小概率输出错误格式或不合逻辑的指令。需要多层校验和纠错。
- 坐标精度问题:基于视觉的坐标点击,精度受屏幕分辨率、缩放比例影响,不如基于DOM的定位精确。
- 复杂逻辑处理能力有限:目前的模型和简单循环,难以处理需要复杂记忆和规划的多层级任务。例如,“找到最便宜的商品并加入购物车”,这需要模型比较多个商品的价格信息,这对4B模型和当前的简单文本描述格式来说负担较重。
- 提示词工程复杂:系统表现极度依赖精心设计的提示词。要让模型理解任务、遵循格式、做出合理决策,需要大量的调试和迭代。
5.3 可行的优化与进阶思路
这套系统目前更像一个有趣的研究原型或特定场景的辅助工具。要走向实用化,可以从以下几个方向深化:
- 混合架构:不追求全流程AI化。将AI用于最擅长的部分:元素定位和意图理解。具体来说:
- 用户用自然语言描述任务。
- AI(大模型)将任务分解为步骤,并为每一步生成“在屏幕上找到某个特征的元素并操作”的指令(如“找到文本包含‘搜索’的按钮”)。
- 一个传统的、稳定的自动化引擎(如Playwright)接收指令,利用其强大的选择器(文本选择器、角色选择器等)去定位元素并执行操作。这样,执行部分又快又稳,AI只负责“看”和“想”。
- 强化视觉感知:用更专业的UI元素检测模型替代通用OCR,专门训练识别按钮、输入框、链接、列表等控件。甚至可以结合屏幕的底层访问性API,获取比像素更丰富的语义信息。
- 引入记忆与状态管理:让模型能记住之前几步做了什么,当前处于任务的哪个阶段。这可以通过在提示词中附加对话历史来实现,或者使用更复杂的智能体框架(如LangChain、AutoGen)来管理状态。
- 专用模型微调:收集大量“屏幕描述-正确操作”的对子,对Qwen3-4B进行微调,让它专门擅长UI自动化决策任务,可以显著提升准确率和减少提示词依赖。
- 完善工具链:开发一个集成的调试和监控界面,实时显示nanobot看到的画面、生成的描述、模型接收的提示词、模型的输出决策以及OpenClaw的执行结果。这对于调试和优化整个流水线至关重要。
这个项目让我深刻体会到,让AI真正“操作”物理世界(哪怕是数字世界的界面)的复杂性。它不仅仅是自然语言理解和生成的问题,更是感知、决策、控制环环相扣的系统工程。目前来看,纯AI驱动的端到端UI自动化距离替代传统自动化测试还有很长的路,但它为我们指明了一个充满可能性的方向:更智能、更自适应、更接近人类交互方式的自动化工具。对于测试工程师来说,学习如何与这些AI智能体协作,将它们融入现有的测试框架,或许是下一个值得投入精力的领域。
