1. 项目概述当AI学会“看”屏幕想象一下你正在测试一个刚上线的网页应用。产品经理提了个需求“验证一下用户从登录到成功下单的整个流程在Chrome、Safari和手机浏览器上是不是都走得通。” 如果是以前你可能得打开三个浏览器手动操作三遍或者花上半天时间用Playwright或Selenium写一堆基于CSS选择器、XPath的自动化脚本。更头疼的是前端同事明天改了个按钮的class名你的脚本可能就全挂了又得重新调试。这就是传统UI自动化测试的痛点高度依赖不稳定的页面结构。我们写的脚本本质上是告诉计算机“去点击那个class为submit-btn的按钮”。但计算机并不理解这个按钮是干什么的它只是机械地执行命令。一旦页面结构变化命令就失效了。而Midscene.js带来的是一种近乎“魔法”的范式转变。它不关心DOM树长什么样它让AI模型直接“看”屏幕截图就像真人用户一样。你只需要用自然语言告诉它“点击那个蓝色的‘提交订单’按钮”或者“在搜索框里输入‘最新款手机’并回车”。Midscene背后的多模态大模型比如Qwen-VL、GLM-4V会理解你的指令分析屏幕上的视觉元素规划操作步骤并驱动鼠标和键盘去执行。这不仅仅是测试工具的升级更是一种思维方式的革新。它让AI成为了一个真正能理解界面、能按你所说去操作的“浏览器操作员”。无论是测试一个复杂的SaaS后台自动化填报某个政府网站的表单还是操作一个完全没有无障碍标签的古老内部系统Midscene都能应对。它的核心价值在于将自动化脚本的维护成本从依赖开发者的频繁更新转移到了AI模型强大的视觉理解能力上使得自动化变得更加健壮和智能。2. 核心原理与架构拆解视觉驱动如何工作要理解Midscene.js不能只把它当成一个“更好用的Selenium”。它的底层架构和运行逻辑与传统工具有本质区别。我们可以把它拆解为三个核心层视觉感知层、智能规划层和执行驱动层。2.1 视觉感知层从像素到语义这是Midscene的基石。传统工具通过浏览器DevTools协议获取DOM树而Midscene获取的是当前屏幕或浏览器窗口的截图Screenshot。这张截图被送入多模态大模型如Qwen2.5-VL、GLM-4.6V。模型在这里完成两项关键任务视觉定位Visual Grounding将你的自然语言指令如“红色的删除图标”与截图中的具体像素区域进行关联。模型会输出一个或多个边界框Bounding Box精确框出目标元素。视觉问答Visual Question Answering回答关于截图内容的提问。例如aiQuery(‘当前页面的标题是什么’)模型会“阅读”截图中的文字并返回答案。这个过程的优势是巨大的。它跳过了所有前端框架和HTML结构的限制。一个用canvas绘制的复杂图表、一个SVG图标按钮、甚至是一个嵌在iframe里的第三方登录组件只要人眼能看见模型就能定位。这解决了传统自动化中“选择器失效”和“无法操作无DOM元素”两大顽疾。2.2 智能规划层理解意图与分解任务当你下达一个复杂指令如“登录邮箱找到最新一封来自‘系统通知’的邮件并下载其中的附件”时Midscene不是盲目地开始点击。它的规划层由大模型驱动会先将这个高级目标分解成一系列原子操作步骤定位并点击“登录”按钮/链接。在用户名输入框输入账号。在密码输入框输入密码。点击“登录”提交按钮。等待收件箱加载定位“系统通知”发件人的邮件。点击该邮件进入详情页。定位并点击“下载附件”按钮。这个规划过程是动态的、基于上下文的。如果第5步发现没有“系统通知”的邮件模型可能会规划“返回收件箱”或“检查垃圾箱”的备用分支。这种基于视觉反馈的实时规划能力是传统录制回放或硬编码脚本完全不具备的。2.3 执行驱动层从规划到动作规划层输出步骤序列后执行驱动层负责将其转化为真实的操作系统事件。Midscene通过适配器Adapter与不同的自动化引擎对接Web端集成Playwright或Puppeteer。当模型返回一个元素的坐标后Midscene会通过Playwright的API在该坐标触发click()、type()等事件。移动端Android/iOS通过Appium、scrcpy或WebDriverAgent等工具将触摸、滑动等手势指令发送到设备。桌面端使用如robotjs或系统原生API来模拟全局的鼠标键盘操作。这一层确保了Midscene的跨平台能力。无论目标是什么只要能为Midscene提供屏幕截图并接收其操作指令自动化就能进行。注意视觉驱动的精度并非100%。模型可能会误识别相似图标或在元素极度密集、模糊时定位不准。因此Midscene的最佳实践是将复杂的端到端流程拆解为更小、更确定的工作流而非完全依赖AI一次性完成超长流程的“自动规划”。3. 环境搭建与快速上手理论讲完我们立刻动手在10分钟内跑通第一个Midscene自动化脚本。这里我们以最常见的Web浏览器自动化为例。3.1 环境准备Node.js与PlaywrightMidscene.js是一个Node.js SDK因此首先需要安装Node.js建议版本18或以上。同时由于我们选择Playwright作为浏览器驱动也需要一并安装。# 1. 初始化一个新的Node.js项目如果已有项目可跳过 mkdir my-midscene-demo cd my-midscene-demo npm init -y # 2. 安装Midscene.js核心包和Playwright适配器 npm install midscene midscene/adaptor-playwright # 3. 安装Playwright及其浏览器Chromium, Firefox, WebKit npx playwright install3.2 获取模型API密钥Midscene本身不提供模型需要你配置一个多模态大模型的API。这里我们以阿里云灵积平台的Qwen2.5-VL模型为例因为它对中文UI的理解效果很好且性价比高。访问阿里云官网注册并登录。进入“灵积”产品控制台。在“模型服务”中找到“Qwen2.5-VL-72B-Instruct”或类似视觉模型开通服务。在“API密钥管理”中创建并复制你的API Key。实操心得对于初学者强烈建议从Qwen2.5-VL或GLM-4V开始它们对中文界面友好文档丰富。DeepSeek-V3等模型虽然强大但可能对UI元素的定位指令需要更精细的调教。可以先在模型提供的在线Playground中用截图测试一下它的理解能力。3.3 编写第一个自动化脚本让AI打开百度并搜索创建一个名为first-ai-opera.js的文件输入以下代码const { Midscene } require(midscene); const { PlaywrightAdaptor } require(midscene/adaptor-playwright); const playwright require(playwright); (async () { // 1. 启动浏览器 const browser await playwright.chromium.launch({ headless: false }); // 设置为true则无头运行 const context await browser.newContext(); const page await context.newPage(); // 2. 创建Playwright适配器 const adaptor new PlaywrightAdaptor({ page }); // 3. 创建Midscene代理并配置模型 const agent new Midscene({ adaptor, model: { // 这里以阿里云Qwen2.5-VL为例 provider: aliyun, apiKey: 你的-API-KEY-放在这里, // 务必替换成你的真实Key model: qwen2.5-vl-72b-instruct, region: cn-hangzhou // 根据你的服务区域填写 } }); try { // 4. 导航到百度 await page.goto(https://www.baidu.com); // 5. 让AI在搜索框输入内容并点击搜索 await agent.aiAct(在页面的搜索框里输入“Midscene.js 自动化”然后点击“百度一下”按钮); // 6. 等待一下结果加载 await page.waitForTimeout(3000); // 7. 让AI点击第一个搜索结果链接 await agent.aiAct(点击第一个搜索结果标题); // 8. 等待新页面加载并让AI验证是否跳转成功 await page.waitForTimeout(2000); const currentUrl page.url(); console.log(当前页面URL:, currentUrl); // 使用aiQuery获取页面标题进行验证 const pageTitle await agent.aiQuery(当前浏览器页面的标题是什么); console.log(AI识别的页面标题:, pageTitle); } catch (error) { console.error(自动化执行出错:, error); } finally { // 9. 关闭浏览器注释掉以便查看结果 // await browser.close(); } })();运行这个脚本node first-ai-opera.js你会看到Chromium浏览器自动打开访问百度在搜索框输入文字并点击搜索然后点击第一个结果。整个过程中你的代码没有使用任何input[typetext]或#su这样的选择器全部由AI通过“看”屏幕来完成操作。4. 核心API详解与实战模式掌握了基础操作后我们来深入Midscene的核心API并了解两种主要的自动化风格自动规划模式和工作流模式。4.1 核心API三剑客aiAct, aiQuery, aiAssertMidscene的API设计非常简洁核心方法就三个足以应对绝大多数场景。1.agent.aiAct(instruction: string): Promisevoid这是最常用的方法用于执行一个操作指令。AI会规划并执行完成该指令所需的所有步骤。// 示例完成一个登录操作 await agent.aiAct(在用户名输入框填写“admin”在密码输入框填写“123456”然后点击登录按钮); // 示例进行一个复杂操作 await agent.aiAct(找到商品列表将价格从低到高排序然后点击第二便宜的商品进入详情页);注意事项aiAct指令应尽可能清晰、原子化。像“测试整个购物流程”这样的指令过于宏大成功率低。应拆解为“搜索商品”、“加入购物车”、“去结算”等多个aiAct。2.agent.aiQueryT(question: string): PromiseT用于向AI提问从当前屏幕中提取信息。你可以指定返回类型string,number,boolean,array等。// 获取页面标题 (字符串) const title await agent.aiQuerystring(当前页面的标题是什么); // 获取所有新闻条目的标题 (字符串数组) const newsHeadlines await agent.aiQuerystring[](列表里所有新闻的标题是什么); // 检查某个状态 (布尔值) const isLoggedIn await agent.aiQueryboolean(页面右上角是否显示了用户的头像); // 获取商品价格 (数字) const price await agent.aiQuerynumber(当前商品的价格是多少元只返回数字。);这是实现视觉断言和数据提取的关键。传统工具需要解析HTML来获取文本而aiQuery直接“读取”屏幕上显示的内容更符合真实用户体验。3.agent.aiAssert(condition: string): Promisevoid用于进行视觉断言。如果条件不满足则抛出错误测试失败。// 断言页面包含成功提示 await agent.aiAssert(页面上显示有“操作成功”的绿色提示信息); // 断言错误消息不存在 await agent.aiAssert(页面上没有出现“用户名或密码错误”的红色文字); // 断言某个元素处于特定状态 await agent.aiAssert(“提交”按钮处于不可点击的灰色状态);aiAssert的强大之处在于它能进行视觉和语义层面的校验而不仅仅是检查DOM节点是否存在。它能判断一个按钮“看起来”是不是禁用的一个提示框“看起来”是不是成功的。4.2 自动化风格选择自动规划 vs. 工作流根据任务复杂度和对稳定性的要求可以选择两种风格。模式一自动规划AI自主规划将复杂任务直接交给AI让它自己分解步骤。适合探索性测试或一次性自动化任务。// AI将自主完成从登录到发布文章的全流程 await agent.aiAct( 1. 使用账号“editortest.com”和密码“pass123”登录内容管理系统。 2. 进入“文章管理”页面。 3. 点击“新建文章”按钮。 4. 填写标题为“Midscene.js视觉自动化测试”选择分类为“技术”。 5. 在正文编辑器里输入一段介绍Midscene的文字。 6. 点击“发布”按钮。 7. 确认发布成功并返回文章列表页。 );优点代码极其简洁像写需求文档一样写自动化。缺点流程长任何一步失败都会导致整个任务中止且调试时难以定位是哪一步的视觉识别出了问题。模式二工作流风格开发者控制流程由开发者编写逻辑控制流只在关键步骤调用Midscene的AI能力。这是生产环境推荐的做法稳定性最高。// 工作流风格登录CMS并发布文章 async function publishArticle(agent, title, content) { // 步骤1导航到登录页并填写表单使用AI定位元素 await page.goto(https://cms.example.com/login); await agent.aiAct(在用户名输入框填写“editortest.com”); await agent.aiAct(在密码输入框填写“pass123”); await agent.aiAct(点击“登录”按钮); await page.waitForURL(**/dashboard); // 步骤2使用aiQuery确认登录成功 const welcomeText await agent.aiQuerystring(页面顶部显示的用户欢迎语是什么); console.assert(welcomeText.includes(editor), 登录可能未成功); // 步骤3导航到文章列表页并点击新建混合使用传统和AI方式 await page.click(nav a[href/posts]); // 使用稳定选择器 await agent.aiAct(点击“新建文章”按钮); // 按钮可能没有固定选择器用AI // 步骤4填写表单AI处理富文本编辑器等复杂组件 await agent.aiAct(在标题输入框填写“${title}”); // 假设正文是一个复杂的富文本编辑器传统方式难以操作 await agent.aiAct(点击正文编辑区域并输入以下内容${content}); // 步骤5发布并断言 await agent.aiAct(点击“发布”按钮); await page.waitForTimeout(1000); // 等待弹窗或跳转 await agent.aiAssert(页面出现了“文章发布成功”的提示信息); }优点流程可控易于调试和错误处理。可以混合使用稳定的传统选择器和AI视觉操作取长补短。缺点代码量稍多需要开发者设计流程。5. 高级特性与集成方案当项目规模扩大就需要用到Midscene的高级特性来提升效率、可靠性和可维护性。5.1 模型策略与配置优化Midscene支持配置多个模型并设置回退策略这对于保证服务的稳定性和降低成本至关重要。const agent new Midscene({ adaptor, model: { // 主模型性能好但成本较高 provider: aliyun, apiKey: process.env.ALIYUN_API_KEY, model: qwen2.5-vl-72b-instruct, }, fallbackModels: [ // 备用模型1成本低能力稍弱 { provider: openai, apiKey: process.env.OPENAI_API_KEY, model: gpt-4o-mini, }, // 备用模型2可自托管完全免费 { provider: custom, apiEndpoint: http://localhost:8080/v1, model: ui-tars, } ], // 配置模型选择策略 modelStrategy: { // 当主模型因超时、配额不足等原因失败时自动切换到备用模型 enableFallback: true, // 对aiQuery这类信息提取任务默认使用更便宜的模型以节省成本 defaultModelForQuery: openai, } });配置建议生产环境使用Qwen2.5-VL或GLM-4.6V作为主模型保证识别精度。将GPT-4o-mini或Claude Haiku作为aiQuery的默认模型大幅降低文本提取的成本。成本敏感/内网环境部署开源的UI-TARS或Qwen2-VL模型到本地GPU服务器通过customprovider连接实现零API成本、高并发的自动化。5.2 缓存与性能提升每次调用模型都发送截图会产生延迟和费用。Midscene提供了智能缓存机制。const { FileSystemCache } require(midscene/cache); const agent new Midscene({ adaptor, model: { /* ... */ }, cache: new FileSystemCache({ // 缓存目录 dir: ./.midscene-cache, // 缓存有效期秒 ttl: 7 * 24 * 60 * 60, // 一周 }), // 相似度阈值界面变化小于此值则使用缓存结果 cacheSimilarityThreshold: 0.98, });工作原理当AI成功定位一个元素如“登录按钮”后Midscene会将此时的屏幕特征和定位结果坐标缓存起来。下次在高度相似的界面上执行相同指令时它会直接使用缓存的结果无需再次调用模型速度从秒级提升到毫秒级。这对于重复执行的测试套件如每日构建后的回归测试能节省大量时间和费用。5.3 与现有测试框架集成Midscene可以无缝嵌入到你现有的Playwright Test或Vitest测试中作为强大的视觉断言和操作补充。集成到Playwright Test示例// tests/visual-auth.spec.js import { test, expect } from playwright/test; import { Midscene } from midscene; import { PlaywrightAdaptor } from midscene/adaptor-playwright; test(用户使用AI视觉操作完成登录流程, async ({ page }) { await page.goto(https://example.com/login); const adaptor new PlaywrightAdaptor({ page }); const agent new Midscene({ adaptor, model: { /* ... */ } }); // 使用aiAct进行视觉驱动操作 await agent.aiAct(输入用户名“testuser”); await agent.aiAct(输入密码“secret”); await agent.aiAct(点击“登录”按钮); // 等待导航 await page.waitForURL(**/dashboard); // 使用aiAssert进行视觉验证替代传统的文本断言 // 传统方式await expect(page.locator(.welcome-msg)).toHaveText(Welcome, testuser!); // AI视觉方式 await agent.aiAssert(页面顶部清晰地显示了“欢迎回来testuser!”的欢迎语); // 混合断言既检查视觉也检查DOM状态 const profileMenuVisible await agent.aiQueryboolean(用户头像或昵称是否显示在右上角); expect(profileMenuVisible).toBeTruthy(); });这样你可以在同一个测试用例中混合使用Playwright稳定的导航、网络拦截功能和Midscene强大的视觉操作与断言能力。5.4 生成可视化测试报告Midscene在每次aiAct或aiAssert时都会在后台记录屏幕截图、AI的指令、规划步骤和执行结果。运行结束后可以生成一份HTML报告。const { generateHtmlReport } require(midscene/reporter); // ... 执行一系列自动化操作 ... // 测试结束后生成报告 await generateHtmlReport(agent.getExecutionRecords(), { outputPath: ./midscene-report.html, title: 用户登录流程视觉自动化测试报告 });打开生成的HTML报告你可以看到一个可逐步骤回放的视图。每个步骤都展示了当时的屏幕截图、AI接收的指令、它“认为”应该点击哪里用红框标出以及最终是否成功。这对于调试失败的测试用例极其有用你一眼就能看出是AI看错了还是页面本身加载异常。6. 常见问题排查与实战技巧在实际项目中应用Midscene你一定会遇到各种问题。下面是我从大量实践中总结出的高频问题与解决方案。6.1 问题排查速查表问题现象可能原因解决方案aiAct点击了错误的位置1. 指令模糊如“点击按钮”但页面有多个按钮。2. 模型对当前UI样式理解有偏差。3. 页面动态加载未完成。1.优化指令使用更精确的描述如“点击蓝色的、写着‘提交订单’的按钮”。2.增加上下文先aiQuery确认页面状态如const pageTitle await agent.aiQuery(‘当前是什么页面’)。3.显式等待在操作前加入page.waitForLoadState(‘networkidle’)或page.waitForTimeout。aiQuery返回信息不准确1. 截图区域文字太小或模糊。2. 问题表述有歧义。3. 模型对复杂布局理解有限。1.调整浏览器缩放或提高截图分辨率在适配器配置中设置。2.简化问题将复杂问题拆解。不问“列表里有什么”而问“第一列的名称是什么”、“第二列的价格是多少”。3.指定返回格式使用aiQuerystring[](‘将所有商品名称以数组形式列出’)。执行速度慢1. 每次操作都调用模型API网络延迟高。2. 模型响应慢。3. 未启用缓存。1.启用缓存见5.2节对静态页面效果极佳。2.切换到更快的模型如gpt-4o-mini用于简单查询。3.合并操作将多个连续点击输入合并到一个aiAct指令中。在iframe或弹窗中操作失败默认上下文在主页面无法“看到”iframe或弹窗内的内容。切换上下文对于Playwright先定位到iframe对象然后为该iframe创建一个新的Midscene agent。const frame page.frameLocator(‘iframe’); const frameAgent new Midscene({ adaptor: new PlaywrightAdaptor({ page: frame }) });CI/CD环境中运行失败1. 无头模式下的字体渲染、分辨率与本地不同。2. CI环境无法访问外部模型API。3. 缺少显示服务器Linux。1.统一环境在CI中固定浏览器窗口大小和分辨率。2.使用自托管模型或确保CI机器网络可通。3.使用xvfb在Linux CI中通过xvfb-run启动虚拟显示。6.2 提升稳定性的实战技巧“混合动力”策略不要全盘抛弃传统选择器。对于导航栏、菜单等极其稳定的元素继续使用page.click(‘data-testidnav-home’)。对于频繁变动、样式复杂或第三方组件再用aiAct。这种混合模式在稳定性和灵活性之间取得了最佳平衡。为AI提供“路标”在复杂的表单或列表中操作时先让AI识别一个稳定的视觉锚点。例如不要直接说“在第三行输入数量”而是说“找到标题为‘商品清单’的表格在它的第三行‘数量’列下方的输入框里填写2”。善用aiQuery进行状态确认在关键操作前后插入aiQuery来确认状态实现自检。例如点击“保存”后可以await agent.aiQueryboolean(‘页面是否出现了“保存成功”的绿色提示’)。如果为false则主动重试或失败。处理动态内容与加载对于加载缓慢的列表或模态框使用page.waitForSelector等待某个根元素出现结合agent.aiAct操作其内部动态内容的方式。例如await page.waitForSelector(‘.modal-content’); await agent.aiAct(‘在弹窗里点击确认按钮’);。设计鲁棒的指令指令应简洁、明确、无歧义。避免使用“这里”、“那个”等代词。多使用元素的文本标签、颜色、相对位置左侧、上方、图标形状等视觉特征进行描述。例如“点击位于‘用户名’输入框右侧的、眼睛形状的‘显示密码’图标”。将Midscene.js引入项目初期可能会觉得指令调优有些繁琐但一旦跑顺你会发现它为UI自动化打开了新世界的大门。它特别适合那些选择器维护成本极高、有大量Canvas/WebGL渲染、或需要跨域iframe操作的场景。从今天开始尝试让AI成为你的浏览器操作员把重复性的界面操作交给它而你可以去思考更复杂、更有价值的问题。