这是一篇试错手记。不是教你怎么做对,而是带你看看我是怎么一步步做"错"的------以及这些弯路最终怎么帮我找到了方向。
开篇:那个"开盲盒"项目的真相
如果你看过这个系列的第一篇,可能还记得我提到过一段"开盲盒"的经历------兴奋地打开 AI 编程工具,让它帮我实现功能,结果来来回回改了好几轮,感觉像在开盲盒。
那个项目,就是我正在探索的 AI 驱动 UI 自动化。
说起 UI 自动化,我并不陌生。之前我做过纯手写脚本的 UI 自动化------用 Selenium、Playwright 一行行写定位器、写操作步骤、写断言。能跑,但维护成本高,页面一改脚本就废。这是传统 UI 自动化的老问题了,做过的人都懂。
所以当 AI 浪潮来的时候,我最好奇的问题是:大模型能把 UI 自动化做到什么程度? 能不能跳过那些脆弱的定位器,直接用自然语言告诉 AI"点这里、填那里"?
带着这个问题,我开始了探索。方向是领导给的------他推荐了一个工具叫 Midscene.js。彼时的我,没有任何 AI 项目经验。
回头看,这既是优势(没有包袱,敢试),也是劣势(没有认知框架,容易走弯路)。
后来的事实证明,弯路我一条都没少走。
一、第一站:Midscene.js ------ 能跑,但只是个玩具
Midscene.js 做的事情很直观:你输入一段自然语言描述的业务操作,比如"进入首页,查询某个设备的状态",它调用大模型分析你的输入,生成一个执行计划(plan),然后一步步在浏览器里执行。
听起来很美好对吧?我当时也这么觉得。
基于 Midscene.js,我搭出了第一个 demo,接入了实际项目。输入一段业务流描述,它确实能在页面上点击、输入、跳转。在这个赛道上,Midscene 做得不错,完成度挺高。
但用了一段时间后,我的结论是:能用,但不能真正提效。
问题出在几个地方。
1.1 无法深入业务
如果一个功能藏得比较深------比如要先打开某个下拉菜单、再切换一个 Tab、再点击某个不起眼的按钮------就算你的自然语言描述非常到位,它也很难保证每一步都精准点对位置。页面越复杂,出错概率越高。
1.2 执行链路脆弱
它的工作流程是:
用户输入自然语言
→ 调用 LLM API 分析语义
→ 生成 plan(步骤列表)
→ 逐步定位元素并执行操作
这个链路中间只要有一步出错------比如某个元素没找到、页面加载慢了------它大概率就直接中断了。不会自己绕过,不会自动重试,只会停在那里。对于探索性的一次性试用可以接受,但对于想要稳定跑起来的自动化流程,这个鲁棒性远远不够。
1.3 Token 成本可感知
每次执行都要调用大模型做语义分析和 plan 生成。粗略估计,一条中等复杂度的业务流(5-8 步操作)单次执行大约消耗 2k-4k tokens。如果要跑一轮覆盖十几个核心流程的冒烟验证,token 消耗已经很可观了------而且这还没算执行中出错重试的额外消耗。
对比传统脚本执行的零边际成本,这个差距在高频场景下会被放大。
用了一阵之后,我甚至产生了一个想法:与其费这个劲集成到项目里,不如直接用 Midscene 的 Chrome 插件在页面上做分析算了------至少那个即开即用,不需要我搭一套工程。
那一刻我开始认真想一个问题:我做这个项目,到底是为了什么?
二、停下来想:我到底需要什么?
Midscene 的经历给了我一个教训:不要拿到一个工具就开始做,先想清楚你要解决的到底是什么问题。
这跟我在第一篇文章里总结的认知一脉相承------AI 不怕你不会写代码,怕的是你不知道自己要什么。UI 自动化也一样,工具不是问题,问题是你要用它做什么场景、解决什么痛点。
冷静下来之后,我把 UI 自动化的使用场景分成了两类:
一类是一次性测试。 比如某个版本上线前做一次全量回归,或者临时验证一个跨浏览器的兼容性问题。这种场景用完即走,不需要长期维护。坦白说,这类场景现有的 AI 工具已经做得很好了。像 OpenAI 的 Codex、各种 AI 浏览器操作助手,它们的浏览器操作能力已经非常强。在这个方向上自研,很难做出差异化,投入产出比不高。
另一类是长期的项目维护。 需要持续运行、持续维护、跟业务深度绑定的自动化能力。这才是自研真正有价值的地方------因为没有任何通用工具能替你理解你的业务。
而长期维护这条线,我又进一步拆成了两个方向:
css
长期项目维护
├── 方向 A:深度绑定业务的脚本生成
│ 核心:构建业务知识库,让 AI 理解你的具体业务
│ 价值:生成精准的、可复用的自动化脚本
│
└── 方向 B:通用化巡检
核心:不依赖特定业务,对任意项目做通用 UI 检查
价值:覆盖面广,一套脚本跑多个项目
想清楚这个分类之后,我排除了一次性场景,把精力聚焦在这两个长期方向上。
接下来的几个月,我在这两个方向上分别深入探索------也分别踩了不少坑。
三、方向 A:深度绑定业务 ------ 知识库的三次进化
要让 AI 深度绑定业务,第一件事是什么?
给它知识。
这是毋庸置疑的。AI 再强大,它也不知道你的系统里"设备管理"页面长什么样、"工单流程"要走几步、"抄表数据"的校验规则是什么。如果不把这些业务知识喂给它,它就只能做最表面的操作------跟 Midscene 没什么区别。
所以我的第一个重心就落在了知识库上。
3.1 第一版:MySQL 精确匹配
我对 MySQL 最熟悉,自然而然地选择了它来存储业务知识。
思路很直接:把页面名称、操作路径、关键元素都存进表里,用户输入一段描述,我去数据库里用 WHERE page_name = '首页' 精确匹配对应的业务流程。
搭了一段时间之后,我发现了一个致命的问题。
自然语言天生是模糊的,而 SQL 查询是精确的。
举个例子:同一个页面,用户可能叫它"首页",也可能叫它"看板",还可能叫它"数据总览"。如果数据库里存的是"首页",那输入"看板"就匹配不上了。
怎么办?把所有可能的别名都录进去?那每个页面要录多少个?而且业务在变、叫法在变,维护成本会越来越高。
或者要求用户输入得非常精确、严格按照预设的格式来?那问题又来了------如果输入要求这么严格,梳理和录入的工作量不亚于直接写自动化脚本了。 这就违背了用自然语言降低门槛的初衷。
MySQL 这条路,走不通。
3.2 第二版:PostgreSQL + pgvector 语义匹配
经过一段时间的调研,我发现了向量数据库。PostgreSQL 的 pgvector 扩展可以把文本通过 Embedding 模型转成向量,然后用余弦相似度做语义级别的模糊匹配。"首页"和"看板"虽然字面不同,但在向量空间中语义相近,是能关联上的。
sql
-- 向量相似度查询示意
SELECT page_name, 1 - (embedding <=> query_embedding) AS similarity
FROM page_knowledge
ORDER BY embedding <=> query_embedding
LIMIT 5;
这看起来是解药。
但用了之后发现,它引入了新的问题:每次查询都要先调用 Embedding 模型做向量化,再做向量检索,链路变长了。 而且业务流程的结构化数据(操作步骤、元素定位、前置条件等)存在向量库里,查询和管理都不如关系型数据库方便。
向量库解决了语义模糊的问题,但不能全盘替代关系型数据库的结构化存储能力。它更适合做"理解",不适合做"存储"。
3.3 第三版:混合架构 ------ 模糊输入,精确输出
两版踩坑之后,答案其实已经浮现了:让向量库和 MySQL 各做各擅长的事。
前半段交给向量库 + 大模型:理解用户的模糊输入,将自然语言转义为系统中标准化的业务术语或唯一 ID。
后半段交给 MySQL:拿着精确的术语/ID,去查询预先存储好的完整业务流程------包括操作步骤、页面路径、元素定位、断言条件等结构化数据。
这样的好处是两全其美------既满足了自然语言输入的模糊性(用户爱怎么说就怎么说),也保证了最终输出的业务流程是准确的、可执行的。
对于一些特别重要的核心流程,还可以进一步抽象成 Agent 的 Skill------预定义好操作序列和异常处理逻辑,连 AI 生成的不确定性都跳过了,直接稳定执行。
css
# Skill 示意:核心流程的稳定封装
skill: "创建工单"
steps:
- navigate: "/workorder/create"
- fill: { selector: "#title", value: "${input.title}" }
- fill: { selector: "#description", value: "${input.desc}" }
- click: "#submit-btn"
- assert: { text: "创建成功" }
on_error: retry(max=2) → screenshot → abort
3.4 配套验证:Demo 矩阵
光有方案思路不够,我需要验证每个环节到底走不走得通。所以围绕这个方向,我做了一系列 demo 来逐一验证:
| Demo | 验证目标 | 结论 |
|---|---|---|
| 语义落库 | AI 能否正确捕捉业务语义并存入向量库 | ✅ 流程走通 |
| 语义匹配 | 模糊输入能否准确匹配到正确的业务流 | ✅ 匹配准确率可接受 |
| 爬虫初始化知识库 | 自动采集页面信息,替代人工录入 | ✅ 可行,但需要处理动态渲染 |
| DIFY 框架集成 | 作为 AI 中枢,串联语义理解 → 知识库 → 脚本生成 | ✅ 架构可行,一笔带过,下篇详说 |
每个 demo 都走通了单点验证。但真正把它们整合成一个完整的系统------那是另一个故事了,我会在下篇详细展开。
这里值得一提的是那个爬虫 demo。原本它只是为了解决知识库初始化的问题------总不能让人一条条手动录入页面信息吧,一是不可靠,二是太繁复。所以我写了爬虫脚本来自动遍历页面、采集信息。
但做着做着我意识到:这个"自动遍历页面"的能力本身,不就是通用化巡检的雏形吗?
这直接启发了我的第二个探索方向。
四、方向 B:通用化巡检 ------ 从野心到边界
在做知识库爬虫的过程中,一个想法自然而然地冒出来:既然能自动遍历页面来采集信息,那能不能更进一步,让 AI 一边遍历、一边做 UI 检查?
这就是通用化巡检的起点。
4.1 为什么我特别看好这个方向
我们公司有大量的项目,而且本地化定制特别多。如果每个项目都要单独做自动化适配,人力投入巨大。很多排期紧张的项目根本没时间做这种沉淀------功能都来不及测,谁还顾得上写自动化?
所以我一直觉得,通用化的脚本价值远高于定制化的脚本。 如果能做出一套不依赖特定业务知识、对任意项目都能跑的通用巡检工具,那它的覆盖面和复用价值是巨大的。
带着这个愿景,我信心满满地开始了。
4.2 第一版:暴力全扫
思路很简单粗暴:像爬虫一样,打开一个页面,找到所有可点击的元素,逐一点击,每点一个就截图,然后让 AI 审计截图------看看页面有没有报错、布局有没有崩、文字有没有异常。
想法很美好------不就是模拟人手工一个个点过去吗?AI 要做的只是"看一眼"截图。
但远没有那么简单。
最先碰到的问题是无限循环。页面之间会来回跳转------A 页面有个链接到 B,B 页面又有个链接回 A。如果不加限制,脚本会在这些页面之间无限打转。
4.3 第二版:深度限制 + 去重
解法很直接:给页面探索加一个深度限制。
python
# 核心探索逻辑(简化示意)
def explore(page, current_depth, max_depth=3):
if current_depth > max_depth:
return
if page.url in visited:
return
visited.add(page.url)
screenshot(page) # 截图供 AI 审计
for element in find_interactive_elements(page):
element.click()
explore(page, current_depth + 1, max_depth)
page.go_back()
设了 max_depth = 3(三层深度),基本解决了无限循环的问题。但紧接着来了第二个问题:大量重复截图。
实际跑下来的数据很直观:一次巡检下来可能采集 200+ 张截图,但其中超过 40% 是重复或无效的 ------点击前后页面内容完全一致。为什么?很多被判定为"可交互"的元素,点击之后页面根本没有任何变化------可能只是一个没有绑定事件的 <div>,或者触发的变化在视觉上不可见(比如某个隐藏字段的值变了)。
但如果要做全量探索,又不能跳过这些元素------万一某个"看似没反应"的元素确实能触发什么呢?
探索深度怎么设?截图怎么去重?页面探索的遍历逻辑怎么优化?......类似的问题不断冒出来。一开始的设想很美好,做出来的东西很现实。
4.4 转机:多语言校验场景
项目一度停滞,直到公司的一个真实痛点把它重新拉回了视野。
我们有不少多语言项目,多语言的 UI 和文字校验一直是个头疼的事情。人工怎么做这个事的?就是一步步点进每个页面,一个个对比中英文有没有缺失、有没有显示异常、有没有溢出。
等等------这不就是我的通用巡检在做的事情吗?自动遍历页面、逐页截图、AI 来审计截图内容。只不过审计的重点从"页面有没有崩"变成了"多语言有没有问题"。
这个真实场景让我重新捡起了通用巡检,但这次我学聪明了------不再追求万能,而是主动设定边界。
4.5 承认边界
- 不点:删除、修改等非安全性操作按钮------通用巡检不应该产生副作用
- 不覆盖:非常隐蔽的深层业务场景------那是深度定制方向(方向 A)该做的事
- 能保证:表面可见的、约 90% 的页面和功能覆盖
另外,针对一些技术架构比较特殊的项目------比如微前端(子应用路由独立管理)、token 化路由(URL 中带动态 token,无法直接复用)------我做了薄薄一层 adapter 适配,让巡检脚本能兼容不同的技术栈。
具体的实现细节和未来的探索方向,我会在下篇单独详细讲解。
五、阶段性总结:踩完这些坑,我学到了什么
回顾两个多月的探索,从 Midscene 开始,到知识库三次进化,到通用巡检从暴力全扫收敛到多语言校验------弯路走了不少,但每一步都不是白费的。
几个关键认知:
1. 先想清楚场景,再决定做不做。 一次性测试场景不值得自研,现有 AI 工具已经够好了。长期项目维护,才是自研的真正价值所在。
2. 能用 ≠ 能提效。 Midscene 教给我的第一课。一个工具 demo 跑通了不代表它能在实际工作中提效。"能不能跑"和"值不值得用"之间,隔着一道叫做"实际场景"的鸿沟。
3. 自然语言的模糊性是核心难题。 知识库的三次进化------从 MySQL 精确匹配到 pgvector 语义匹配再到混合方案------都围绕着同一个问题:怎么让机器理解人类不精确的表达。这个问题在 UI 自动化领域尤其突出,因为人对界面的描述天然是模糊的。
4. 承认边界比追求万能更重要。 通用巡检从"全页面暴力扫描"收敛到"表面 90% 覆盖 + 多语言校验",看起来是在缩小范围,实际上是在找到它真正能落地的位置。一个能稳定覆盖 90% 的工具,比一个理论上能覆盖 100% 但实际跑不起来的工具有价值得多。
5. 每个 demo 都有价值。 即使最终的方案不是最初的设想,试错过程中积累的认知和组件------知识库方案、爬虫能力、语义匹配流程------这些都会在后面派上用场。做知识库爬虫时启发了通用巡检,就是最好的例子。
结尾:坑踩完了,方向清楚了
这篇文章写的全是"怎么走弯路"。但踩完这些坑之后,我对 AI 驱动的 UI 自动化到底能做什么、不能做什么,比两个月前清楚了太多。
下一篇,我会分享目前确定下来的方向------知识库最终怎么落地、通用巡检怎么实现、DIFY 作为 AI 中枢怎么把这些能力串联起来、以及最终跑出来的效果。不再是试错,而是这些弯路之后,我真正跑出来的东西。
本文是「AI 质量工程」系列文章。前两篇分别聊了测试开发的 AI 工作流和自动化脚本在 AI 时代的定位。这一篇开始进入 AI 驱动 UI 自动化的深水区------先看坑,下篇看路。欢迎交流。