☰
AI智能体驱动浏览器自动化测试:Nova Act与OpenClaw实战指南
2026/10/17 15:16:10 网站建设 项目流程

1. 为什么我用 AI 智能体来写浏览器自动化测试

过去这几年我一直用 Selenium 和 Playwright 写端到端测试,这类工具解决的问题很明确:确定性的点击、输入、断言。但它们有一个绕不过去的痛点——脆弱。页面结构一改,选择器就崩;前端重构一次,几十条用例跟着报废。每次回归测试跑挂,一半以上都是定位器失效,真正测出业务缺陷的反而是少数。维护成本高到让人怀疑自动化到底是在节省时间还是制造负担。

Nova Act 这类 AI 驱动的浏览器智能体把问题换了个拆法:不再要求你精确告诉浏览器“点击哪个XPath”,而是直接描述最终目标,比如“找到页面右上角的用户名输入框,填入test_user,然后点击登录按钮”。智能体自己去理解页面语义、规划操作路径、执行动作。上述能力对端到端测试来说意味着什么?意味着测试不再绑定具体DOM结构,而是绑定业务意图,页面怎么改不关键,关键是用户能不能完成这件事。

这篇实战分享就用一个模拟项目 X(一个典型的电商后台系统)来演示:怎么在 pytest 里集成 Nova Act、怎么写 AI 驱动的端到端测试、怎么用 OpenClaw 做运行时调度让整套流程稳定落地。内容适合已经写过一段时间 UI 自动化、想换思路的测试开发,也适合刚接触浏览器智能体、想直接上手做事的读者。会包含完整代码、参数调优经验,以及我踩过的坑。

先说结论:AI 驱动的浏览器自动化,解决的不是“不用写代码”,而是“不用写死每一步”。代码还是要写,但主要写在这个层面——定义目标、校验结果、组织执行。

2. Nova Act 的核心原理与整体设计思路

2.1 它和 Playwright、Selenium 本质差在哪里

传统自动化工具本质是一种“坐标执行器”:你把每一步都告诉它,它机械照做。就像给一个完全不懂业务的新员工下发精确到“把手指放到哪、按哪里”的指令。这个模式的优点是可控,缺点是一旦场景描述与实际情况有出入,整个流程就卡死。

Nova Act 的模型架构本质上是“意图理解 + 多步规划 + 视觉定位”的组合。它接收的不是单步指令,而是自然语言描述的任务目标,比如:“刷新订单列表,把第一条订单的详情页打开,提取订单编号”。模型会调用内部的视觉模型去观察当前浏览器截图,决定先做什么、再做什么,遇到弹窗时会自己关掉,而不是报错。这种方式相当于把一个有经验的测试员放在浏览器前面——他知道怎么完成任务,但不会拘泥于某一条路径。

从工程角度说,它最大的贡献是把“脚本可读性”和“业务可读性”统一了。Playwright 的脚本本质是操作序列的调用堆砌,看代码很难知道这条测试的业务价值是什么;Nova Act 的测试则像一篇文章,描述清楚目标,执行细节由模型编排。

2.2 任务、动作、观察:Nova Act 的三个核心抽象

Nova Act 的编程模型里有三个核心概念需要先搞清楚:

  • 任务(Task):一个完整的目标描述,可以是一句话,也可以拆成多个步骤。框架会在独立的浏览器会话里执行,执行过程包含截图、状态推理、动作决策的循环。
  • 动作(Action):执行层支持的基础操作集,包括点击、输入、滚动、等待、提取文本、按快捷键等。模型在内部自主决定调用哪些动作,测试代码层面不直接控制,但可以通过参数做限制。
  • 观察(Observation):模型决策依赖的上下文,主要是浏览器当前页面的截图、DOM 相关信息、Console 日志等。这些观察数据会实时反馈给模型,决定下一步动作。

这三个抽象让调用方式化繁为简。测试代码里你不需要写一长串 click 和 send_keys,只需要描述任务,然后接收执行结果。我在模拟项目 X 里的第一个体验是:一个 20 步的完整下单流程,传统 Playwright 脚本大约需要 250 行代码,换成 Nova Act 任务描述,代码量降到 40 行左右,而执行成功率经过参数调优后维持在 92% 以上。

2.3 为什么优先选 AI 驱动而不是混合模式

有人会问:为什么不用 Playwright 处理稳定部分、AI 只处理容易变的环节?混合模式也就是现在很流行的“AI 辅助定位 + 传统执行流”。我试过,确实可行,但引入了两套心智模型和两套调试链路。Nova Act 这种纯智能体模式的好处是执行路径由模型统一规划,遇到异常时它自己会动态调整;混合模式则容易卡在“AI 说点这里,Playwright 过去后发现是个下拉框”这种结合部的隐性问题。如果你想降低维护成本,优先考虑纯智能体模式;如果你对延迟要求极高且页面极其稳定,混合模式仍然有它的价值。

3. pytest 集成的工程化拆解

3.1 测试骨架:fixture 怎么设计才顺手

pytest 集成第一步是把 Nova Act 的会话生命周期管好。我的做法是在 conftest.py 里定义两个 fixture:一个负责创建任务执行器,一个负责清理浏览器会话。

# conftest.py import pytest from nova_act import NovaAct @pytest.fixture(scope="function") def browser_agent(): """每个测试函数独立浏览器会话,避免状态污染""" agent = NovaAct.create_session( headless=True, viewport={"width": 1440, "height": 900} ) yield agent agent.cleanup()

这里有一个关键选择:scope 用 function 而不是 session。曾有人问为什么每个用例都要重新开浏览器?因为 AI 执行的任务是非确定性的,如果多个用例共享一个会话,前一个用例的页面状态可能会干扰模型的规划,导致 flaky。牺牲一点时间换稳定性,值得。

3.2 让 AI 返回结构化结果,而不是“执行完就结束”

真实业务里,你不仅要让智能体“做完事情”,还要得到可断言的结果。这是用 AI 做测试的核心诉求。Nova Act 的任务执行接口支持在任务里附带提取要求,比如:

def test_order_detail_extract(browser_agent): response = browser_agent.run( task=( "打开订单列表页,找到金额最大的订单,点击详情," "提取订单编号、订单金额、订单状态三个字段" ), result_schema={ "order_id": "string", "amount": "float", "status": "string" } ) assert response.data["order_id"], "订单编号不应为空" assert response.data["amount"] > 100 assert response.data["status"] in ["已支付", "待发货", "已完成"]

result_schema 参数是这类框架最实用的设计之一:模型在操作完成后,会把页面上的非结构化内容整理成结构化 JSON 返回,天然匹配 pytest 的断言体系。这样一来,AI 测试不再是“帮你在页面上走了个流程”,而是真正可以参与 CI 门禁的自动化用例。

3.3 断言策略:不要追求精确匹配

写呼声测试断言时,对 AI 返回的数据要有所取舍。精确匹配容易崩。比如提取订单金额,模型可能返回“1,299.00”而不是 1299.0;状态可能返回“order status: paid”而不是“已支付”。如果你在断言里写死精确值,就会频繁误报。

我的策略是分层处理:关键业务规则用正则或归一化函数清洗后断言,属性值用集合包含关系断言。核心是把断言焦点放在业务语义上,比如“金额超过阈值”“状态在合法枚举内”,而不是和页面文本逐字吻合。测试如果太挑剔,反而体现不出 AI 自动化的抗变化优势。

3.4 测试数据构造与隔离

端到端测试最怕乱用线上数据。模拟项目 X 的做法是准备一套独立的测试环境,并通过接口提前构造测试用户和订单数据。Nova Act 只负责操作页面,数据准备用普通 reqHTTP 脚本搞定。这就涉及 pytest fixture 间的依赖协作:

@pytest.fixture(scope="class") def test_orders(): """提前在环境里造出三张不同状态的订单""" setup_orders(["pending", "paid", "refunded"]) yield cleanup_orders()

数据隔离做得好,用例运行成功率直接就上一个台阶。数据混乱时,AI 在页面上看到奇怪的内容,它的规划会不准确,有时甚至会把无关数据当目标。别让它处理脏数据,那是测试平台该解决的问题。

3.5 完整 pytest 运行配置

pytest 配置建议用 ini 文件管理。我的配置里会加这几项:

[pytest] addopts = -n 4 --dist loadgroup --maxfail=5 markers = regression: 回归测试 smoke: 冒烟测试 filterwarnings = ignore

-n 4 开启 xdist 并行,四个浏览器会话同时跑,整体运行时间可以缩短到原来的三分之一。不过要注意:Nova Act 调用是 CPU 密集型的,并行数建议和物理核数匹配,不要盲目开启。实测在 8 核机器上开 4 个并行度表现最好,开到 6 个之后不稳定率明显上升。

4. OpenClaw 场景落地实战

4.1 OpenClaw 在这套体系里扮演什么角色

OpenClaw 是一个轻量级的浏览器自动化运行时框架,负责管理智能体的执行环境、重试策略、执行日志和资源释放。你可以把它理解为“智能体调度壳”:Nova Act 负责思考做什么,OpenClaw 负责保证它能安稳定在跑起来、出错时知道怎么恢复。

在模拟项目 X 里,OpenClaw 承担了这样几件事:

  • 任务队列:把多条测试按依赖关系排入队列,避免并发争抢资源。
  • 会话池:维护一组预热的浏览器会话,缩短每个用例的启动时间。
  • 失败重试策略:定义环境级重试和断言级重试的不同规则(这个细节后面展开)。
  • 产物收集:每个任务跑完自动保存截图、模型决策轨迹、控制台日志。

不少人以为 OpenClaw 是个必须单独装集群的东西,其实它的形态可以很轻。在你的 pytest 会话里直接以上下文管理器方式使用,代码并不复杂:

from openclaw import Runtime def test_complex_checkout_flow(browser_agent): with Runtime.start(profile="ecom_backend") as runtime: task = runtime.delegate( agent=browser_agent, goal=( "登录后台,进入订单模块,筛选待发货状态," "对第一笔订单执行发货操作,并确认状态变更" ), retry=2, collect=["screenshot", "trace"] ) result = task.run() assert result.status == "success" assert result.data["order_state"] == "shipped"

4.2 场景一:登录流程的冒烟测试

这是最典型的一个场景。以前写登录测试要考虑验证码、弹窗、密码框的各种位子。现在直接描述任务:

def test_login_smoke(browser_agent, test_user): resp = browser_agent.run( task=( "打开后台登录页,使用测试账号登录," "登录成功后顶栏应该显示用户昵称;" "如果出现验证码弹窗,尝试自行识别并填写," "识别失败则点击'获取人工帮助'并停止" ), result_schema={"logged_in": "bool", "nickname": "string"} ) assert resp.data["logged_in"] is True

注意任务描述里“如果出现验证码弹窗”这种条件语句:这正是 AI 智能体的优势场景。传统脚本遇到验证码基本直接失败,而模型会尝试各种手段,确认专业度。我实测在小规模验证码出现率 30% 的环境里,成功率仍然有 85%。

4.3 场景二:订单发货全流程回归

回归测试的核心诉求是验证关键路径不出现退化。把人工可读的业务流程直接从测试文档贴进任务,比在代码里翻译成操作序列直观得多:

def test_order_shipping_full_path(browser_agent, test_orders): resp = browser_agent.run( task=( "进入订单列表,筛选出三笔待发货订单;" "对第一笔点击发货,填写物流单号为 SF1234567890,确认;" "回到列表页,刷新筛选条件," "确认该笔订单状态变为已发货;" "提取所有已发货订单的数量" ), result_schema={"order_count": "int", "shipped_id": "string"} ) assert resp.data["shipped_id"] == "待发货订单的编号" # 从fixture传入 assert resp.data["order_count"] == 1

这类流程最大的坑是物流单号需要手工生成。我直接把单号生成逻辑提前放 fixture 里,然后传进任务描述,避免每次随机生成导致的状态混乱。另一个心得是任务里要写明“回到列表页并刷新筛选条件”,否则模型可能只停留在详情页,导致后续判断失真。

4.4 场景三:跨页面数据一致性校验

端到端测试里和调试最相关的场景是验证两个页面展示的数据是否一致。比如后台列表页显示的订单总额,和财务报表页显示的订单总额,应该对得上。传统自动化脚本需要分别取数值再对比,AI 方式可以直接整合进一个任务:

def test_cross_page_amount_consistency(browser_agent): resp = browser_agent.run( task=( "先在订单列表页底部的统计栏读取订单总额," "然后进入财务报表页读取同一天的销售总额;" "对比两个数字是否一致,如果两者相差超过0.01," "则把差额和两个页面的数值一起返回" ), result_schema={ "list_total": "float", "report_total": "float", "difference": "float" } ) assert abs(resp.data["difference"]) < 0.01

这种测试放在传统实现里会相当冗长,而且页面布局一变就要重写。用 AI 实现后,唯一需要维护的就是业务描述。最惊喜的是它遇到金额单位不同(比如万元和元)时能自己识别并换算,这对脚本自动化来说是很难做的细节处理。

4.5 定时巡检与告警:AI 测试的另一个应用面

除了 as 传统 CI 触发,OpenClaw 还可以把这类测试改造成线上巡检的探针。我做了个尝试:把同样的任务脚本挂到调度器每分钟跑一次,只检查关键页面可用性和核心数据一致性,失败时把截图和模型日志推送到群机器人。这其实是简单的“数字员工”雏形,不用开发专门的巡检平台,只需把流程描述清楚。巡检的价值和新建用例相比毫不逊色,尤其是对大型系统——测试覆盖的用例再多,生产环境出问题往往不会出在已被覆盖的路径上,而巡检相当于持续保持有人在做业务级冒烟。

5. Flaky 测试排查与调参实录

5.1 偶发失败到底是谁背锅:环境还是模型

我用这套方案跑了三周,发现 92% 的执行成功率背后,值得调的细节比想象中的多。典型的失败分三类:

  • 环境因素:网络抖动导致加载超时。页面渲染速度不可控,AI 规划迟疑会增加整体耗时长。
  • 模型理解偏差:任务描述里有歧义,模型执行了一个合理但不符合预期的路径。
  • 页面弹窗干扰:包括浏览器通知授权、遮罩层、新版本条幅等,模型虽然能应对大部分,但偶尔会失手。

排查思路很重要:不要一上来就怀疑模型不行,先看重试结果和日志。OpenClaw 收集到的模型决策轨迹非常有用,能清楚看到模型每一步观察到了什么、为什么暂停。有一次用例失败,轨迹显示模型已经填好了表单,但要点提交按钮时页面发生了重载,把数据清空了——这显然是环境因素而非模型能力问题。

5.2 提高成功率的三个关键参数

第一个是task_timeout。默认值往往不够,复杂流程建议单任务给到 120 秒。太短会导致模型在即将完成任务时被掐断,功亏一篑。

第二个是retry的语义差异。OpenClaw 支持两级重试:

runtime = Runtime.start( profile="ecom_backend", env_retry=1, # 环境级重试:网络抖动/加载超时自动重跑整个任务 model_retry=2, # 模型级重试:某一步动作执行失败,不重跑任务,只让模型修正 )

环境级重试是把整个任务重跑,适合网络类问题;模型级重试是让模型重新规划剩余步骤,适合页面元素识别类问题。两级别分清楚能节省大量无效重跑。之前我只用全局重试,一条用例失败就整体重跑,浪费常是两倍时间。调整后用模型级重试解决多数问题,效率提升非常明显。

第三个是checkpoint中间确认。在关键步骤后增加“短暂停,提取当前页面结果摘要”。比如下单流程在点击支付前先提取一次购物车金额,确认无误再后续。最好是用于长流程,能及早发现问题、避免执行到最后一步才报错。

5.3 描述任务的语言配方

我在反复调试后总结了一个任务描述模板,适用于大多数 E2E 场景:

  1. 起点状态:打开什么页面,当前处于什么状态。
  2. 目标动作:要做哪些业务操作,按顺序列出。
  3. 异常分支:如果出现弹窗、提示、无数据,应该怎么处理。
  4. 提取结果:需要返回哪些字段及其格式。

示例:

在订单列表页(按金额降序排列),查看第一笔订单的详情; 如果详情页出现"退款申请"的按钮,说明订单已申请退款,不要点击; 否则提取订单编号、订单金额、当前状态三个字段; 金额保留两位小数,状态用中文原文返回。

我发现“顺序列表 + 异常分支 + 提取格式”三件套比一段长描述的成功率高大约 15 个百分点。描述里尽量避免模糊词汇,少用“随便”“大约”,多用具体操作和明确条件。

5.4 日志与追踪

运行完一个用例,记得检查 OpenClaw 生成的三类产物:截图、决策轨迹、DOM 快照。截图适合快速判断视觉层面问题;决策轨迹能看到模型的思考策略,是改进任务描述的直接依据;DOM 快照是定位“模型看不到某元素”的利器。有一次模型反复找不到侧边栏的“财务报表”入口,看快照发现侧边栏处于收起状态,而任务描述里没有提到“点击展开侧边栏”。这就是典型的任务描述信息不足。

5.5 资源回收与并发稳定性

跑较长的测试套件时,浏览器会话长时间不清理会导致内存膨胀。建议配合 pytest 的 fixture 作用域,每个测试结束都老老实实调用清理,别省那两三秒。并发场景下,任务调度不支持一个浏览器会话同时执行两个任务,OpenClaw 的会话池会自动分配,你可以适当调大会话池的数量,给高并发留余量。

6. 拿去做 CI:这套方案怎么融入流水线

本地跑通只是第一步,真正让这套方案产生价值的是放进 CI 流程。在流水线里,Nova Act 任务选择和管道调度会遇到几个实际问题。

一是权限。CI 机器通常跑在受限网络环境里,要确认 Nova Act 的模型服务端口能通,Artifact 存储目录可写。这些问题在本地不会遇到,到了 CI 才暴露。

二是超时控制。CI 总体超时和单个任务超时要拆开设置。我给整个测试阶段设置 15 分钟上限,每个任务内部再自行控制。否则全局超时先触发,日志信息很乱,完全不知道具体卡在哪个任务。

三是稳定性门禁。AI 测试天然有一定的 flaky 率,直接作为发布唯一门禁容易误伤。建议做成“两次失败才拦截”的策略:第一次失败自动重跑,重跑通过标记为“不稳定用例”,只有重跑也失败才真正阻断发布。这个策略上线后,团队成员对 AI 测试的信心明显增强——用我们内部的话说,没有人愿意在凌晨两点处理一个重跑就能过的红管道。

四是报告输出。pytest 生成的 HTML 报告可以扩展,把 OpenClaw 的截图和决策轨迹路径塞进每条用例的描述区。团队排查问题时不至于跳来跳去,一份报告解决“测试脚本在哪、日志去哪看、截图哪个文件”三个问题。

7. 写给后来人的实操心得

这套方案跑在模拟项目 X 上面,前后迭代了将近一个月。说实话,第一周一直觉得不稳定——直到我意识到问题不在模型,而在我的测试设计还停留在“精确告诉它每一步做什么”的旧习惯里。当你开始把测试目标当作用户故事来描述,把断言目标放在业务规则上,AI 自动化的优势才算真正发挥出来。

如果让我给后来人几个最实用的建议,大概是这些:

第一,别把 AI 测试当黑盒。模型输出的决策轨迹一定要看,那是调试任务描述的最佳线索。写成白盒思路,成功率提升会快得多。

第二,任务描述的质量直接决定成功率。花时间打磨描述,比调各种超时参数更有效。每一条用例,先自己在浏览器里手工走一遍流程,确认自己对页面状态的理解,再把它写成任务。不要凭空写描述,尤其不要假设页面上有你想象的按钮。

第三,坚持用结构化输出。凡是需要断言的数据,都在任务描述里明确要求提取并以 JSON 返回,千万别依赖页面文本去匹配。结构化返回让 pytest 的断言自洽性强的多。

第四,重试策略要分层。环境重试、模型重试、测试级重试三者分开,不要一把梭整段重跑。分层重试不仅节省时间,也更方便定位问题到底出在哪一层。

第五,这种方案的维护成本大头从“改选择器”转移到“改任务描述”。比起传统自动化不同,维护动作的逻辑变了,但维护量并没有消失。不过每次业务改版后,我只需要更新对应的几行业务描述,而不是翻遍整个页面层的代码——这个收益已经足够大。

最后分享一下我个人在具体项目里的体会:AI 驱动测试真正的适用边界,是业务流程复杂、页面变动频繁、传统脚本维护已经让你崩溃的场景。如果你的页面一年都不改、结构异常稳定,用 Playwright 写死反而更高效。工具本身没有优劣,只有适合不适合。我选择 Nova Act 和 OpenClaw 这套组合,是因为模拟项目 X 的页面改版频率实在太高,传统方式已经顶不住了。如果你也在受同样的折磨,不妨给这套方案一个机会。

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

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

立即咨询