这两年做自动化最大的感受,不是脚本越写越复杂,而是“怎么让自动化理解页面”这件事被彻底换了个玩法。我日常主力里有一套AI浏览器代理工具,说白了就是让AI替我把浏览器里的活儿干了:它自己看页面、自己决定点哪里、自动填表单、自动抓表格数据,最后把这一套动作串成完整自动化流程。先澄清一个容易误会的地方:标题里的“代理”是Agent的意思,也就是AI智能体,它代理的是“你在浏览器里的操作”,不涉及任何网络通信链路的改造。它能解决的核心问题是:那些写脚本成本高、维护更烦人的重复网页操作,现在可以用自然语言描述出来,让AI直接执行。本文基于我这套工具的实践,聊聊它能做什么、我是怎么组装的、落地了哪些场景,以及过程中踩过的坑。适合自动化测试工程师、跨境电商运营、还有被重复网页操作折磨的办公人群看。
1. AI浏览器代理工具到底是什么:从“录脚本”到“看屏幕”
1.1 录屏回放、元素定位、AI决策:三代自动化有什么本质差别
先说清楚我为什么需要这么一套东西。浏览器自动化其实不是新概念,最早一批工具是“录屏回放”,你在浏览器里手动操作一遍,工具把鼠标键盘动作录下来,下次重放。这玩意儿最痛的地方是:页面稍微改个布局、多插一个弹窗,回放就全崩。原因很简单,它记录的是“坐标和事件”,根本不理解自己在干什么。就像照着菜谱做菜,菜谱一丢就当场傻眼。
第二代是元素定位加脚本逻辑,也就是大家熟悉的Selenium、Playwright这套思路。你通过CSS选择器、XPath把页面上的按钮、输入框定位出来,再写断言和逻辑。这套方案到今天依然是主流,但维护成本非常真实。前端一个class改个名,或者按钮文案从“登录”改成“立即登录”,你的脚本就得跟着改。更别提动态表格、多iframe、懒加载这些场景,定位元素的时间往往比写业务逻辑还长。
第三代就是我现在说的AI浏览器代理。它不要求你在代码里写死每个元素,而是让大模型理解页面上下文,再用自然语言描述目标,AI自己决定下一步动作。这个改变本质上是把自动化从“坐标驱动”升级成“意图驱动”。以前脚本是人翻译给机器听,现在是机器自己听指令干活。就像一个新手厨师永远不敢离开菜谱,而AI代理更像一个有经验的帮厨:看到土豆就知道要削皮切块,看到锅热了就问你要不要下菜。
1.2 它能做什么、不能做什么,以及我对能力边界的理解
从我现在的使用范围看,它主要覆盖四类事情。第一,重复性网页操作:每天登录后台、导出报表、填一堆重复表单。第二,跨平台数据同步和抓取:比如跨境电商多平台订单抓取、把A系统的数据搬到B系统。第三,UI自动化测试:给定一条业务路径描述,AI去自动点击、填表、验证结果。第四,把多个步骤编排成完整工作流,AI负责看页面执行,外层脚本负责调度、报告、通知。
它不能做什么?先说能力边界。它所有的操作都建立在浏览器环境之内,无法替代后端接口压测,也无法处理那些不依赖浏览器界面的服务端逻辑。对反爬做得比较严的站点,它同样会受限,因为本质上还是一个自动化浏览器。你能做的只是控制访问频率、只获取授权范围内的数据,没有任何一种浏览器自动化能绕过服务端的风控策略,遇到这种情况,正确做法是放弃硬抓,申请官方API通道。
另外要注意的是,这套工具的目标是“提高重复操作的效率”,不是“无脑替你决策”。AI在单步操作上确实聪明,但在涉及多个系统、多步判断的复杂任务里,如果没有外层脚本的约束和目标拆分,它会跑偏。所以我的定位一直是:AI负责执行和感知,人负责定义目标和校验结果。
2. 架构拆解:我的AI浏览器代理自动化能力是这样组装的
2.1 五个核心组件:浏览器、感知层、决策层、执行层、编排层
整套系统看起来是个工具,实际上我把它拆成了五个层次,每层只干一件事,出了问题也好排查。
第一层是浏览器运行时,我用的是Playwright驱动Chromium。这层负责打开页面、执行点击输入、读取页面状态。第二层是感知层,这一层最关键,它负责把页面“翻译”给AI看。不能直接拿整页HTML扔给大模型,信息太杂、Token太贵,而且大模型看不懂底层字节码。我的做法是提取页面上的可交互元素清单,把按钮、输入框、链接、下拉框的文案和标识符整理成结构化文本,让AI拿到的是“这个页面有哪些能点的东西”,而不是一堆标签符号。
第三层是决策层,也就是大模型接口。它根据感知层提供的页面上下文和目标指令,输出下一步要做的动作,统一格式是JSON。第四层是执行层,负责把AI返回的动作指令翻译成Playwright调用,完成点击、输入、跳转这些真实操作。第五层是编排层,用pytest、定时任务、工作流脚本来管理整个任务的开始、结束、断言、重试和报告。
这五层里最容易被忽略的是编排层。很多人做完第一版AI浏览器代理,发现单个操作很聪明,但整套流程跑起来却乱糟糟,问题就出在没有编排。AI在单步决策上很强,但缺乏对全局任务的记忆和校验能力,所以必须由外层脚本告诉它:现在执行到第几步、上一步是否成功、下一步该往哪个方向走。
2.2 为什么底座选Playwright而不是Selenium
底座选型这件事,我纠结过挺久。我之前用Selenium做了两年自动化测试,不是它不好,只是当我需要把浏览器的控制权交给AI时,有几个点是硬需求,对比下来Playwright更合适。
第一是自动等待机制。Selenium需要手动写显式等待,WebDriverWait用起来又长又啰嗦,页面加载快了慢了都容易出问题。Playwright内置了自动等待,点击元素前会自动判断可见、可点、稳定,这在AI循环里太重要了,因为AI无法像人一样实时判断“页面到底加载完没有”。
第二是网络请求拦截能力。AI代理经常要等一个接口返回之后再操作,Playwright可以直接等特定响应完成,这在订单数据抓取场景里特别实用。第三是上下文隔离。Playwright的BrowserContext可以低成本实现多用户登录态隔离,我可以同时开几个店铺后台,互不干扰。第四是有codegen录制能力,虽然AI代理不依赖录制,但调试的时候用它快速定位某个元素,还是很顺手。
我把自己的体验整理成一张选型对照表,便于你按需选择:
| 能力项 | Playwright | Selenium |
|---|---|---|
| 自动等待 | 内置,点击前自动校验 | 需要WebDriverWait手动管理 |
| 动态定位 | 支持get_by_role、get_by_label等语义API | 主要依赖XPath和CSS |
| 网络控制 | 能拦截和等待响应接口 | 较弱 |
| 多上下文 | 原生支持,隔离干净 | 配置麻烦 |
| AI生态 | 数据快照、截图、注入方便 | 相对传统 |
这个表不是要否定Selenium,如果团队已经有一套成熟的Selenium框架,没必要推翻重来。但如果你是搭一套新的AI浏览器代理,我建议直接上Playwright,省掉一半等待和兼容性的烦心事。
2.3 Python + pytest + 大模型接口的搭配方式
技术栈我选了Python,主要原因倒不是Python本身多厉害,而是自动化测试领域的生态都堆在Python这边:pytest的fixture管理、pytest-html的报表、各种大模型API的SDK,用起来都顺手。整个项目结构也不复杂,核心就三层:Agent层负责AI决策和执行循环,Page层负责封装浏览器操作,Test层负责业务编排和断言。
大模型接口我建议用OpenAI兼容协议来做,好处是以后想换任意一家支持该协议的模型,只需要改BaseURL和模型名。我用环境变量把API Key放在外部,代码里不写死任何密钥。有人可能会问,为什么不用LangChain?其实LangChain在我这套架构里只占很小一部分,我更多是直接调用Chat Completions接口,自己控制提示词和动作协议。如果只是做一个浏览器代理,没必要把LangChain的工具调用链路全部引进来,简单的东西反而容易排查。
3. 三个直接落地的场景:订单抓取、UI自动化测试、办公工作流
3.1 跨境电商多平台订单抓取是怎么跑通的
这个场景是我最早跑通的业务案例。做跨境电商的运营经常会面临一个困境:同时开着Amazon、eBay、速卖通好几个后台,每天要把订单数据导出成Excel,再汇总到一张总表里。手工操作的话,一个店铺按5分钟算,三个平台下来就是十几分钟打底,而且天天重复,特别容易出错。
用AI浏览器代理的思路就很直接。第一步,先保存每个平台的登录状态,Playwright可以登录一次后把StorageState存成JSON文件,后续每次启动直接加载,省掉扫码和验证的环节。第二步,让AI在订单页面定位表格区域,提取订单号、商品名称、数量、金额、收货国家这些字段。这里要重点说下提取方式:我并没有让AI自己去猜整个表格结构,而是在Prompt里给出明确的页面上文和需要的字段清单,AI只负责从可见表格里找到对应列。第三步,把数据统一格式输出成CSV或写入数据库,再触发报表脚本生成汇总。
实操中比较坑的地方在于,这类后台系统很多是懒加载表格,滚动到底才加载下一页数据。解决方案是给动作协议加一个scroll动作,AI判断当前表格数据不足时就先滚动再提取。另外提醒一句,做数据抓取一定要守住合规边界,只抓自己有权限的店铺数据,控制抓取频率,别对别人的店铺或公开数据做批量采集,这不仅涉及平台风控,也可能踩到数据合规的红线。
3.2 用AI生成UI自动化测试脚本:不再一个class一个class找选择器
我以前写UI自动化测试用例,至少有三分之一时间花在定位元素上。打开开发者工具,复制XPath,然后发现这个XPath是绝对的,上一层加个div就全废。后来做了这套AI浏览器代理后,我换了一种方式:由AI根据业务路径去生成测试动作,再由测试框架做断言。
具体流程是这样的。测试人员只需要写一句自然语言描述,比如“打开商城首页,搜索‘手机’,进入第一个商品详情页,加入购物车,去结算”。AI代理会自己打开页面,找到搜索框输入关键词,点击搜索结果,完成加购操作。这个过程里不需要我预先把选择器写进代码,AI通过感知层给到的可交互元素清单,实时决定哪个元素是搜索框、哪个是商品卡片。这种做法对前端改动的容忍度明显更高,因为AI依赖的是“用户看得到的文案和结构”,而不是底层的class名。
当然,断言还是要人写的,AI不会替你判断业务是否正确。我的做法是在AI完成步骤后,用Playwright的断言去检查关键状态的可见性或者文本内容。比如结算页有没有出现“订单确认”标题,购物车角标数量是不是1。这其实是一种混合模式:AI负责高频变化的操作步骤,确定性代码负责核心业务校验,两边各管自己擅长的部分。
3.3 繁琐的网页操作和跨机器文件流转
除了电商和测试,日常办公里AI浏览器代理的价值更大。比如每天上班要打开内部系统,填一堆重复表单,点掉各种弹窗,再下载几十个报表。这种活儿用脚本写吧,因为系统是老旧的表格布局,选择器又长又脆弱,写完的维护成本远高于收益。但换成AI代理之后反而简单了,直接把“用户看得见的步骤”描述给AI,它就能照着操作。
还有一个我经常用的组合是浏览器操作加上跨机器文件流转。有时我需要在一台Linux服务器上跑分析脚本,再把生成的文件传到本地Windows机器上。这里我用的是最常见的SSH/SCP命令脚本,属于非常常规的运维手段。整个流程可以串起来:AI代理在网页上触发服务器任务,外层脚本通过SSH连接服务器执行脚本和文件传输,把文件拉到本地,再由AI代理把文件内容填进网页表单或者上传到系统后台。这样组合的好处是,AI不用硬扛“跨机器”这种它不理解的操作,SSH负责它该负责的传输,AI只负责它在行的浏览器操作,各司其职,整体稳定性反而更高。
4. 从0到1搭建一个AI浏览器代理自动化项目
4.1 环境准备与最小工程结构
我直接还原搭建流程,你跟着做就能跑通最小版本。环境要求是Python 3.10以上,先装依赖:
pip install playwright pytest pytest-html playwright install chromium这里说明下,pytest-html是用来生成HTML测试报告的,如果暂时不需要报告,可以先不装。工程目录我喜欢这样组织:
ai_browser_agent/ ├── agent.py # AI决策与执行循环 ├── page_utils.py # 可交互元素提取、滚动、截图 ├── conftest.py # pytest的浏览器fixture ├── test_workflow.py # 业务用例 └── .env # 存放API密钥先写最简单的浏览器fixture给pytest用:
# conftest.py import pytest from playwright.sync_api import sync_playwright @pytest.fixture(scope="session") def browser(): with sync_playwright() as p: b = p.chromium.launch(headless=False) yield b b.close()headless=False的好处是调试时你能亲眼看到AI操作到哪一步,等跑稳定了再改成无头模式,在服务器上跑任务时建议用无头模式。
4.2 核心循环:让大模型看懂页面并下发动作指令
核心代码是agent.py里的主循环。我先定义一个动作协议,目前包含六个动作:
- goto:跳转指定URL
- click:点击指定名称的元素
- fill:向输入框填入内容
- extract:提取页面数据
- wait:等待一段时间
- done:任务完成
要让AI看到页面可交互元素,先写一个提取函数:
# page_utils.py def get_interactive_elements(page): items = [] selectors = "button, input, a, select, textarea, [role=button]" for el in page.locator(selectors).all(): tag = el.evaluate("e => e.tagName") if tag == "INPUT": name = ( el.get_attribute("placeholder") or el.get_attribute("aria-label") or el.get_attribute("name") or "" ) else: name = el.inner_text(timeout=2000).strip()[:50] if name: items.append(f"<{tag}> {name}") return " | ".join(items[:60])这一步为什么重要?直接拿body文本给大模型,AI很难分清哪些是可点的、哪些只是描述文字。给一份可交互元素清单,就像给司机一张标了路况的地图,决策准确率会高很多。
然后主循环长这样:
# agent.py import json import os import re from openai import OpenAI client = OpenAI( api_key=os.getenv("LLM_API_KEY"), base_url=os.getenv("LLM_BASE_URL") ) PROMPT = """ 你是一个浏览器自动化代理。你只能输出JSON动作。 可用动作:goto, click, fill, extract, wait, done。 当前页面可交互元素: {elements} 用户任务:{task} 请基于当前页面状态输出下一步动作,一次只输出一个动作。 """ def run_browser_task(page, task: str, max_steps=15): step = 0 while step < max_steps: elements = get_interactive_elements(page) prompt = PROMPT.format(elements=elements, task=task) resp = client.chat.completions.create( model=os.getenv("LLM_MODEL", "gpt-4o-mini"), messages=[{"role": "user", "content": prompt}], temperature=0 ) content = resp.choices[0].message.content.strip() content = re.sub(r"```json|```", "", content) action = json.loads(content) action_type = action.get("action") target = action.get("target", "") value = action.get("value", "") if action_type == "goto": page.goto(value, timeout=30000) elif action_type == "click": page.get_by_role("button", name=target, exact=False).first.click() elif action_type == "fill": page.get_by_placeholder(target).first.fill(value) elif action_type == "extract": result = page.locator(target).all_inner_texts() print("提取内容:", result[:5]) elif action_type == "wait": page.wait_for_timeout(int(value or 1500)) elif action_type == "done": break step += 1这里有一个关键选择:把temperature设为0,让模型尽量稳定输出,不至于同一页面两次决策差异很大。动作执行时用Playwright自身的自动等待,尽量避免元素还没加载完就点击的尴尬。
4.3 和pytest结合,把AI动作变成可断言的测试用例
有了上面的核心循环,接入pytest就很简单了。我在test_workflow.py里写用例,用自然语言描述业务流程,AI代理执行,最后用普通断言做业务校验:
# test_workflow.py def test_search_and_add_to_cart(browser): page = browser.new_page() page.goto("https://your-shop.example.com") run_browser_task(page, "搜索手机,进入第一个商品详情页,加入购物车") cart_count = page.locator(".cart-badge").inner_text() assert int(cart_count) >= 1跑测试直接用pytest命令:
pytest test_workflow.py -v --html=report.html这套组合的收益是:业务需求变化时,只改自然语言描述,而不需要去改背后的定位代码。但也送给新接触的人一句忠告:AI生成的自动化测试更适合流程冒烟,不太适合对性能和边界值这类精确断言要求极高的场景。AI帮你把流程跑通,最终校验还是落到普通代码上,别把AI当成不用写断言的免死金牌。
4.4 稳定性和成本控制:AI定位不是万能的
这部分是我最想讲的。很多项目挂就挂在稳定性和成本失控上。
先说稳定性。生产环境里不要让AI每一步都自由决策,正确的策略是“确定性优先,AI兜底”。能写死选择器的关键节点,就直接写死,比如登录按钮、提交按钮这些核心操作;只有在元素频繁变化、选择器脆弱的地方,才交给AI语义定位。另外,动作循环要设置最大步数上限,避免异常页面让AI无限循环。我还会在每个关键动作后面加一个状态检查,如果上一步失败,直接跳出重试,而不是硬着头皮往下执行。
再说成本。AI浏览器代理最烧钱的是Token,而Token消耗大户是感知层传给大模型的页面上下文。优化方法有三个:一是只传可交互元素,不传整页HTML;二是对元素数量做截断,先取前60个;三是把一次性的大任务拆成多个小步骤,每步决策上下文更小更准。我实测下来,一次10步左右的流程,Token费用可以控制在几毛钱以内,完全在可接受范围。
5. 常见问题与排查技巧实录
5.1 高频故障与解决方案速查表
AI浏览器代理的故障模式和传统自动化脚本不太一样,我把实际遇到的高频问题整理成一张速查表,先收藏,出了状况照着查:
| 现象 | 可能原因 | 排查与解决 |
|---|---|---|
| AI反复点同一个错误元素 | 可交互元素清单太长,相似按钮太多 | 缩小上下文,只取当前可见区域元素,或给按钮加更具体的文案 |
| 点击后无反应 | 元素被弹窗遮挡或还在懒加载 | 先执行一次wait或scroll再点击,必要时设置click的timeout |
| 提示找不到元素 | 页面是iframe内部元素 | 用frame_locator定位iframe内部,或让AI在动作里带上frame信息 |
| 登录态每次都要重新验证 | 没有保存StorageState | 登录成功后调用context.storage_state()保存,后续启动直接加载 |
| Token消耗异常高 | 每次决策都传整页HTML | 换成可交互元素清单,并对长度做截断 |
| 任务跑到一半卡住 | 页面出现未知弹窗或验证码 | 异常分支检测逻辑:遇到弹窗先关闭,遇到验证码就停止并通知人工 |
| 用例偶发失败 | 网络慢导致响应未完成 | 关键接口用expect_response等待返回,不要只靠固定sleep |
5.2 我在实践中踩过的三个坑
第一个坑是过度相信AI的每一步决策。最早做的版本是让大模型从页面跳转、点击、校验全程自由发挥,结果在一次任务里它连续点击同一个不相关链接三次,整个流程跑偏。后来我强行规定:每个节点的目标必须来自外层任务拆分,AI只能决定“怎么执行”,不能决定“执行什么目标”。这个改动直接把成功率拉高一大截。
第二个坑是感知层给的信息太“脏”。有一段我图省事,直接截取body的innerText给大模型,结果AI经常分不清页面底部版权信息和顶部导航哪个是按钮。后来改成只提取可交互元素,并给每个元素标注标签类型,决策准确率才真正稳定下来。这里面的经验是:不要让AI在噪音里自己找信号,你要先帮它把页面结构提纯。
第三个坑是忘了给“完成条件”下定义。很多任务不是天然有终点的,比如“抓取所有订单”,AI可能会一直抓下去。后来我把任务目标细化成“抓到当前第1页的20条订单并停止”,在动作协议里加done动作,并在外层脚本设置最大步数,问题才算解决。用这类工具之前,先想好终止条件,是自动化项目最容易被忽略的一环。
最后再说一个我个人的体会。AI浏览器代理工具不是把老的自动化脚本技巧扔进垃圾桶,它更像是在你原来的自动化能力旁边装了一个能听懂人话的驾驶辅助。我到现在依然会手写核心脚本、手写断言、手工控制频率和合规边界,AI只负责接管那些选择器维护成本高的重复动作。如果你准备尝试,我建议先别急着做全链路全自动,挑一个每天重复且页面变化频繁的单一动作入手,比如每天导出报表或者填一张表单,把最小闭环跑稳,再慢慢扩展。这套工具的收益曲线是加速的,前期搭建辛苦一点,后期每次业务系统改版,你都会庆幸当初留了这层容错。