1. 为什么“写完即弃”的自动化脚本,反而成了团队的长期负债
先聊点实在的。Playwright 这两年基本成了Web自动化测试的默认选项,语法干净、多浏览器支持、codegen 一键录脚本、自动等待机制也比 Selenium 时代强太多。但有一个问题始终绕不开:脚本写完只是开始,维护才是真正吞时间的无底洞。
我见过太多团队的状态:版本上线前一晚,回归测试跑完一片红,点开报告全是“element not found”和“page.waitForTimeout(5000) 后还是超时”。开发人员忙着改业务代码,没人愿意碰测试脚本;测试人员只能一条条手工核对,把失效的选择器换一换、等待时间调一调,然后继续跑,继续崩。用我一个朋友的话说:“Playwright 帮我节省了写用例的时间,又原封不动地还给了修脚本的时间。”
这个痛点的本质是什么?是业务迭代太快,前端DOM结构调整频繁,而测试脚本的选择器、等待条件、断言逻辑都是静态的。静态的东西碰上动态的环境,必然腐化。传统做法是靠人来补位,但人肉维护有两大致命问题:
- 滞后性:失败报告只能告诉你“某条用例挂了”,不会告诉你“为什么挂、该怎么改”。你得手动跳进排查流程。
- 带宽瓶颈:自动化用例数量上百之后,维护工时是指数增长的,而不是线性增长。脚本越多,单次迭代要修的用例就越多。
正是在这个背景下,我开始尝试把 AI 引入维护链路,目标不是用 AI 替代人去“看”报告,而是让 AI 参与从“发现失败”到“定位原因”再到“输出修复补丁”的完整闭环。这篇文章就记录一次完整的实践过程:我如何把 Playwright 的失败信息、DOM 状态、运行痕迹喂给AI,并让 AI 给出可落地的自动修复结果,同时保留人工兜底的安全网。
如果你现在正被自动化脚本的维护量压得喘不过气,或者想搞清楚“AI 测试”这个热词到底能干什么、不能干什么,这篇文章应该能给你一个比较落地的参考。
2. 动手前先把边界想清楚:AI 修复不能、也不该替代什么
很多人在引入 AI 时容易走一个极端,恨不得让 AI 全程托管,出了问题全自动修完直接提交。我的建议是:在动手设计之前,先把“AI 能安全做什么”和“AI 不能做什么”的边界划清楚。这不是保守,而是工程上的自我保护。
2.1 适合交给 AI 处理的失败类型
以 Playwright 的失败为例,日常回归中真正的业务断言错误(比如页面渲染出了错误的金额、下单流程状态不对)其实是少数,更多的失败发生在三个层面:
- 元素定位失效:前端改了 class、id、data-testid,或者 DOM 结构层级变了,导致
page.click()、page.fill()找不到目标。 - 等待与超时问题:某些场景下,元素出现的时间变长(比如接口响应变慢、图片懒加载),脚本的默认超时不够,或者等待条件写得不合理。
- 动态内容或状态干扰:页面出现了浮动弹窗、toast 提示、A/B 实验组件等,遮挡了点击目标,或导致后续步骤的期望状态被干扰。
这三类失败有一个共同点:问题不干净定位,但修法相对标准化。比如定位失效,核心工作就是“找到一个仍然能唯一定位该元素的新选择器”;超时问题,核心工作是“把固定等待改成条件等待,或适当放宽超时阈值”。这些工作非常适合 AI 处理,因为 AI 不需要理解业务逻辑的深意,只需要依据页面现状和失败上下文做推断。
2.2 必须保留人工决策权的地带
真正需要警觉的是业务断言的失败。如果一个用例验证的是“价格计算逻辑”,AI 根据页面现状把断言值从100改成120,这个“修复”可能是在掩盖一个线上严重缺陷。所以我的设计原则是:
- 仅对“技术性失败”启用自动修复,包括选择器失效、等待超时、动态遮挡。
- 业务断言失败一律进入人工队列,AI 可以辅助分析,但不允许直接改断言预期。
这个边界设定后,整个系统的工作量就明确下来了:AI 修复的价值集中在“把那些本来就不该手动刷的脏活累活自动干掉”,而真正需要人脑判断的部分,AI 只做信息压缩和分析辅助。
2.3 闭环不能是“AI 说了算”,必须有人工可干预的手刹
这里还要强调一点:闭环不是让 AI 绕过人去做所有事,而是让人在更高层面做决策(比如审核补丁、确认回归结果),把低价值重复劳动交给 AI。所以我设计了三个介入点:
- 补丁生成后必须人工审核,不自动合并代码;
- 修复验证通过后要自动跑全量相关用例,而不是只跑那一条;
- 每一条修复记录都要沉淀为日志,方便追溯 AI 在什么情况下改了什么东西、为什么改。
有了这些边界和手刹,再去设计技术方案就不会跑偏。接下来进入正题。
3. 自动修复闭环的整体架构:五个环节怎么串成一条流水线
这一节先讲整体设计,让读者对整个系统的拼图有完整概念,后面再拆开讲每个环节的实现细节。
整个闭环可以概括为五步:
- 触发失败:Playwright 测试运行失败后,自动收集上下文。
- 信息提取:从失败点、DOM 快照、控制台日志、网络请求等维度提取关键证据。
- AI 诊断:将证据输入大模型,要求其判断失败原因、给出修复建议。
- 生成补丁:在测试仓库中生成候选补丁,用独立分支提交。
- 验证与沉淀:执行回归验证,通过后人工审核合并,并将失败模式存入知识库。
画成流水线的话,是这样一条链路(我这里不用流程图,用文字描述):
测试执行 → 失败事件触发 → 上下文快照收集 → 结构化失败信息组装 → LLM诊断调用 → 修复补丁生成 → 新建分支并提交 → 自动回归验证 → 人工审核 → 合并关闭工单在技术选型上,我采用的是:
- 测试框架:Playwright(Python 版本),原因后面细说;
- AI 调用层:通过 OpenAI 兼容接口调用大语言模型,便于切换不同模型供应商;
- 代码仓库与CI:用 GitLab CI 跑定时回归任务,集成机器人账号自动创建 MR;
- 知识沉淀:失败日志与修复记录存 SQLite,做轻量级本地知识库。
这里有一个关键设计决定:我不选择在测试框架内部直接调用 AI,而是把 AI 修复做成一个独立的“诊断服务”。测试失败后只负责产出快照和元数据,由外部调度器决定是否交给 AI 处理。这样做的原因是:
- 测试执行环境希望尽量轻量、稳定,不依赖外部的模型接口;
- 失败诊断是异步的,不应该阻塞 CI 的当场结果;
- 后期换模型、加规则、做权限控制都很方便,不需要动测试代码。
接下来按五个环节拆解实现细节。
4. 失败发生时,先保证“证据”采集得足够全且结构化
我最早做这个项目时踩过一个很大的坑:第一次调通 AI 修复后,发现 AI 给出的建议经常是让你“检查元素是否存在”“确认页面是否加载完整”之类的废话。排查了很久,最终意识到问题不在模型能力,而在输入质量——我只把失败的堆栈和错误信息传给了模型,信息量太少,模型基于有限信息只能做模糊猜测。
AI 诊断的效果上限,取决于你喂给它的证据颗粒度。想把 AI 修复做好,第一步不是调模型,而是把 Playwright 失败时的现场完整记录下来。
4.1 Playwright 提供的原生快照能力
Playwright 本身已经有一套很完善的失败现场记录能力,关键在于你会不会用。我在 fixture 里配置了这些收集项:
| 信息类型 | 获取方式 | 用途 |
|---|---|---|
| 失败时的页面截图 | page.screenshot() | 让 AI 能看到视觉布局状态 |
| 完整页面 HTML | page.content() | 分析 DOM 结构、查找选择器 |
| 关键元素快照 | locator.aria_snapshot() | 理解当前页面的可访问性结构 |
| 浏览器控制台日志 | page.on('console') | 发现 JS 报错、资源加载失败 |
| 页面错误事件 | page.on('pageerror') | 获取未捕获异常 |
| 网络请求失败 | page.on('requestfailed') | 发现接口挂了、跨域问题 |
| 追踪文件 | browser_context.tracing | 完整操作回放、网络瀑布流 |
在旧版本的 Playwright 里,这些信息分散在 API 中,要先注册事件监听器,再手动保存。新版 Playwright 已经内置了非常方便的 fixture 机制,只要在conftest.py里定义一个失败处理函数,就能把现场信息统一落盘。我的做法是把每一次失败都打包成一个独立目录,命名规则为{timestamp}_{test_name}_{status},目录内包含截图、HTML、日志、追踪文件等。
4.2 对 DOM 做“去噪”比全部塞给模型更有效
在第一次实验时,我直接把完整的page.content()塞给模型。结果模型提示词很容易超过上下文长度,而且页面里动不动几千个节点,大部分是无关的脚本、样式、广告位代码,对诊断没什么价值。
后来我转变思路,做了一层 DOM 预处理,只提取与失败点相关的“局部上下文”:
- 如果失败发生在
locator.click(),就提取该 locator 当前的解析结果,以及周围父级、子级的关键节点信息; - 如果失败是找不到元素,就把页面中所有可交互元素的摘要(tag、id、class、text 摘要)提取出来,按在 DOM 中的相对位置排序;
- 如果是超时错误,额外提取等待期间网络请求的耗时列表,看是不是有接口确实卡住了。
这个提取层我用了BeautifulSoup来过一遍 HTML,同时用locator.evaluate()在浏览器环境里执行一段 JS,直接从布局引擎拿到元素的真实可视状态。数据再喂给 AI 时,体积缩小了一个数量级,但关键信息反而更突出。
这里给一个核心提示:
失败现场收集的完整性和结构化程度,直接决定了 AI 诊断的下限。宁可多收集、再裁剪,也不要一开始就不收集。
4.3 补充测试代码本身的上下文
另外一个容易忽略的点是:AI 不只应该看到“页面现在长什么样”,还应该看到“测试脚本原本试图做什么”。同一类失败,在断言上下文不同时,修复策略是截然不同的。
所以我还会把失败用例的源码片段(尤其是失败步骤前的 20~30 行代码)提取出来,和页面快照一起打包。这个功能实现起来非常容易,用inspect.getsource()就能拿到测试函数的源码,再按行号截取前文。这样组装出来的“信息包”就具备了完整的因果链:脚本想做什么 → 页面实际是什么 → 中间发生了什么导致失败。
5. 组装诊断数据包:怎么把“现场信息”翻译成 AI 能高效理解的格式
收集证据和让模型读懂证据是两回事。直接把截图、HTML、日志、源码一股脑传给模型,效果依然往往不好。原因有两个:
- 多模态模型对截图的局部细节理解能力还不稳定,有时会“看错”页面元素;
- 一长串 HTML 丢进去,模型注意力会被无关信息分散,很难聚焦到你强调的失败点。
所以需要一套“结构化数据包”的组装方案。我把它当作给大模型写“案情简报”,核心是让模型在了解整体背景的同时,把注意力集中在失败点相关的局部事实上。
5.1 数据包的标准结构
我的 prompt 组装逻辑是把信息分层组织,最终形成一个 JSON 结构,类似这样(简化示例):
{ "test_info": { "test_name": "test_checkout_flow", "test_file": "tests/test_payment.py", "failed_step": "page.click('button[data-testid=\"confirm-order\"]')", "error_type": "TimeoutError", "error_message": "locator.click: Timeout 30000ms exceeded." }, "page_snapshot": { "screenshot_path": "artifacts/test_checkout_flow/screenshot.png", "interactive_elements": [ {"tag": "button", "classes": "btn-primary", "text": "确认订单", "visible": true}, {"tag": "button", "classes": "btn-outline", "text": "返回购物车", "visible": true} ], "dom_structure_summary": "页面顶部有 header,主区域包含订单金额、收货地址表单、底部操作栏..." }, "console_errors": [], "network_failures": [ {"url": "/api/v1/order/confirm", "status": 500, "duration": 1200} ], "test_source_excerpt": "def test_checkout_flow():\n ..." }注意这里的关键设计:图片和 DOM 摘要不是直接拼进 prompt 正文,而是作为“附件”引用。我选用的模型支持视觉输入,定期跑回归时可以让它直接读截图附件。之所以不把截图 base64 之后塞进 JSON,是为了避免 JSON 体量过大导致模型高延迟。
5.2 Prompt 模板:给模型一个“诊断专家”的人设和流程约束
模型发挥的稳定性,很大程度取决于 prompt 是否有清晰的任务拆解和输出约束。我最终使用的 prompt 模板有几个关键要素:
- 先定性,再定案:要求模型必须先判断失败类型(选择器失效、等待超时、动态遮挡、业务断言失败、环境问题等),不判断类型不许直接给修复代码。
- 分步推理:要求模型按“失败现象 → 可能的根因 → 验证方式 → 修复方案”四个步骤输出,避免跳步。
- 输出格式严格约束:要求输出必须是 JSON,包含
failure_type、root_cause_analysis、suggested_fixes,其中suggested_fixes是一个数组结构——每一项包含file_path、old_code、new_code、change_reason。这个结构直接对接后续的补丁生成逻辑。
核心 prompt 大致是这个风格:
你现在是一个资深测试开发工程师,专门负责 Playwright 自动化脚本的维护工作。 下面是一个自动化测试失败的现场信息包,请按以下流程分析: 1. 先判断失败类型; 2. 再分析可能的根因; 3. 最后给出可落地的修复方案。 要求: - 修复方案必须具体到代码级别,给出 old_code 和 new_code; - 如果失败原因是业务断言错误,不要修改断言值,只在分析中说明风险; - 如果信息不足以判断,请明确输出 insufficient_info=true。这套 prompt 我迭代了很多版,体会是:约束输出格式比约束“你怎么思考”更重要。模型很聪明,你给它的结构越明确,它输出的可解析性就越高;一旦让它自由发挥,后续写解析器的成本反而更高。
5.3 让截图信息不再“裸奔”:视觉信息与 DOM 摘要互补
在实际测试中,有时页面元素明明渲染了,但 DOM 里的 class 已经和脚本里的选择器对不上,这时截图能给的信息就非常关键。我观察到模型看截图时,对“某个按钮上有什么文字、在哪个位置”这类问题是十分擅长的,比看一堆 HTML 判断得更准。
但完全依赖截图也不行,截图上看不到元素的 class 名和 DOM 层级。所以我的策略是:给模型同时提供:
- 截图(视觉布局);
- 关键交互元素的摘要列表(带 tag、class、text、是否可见);
- 失败点附近的 DOM 结构片段(原始 HTML,做截断处理)。
这三个纬度合在一起,模型基本可以拼出完整现场。我实测下来,用这种方式诊断“选择器失效”问题,模型给出正确修复方向的概率能到八成以上。
6. AI 诊断的两种策略:单次推理与反思-重试模式
拿到了结构化的数据包,接下来就看模型本身的诊断能力了。但这里有一个值得讲清楚的经验:不要指望一次调用就把问题解决得漂漂亮亮,设计上要给模型“第二次机会”。
6.1 单次推理:适合模式明确的失败
对于失败原因非常典型的情况,比如>def diagnose_and_fix(failure_package): diagnosis = call_llm(build_prompt(failure_package)) for attempt in range(2): if not needs_reflection(diagnosis): break simulation_result = simulate_fix(diagnosis.suggested_fixes) if simulation_result.passed: break diagnosis = call_llm(build_reflection_prompt(failure_package, diagnosis, simulation_result)) return diagnosis
实测下来,这个“反思-重试”机制能把复杂问题的修复准确率提高至少两成,代价是模型调用次数多了一两轮。考虑到诊断场景不是高频调用,这笔开销是值得的。
6.3 模型选型上的踩坑记录
在模型选择上,我做过一组对比测试。第一版用的是纯文本模型,发现对截图的视觉信息完全没利用上,很多“明明截图里能看到问题”的场景直接废掉。后来切到带视觉能力的模型,效果明显变好。这里给个建议:
- 优先选支持视觉输入的模型,因为页面截图对诊断的增益很大;
- 上下文窗口尽量选大一点的,虽然做了 DOM 裁剪,但复杂页面依然可能产生较大 token 量;
- 延迟容忍度要比纯在线对话场景高,因为诊断是异步的,多等两三秒没问题。
我最终使用的是智谱的 GLM-4V 系列。它在视觉理解能力、结构化输出稳定性、价格三个维度上比较均衡。如果你刚好在选型,可以做一组你业务失败样本集的评测,而不是只看基准测试分数。
7. 从诊断到补丁:如何安全地让 AI 修改测试代码
AI 给出修复方案是一回事,真正把修复落进代码仓库又是另一回事。这一环节的安全性和可靠性尤其重要:测试代码也是代码,改坏了影响的不只是单条用例,可能会掩盖真实缺陷,甚至导致误报变漏报。
7.1 补丁生成器的设计:不做整体重写,只做最小改动
我最初的方案很粗暴:让 AI 直接返回整个测试函数的新版本,然后用新版本替换旧版本。实践了一周后发现了问题——AI 偶尔会“好心”地顺手修正一些代码风格问题、重命名变量、调整空白行,导致 diff 变得很大,人工审核工作量陡增,还出现了测试逻辑被意外改变的情况。
后来的方案改成只允许生成数据包中suggested_fixes指定的改动点,每个改动点就是一组old_code → new_code的精确替换。用传统的diff/match方式在源码中定位并替换,替换后必须满足两个条件:
- 源码中
old_code只能匹配到一处,否则直接转人工处理; - 替换后 diff 必须只包含该改动点,不得有任何多余变更。
这种“手术刀式”的改动方式,让人工审核只需要看几行 diff,而不是重新通读整个函数。审核成本降到很低,决策就更容易。
7.2 代码定位与匹配的工程实现
在实现代码定位时,我用了 Python 的difflib加上自定义的上下文对齐逻辑。核心步骤是:
- 读入测试文件,按行拆分成列表;
- 对每个
old_code片段进行“模糊匹配”:忽略首尾空白和空行差异; - 如果匹配数量不为 1,记录冲突并转人工;
- 匹配成功后,按行替换并重新拼装文件;
- 用
ast.parse()验证替换后的文件语法是否正确,语法错误则放弃该补丁。
ast.parse这一步异常重要。AI 生成的代码里有相当一部分问题通过语法解析就能排除掉,比如括号不匹配、缩进错误、引号未闭合等等。如果语法验证都过不了,任何后续动作都无意义。
7.3 分支隔离与 MR 提交
补丁生成后,我不会直接提交到主分支。具体流程是:
- 基于当前主分支创建一个新分支,命名规则是
ai-fix/{test_file}/{timestamp}; - 在分支上应用补丁,撰写 commit message,注明哪些失败触发的、AI 诊断的结论是什么;
- 通过 GitLab API 创建 Merge Request(MR),并把失败链接、AI 分析摘要、改动原因都填进 MR 描述;
- 触发一套精简回归任务,只跑与该测试文件相关的用例集合;
- 人工在 MR 上审核,觉得没问题了再点合并,有问题就关闭或手动修正。
这里有个容易忽略的细节:MR 的标题和描述是给人看的,不是给机器看的。你写得越清楚,审核者确认起来越快。我固定了一套 MR 模板:
## 自动修复说明 - **触发失败的 CI 链接**:xxx - **失败类型**:选择器失效 - **根因分析**:新版本前端将按钮 class 从 btn-primary 改为 btn-confirm - **修复内容**:更新 test_checkout_flow 中确认订单按钮的选择器 - **验证结果**:针对该步骤的最小模拟验证通过,相关用例集通过回归这套格式让测试负责人即使不了解 AI 细节,也能快速判断这次改动是否可信。
7.4 修复验证要考虑“全链路回归”,不能只跑补丁点
补丁点验证通过不代表整条用例一定绿。我在实践中见到过一个典型案例:AI 成功修复了一个选择器失效问题,但该用例后续步骤依赖前面步骤产生的 DOM 状态,而 AI 修复时改变了元素的点击方式(从click()改为press("Enter")),导致后续步骤的状态错乱,用例反而提前失败。
所以我把验证拆成两级:
- 一级验证(快速):仅执行修复点前后的最小步骤,确认“能定位、能交互”;
- 二级验证(完整):在独立分支上跑该测试文件下的完整用例集,确保整条用例链路通过。
只有两级验证都过了,才把 MR 标记为“待人工审核”。这样虽然慢一点,但能显著降低“修一处、崩另一处”的风险。
8. 踩坑实录:我在这个闭环里踩过的五个真实问题
这个项目从第一版能跑到今天,中间踩过的坑不少。下面挑五个最有代表性的写出来,每一个都对应一个真实的问题场景和解决思路。
8.1 AI 拿整页 HTML 做分析,token 消耗爆炸
问题在第一版就出现了。一个普通的电商结算页,完整的 HTML 有几千行,一次性塞给模型,单次调用的 token 量高达两三万。跑一轮回归遇到十个失败用例,光 token 费用就非常可观,而且响应时间很长。
后来我做了两层裁剪:第一层把<script>、<style>和隐藏节点的内容全部剔除;第二层只保留失败点附近的 DOM 子树,以及页面中所有可交互元素的摘要。裁剪之后,单次调用的输入 token 压缩了 90% 以上,模型注意力也更集中了。
8.2 模型把“真正的缺陷”当成“脚本问题”修复了
这个坑比较危险。有一次某个页面的价格字段因为后端接口改了字段名,导致页面上的金额变成了NaN,测试断言自然就失败了。AI 分析数据包时,看到 DOM 里有一个NaN文本,居然给出了一条“建议”:把断言的期望值从"99.00"改成"NaN"。
好在我事先做了“业务断言不允许自动修改”的边界设定,这个建议被系统拦截,进入人工队列。业务团队最后定位到是接口字段映射错误,属于线上缺陷。
这提醒我:自动修复系统的核心不是“AI 多聪明”,而是边界规则有多硬。边界设置得越明确,AI 的鲁棒性就越强。
8.3 修改选择器时,AI 选了“能匹配但现在不该用”的隐藏元素
还有一个案例是点击登录按钮失败,AI 给出的修复方案是把选择器改成页面底部 footer 里的一个隐藏链接(该链接文本恰好也叫“登录”)。从纯 DOM 匹配的角度看,这个选择器确实能定位到元素,但该元素在视口外且不可见,实际运行时大概率依然会失败。
后来我在信息包里增加了两个字段:元素是否可见和元素是否在视口内。这两个字段来自浏览器运行时offsetParent、getBoundingClientRect()的计算,AI 据此就知道该选哪个元素了。加上这个信息之后,此类无效修复基本消失。
8.4 并行跑多个 AI 修复任务时,API 限流和资源冲突
当 CI 一次出现十几个失败用例时,如果十几个任务同时向模型服务发起请求,很容易触发限流,甚至出现超时重试时重复提交补丁的情况。后来我在调度层加了一个轻量级队列:同时最多跑 3 个诊断任务,其余排队等待。
这个简单限制带来的收益非常明显:模型调用的失败率大幅下降,分支提交的并发冲突问题也几乎没再出现过。
8.5 先用“历史失败用例集”做回归评测,再谈放心使用
最后也是最重要的一个坑:不要一上来就全量启用自动修复。我花了整整两天,从仓库里整理了最近三个月的失败用例,按失败类型抽样了 50 条,跑了一遍自动修复流程,人工判断每一单的修复建议是“正确”“部分正确”还是“错误”。用这批结果去评估模型选型和 prompt 调优的效果。
这个评测集后来成了项目的核心资产,每次换模型、调 prompt、改信息采集逻辑,都用同一批数据做回归对比。没有这个评测集,你对系统性能只有感觉,没有数据,后续优化无异于盲人摸象。
9. 这个方案现在的运行效果与效率账
项目运行了大概两个月后,我按实际数据算过一笔账。跑一个中型电商前端的自动化回归,Playwright 用例大约 260 条,每次迭代平均触发失败用例是 28 条左右。在没有 AI 修复之前,人工处理这些失败平均需要三名测试工程师合计工作大半天。
引入闭环修复后:
- 约 65% 的失败用例自动进入修复流程;
- 其中约七成生成的有效补丁通过人工审核;
- 最终一次回归后需要人工介入的失败从 28 条降低到 8 条左右;
- 平均修复时长从“数小时”压缩到“十几分钟”。
也就是说,AI 修复并不能覆盖全部工作,但它把团队从大量机械性的定位、查找、替换中解放出来,让人能集中精力处理那些真正需要业务判断的问题。
下面是按失败类型划分的效果对比:
| 失败类型 | 占总失败比例 | AI 修复成功率 | 人工介入成本 |
|---|---|---|---|
| 选择器失效 | 38% | 明显较高 | 低 |
| 等待/超时问题 | 27% | 中,需结合性能数据判断 | 低 |
| 动态遮挡/状态干扰 | 15% | 中等偏下 | 中 |
| 业务断言失败 | 12% | 不自动修复 | 高 |
| 环境/网络问题 | 8% | 不修复,仅标记 | 低 |
数据说明一个道理:AI 修复的“甜点区”非常集中在选择器失效和等待条件优化上。这两类问题的根因模式清晰,修复动作标准化,最容易被 AI 学习和模仿;而需要业务知识的技术栈问题,AI 能提供的帮助仍然有限,这一部分不要强行自动化。
10. 给正在做同类尝试的团队几个硬建议
如果你也想把这套思路引入自己的项目,下面几条建议来自我的实际教训,应该能帮你少走不少弯路。
信息采集能力先于 AI 能力建设。不要一上来就接大模型,先把 Playwright 失败现场的信息采集做好。测试脚本、截图、DOM 快照、控制台日志、网络状态,这些是 AI 分析的原材料。原材料质量不行,后面所有环节都是白搭。
从最窄的失败类型开始做起。一次性覆盖所有失败类型意味着系统复杂度暴涨。我的建议是先把“选择器失效”这一种类型做到高准确率,跑顺了整个 Springboard 流程,再逐步扩展其它类型。
人工审核的体验决定了项目能不能走远。如果人工审核一个 MR 要花十分钟,审核者很快就会产生抵触情绪。所以补丁一定要“最小化”,MR 描述一定要清晰,审核时间务必控制在两分钟以内。新手期的运营重点不是提高 AI 修复率,而是降低人工审核负担。
所有 AI 操作都要留痕。现在看起来是 AI 在修代码,但将来一定会有“AI 为什么要这么修”“这个改动是谁批准的”之类的追溯需求。日志记录做好,包括模型输入、输出、推理过程、模拟验证结果,全部落库。这个习惯在关键时刻能救命。
把历史失败样本做成评测集。这是整个项目最值得投入的一环。没有评测集,你就无法客观评估模型改进的效果;有了评测集,每次调优都能用数据说话。我自己的经验是:评测集带来的复利效应,超过了其它任何一个模块。
11. 后续扩展方向:从“修用例”到“防失败”
目前这套系统解决的是“测试失败后怎么办”的问题,但下一步的想象空间显然更大:既然 AI 能根据失败现场反推原因,那它理论上也能在提交阶段就预判哪些改动可能导致测试用例失败。
我下一步的计划是把 AI 的诊断能力前移:
- 在开发提交代码的 MR 阶段,自动生成改动涉及的前端组件清单;
- 将组件清单与现有测试用例的依赖关系做映射;
- 提前识别哪些用例可能受影响,并给出“建议回归范围”;
- 如果可能,直接在代码 review 阶段给出前端改动与既有测试断言之间的潜在冲突提示。
这个方向一旦跑通,自动化的定位就从“事后维护”进化到“事前预防”,团队节省的不只是修脚本的时间,还有等待回归结果、反复沟通的成本。
另外,模型微调也是一个值得探索的方向。现在用通用大模型做诊断,虽然效果不错,但很多判断依然依赖模型自身对前端技术的理解。如果能把我们历史上人工修复过的实际案例整理成微调数据集,训练一个“测试维护专用助手”,理论上准确率和稳定性都会再上一个台阶。不过微调的工程门槛和成本都比较高,建议先把通用模型方案跑透,再评估要不要走到这一步。
回到最初的问题:AI 能不能真正参与 Playwright 自动化维护?我的答案是能,但前提是你要清楚它参与的是哪一段。AI 最擅长的是在信息充足的情况下做模式识别和代码生成,最适合处理那些“有标准答案”的修复动作;而真正需要人在环里的,是定义边界、审核结果、处理异常。把 AI 的能力和人的判断力放在各自最合适的位置上,这个闭环才能转得又快又稳。