基于OpenClaw与千问3.5-27B的智能UI自动化测试实践
1. 项目概述当UI自动化测试遇上大模型去年我负责一个大型电商后台系统的质量保障工作。每周迭代团队都要手动执行超过200个UI测试用例从登录、商品上架到订单处理、报表生成整个过程耗时耗力且极易因疲劳而遗漏细节。更头疼的是前端页面频繁改版传统的基于DOM元素定位的自动化脚本比如用Selenium或Cypress写的脆弱不堪一个CSS类名或ID的改动就能让整个测试套件“瘫痪”维护成本高得吓人。就在我们为自动化测试的“智能化”和“健壮性”发愁时一个技术组合进入了我们的视野OpenClaw与千问3.5-27B。简单来说这个项目探索的是一种全新的UI自动化测试范式。它不再仅仅依赖僵硬的代码脚本和脆弱的元素选择器而是将测试用例的“生成”与“执行”都交给了大语言模型LLM。OpenClaw作为一个开源的AI智能体框架负责提供与真实浏览器或应用交互的“手”和“眼”而本地化部署的千问3.5-27B模型则扮演了测试用例的“大脑”——它能理解自然语言描述的需求分析屏幕截图并指挥OpenClaw执行一系列操作最后还能像测试工程师一样对结果进行视觉和逻辑上的判断。这套方案的核心价值在于解决了传统UI自动化的两大痛点维护成本和认知能力。对于频繁变动的UI模型可以通过视觉理解自动适应无需人工重写定位器对于需要主观判断的验证点如“提示信息是否友好”、“布局是否美观”模型的多模态能力提供了前所未有的可能性。接下来我将详细拆解我们是如何从零搭建这套系统并让它真正在项目中跑起来的。2. 核心思路与技术选型解析2.1 为什么是OpenClaw 千问3.5-27B在决定技术栈之前我们评估了市面上几种主流的“AI测试”方案。有些云服务提供了基于OCR和CV的测试能力但存在数据安全和网络延迟问题有些方案则需要将测试脚本完全重构成特定的DSL领域特定语言学习成本和迁移代价太高。OpenClaw吸引我们的地方在于它的轻量、开源和灵活性。它本质上是一个将自然语言指令转化为具体操作系统级动作点击、输入、截图的代理框架并且原生支持通过OpenAI兼容的API与各类大模型对接。选择千问3.5-27B模型在本地部署则是基于安全、成本和性能的综合考量。27B参数的规模在精度和推理速度上取得了很好的平衡足以理解复杂的测试指令和进行细致的图像分析。最重要的是本地部署意味着所有测试过程、屏幕截图、应用数据都不会离开公司内网这对于测试涉及敏感业务数据的后台系统至关重要。我们可以在星图GPU平台或内部GPU服务器上部署该模型镜像获得稳定、专属的推理能力。2.2 架构设计与工作流整个系统的架构可以概括为“指令-感知-决策-执行”的闭环指令输入测试工程师用自然语言或结构化的YAML描述测试场景如“验证用户使用正确密码登录后会跳转到仪表盘页面”。模型决策千问3.5-27B模型接收指令结合当前步骤的上下文如上一步的截图、操作结果决定下一步要执行什么操作如在哪个输入框输入什么文本。动作执行OpenClaw框架接收模型发出的标准化动作指令如{“action”: “click”, “selector”: “.login-btn”}并通过底层驱动如Playwright、Appium在真实的浏览器或应用中执行。环境感知动作执行后OpenClaw会捕获新的屏幕状态截图、DOM快照并将其作为新的上下文反馈给模型。验证与判断在关键检查点模型会分析截图判断测试结果是否通过如截图里是否出现了“登录成功”的提示元素。这个循环持续进行直到完成整个测试场景。与传统脚本最大的不同在于决策逻辑是动态的、基于理解的。如果预定的按钮没找到模型可以分析截图寻找功能相似的替代控件而不是直接报错失败。3. 环境搭建与核心配置实战3.1 OpenClaw的安装与初始化OpenClaw的安装过程相对 straightforward。我们选择在Linux测试服务器上进行部署。官方提供了一键安装脚本但为了更好的可控性我推荐分步安装。首先确保系统已安装Python 3.8和Node.js因为OpenClaw的某些组件依赖于Node。然后通过pip安装核心包pip install openclaw-core接下来安装浏览器自动化驱动。OpenClaw支持Playwright作为后端这是我们的首选因为它对现代Web渲染支持更好且自带浏览器。# 安装Playwright及Chromium浏览器 pip install playwright playwright install chromium安装完成后运行初始化命令。这一步会引导你完成基础配置并启动一个常驻的后台服务daemon用于监听模型和测试任务。openclaw onboard --install-daemon在配置向导中有几个关键选择运行模式选择Advanced以便手动配置我们自己的千问模型。模型提供商选择Custom或OpenAI-Compatible。API端点这里填入我们本地部署的千问3.5-27B模型的API地址例如http://your-gpu-server:8080/v1。API密钥如果模型服务设置了鉴权在此填入我们内网部署的测试模型通常设为sk-no-key-required或留空。注意openclaw onboard过程会在用户目录下生成配置文件如~/.openclaw/config.yaml。如果后续需要更改模型端点可以直接编辑这个文件而无需重新运行向导。3.2 千问3.5-27B模型的本地部署与对接模型的部署我们使用了星图GPU平台提供的预置镜像这省去了自己配置CUDA环境、下载模型权重的繁琐步骤。基本步骤如下在星图平台选择qwen-3.5-27b-instruct镜像创建实例。配置实例规格根据测试并发量选择GPU型号A10对于初期测试足够并设置合适的存储。实例启动后平台通常会提供一个开箱即用的WebUI和API服务端点。API服务一般基于vLLM或TGI框架部署默认提供OpenAI兼容的接口。我们需要确认API的完整URL通常是http://实例IP:端口/v1。关键是要测试/v1/chat/completions这个端点是否可用。使用一个简单的curl命令来验证OpenClaw能否与模型正常通信curl http://your-gpu-server:8080/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen-3.5-27b-instruct, messages: [{role: user, content: 请回复‘你好世界’}], max_tokens: 10 }如果收到包含正确回复的JSON响应说明模型服务正常。接下来在OpenClaw的配置中填入这个端点URL。OpenClaw会向这个端点发送格式化的提示词Prompt其中包含了当前的测试步骤、屏幕截图可能以Base64编码或图片URL形式、历史操作等信息模型则需要返回结构化的下一步操作指令。实操心得模型部署后务必在OpenClaw中测试一个最简单的指令如openclaw exec “打开浏览器访问百度首页”。这个命令会触发OpenClaw与模型的完整交互链。如果失败需要依次排查网络连通性、API接口格式、模型返回的JSON结构是否符合OpenClaw的解析期望。最常见的坑是模型返回了非结构化的自然语言而不是OpenClaw需要的动作JSON。这需要在部署模型时确保其指令跟随Instruction Following能力足够强或者通过System Prompt进行约束。4. 测试用例的编写从YAML到自然语言4.1 基础YAML用例结构OpenClaw支持用YAML文件来定义测试用例这是一种在灵活性和可维护性之间取得平衡的方式。一个基本的测试用例文件包含以下部分name: “电商用户登录与登出流程测试” description: “验证注册用户可以使用正确凭据登录并在登出后返回登录页” start_url: “https://staging-mall.example.com” steps: - action: “screenshot” name: “记录登录页初始状态” save_to: “artifacts/login_page_initial.png” - action: “type” # 传统定位方式CSS选择器 selector: “input[data-testid’username’]” text: “${env.TEST_USERNAME}” # 支持环境变量 - action: “type” selector: “#password” text: “${env.TEST_PASSWORD}” secret: true # 标记为敏感信息日志中会隐藏 - action: “click” selector: “button:has-text(‘登录’)” - action: “wait_for” condition: “navigation” timeout: 10000 # 等待10秒 - action: “assert” type: “url_contains” value: “/dashboard” name: “验证登录后跳转到仪表盘” - action: “llm_judge” # 调用大模型进行判断 prompt: | 请分析当前页面截图判断用户是否成功登录。 成功登录的迹象包括 1. 页面顶部显示用户姓名或“欢迎回来”字样。 2. 主导航栏包含“我的订单”、“个人中心”等登录后菜单。 如果登录成功请回复JSON{“success”: true, “reason”: “找到[具体找到的文本]”} 如果失败请回复JSON{“success”: false, “reason”: “未发现成功登录迹象发现[页面上的其他文本]”} image: “$last_screenshot” # 引用上一步的截图这个YAML文件定义了一个清晰的步骤序列。OpenClaw的执行引擎会按顺序执行这些步骤并将每一步的结果成功/失败、截图、输出记录下来。4.2 融入大模型能力的进阶用例YAML的强大之处在于可以无缝嵌入对大模型的调用。上面的例子中已经展示了llm_judge动作。更进一步我们可以让模型来生成操作序列。name: “智能探索式测试商品搜索与筛选” steps: - action: “open_url” url: “https://staging-mall.example.com” - action: “llm_plan” # 关键步骤让模型生成后续测试步骤 prompt: | 你是一名测试工程师。当前处于电商网站首页。 你的测试目标是找到一款“蓝牙耳机”将其按“价格从低到高”排序然后查看第一个商品的详情页。 请规划出具体的操作步骤序列每个步骤请用以下JSON数组格式输出 [ {“action”: “action_name1”, “selector”: “...”, “text”: “...”}, {“action”: “action_name2”, “selector”: “...”, “text”: “...”} ] 只输出JSON不要有其他内容。 model: “qwen-3.5-27b” # 可以指定使用哪个已配置的模型 save_output_to: “generated_steps” - action: “execute_plan” # 执行模型生成的计划 plan: “${steps[1].output}” # 引用上一步的输出在这个用例中我们只定义了起点和最终目标中间的点击哪里、输入什么、如何排序全部交给千问3.5-27B来实时规划。这极大地提升了测试脚本的自适应能力。当网站前端的组件结构发生变化时只要模型能理解新界面就能生成新的操作路径而无需人工更新YAML文件中的每一个selector。注意事项完全依赖模型生成步骤存在不确定性。模型可能会生成无效或循环的操作。最佳实践是采用混合模式对于核心、稳定的业务流程如登录、支付使用预定义的、精确的YAML步骤保证可靠性对于UI变化频繁或探索性的测试场景采用llm_plan来增强适应性。同时一定要对模型生成的计划设置超时和循环检测避免测试卡死。5. 执行引擎与视觉验证深度解析5.1 OpenClaw如何执行一个步骤理解执行引擎的工作原理对于调试测试用例至关重要。当OpenClaw处理一个action时它大致经历以下阶段上下文构建引擎会收集当前测试会话的所有上下文信息包括当前URL、上一步的截图、DOM树可选、之前步骤的输出、以及整个测试用例的全局变量。指令格式化如果该动作涉及大模型如llm_judge,llm_plan引擎会将上下文和动作中定义的prompt组合成一个完整的提示词发送给配置的千问模型。动作解析与执行对于模型返回的结果或YAML中定义的标准动作如click,type引擎会将其解析为底层驱动Playwright能理解的指令。对于selector它会先尝试用CSS/XPath定位如果失败且配置了备选方案如视觉描述则会触发视觉定位流程。结果捕获与状态更新动作执行后引擎会捕获新的页面状态截图、网络响应、控制台日志等更新上下文并记录该步骤的成功/失败状态。5.2 基于多模态模型的视觉验证这是本方案最出彩的部分。传统的视觉验证通常基于像素对比pixel-to-pixel diff或OCR文字识别。前者对任何微小的渲染差异都极其敏感误报率高后者则受限于识别精度和排版。千问3.5-27B这类多模态大模型带来了语义层面的视觉验证。我们不再问“这两个区域的像素是否完全一致”而是问“这两张图所表达的业务状态是否一致”。在YAML中我们可以这样定义复杂的视觉验证validations: - name: “验证订单提交成功页面” type: “llm_compare” baseline_image: “baselines/order_success_v2.png” # 基线图代表正确状态 current_image: “$last_screenshot” # 当前测试截图 prompt: | 请比较两张截图判断当前测试截图是否表示“订单提交成功”。 成功的明确标志包括 1. 有显著的绿色对勾或“成功”图标。 2. 显示“订单提交成功”或类似含义的标题文字。 3. 包含一个有效的订单编号一串数字。 4. 有“查看订单”或“返回首页”的按钮。 请忽略以下无关差异 - 订单编号的具体数字不同。 - 当前日期时间不同。 - 浏览器窗口大小和滚动条位置的微小差异。 请仅输出一个JSON对象{“match”: true/false, “confidence”: 0-1之间的浮点数, “reason”: “简要说明原因”}模型会分析两张图片基于对“成功页面”的语义理解做出判断并给出置信度。这种方式对UI的非功能性调整如间距、字体微调不敏感但对功能状态的改变如成功图标变成了警告图标非常敏感更贴近人工测试的思维方式。实操心得视觉验证的准确性极度依赖于提示词Prompt的质量。编写Prompt时要像给新人测试员讲解一样明确“什么是成功”“什么是需要忽略的”。建议为每个重要的验证点建立“基线图库”并定期用模型重新评估这些基线图是否仍然代表正确的业务状态。当UI大改版时需要更新基线图库。6. 高级技巧与性能优化6.1 元素定位的混合策略与容错元素定位是UI自动化的阿喀琉斯之踵。我们发展出一套“三级降级定位策略”写在YAML中如下- action: “click” selector: primary: “css:#submitOrderBtn” # 首选唯一ID fallbacks: # 降级方案 - “xpath://button[contains(class, ‘primary-btn’) and text()‘提交订单’]” - “vision:一个蓝色的、圆角矩形的主按钮上面写着‘提交订单’位于页面底部购物车摘要框的右侧” timeout: 15000 # 总定位超时时间 retry_logic: # 重试逻辑 strategy: “progressive” # 渐进式先等2秒再等5秒最后用视觉 intervals: [2000, 5000] on_final_failure: “llm_recover” # 最终失败时调用模型尝试恢复OpenClaw会按顺序尝试primary和fallbacks中的定位器。vision描述会被发送给千问模型模型会分析当前截图找出最符合描述的UI元素并返回其坐标或生成一个新的CSS选择器。retry_logic和on_final_failure则提供了最终保障让测试流程不至于因为一时性的元素加载延迟或微小UI变动而彻底中断。6.2 测试数据管理与动态注入静态的测试数据无法覆盖边界情况。我们将测试数据准备也纳入了AI的职责范围。- action: “llm_generate_data” prompt: | 请生成一组用于测试用户注册功能的测试数据要求 1. 一个有效的电子邮箱格式正确。 2. 一个符合“强密码”规则的密码包含大小写字母、数字、特殊字符至少12位。 3. 一个中文用户名。 请以JSON格式输出{“email”: “…”, “password”: “…”, “username”: “…”} save_to: “register_data” - action: “type” selector: “#email” text: “${register_data.email}” # 使用生成的数据 - action: “type” selector: “#password” text: “${register_data.password}” secret: true这样每次测试运行都能使用新的、符合规则的测试数据提高了测试的覆盖率和真实性。对于需要关联数据的场景如用刚注册的用户登录可以通过OpenClaw的上下文变量机制轻松传递。6.3 并发执行与资源管理当测试用例成百上千时串行执行是不可接受的。OpenClaw支持通过配置文件或命令行参数指定并发工作进程数。openclaw run ./test_suite/ --workers 4 --model-instances 2这里--workers 4表示启动4个测试执行worker--model-instances 2表示创建2个模型API连接池。每个worker会从任务队列中拉取测试用例执行。关键在于平衡worker数受限于测试机器的CPU/内存模型实例数受限于GPU服务器的并发推理能力。需要监控GPU显存使用情况避免因并发过高导致模型响应超时或OOM内存溢出。我们通常将测试用例按业务模块划分到不同的YAML文件然后使用一个总控脚本并行执行这些测试集并汇总所有结果生成统一的HTML报告。7. 踩坑实录与常见问题排查在实际落地过程中我们遇到了不少问题这里分享几个最具代表性的案例和解决方案。7.1 模型响应不稳定或格式错误问题现象测试执行时经常在llm_judge或llm_plan步骤失败日志显示“无法解析模型响应”或“模型返回非JSON内容”。根因分析Prompt设计不佳提示词没有明确要求模型返回严格的JSON格式导致模型“畅所欲言”。模型超参问题温度temperature设置过高导致输出随机性太强。上下文过长随着测试步骤进行携带历史截图和操作记录的上下文越来越长可能超出模型的有效上下文窗口导致模型性能下降或输出混乱。解决方案强化Prompt工程在System Prompt或每个用户Prompt的结尾用非常严格的格式要求来约束模型。例如你必须且只能输出一个JSON对象格式如下{action: click, selector: ..., reason: ...}。不要输出任何其他解释、Markdown格式或额外文本。调整推理参数在调用模型API时设置temperature0.1甚至temperature0来追求确定性设置max_tokens500限制输出长度。优化上下文管理OpenClaw默认可能会携带大量历史信息。我们修改了配置只保留最近3步的截图和关键结果并使用“摘要”来代替冗长的原始操作记录显著降低了Token消耗。7.2 视觉定位不准或速度慢问题现象使用vision描述定位元素时要么找不到要么找错了而且整个过程耗时好几秒。根因分析描述过于模糊“一个按钮”这种描述没有区分度。页面元素过于相似页面上有多个蓝色按钮。截图质量或时机问题截图时页面可能还在加载或动画中导致模型看到的画面不准确。解决方案编写精准的视觉描述采用“位置外观文本邻近元素”的组合描述。例如“位于页面中央登录表单底部背景为深蓝色、圆角矩形、带有白色‘登录’文字的按钮它的上方是一个密码输入框。”结合区域限定如果知道目标元素的大致区域可以先截图该区域再将小图送给模型分析减少干扰提高精度和速度。增加等待与重试在视觉定位前确保UI已稳定。可以添加wait_for动作等待某个关键元素出现后再进行截图和视觉分析。7.3 测试流程陷入死循环问题现象测试卡在某一步不断重复点击同一个元素或刷新页面。根因分析这通常发生在使用llm_plan让模型自主规划时。模型可能因为对页面状态判断错误规划出了一系列无效操作并且每次执行后状态未达预期它又规划出同样的操作。解决方案设置循环检测与熔断在测试框架层我们增加了状态检测机制。如果连续3个步骤后的页面URL和主要元素哈希值没有变化则判定可能进入循环立即终止当前测试用例标记为“失败”并记录下循环前的上下文用于分析。提供更丰富的状态反馈给模型除了截图我们将页面的URL变化、主要的H1标题文本、以及前几步操作的结果摘要也作为上下文提供给模型帮助它更准确地感知当前状态。人工干预与样本学习对于频繁出现循环的场景我们将出错的上下文和最终人工纠正的操作路径记录下来形成一个“纠正样本库”。在后续的测试中当模型规划步骤前会先在样本库中寻找相似场景如果找到则优先采用历史成功的操作路径而不是完全依赖模型即时生成。7.4 性能瓶颈与成本考量问题现象全量测试套件运行时间过长GPU服务器负载很高。根因分析每个涉及模型的步骤判断、规划、视觉定位都需要调用GPU进行推理这是最耗时的部分。高并发下GPU内存可能成为瓶颈。解决方案测试用例分级与筛选不是所有测试都需要AI参与。我们将测试用例分为三级L1-核心流程使用稳定的YAML脚本不调用模型保证速度与稳定。L2-主要功能在关键验证点使用llm_judge进行语义验证。L3-探索与兼容性全程使用llm_plan用于探索新路径或验证UI兼容性。 日常回归只跑L1和L2L3在夜间或周末低峰期执行。模型服务优化对千问3.5-27B模型进行量化如使用GPTQ、AWQ量化到Int4可以在几乎不损失精度的情况下显著降低显存占用和提高推理速度从而支持更高的并发度。结果缓存对于某些静态页面的判断结果如“首页布局是否正确”如果页面长时间未变更可以将模型的判断结果缓存起来下次直接使用避免重复推理。这套OpenClaw结合千问3.5-27B的自动化测试方案经过半年多的实践已经成为了我们团队质量保障体系中不可或缺的一环。它并没有完全取代传统的自动化脚本而是作为一种强大的补充和增强专门攻克那些变化快、验证逻辑复杂、传统脚本难以维护的测试场景。最大的体会是拥抱AI不是要追求全自动的“银弹”而是要学会如何将人的测试智慧与机器的执行能力更好地结合让测试工程师从重复的“点点点”中解放出来去设计更巧妙的测试场景和探索更隐蔽的软件缺陷。