基于Phi-3-mini与OpenClaw的AI驱动自动化测试实践

发布时间:2026/6/30 6:26:33
基于Phi-3-mini与OpenClaw的AI驱动自动化测试实践 1. 项目概述当AI大模型遇上自动化测试最近在搞自动化测试的朋友估计都听过一个词AI Agent。简单来说就是让AI像人一样去操作软件、执行任务。我之前也折腾过不少方案要么是写死规则的脚本维护起来头大要么是调用一些视觉识别API成本高不说稳定性还堪忧。直到我开始尝试用微软开源的Phi-3-mini-128k-instruct这个“小钢炮”模型结合OpenClaw这个新兴的自动化框架来批量执行Python脚本整个流程的效率和智能化程度直接上了一个台阶。这个组合的核心思路很清晰用轻量但足够聪明的AI模型Phi-3-mini来理解任务意图和动态环境用OpenClaw作为“手和脚”去精准执行操作最终实现Python脚本的自动化、批量化运行与测试。它解决的痛点非常明确传统的UI自动化测试脚本比如基于Selenium、Playwright写的在面对频繁变化的页面元素、复杂的业务流程时极其脆弱一个按钮的ID变了或者页面加载慢了一秒整个脚本就可能挂掉。而引入AI模型后我们可以用自然语言描述任务比如“登录系统找到最新的订单并导出报告”让AI去理解并生成或调整执行步骤再由OpenClaw去可靠地执行这些原子操作这样脚本的健壮性和适应性会强很多。这套方案特别适合几类场景一是测试左移开发在提交代码后可以快速用自然语言描述测试用例让AI自动生成并执行测试脚本快速反馈二是复杂的端到端E2E业务流程测试比如一个电商的下单-支付-退款全流程用传统脚本写起来很冗长而用AI驱动可以更灵活地处理流程中的分支和异常三是需要处理非结构化界面或老旧系统的自动化任务这些系统可能没有良好的可访问性支持传统定位方式失效AI的图像理解和推理能力就能派上用场。接下来我会带你从零开始拆解如何搭建这个环境并分享我在实际项目中趟过的一些坑和总结出的最佳实践。你会发现虽然听起来高大上但一步步来门槛并没有想象中那么高。2. 核心工具选型与部署踩坑实录工欲善其事必先利其器。在这个方案里三个核心组件是Phi-3-mini-128k-instruct模型、OpenClaw框架以及你的Python脚本资产。每一环的选型和部署都藏着细节搞错了后面就会步步维艰。2.1 为什么是Phi-3-mini-128k-instruct市面上开源模型那么多为啥偏偏选这个3.8B参数的“小个子”这是经过一番对比和实测后的决定。首先它足够轻量。相比动辄7B、13B的模型Phi-3-mini对硬件要求友好得多在我的RTX 3060 12GB显卡上就能流畅跑起FP16精度甚至用CPU推理虽然慢点也不是不能接受。这对于需要长期运行、可能部署在测试机上的自动化任务来说成本可控。其次也是更重要的它的指令跟随Instruction Following能力在同尺寸模型中非常出色。微软在它身上做了大量的指令微调这使得它能很好地理解“请点击那个蓝色的提交按钮”、“在表格第二行找到金额大于100的条目”这类操作指令。我们不需要它进行天马行空的创作就需要它精准地理解任务并输出结构化的操作步骤这一点Phi-3-mini做得很好。最后128k的上下文长度是巨大优势。自动化测试的一个场景是需要让AI记住之前操作的历史和当前页面的状态比如一堆HTML元素或截图信息上下文短了根本记不住。128k的超长上下文足以我们把一个复杂任务的多次交互历史、页面DOM树片段都喂给它让它做出更连贯的决策。注意模型下载建议直接从Hugging Face的官方仓库microsoft/Phi-3-mini-128k-instruct获取。网上有些第三方转换的GGUF格式版本虽然方便CPU运行但可能会丢失一些原始模型的细微调优特性对于指令跟随的准确性可能有影响。我建议优先使用原版Transformers格式。2.2 OpenClaw不只是另一个自动化框架OpenClaw在国内开发者社区的热度最近在快速上升但资料还相对零散。它本质上是一个AI驱动的自动化代理框架和纯粹的录制回放工具如Selenium IDE或库如Playwright有本质区别。它的核心思想是提供一个标准化的“环境”给AI模型AI通过这个环境去感知获取屏幕截图、DOM、控件树和行动点击、输入、滚动。我选择OpenClaw而不是自己从头造轮子主要看中两点一是抽象层次好。它把与操作系统、浏览器交互的脏活累活都封装好了提供了统一的Action接口如click,type,scroll我们只需要关心给AI什么输入以及解析AI的输出成这些Action。二是正在快速迭代社区活跃。虽然它现在可能还有些小bug但你能看到它在积极融合MCPModel Context Protocol等新协议生态在扩大这意味着未来的可扩展性更强。部署OpenClaw官方推荐用Docker这确实是最省心的方式。但如果你像我一样需要在本地开发调试或者宿主机环境特殊手动部署就不可避免。这里有个大坑依赖冲突。OpenClaw的Python环境依赖比较新比如它可能要求playwright1.40而你的老项目可能还锁在1.38。最稳妥的办法是使用虚拟环境venv或conda为OpenClaw单独创建一个纯净的环境。# 创建并激活虚拟环境 python -m venv openclaw_env source openclaw_env/bin/activate # Linux/Mac # openclaw_env\Scripts\activate # Windows # 克隆仓库并安装核心依赖 git clone https://github.com/openclaw-ai/openclaw.git cd openclaw pip install -e . # 可编辑模式安装方便修改源码 playwright install # 安装浏览器驱动部署完成后一定要跑一下它的示例脚本验证最基本的环境感知比如截图和动作执行比如打开浏览器点击是否正常。很多时候问题出在系统权限如Linux下对/dev/shm的访问或缺失的系统库如libgtk-3上。2.3 环境联调让AI和OpenClaw握手单独部署好模型和框架只是第一步关键是要让它们能协同工作。这里的架构通常是你的主控Python脚本作为大脑负责调度。它加载Phi-3模型接收任务描述调用OpenClaw的API获取当前环境状态截图可访问性树将“任务描述环境状态”组合成Prompt送给模型解析模型返回的下一步操作指令再通过OpenClaw的API执行操作。如此循环直到任务完成。我设计了一个最简单的连接示例# 文件名ai_driver.py import torch from transformers import AutoModelForCausalLM, AutoTokenizer from openclaw import OpenClawClient # 假设OpenClaw提供了Python SDK class AITestDriver: def __init__(self, model_path, openclaw_server_urlhttp://localhost:8000): # 加载Phi-3模型和分词器 self.tokenizer AutoTokenizer.from_pretrained(model_path) self.model AutoModelForCausalLM.from_pretrained( model_path, torch_dtypetorch.float16, device_mapauto # 自动分配GPU/CPU ) # 连接OpenClaw服务 self.claw OpenClawClient(openclaw_server_url) def think_and_act(self, task_description): 核心循环感知-思考-行动 # 1. 感知通过OpenClaw获取当前环境状态 # 通常包括截图base64和可访问性树XML/JSON state self.claw.get_state() screenshot_info state.get(screenshot) dom_tree state.get(dom, ) # 2. 思考构建Prompt让模型决定下一步做什么 prompt self._build_prompt(task_description, screenshot_info, dom_tree) inputs self.tokenizer(prompt, return_tensorspt).to(self.model.device) with torch.no_grad(): outputs self.model.generate(**inputs, max_new_tokens200) response self.tokenizer.decode(outputs[0], skip_special_tokensTrue) # 3. 解析从模型回复中提取结构化操作指令 action, params self._parse_model_response(response) # 4. 行动通过OpenClaw执行操作 if action and action ! stop: result self.claw.execute_action(action, **params) return result, action else: return None, stop def _build_prompt(self, task, screenshot_info, dom): # 这里是Prompt工程的关键直接决定模型表现 # 一个简单的示例 system_msg 你是一个自动化测试助手。根据当前屏幕信息和DOM树决定下一步操作来完成用户任务。只输出JSON格式{\action\: \click\|\type\|\scroll\|\stop\, \params\: {...}} user_msg f任务{task}\n当前DOM摘要{dom[:2000]}...\n请决定下一步操作。 return f{system_msg}\n\n{user_msg} def _parse_model_response(self, response): # 尝试从回复中解析JSON这里需要健壮的解析逻辑 import json try: # 假设模型回复是纯JSON或者包含在json 块中 if json in response: json_str response.split(json)[1].split()[0].strip() else: json_str response.strip() data json.loads(json_str) return data.get(action, stop), data.get(params, {}) except json.JSONDecodeError: # 解析失败时的降级策略例如尝试关键词匹配 if 点击 in response or click in response.lower(): # 这里可以加入更复杂的逻辑来提取坐标或选择器 return click, {selector: button:has-text(提交)} # 示例 return stop, {}这个示例虽然简单但勾勒出了核心循环。在实际项目中_build_prompt和_parse_model_response这两个函数是需要你花80%精力去打磨的它们直接决定了整个系统的智能程度和可靠性。3. 批量执行Python脚本的工程化实践有了能单步思考和执行的基础框架下一步就是如何规模化批量地运行我们已有的或新生成的Python测试脚本。这里的“批量”不是简单用os.system循环调用而是要融入调度、监控、报告和错误处理。3.1 脚本管理与参数化驱动首先你的Python测试脚本需要被“改造”以适应AI驱动的环境。传统的脚本可能直接硬编码了定位器和操作。在新的范式下脚本更应该被看作一个由高级任务描述构成的清单或者是一个生成此类清单的模板。我推荐两种模式描述文件驱动为每个测试场景创建一个YAML或JSON文件描述测试步骤。主控程序读取这些文件将每一步的描述喂给AI驱动。# test_login.yaml name: 用户登录测试 steps: - description: 在浏览器中打开登录页 https://example.com/login action: navigate params: url: https://example.com/login - description: 在用户名输入框中输入测试账号 test_user action: type # 这里可以不写死选择器让AI根据描述去找 # params: # selector: #username - description: 在密码输入框中输入密码 password123 action: type - description: 点击‘登录’按钮 action: click然后你的主控程序遍历这些steps将description和当前状态发给AI由AI决定具体操作参数。这样即使页面元素变了只要描述语义不变AI就有可能找到新的正确元素。脚本模板变量替换对于更复杂的逻辑如循环、条件判断可以维护Python脚本模板使用Jinja2等模板引擎将需要AI决策的点作为变量。运行前由AI或规则引擎填充这些变量。# template_test_order.py.j2 def test_order(): open_url({{ login_url }}) login({{ username }}, {{ password }}) # AI决策点如何找到商品并加入购物车 product_to_select decide_product_from_list() # 这个函数内部调用AI add_to_cart(product_to_select) proceed_to_checkout()3.2 任务队列与并行执行控制当你有成百上千个测试用例或脚本需要运行时串行执行是不可接受的。我们需要引入任务队列。我个人偏好使用RQRedis Queue或Celery因为它们轻量且与Python集成好。架构是这样的一个任务分发器Dispatcher负责读取所有待执行的脚本/描述文件将其封装成任务推送到Redis队列中。多个工作进程Worker从队列中取出任务执行每个Worker都包含一个完整的AI驱动环境即加载了Phi-3模型和OpenClaw客户端。这里的关键是环境隔离。每个Worker必须有自己的独立环境包括浏览器实例、模型实例如果GPU内存够可以共享加载但要注意并发锁和临时目录。否则并行任务会相互干扰比如一个任务关闭了浏览器导致另一个任务失败。# worker.py 示例 import redis from rq import Worker, Queue, Connection from ai_driver import AITestDriver # 上一节定义的类 listen [default] redis_conn redis.from_url(redis://localhost:6379) def run_test_task(task_description_file): 每个Worker执行单个任务 driver AITestDriver(model_path./phi3-model) driver.claw.launch_browser(headlessFalse) # 启动浏览器 with open(task_description_file, r) as f: steps yaml.safe_load(f)[steps] for step in steps: result, action driver.think_and_act(step[description]) if action stop and result is None: print(f任务提前终止于步骤{step[description]}) break # 可以在这里加入检查点验证操作结果是否符合预期 # assert 登录成功 in driver.claw.get_page_text() driver.claw.close_browser() return {status: success, task_file: task_description_file} if __name__ __main__: with Connection(redis_conn): worker Worker(list(map(Queue, listen))) worker.work()使用supervisor或systemd来管理这些Worker进程的启动和守护确保它们挂了能自动重启。3.3 结果收集、报告与错误自愈批量执行最怕的就是黑盒跑完了不知道哪些成功哪些失败为什么失败。一个健壮的体系必须包含完善的结果收集。结构化日志不要只用print。每个Worker在执行时应该将关键事件开始任务、AI决策、执行动作、遇到错误以结构化的格式如JSON写入日志文件或直接发送到中央日志服务如ELK栈或Loki。日志里必须包含任务ID、时间戳、截图在错误时、AI的原始回复和解析后的操作。测试报告生成任务完成后Worker应生成一个标准格式如JUnit XML、Allure JSON的报告片段。由一个汇总服务收集所有片段生成统一的HTML测试报告清晰展示通过率、失败用例、错误截图和日志。错误自愈与重试机制这是AI驱动自动化的优势所在。当某个步骤失败比如AI点击了错误元素不应该立即标记整个用例失败。可以设计一个重试策略将失败时的屏幕状态和错误信息再次作为输入喂给AIPrompt改为“上一步操作失败了错误是‘元素未找到’请重新评估当前界面并尝试另一种方式完成任务”。AI可能会尝试点击另一个相似按钮或者先滚动再查找。我通常会给每个步骤2-3次重试机会。def execute_step_with_retry(driver, step_description, max_retries3): for attempt in range(max_retries): result, action driver.think_and_act(step_description) if action stop and result is None: if attempt max_retries - 1: # 重试前可以让AI先总结一下失败原因 diagnosis_prompt f上一步尝试完成‘{step_description}’时似乎失败了当前状态依旧。请分析可能的原因并给出新的方案。 # 这里可以调用一个专门的“诊断”模型或模式 continue else: raise StepFailedError(f步骤‘{step_description}’重试{max_retries}次后仍失败。) # 执行成功验证结果 if validate_step_result(result): return result else: # 结果验证失败也触发重试 continue raise StepFailedError(f步骤‘{step_description}’结果验证失败。)4. 提示工程与模型调优实战心得整个系统的智能核心在于你如何与Phi-3模型对话也就是Prompt Engineering。经过大量实测我总结出了几个非常有效的模式。4.1 结构化Prompt模板设计给AI的指令必须清晰、结构化并且要把它当成一个“有点死板但很听话的新手操作员”。我的Prompt通常分为四部分角色与能力定义明确告诉模型它现在是什么角色具备什么能力。当前环境状态以文本形式描述屏幕上的关键信息从DOM树中提取并附上截图的存在性提示注意我们通常不直接把Base64图片传给文本模型而是告诉它“有一张当前界面的截图可供参考”具体截图可以通过多模态模型处理或作为上下文元数据。任务目标与历史清晰说明这一步要干什么以及之前几步做了什么提供简短历史。输出格式约束强制要求模型以指定格式如JSON回复只包含允许的动作类型和参数。一个高级别的Prompt示例你是一个专业的Web自动化测试助手。你可以通过OpenClaw框架执行点击(click)、输入(type)、滚动(scroll)、等待(wait)、导航(navigate)等操作。 当前浏览器页面是一个电商网站的商品列表页。页面顶部有一个搜索框下方有多个商品卡片每个卡片包含商品图片、名称、价格和一个“加入购物车”按钮。屏幕中央有一个横幅广告。 刚刚完成的操作是打开了浏览器并导航到了这个页面。 当前任务目标是找到第一个价格低于50元的商品并点击它的“加入购物车”按钮。 请根据以上描述决定下一步最合适的操作。你只能输出一个JSON对象格式如下 { reasoning: 简要说明你为什么选择这个操作1-2句话, action: click | type | scroll | wait | navigate | stop, params: { // 根据action不同参数不同 // click: {selector: CSS选择器或文本内容, x: 可选坐标, y: 可选坐标} // type: {selector: 输入框选择器, text: 要输入的文本} // scroll: {direction: up|down|left|right, amount: 像素数或page} // wait: {time: 秒数, for: 等待的元素选择器可选} // navigate: {url: 目标网址} // stop: {} } }这种结构化的Prompt能极大提高模型输出动作的准确性和可解析性。reasoning字段对于调试和后续分析AI的决策过程非常有用。4.2 上下文管理与历史压缩Phi-3-mini有128k上下文但也不是无限的。一个漫长的测试流程每一步的交互都追加到上下文里很快就会耗尽。我们必须管理上下文。我的策略是滑动窗口摘要。不是保留所有原始历史而是维护一个“摘要”。每完成5-10步就让模型或者用一个更小的、专门做摘要的模型对之前的历史进行总结生成一段简短的摘要文本例如“用户已登录浏览了手机分类将一款价值2999元的手机加入了购物车目前处于购物车页面。”。然后将这个摘要作为新的“历史”放入后续步骤的Prompt中替换掉冗长的原始记录。这样可以始终保持上下文在可控长度内同时不丢失关键的任务状态信息。4.3 针对领域任务的微调可选但有效如果你有大量的、特定领域的自动化操作日志比如操作公司内部CRM系统的日志那么用这些数据对Phi-3-mini进行轻量级的微调LoRA效果会有显著提升。微调的目标是让模型更熟悉你业务中的特有名词、UI组件命名和操作模式。例如你可以收集一批成功的操作序列{“屏幕状态描述” “CRM联系人列表页” “指令” “找到名叫张三的客户并点击进入详情” “动作” {“action” “click” “params” {“selector” “tr:has-text(‘张三’)”}}}。用几百条这样的数据做LoRA微调模型在你特定系统上的表现会稳定得多。这相当于为它注入了“领域知识”。5. 避坑指南与性能优化在实际项目中趟过的坑比任何文档都宝贵。这里分享几个让我熬夜最多的点。5.1 稳定性陷阱与超时控制AI模型生成的内容具有不确定性可能偶尔会“胡言乱语”输出一个无法解析的指令或者陷入死循环比如反复滚动页面。因此必须在主控循环中加入严格的超时和熔断机制。单步超时给model.generate和claw.execute_action都设置超时。如果模型思考超过10秒或者执行动作超过30秒没反应就中断当前步骤触发重试或失败处理。循环检测记录最近N步的操作序列。如果检测到完全相同的操作如scroll down连续出现超过3次很可能陷入了循环应中断任务并报警。异常回复处理在_parse_model_response函数里要对模型回复做健壮性检查。除了JSON解析还要检查action是否在允许列表中params是否包含必需的字段。对于无法处理的回复可以回退到一个预定义的“安全操作”比如{action: wait, params: {time: 2}}让系统暂停一下然后重新获取状态并思考。5.2 选择器生成与元素定位的可靠性模型在回复中需要给出操作的具体参数比如点击的CSS选择器。让模型直接生成精确的CSS选择器如#main div.content button:nth-child(3)是非常容易出错的。更好的做法是让OpenClaw提供候选元素列表在get_state()时不仅返回DOM树还让OpenClaw返回一个当前页面所有可交互元素的列表每个元素附带其可读的文本、角色、位置以及一个稳定的后端标识符如xpath或accessibility id。让AI做选择题在Prompt中将这个元素列表只包含关键属性如文本、角色提供给模型。模型的输出动作参数里不再是一个原始的CSS选择器字符串而是这个列表中的索引或ID。然后由主控程序将这个ID映射回真正的定位器再交给OpenClaw执行。这大大降低了模型输出的复杂度提高了可靠性。5.3 性能瓶颈分析与优化当批量执行几十个任务时性能问题会凸显。主要瓶颈在两方面模型推理速度Phi-3-mini在GPU上推理一次生成200个token大约需要1-3秒。如果每个测试步骤都要调用累积起来时间很长。优化方法缓存对于相同的“状态指令”输入输出很可能相同。可以建立一个简单的哈希缓存避免重复调用模型。步骤聚合对于一些简单的、连续的操作比如在表单中连续输入多个字段可以在一个Prompt里让模型规划多个步骤输出一个动作列表然后批量执行减少模型调用次数。使用量化模型将模型转换为INT8或GPTQ量化格式能显著提升推理速度对精度损失很小非常适合自动化这种任务。浏览器与OpenClaw开销每个Worker一个浏览器实例很耗资源。使用无头模式在不需要观察的测试环境中务必使用headlessTrue模式能节省大量内存和GPU资源。浏览器实例复用在一个Worker内一个浏览器实例可以顺序执行多个测试任务注意清理Cookies和LocalStorage而不是每个任务都开一个新的。调整OpenClaw的轮询间隔OpenClaw获取屏幕状态可能有默认的轮询频率。如果不是对实时性要求极高可以适当调低这个频率减少系统开销。5.4 常见错误与快速排查表错误现象可能原因排查步骤模型输出乱码或无关内容Prompt格式不对或系统提示词被淹没检查发送给模型的完整Prompt确保系统指令在开头且清晰。尝试在Prompt开头加上“### 系统指令 ###”等强分隔符。OpenClaw执行动作失败报“元素未找到”AI生成的选择器不对或页面尚未加载完成1. 检查AI回复中的选择器是否合理。2. 在执行动作前增加一个wait动作等待元素出现。3. 让OpenClaw返回更丰富的元素列表供AI选择。任务陷入无限循环AI决策逻辑陷入局部最优或状态感知失效1. 检查上下文历史看是否状态描述重复。2. 实现循环检测机制强制跳出。3. 在Prompt中强调“避免重复操作”。批量任务中部分Worker卡死资源竞争如GPU内存溢出或浏览器崩溃1. 监控GPU内存使用。2. 为每个Worker设置任务超时和看门狗。3. 检查浏览器进程是否残留实现进程清理脚本。测试结果不稳定时好时坏页面加载时间波动或AI决策的随机性1. 在关键断言前增加显式等待。2. 对于AI决策可以引入“投票机制”同一状态让模型思考多次取多数票的动作执行。3. 适当降低模型生成时的temperature参数减少随机性。最后我想说的是将Phi-3-mini和OpenClaw结合用于自动化测试目前还是一个前沿的、需要大量调试和适配的领域。它不会完全替代你精心编写的、高稳定性的单元测试或API测试。但它为处理那些变化频繁、逻辑复杂、传统自动化维护成本极高的UI场景打开了一扇新的大门。我的体会是初期投入在Prompt工程和系统稳定性上的时间会比较多但一旦流程跑通对于应对频繁的UI变更和探索性测试它能带来的长期收益是显著的。先从一个小而具体的场景开始尝试比如自动登录或者填写一个复杂表单积累经验后再逐步扩大范围这样更容易获得正反馈并坚持下去。