☰
MCP+Playwright:AI Agent浏览器自动化测试实践
2026/10/5 6:20:08 网站建设 项目流程

上个月排查线上问题,前端同事改了个按钮文案,自动化用例里跟文本强绑定的定位器直接红了一大片。这种场景但凡做过Web自动化的人都熟悉,选择器、等待、弹窗、iframe,任何一个环节变动都可能让精心维护的用例变成摆设。我最近两个月一直在折腾一套组合:让AI Agent通过MCP协议直接驱动Playwright操作浏览器去做测试。这跟传统"写脚本、跑断言"的思路完全不同,核心是把浏览器能力封装成MCP服务端暴露给大模型,让模型像一个真人那样去观察页面、点击、输入、验证。

这篇文章是我这两个月跑下来的完整记录,覆盖了MCP和Playwright怎么对接、链路里真正起作用的机制、实际跑过的案例,以及那些让人血压飙升的翻车瞬间。如果你正在做Web自动化测试、或者打算把AI Agent落到具体工程场景里,这篇应该能帮你少踩不少坑。

1. 先搞清楚一件事:MCP协议解决的是"AI怎么操作浏览器"的机制问题

1.1 为什么传统的"AI加自动化"总是差一口气

很多人一听到"AI驱动测试",第一反应是让大模型写Playwright代码。这个思路我早试过,确实能用,但有个天花板:模型生成完代码,执行还是靠传统方式,页面一变化,代码一样挂。更麻烦的是,网页是一个强交互环境,不是丢一个静态描述给模型就能搞定的,它得"看着"页面状态不断调整下一步动作——这才是人和脚本之间真正的差别。

也有团队尝试把大模型直接嵌到测试框架里,让模型自己判断页面元素、生成定位表达式。但这样做的代价很大:每次都要把整个页面结构塞进上下文,Token开销惊人,模型的"判断"也经常偏离真实浏览器状态。说白了,这个方向卡在"模型与浏览器之间没有一条标准、实时、双向的通道"。

1.2 MCP用"工具调用"把浏览器能力标准化了

MCP(Model Context Protocol)解决的就是这个问题。它是一个开放协议,思路很直白:把外部能力统一抽象成工具(Tool),大模型通过标准化的请求去调用这些工具,工具执行完把结果返回给模型。整个过程基于JSON-RPC 2.0,任何支持MCP的客户端都能用同一套机制对接任意MCP服务端。

放到我们这个场景里,Playwright MCP服务端把浏览器自动化能力变成了一个个工具,包括页面跳转、点击、输入、截图、读取控制台等等。大模型不用先"学"Playwright的API,它只需要在MCP协议下看到这些工具的名字、参数说明,自然就能根据用户的目标自行编排调用了。

它和"直接写脚本"的本质区别,我用一个表对比过:

维度传统Playwright脚本Playwright MCP加AI Agent
用例编写方式手工逐行写选择器和操作步骤自然语言描述目标,AI规划动作序列
应对页面变化选择器失效即报错,需要人工维护模型会重新观察页面,根据当前真实状态推导
运行确定性同输入必然同输出有一定随机性,但更贴近真实用户行为
适用场景确定路径的回归验证探索性测试、流程复杂且变动频繁的场景
维护成本中后期持续投入主要花在审核AI行为和补充边界条件上

1.3 为什么这条协议值得关注

MCP从提出到现在,生态起来的速度非常快。微软在Windows、GitHub、VS Code里相继接入,OpenAI也在自己的产品里支持MCP标准。这意味着MCP不太可能只是一个过渡方案,而是"AI连接真实世界"的基础设施。只要协议活下来,我们今天做的这套Playwright接入方式,未来也可以平滑迁移到其他浏览器工具、移动端自动化、桌面应用操作上,不需要改AI侧的逻辑,只需要替换MCP服务端。这一点,是整个架构里我最看重的地方。

2. 环境搭建与联动配置:把Playwright MCP服务端跑起来

2.1 本地启动服务端,这一步很简单但有个坑

Playwright官方发布了MCP服务端包,包名是@playwright/mcp,通过npx就能启动,不需要单独下载二进制,它会自动装好Chromium。

npx @playwright/mcp@latest --headless --port 8931

我实际跑的时候,Node版本必须大于18,否则会报依赖错误。另一个坑是,如果之前装过旧版Playwright,npx可能缓存了旧包,要加@latest强制拉最新版本。把--headless去掉就是有头模式,调试时建议开着,你能直接看到AI在浏览器里"表演"。

2.2 让大模型客户端认识这个服务端

启动服务端只是第一步,关键是让AI客户端能连上来。以Claude Desktop为例,需要编辑MCP配置文件:

{ "mcpServers": { "playwright": { "command": "npx", "args": ["@playwright/mcp@latest", "--headless"] } } }

配置文件路径在Claude Desktop的设置里能找到,不同操作系统路径不一样。保存后重启客户端,在工具列表里就能看到Playwright暴露出来的一系列browser工具。

如果你用的不是Claude Desktop,比如Cherry Studio、VS Code里的MCP插件,配置入口名称可能不同,但核心都是两件事:填命令、填参数。有些客户端支持HTTP方式对接,那就直接填http://localhost:8931/sse,走SSE通道,适合在同一台机器上让多个客户端共享一个浏览器服务。

2.3 跑通验证链路,确认模型真的能控制浏览器

配置完先别急着写复杂的测试。我用一个最简单的指令验证:

打开 https://example.com ,把页面上的所有链接列出来。

正常情况下,模型会调用browser_navigate跳转页面,然后调用browser_snapshot读取页面结构,最后把链接列表整理给你。如果这一步通了,说明整条链路是通的;如果卡住,九成是配置没生效或者端口被防火墙拦了。

这一步验证非常关键,因为后续所有的测试能力都建立在"模型能看到真实页面状态"的基础上。如果模型连页面都读不到,后面的智能判断全是空谈。

2.4 几个值得早点知道的参数

参数作用我的建议
--headless无头模式运行浏览器调试期别用,观察AI行为很直观
--port指定HTTP端口多客户端共享时用,注意端口冲突
--user-data-dir指定浏览器用户数据目录想保存登录态时用,团队落地时谨慎
--device模拟移动设备做移动端适配测试时用
--ignore-https-errors忽略证书错误测试环境证书不规范时用

配置有--user-data-dir能保存登录状态,AI跑了半天突然要登录验证,这个参数能省很大事。但如果团队里多个人共用同一个配置目录,并发时会打架,所以最好每个任务单独一个目录,跑完就清理。

3. 核心机制拆解:一次测试任务背后,模型和浏览器是怎么配合的

3.1 从一条指令到浏览器动作,中间发生了什么

我拿一个实际场景拆开讲。假设给AI的命令是:"打开登录页面,输入错误的账号密码,看它会不会弹错误提示。"

传统脚本执行起来是确定性的:goto、fill、click、expect。但MCP模式下,模型会走一套"观察-决策-执行-确认"的循环:

  1. 模型先调用browser_navigate,地址设为登录页URL;
  2. 页面加载完成后,模型调用browser_snapshot获取当前页面的可访问性树,这一步等于人用眼睛扫了一遍页面;
  3. 模型根据快照里的输入框和按钮信息,调用browser_type输入账号、密码;
  4. 点击登录按钮之前,模型往往会先browser_snapshot确认按钮当前可用,而不是盲目点击;
  5. 点击后再次browser_snapshot,读取页面是否出现错误提示文案;
  6. 模型把错误提示内容整理成结论返回给用户。

整个过程中,模型随时可以用截图、控制台日志来辅助判断,每一步都是活的。这个循环的本质,是把自动化从"提前写死步骤"变成了"根据实时页面状态动态决策"。

3.2 Playwright MCP暴露的工具集里,哪些最常用

我这两个月跑下来,常用的工具大概这些:

工具名作用使用频率
browser_navigate跳转到指定URL极高
browser_snapshot获取当前页面可访问性树快照极高
browser_click点击指定元素极高
browser_type向输入框填入内容高
browser_screenshot页面截图高
browser_select_option选择下拉框选项中
browser_hover悬停元素,触发浮层中
browser_wait等待指定条件满足中
browser_console读取控制台日志和网络错误中
browser_tab_switch切换标签页低

注意,这些工具的具体名称在不同版本里可能微调,但模型本身会通过MCP的list_tools动态获取当前可用工具,不需要死记。真正要理解的是browser_snapshot的设计——它返回的不是完整HTML源码,而是页面的可访问性树(Accessibility Tree),也就是辅助技术读到的语义结构。这样做的好处是双重的:一方面大幅压缩了进入模型上下文的数据量,另一方面隐藏了无关的样式脚本噪音,让模型聚焦在按钮、输入框、文本这些真正影响交互的元素上。用可访问性树而不是截图喂给模型,是我认为Playwright MCP做得最聪明的设计。截图体积大、文本信息难提取,而可访问性树既小又结构化,直接决定了模型的理解质量。

3.3 和传统Playwright脚本的本质区别:确定性 vs 探索性

传统脚本是确定性的,同样的代码,今天跑和明天跑结果一样,但这个特性在快速迭代的页面上反而是负担。页面结构稍微一改,脚本就挂。MCP模式下模型每次执行都可能走不同路径,它不依赖固定选择器,而是通过观察页面语义临时决定下一步,这本质上更像一个会变通的测试人员,而不是一段死板的代码。

我用一个具体例子说明。测一个搜索功能,传统脚本是:

await page.goto('https://example.com/search'); await page.getByRole('textbox', { name: '搜索' }).fill('MCP'); await page.getByRole('button', { name: '提交' }).click(); await expect(page.getByText('搜索结果')).toBeVisible();

MCP模式下,AI的指令是"在搜索框输入MCP,提交后确认结果区域出现文本"。模型可能会先导航到搜索页面,如果发现页面上有两个输入框,它会优先选择带"搜索"标签的那个,而不是靠选择器硬撑。页面结构变化时,模型会就地反应,比如按钮文案改成"立即搜索",它会基于语义重新定位。

这种探索能力在回归测试里特别值钱。传统脚本面对文案调整只能报错等人修,AI Agent则会自己找到新入口继续跑。当然,探索性也带来了不确定性,所以后面我会专门讲怎么用"约束卡"来降低风险。

4. 从"一句话需求"到真实可用的测试:三个跑通的场景

4.1 登录流程的智能回归

登录是最常见也最适合验证AI Agent能力的场景。我给它下的指令通常是:

打开 https://demo.test-store.com/login ,先用 demo_user 和错误密码 P@ssw0rd_wrong 登录,确认页面出现密码错误提示;再用正确密码 P@ssw0rd 登录,确认跳转到用户中心,并截图给我。

执行过程中,AI会自己处理等待、弹窗、错误提示的位置。有一次页面加载慢,模型点击登录按钮后没有立刻看到提示,它调用了browser_wait等了两秒,然后再browser_snapshot。这种"耐心"写进传统脚本里就是一段硬编码的sleep,而在MCP模式下是模型根据当前状态主动选择的策略。

不过提醒一句:AI的密码猜测策略跟人不一样,它有时候会尝试从历史消息里推断密码格式。所以涉及登录测试时,指令里最好明确"不要猜测其他密码,只使用给定值",避免它真的触发账号锁定策略。

4.2 跨页面数据核验,这个场景比预想的能打

Web测试里有一类场景很麻烦:在A页面操作完,要去B页面验证数据是否一致。比如下单后去订单中心核验金额。传统脚本要维护跨页面的数据传递,变量、断言、顺序都得设计清楚。MCP模式下,模型天然理解上下文,它知道"下单页填的金额"和"订单列表里显示的金额"是同一个业务数据。

我跑过这样一个用例:

在结算页选择商品A和商品B,提交订单,然后去订单中心,找到刚刚生成的订单,核对明细里的商品数量和总金额是否匹配结算页的合计。

AI的执行路径大致是:导航到结算页、选择商品、读取合计金额、提交订单、进入订单中心、搜索最新订单、展开明细、对比金额。整个过程里它多次用快照和截图来确定当前位置,而不是盲目相信URL。这个场景跑下来的稳定性,比我想象中好得多。

4.3 让AI跑完流程后生成可复用的Playwright代码

除了直接让AI操作浏览器,还有一个更实用的模式:让AI在浏览器里把业务流程摸一遍,然后把操作过程生成一份结构化的Playwright脚本,回灌到代码仓库里。

指令示例:

请完整执行一遍从首页到结算页的购买流程。执行完后,基于你刚才的操作路径,生成一份可运行的Playwright测试脚本,使用data-testid作为首选定位方式,断言尽量完整。

AI生成的脚本质量我见过好有差。好的情况下,它给出的脚本长这样:

import { test, expect } from '@playwright/test'; test('登录后跳转到仪表盘', async ({ page }) => { await page.goto('https://demo.test-store.com/login'); await page.getByLabel('用户名').fill('demo_user'); await page.getByLabel('密码').fill('P@ssw0rd'); await page.getByRole('button', { name: '登录' }).click(); await expect(page).toHaveURL(/dashboard/); await expect(page.getByText('欢迎回来,demo_user')).toBeVisible(); });

这段代码的结构和断言逻辑都没问题,可以直接用。但我也收到过用模糊xpath当定位器、断言写得太弱的脚本,所以"AI生成代码"这个模式必须配一道人工review关卡,不能无脑合入。

两种模式各有适用场景,我的判断是这样:

模式优势风险最佳场景
AI直接执行测试无需维护代码,灵活适应页面变化执行路径不可复现,结果依赖模型发挥探索性测试、临时验证
AI生成脚本回灌仓库代码可版本化、可集成CI模型生成的代码质量波动稳定流程的基线用例建设

5. 跑了两个月之后:哪些场景让我眼前一亮,哪些地方现场翻车

5.1 惊喜时刻:AI做得比预期好的地方

先说几个让我意外的点。

第一,跨页面多步骤操作的真实感。AI在步骤之间会主动确认环境状态,比如登录后先看一眼是不是跳到了目标页,再继续下一步。传统脚本一旦选择器过期就会中断,而AI会用语义理解绕过页面结构变化,这类容错是传统自动化最羡慕的。

第二,对"页面状态"的判断能力。给它一个带筛选条件的后台列表页,它能自己识别"当前筛选条件是什么""列表是否为空""有没有加载失败提示",这些都是探索性测试里最花时间的部分。

第三,生成测试数据的思路。我让AI构造一份边界值测试数据,它结合自己浏览器的交互经验,主动建议了空字符串、超长字符串、特殊字符、数字边界等维度,最后还真的把每条数据都跑了一遍,输出了一张通过/失败的对照表。这已经不是"工具人"式的执行,更像一个知道该怎么测的初级测试工程师。

5.2 翻车现场:那些让人血压升高的瞬间

但AI Agent远没到"放心撒手"的程度,我记录了几个典型的翻车场景。

第一个是弹窗误判。购物车加购后进入结算页,页面弹出了一个优惠券提示框,下方有"去使用"和"继续结算"两个按钮。在可访问性树里,这两个按钮的语义差别不大,模型犹豫了半天,最后点了"去使用",直接跳到领券中心,流程全乱了。

第二个是下载行为引发连锁反应。AI执行一个下载报表的指令,点击下载按钮后,Chrome底部的下载栏弹了出来。模型不认识下载栏,以为页面出了问题,开始反复刷新当前页。后来我在配置文件里把浏览器下载行为改为自动保存到固定目录,并在指令里显式注明"下载完成后不要刷新页面"才解决。

第三个是"退出登录"误触。AI要清空筛选条件,页面上有"清空"和"退出登录"两个相邻按钮,模型定位错了,直接把登录态搞丢了,后续步骤全部失效。这种问题在语义相近、位置相邻的元素上屡屡出现。

我把这些翻车经验整理成了一份"约束卡",每次跑AI测试之前都附在指令里:

  • 明确任务边界,禁止触碰的按钮(如退出登录、删除、支付)直接列出;
  • 要求优先使用data-testid定位,文案仅作为辅助验证;
  • 遇到弹窗时,先截图并描述弹窗内容,再决定是否操作,不猜测;
  • 下载行为统一交给浏览器配置处理,AI不得自行判断下载栏;
  • 重要步骤执行后必须截图留痕,便于回查。

这份约束卡不是让AI"更聪明",而是把风险边界划清楚。AI的能力边界就在那里,你要做的是在它能力范围内用足它,在边界线上给它装上护栏。

5.3 关于稳定性,我的观察

不稳定是这个方案现阶段最大的短板。同一个指令,AI十次可能有八次走同一条路径,但剩下两次会换动作。这种随机性在探索性测试里是优点,但在需要严格复现的回归测试里就是风险。所以我的建议是,不要让AI Agent承担需要百分百确定性的回归任务,它更适合做"发现类"测试——跑一遍流程,找出异常、截图、报告,而不是负责给整个版本质量背书。

6. 从个人尝鲜到团队落地:值得保留的基础设施和几条铁律

6.1 让AI Agent在隔离环境里跑,这是第一条铁律

AI Agent在浏览器里是"自主行动"的,这意味着它可能点错按钮、填错数据、触发一些你不想触发的操作。我第一次跑真实环境的测试时,深深体会到了什么叫"手心冒汗"——它差一点就在生产环境里提交了一个真实订单。

从那次之后,我的所有AI测试任务都遵循几个硬性条件:只在测试环境跑,使用独立的用户数据,每次任务初始化干净的用户会话--user-data-dir。有条件的话,把整个服务端容器化,每个任务起一个独立的Chromium实例,跑完直接销毁。

6.2 保留传统断言基线,AI负责探索,代码负责兜底

这里我想澄清一个误区:AI Agent不是来替代Playwright脚本的。我现在的团队实践是两条腿走路,AI Agent负责探索性测试、挖掘异常场景、生成初版用例代码;传统Playwright脚本继续负责确定性的断言基线——凡是需要精确校验数值、严格验证返回状态的地方,仍然靠传统代码。CI流水线里,两类测试可以并行跑,AI Agent的发现类任务用allow_failure标记,只报告不阻塞,等它的历史稳定率达到一定水准再考虑转正。

6.3 可追踪性:没有日志的AI测试就是黑匣子

AI自主操作,最大的管理难点就是"它到底做了什么"。我的做法是:每个AI测试任务强制开启三段日志,浏览器操作日志、控制台和网络异常日志、每一步的截图记录。截图尤其重要,出问题的时候一张图能说明白的事,比一百行对话记录都直观。另外,每次任务结束时让AI提交一份简明报告,包含执行路径、关键动作、疑似风险点。这个过程一开始会很繁琐,但坚持下来,你会攒下一批"AI测试行为样本",对持续优化约束卡非常有价值。

6.4 给团队设立几条不可逾越的红线

经验下来,我总结了几条项目落地的红线:

红线原因
禁止AI点击支付、删除、提交生产订单等不可逆操作一旦误操作,后果不可挽回;尽量在测试环境还原场景
必须使用测试环境,数据可随时重置隔离风险,保证AI操作不污染真实数据
每个AI生成的测试代码合入前必须人工审核生成代码质量波动大,缺陷代码合入仓库会带偏后续行为
每次任务保留完整日志与截图可回查,可复盘,是后续优化的依据

6.5 MCP生态接下来会波及的方向

写这篇文章的时候,我的一个直觉是:MCP这套"服务端暴露工具、AI统一调用"的模式,会很快渗透到测试工程的其他角落。移动端测试已经有团队在尝试给Appium、Maestro做MCP服务端,桌面应用自动化、API测试也在出现类似封装。这意味着未来测试工程师的核心技能,可能不再是背诵某个框架的API,而是学会定义"AI能调用什么工具、不能调用什么工具"。今天在Playwright上积累的这套实践,本质上是在为那个方向做准备。

跑了两个月,我最深的感受就是:别把AI Agent当成全能测试员,它更像一个熟悉业务、学得快但偶尔毛躁的新同事。给它清晰的目标、受限的权限、能看的日志,它能在你顾不上做探索性测试的时候替你跑一遍流程;但你要是把生产环境、支付入口、删除按钮都敞开着丢给它,翻车只是时间问题。我现在的工作流已经稳定下来:AI Agent负责探索和脚本生成,传统Playwright负责断言基线,中间夹一道人工审核。我最近已经开始在移动端Web和混合应用上试同样的模式,等跑出一批数据再回来补充。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询