mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
3008 words
8 minutes
Midscene.js 新手入门:用自然语言完成网页自动化与 UI 测试
2026-08-18

写过 UI 自动化的人,大概率见过这样的代码:

await page.locator('#search-input').fill('Midscene.js');
await page.locator('.search-button').click();
await expect(page.locator('.result-list')).toBeVisible();

它很精确,但也很依赖页面结构。只要前端把 id、类名或者 DOM 层级改掉,测试脚本就可能失效。

Midscene.js 提供了另一种思路:让多模态模型观察页面截图,再根据自然语言理解界面、定位元素并执行操作。

同一段操作可以写成:

await agent.aiAct('在搜索框输入 Midscene.js,然后点击搜索按钮');
await agent.aiAssert('页面已经展示与 Midscene.js 相关的搜索结果');

这篇文章从零开始介绍 Midscene.js。读完后,你将能够:

  • 理解它和 Playwright 的关系;
  • 配置一个支持视觉理解的模型;
  • 编写第一段 AI 网页自动化脚本;
  • 使用自然语言完成操作、等待、取数和断言;
  • 将它接入 Playwright 测试;
  • 理解它的成本、稳定性和适用边界。

1. Midscene.js 是什么#

Midscene.js 是一个开源、视觉驱动的 UI 自动化框架。它让我们用自然语言描述目标,再由 AI 根据当前界面规划并执行操作。

它不只支持网页,还可以用于 Android、iOS、HarmonyOS、桌面应用和自定义界面。本文先从最容易上手的网页自动化开始。

传统 Playwright 通常这样工作:

测试代码
CSS / XPath / role 定位器
直接操作 DOM 元素

Midscene 的典型链路是:

自然语言目标
获取当前页面截图和界面信息
多模态模型理解页面
规划点击、输入、滚动等步骤
通过 Playwright 执行操作
继续观察,直到目标完成

因此,Midscene 不是 Playwright 的替代品。Playwright 负责真正控制浏览器,Midscene 在它上面增加了视觉理解和自然语言规划能力。

2. 它适合解决什么问题#

Midscene 比较适合:

  • 页面结构经常变化,选择器维护成本很高;
  • 快速编写业务流程演示或自动化原型;
  • 对后台系统进行语义化 UI 测试;
  • 从视觉布局复杂的页面提取结构化数据;
  • 页面元素缺少稳定的 iddata-testid
  • 希望用接近测试用例的语言描述操作。

例如:

登录商城后台
搜索名称包含“手机”的商品
打开库存最低的商品
确认页面显示库存预警

如果完全使用传统定位器,这条流程可能涉及大量选择器。Midscene 可以直接理解“库存最低”“库存预警”这些语义。

但它不适合替代所有自动化代码。支付提交、删除数据、权限校验等高风险操作,仍然应该使用确定性定位器、后端接口校验和严格断言。

3. 两种入门方式#

官方提供两条快速体验路径:

3.1 Chrome 扩展#

如果只是想体验,可以先安装 Midscene Chrome 扩展。打开任意网页后,在扩展中输入自然语言指令,不需要创建 Node.js 项目。

它适合:

  • 验证模型配置是否正确;
  • 尝试一句提示词能否完成目标;
  • 观察 AI 如何理解页面;
  • 在写代码前快速调试操作描述。

扩展更像一个 Playground。确认提示词有效后,再把它迁移到 SDK 脚本中。

3.2 JavaScript SDK#

SDK 适合需要重复执行、加入版本管理、接入 CI 或 Playwright 测试的场景。

本文主要讲 SDK 的使用方法。

4. 准备开发环境#

需要准备:

Node.js 18 或更高版本
npm / pnpm
一个支持视觉理解的多模态模型

创建项目:

mkdir midscene-demo
cd midscene-demo
npm init -y

安装依赖:

npm install --save-dev @midscene/web playwright tsx dotenv
npx playwright install chromium

其中:

  • @midscene/web:Midscene 网页自动化 SDK;
  • playwright:控制浏览器;
  • tsx:直接运行 TypeScript;
  • dotenv:从 .env 文件加载模型配置。

package.json 中增加命令:

{
"scripts": {
"demo": "tsx demo.ts"
}
}

5. 配置多模态模型#

Midscene 依赖模型理解页面截图,所以普通纯文本模型不能完成全部工作。

当前版本推荐使用四个环境变量:

MIDSCENE_MODEL_BASE_URL=https://你的模型服务地址/v1
MIDSCENE_MODEL_API_KEY=你的API密钥
MIDSCENE_MODEL_NAME=你的模型名称
MIDSCENE_MODEL_FAMILY=对应的模型家族

四个变量分别表示:

变量作用
MIDSCENE_MODEL_BASE_URLOpenAI 兼容接口地址,不要手动追加 /chat/completions
MIDSCENE_MODEL_API_KEY模型服务密钥
MIDSCENE_MODEL_NAME实际调用的模型名称
MIDSCENE_MODEL_FAMILY告诉 Midscene 如何适配模型的视觉定位格式

例如,使用官方快速开始中展示的 OpenRouter 配置形式:

MIDSCENE_MODEL_BASE_URL=https://openrouter.ai/api/v1
MIDSCENE_MODEL_API_KEY=替换成你自己的密钥
MIDSCENE_MODEL_NAME=qwen/qwen3.7-plus
MIDSCENE_MODEL_FAMILY=qwen3

模型和 MODEL_FAMILY 必须匹配,不要根据模型名称自己猜。不同模型的最新配置应查看官方的模型支持文档

早期文章中可能会看到 OPENAI_API_KEYOPENAI_BASE_URL。当前版本仍然兼容这些变量,但官方已经推荐使用 MIDSCENE_MODEL_*

将密钥文件加入 .gitignore

.env
midscene_run/

不要把真实 API Key 提交到 Git。

6. 编写第一段自动化脚本#

新建 demo.ts

import { chromium } from 'playwright';
import { PlaywrightPageAgent } from '@midscene/web/playwright';
import 'dotenv/config';
const browser = await chromium.launch({
headless: false,
});
const page = await browser.newPage({
viewport: { width: 1280, height: 800 },
});
await page.goto('https://www.bing.com');
const agent = new PlaywrightPageAgent(page);
await agent.aiAct(
'在搜索框输入 Midscene.js,点击搜索,并等待搜索结果出现',
);
await agent.aiAssert(
'页面中已经出现与 Midscene.js 相关的搜索结果',
);
await browser.close();

运行:

npm run demo

第一次建议设置:

headless: false

这样可以直接看到浏览器如何输入和点击。流程稳定后,再改成无头模式运行。

PlaywrightPageAgent 表示这个 Agent 绑定到一个 Playwright Page。旧示例中的 PlaywrightAgent 目前仍然可用,但它是为了兼容保留的别名,新代码优先使用 PlaywrightPageAgent

7. 最常用的四类 API#

Midscene 的常用能力可以归纳为:

Act:操作页面
Wait:等待页面进入某种状态
Query:理解并提取页面数据
Assert:判断页面是否满足条件

7.1 aiAct:完成一系列操作#

await agent.aiAct(
'点击右上角登录,在用户名中输入 demo,密码中输入 123456,然后点击登录',
);

aiAct() 会让模型持续观察、规划和执行,直到认为目标已经完成。

一个指令里可以包含多个步骤,但不要一次塞入过长的业务流程。建议按业务阶段拆分:

await agent.aiAct('打开登录窗口');
await agent.aiAct('输入测试账号和密码并登录');
await agent.aiWaitFor('用户头像已经出现在页面右上角');

这样失败时更容易定位是哪一步出了问题。

7.2 aiWaitFor:等待语义状态#

await agent.aiWaitFor('商品列表加载完成,并且至少显示一件商品', {
timeoutMs: 10_000,
});

它适合等待“列表出现”“弹窗关闭”“提交成功”等视觉状态,比固定 sleep(5000) 更贴近真实目标。

如果页面有确定的网络响应或 DOM 状态,优先使用 Playwright 的确定性等待:

await page.waitForResponse('/api/products');

视觉等待和确定性等待可以混合使用。

7.3 aiQuery:提取结构化数据#

const products = await agent.aiQuery<
Array<{ title: string; description: string }>
>(
'{ title: string, description: string }[], 提取前三条 Midscene.js 相关搜索结果',
);
console.log(products);

相比“告诉我页面上有什么”,明确写出数据结构更稳定:

{ title: string, price: number }[]

Midscene 还提供几个方便的类型化查询:

const title = await agent.aiString('第一条结果的标题');
const count = await agent.aiNumber('当前页面显示多少条搜索结果');
const hasLogin = await agent.aiBoolean('页面上是否存在登录按钮');
const location = await agent.aiLocate('第一条搜索结果的位置');

需要参与程序判断的数据,建议使用类型化方法或 aiQuery,不要从一大段自然语言回答中手动截取。

7.4 aiAssert:进行自然语言断言#

await agent.aiAssert('搜索结果区域至少包含一条与 Midscene.js 相关的结果');

断言失败时,Midscene 会抛出异常,并在报告中给出相关信息。

但是,金额、订单状态、权限等关键事实最好提取后用普通代码断言:

const stock = await agent.aiNumber('第一件商品的库存');
if (stock < 0) {
throw new Error(`库存不能小于 0,当前值为 ${stock}`);
}

AI 断言适合判断视觉语义,JavaScript 断言适合判断精确数据。

8. 精细操作 API#

如果不需要模型规划多个步骤,可以使用更直接的操作方法:

await agent.aiInput('Midscene.js', '页面顶部的搜索框');
await agent.aiTap('搜索按钮');
await agent.aiScroll(
{ scrollType: 'untilBottom' },
'搜索结果区域',
);
await agent.aiRightClick('第一条搜索结果');

它们仍然使用 AI 定位目标元素,但执行动作更加明确。

经验上可以这样选择:

多个连续步骤、不确定下一步页面 → aiAct
明确输入某个字段 → aiInput
明确点击某个语义元素 → aiTap
等待视觉状态 → aiWaitFor
提取页面内容 → aiQuery
验证视觉结果 → aiAssert

9. 把 Midscene 接入 Playwright Test#

一次性脚本适合体验,项目中的 UI 回归测试更适合使用 @playwright/test

安装:

npm install --save-dev @playwright/test

创建 playwright.config.ts

import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './e2e',
timeout: 120_000,
reporter: [
['list'],
['@midscene/web/playwright-reporter'],
],
use: {
headless: true,
viewport: { width: 1280, height: 800 },
},
});

创建 e2e/fixture.ts

import { test as base } from '@playwright/test';
import {
PlaywrightAiFixture,
type PlayWrightAiFixtureType,
} from '@midscene/web/playwright';
export const test = base.extend<PlayWrightAiFixtureType>(
PlaywrightAiFixture({
waitForNetworkIdleTimeout: 1000,
}),
);
export { expect } from '@playwright/test';

创建 e2e/search.spec.ts

import { test, expect } from './fixture';
test('搜索 Midscene.js', async ({
page,
aiInput,
aiTap,
aiWaitFor,
aiQuery,
aiAssert,
recordToReport,
}) => {
await page.goto('https://www.bing.com');
await aiInput('Midscene.js', '搜索框');
await aiTap('搜索按钮');
await aiWaitFor('搜索结果已经加载完成');
const titles = await aiQuery<string[]>(
'string[], 提取前三条搜索结果的标题',
);
expect(titles.length).toBeGreaterThan(0);
await aiAssert('结果中至少有一条与 Midscene.js 相关');
await recordToReport('搜索结果', {
content: JSON.stringify(titles),
});
});

运行:

npx playwright test

这样可以继续使用 Playwright 的测试组织、超时、重试和断言,同时使用 Midscene 处理视觉理解和语义定位。

10. 如何写出更稳定的提示词#

AI 自动化的稳定性很大程度上取决于指令是否清楚。

10.1 描述可观察目标#

不推荐:

处理一下商品

推荐:

在商品列表中找到名称包含“耳机”的第一件商品,打开详情页

10.2 提供界面线索#

点击页面右上角、购物车图标左侧的登录按钮

位置、文字、颜色和相邻元素都能帮助模型定位。

10.3 一个指令只承担一个业务阶段#

不要把登录、搜索、下单、付款、退出全部放进一次 aiAct。步骤越长,调试和重试越困难。

10.4 明确结束状态#

点击保存,并等待页面右上角出现“保存成功”提示

只有操作而没有结束条件,模型可能过早判断任务完成。

10.5 取数时给出结构#

{ name: string, price: number, stock: number }[],提取当前页全部商品

结构越明确,后续代码越容易处理。

11. 推荐使用“AI + 确定性代码”混合模式#

全部交给 AI 看起来代码最少,但不一定最可靠。

推荐分工:

Playwright:打开固定 URL、注入登录态、等待接口、精确提交
Midscene:理解复杂页面、寻找语义元素、提取视觉数据
普通断言:校验金额、数量、状态码和权限结果

例如:

await page.goto('https://example.com/admin/products');
await agent.aiAct('打开库存最低的商品详情');
const product = await agent.aiQuery<{
name: string;
stock: number;
}>('{ name: string, stock: number },提取当前商品名称和库存');
expect(product.stock).toBeGreaterThanOrEqual(0);

这类混合方式兼顾了灵活性和确定性。

12. 调试与运行报告#

Midscene 会生成运行报告,用来查看:

  • AI 看到了什么页面;
  • 模型生成了什么执行计划;
  • 定位到了哪个元素;
  • 实际执行了哪些动作;
  • 哪一步出现错误。

当脚本失败时,不要只增加 sleep,应该先看报告并判断:

页面是否还没加载完成
模型是否选错了元素
指令是否存在歧义
弹窗是否遮挡目标
页面是否打开了新标签页
模型配置是否支持视觉定位

对于固定出现的 Cookie 弹窗,可以在创建 Agent 时补充上下文:

const agent = new PlaywrightPageAgent(page, {
actionContext: '如果出现 Cookie 同意弹窗,先点击接受,再执行任务。',
});

13. 常见问题#

13.1 提示缺少 API Key#

检查是否加载了:

import 'dotenv/config';

并确认 .env 位于运行命令所在目录。

13.2 模型能回答文字,但不会点击#

通常是模型不支持视觉定位,或者 MIDSCENE_MODEL_FAMILY 配置不匹配。以官方模型支持表为准。

13.3 页面输入时丢字符#

受控输入框可能无法处理过快输入,可以配置:

const agent = new PlaywrightPageAgent(page, {
keyboardTypeDelay: 80,
});

13.4 点击后打开新标签页#

页面级 Agent 默认更偏向保持在当前页。如果业务确实需要管理多个页面,可以关闭同页限制,并为新页面创建 Agent,或者使用 PlaywrightBrowserAgent

13.5 测试偶尔成功、偶尔失败#

依次检查:

  1. 是否使用了固定等待而页面加载速度不稳定;
  2. 提示词是否同时包含太多步骤;
  3. 页面是否有随机弹窗;
  4. 浏览器窗口大小是否固定;
  5. 模型和模型家族是否匹配;
  6. 是否应该将关键步骤改为 Playwright 定位器。

13.6 运行速度比普通 Playwright 慢#

这是正常现象。Midscene 需要截图、调用模型、规划和验证,延迟与 Token 成本都高于确定性脚本。

不要为了“更 AI”而把所有点击都改成模型调用。稳定选择器能够完成的动作,继续使用 Playwright 通常更便宜、更快。

14. 使用时需要注意的安全问题#

Midscene 可以点击、输入、上传文件,因此它拥有真实操作界面的能力。

在测试环境中使用时应注意:

  • 不要将生产管理员账号交给自动化脚本;
  • 不要让不可信网页内容改变高风险操作目标;
  • 删除、支付、发布等操作保留人工确认;
  • 上传文件时限制允许访问的目录;
  • 模型 API Key 只通过环境变量或密钥服务提供;
  • CI 中使用独立测试账号和隔离数据;
  • 对 AI 操作保留报告和审计记录。

自然语言指令可以提高开发效率,但不能替代服务端权限校验。

15. 一个合理的学习顺序#

新手可以按以下路线学习:

Chrome 扩展体验自然语言操作
PlaywrightPageAgent 编写单文件脚本
掌握 aiAct / aiWaitFor / aiQuery / aiAssert
使用 aiInput / aiTap 完成精细操作
接入 Playwright Test
查看报告并优化提示词
采用 AI + Playwright 混合模式
接入 CI 和专用测试数据

不要一开始就用它完成几十步的下单流程。先选择一个页面、一项操作和一个断言,稳定后再逐步扩展。

16. 本文总结#

Midscene.js 为 UI 自动化增加了一层视觉理解和自然语言规划能力:

Playwright 控制浏览器
+ 多模态模型理解页面
+ 自然语言描述操作目标
+ aiQuery 提取结构化数据
+ aiAssert 验证视觉语义
+ 运行报告辅助调试

它最大的价值不是让我们彻底告别选择器,而是让过去难以维护的视觉定位和复杂页面理解变得更简单。

真正稳定的使用方式通常是:

用 Midscene 处理不确定、视觉化、语义化的部分,用 Playwright 和普通代码处理确定、精确、高风险的部分。

如果只是刚开始学习,先完成本文的搜索脚本,再把目标页面替换成自己的商城后台。尝试让它搜索商品、打开详情、提取库存并完成语义断言,就能很快理解 Midscene 的工作方式。

参考资料#

Share

If this article helped you, please share it with others!

Midscene.js 新手入门:用自然语言完成网页自动化与 UI 测试
https://mizuki.mysqil.com/posts/midscenejs-beginner-guide/
Author
梦幻晨风
Published at
2026-08-18
License
CC BY-NC-SA 4.0

Some information may be outdated

Table of Contents