前两天一个做运营的朋友跟我吐槽,说每天上班最烦的事情就是来回切换系统:ERP里抄订单号、到物流后台查轨迹、再去财务系统对账,一个上午就没了。他说,能不能让AI直接帮我点鼠标?其实他说的这个事,就是浏览器自动化,也就是现在AI领域最实用的落地场景之一。让AI像人一样打开浏览器、理解页面内容、点击按钮、填写表单、提取数据,整条链路跑下来不需要人盯着。
这个东西不是概念,也不是PPT里的未来畅想。市面上已经有不少成熟的开源框架和商业方案,核心思路可以概括为三件事:让AI“看懂”页面、让AI“决定”做什么、让AI“动手”执行。我最近正好基于开源方案自建了一套浏览器自动化工作流,跑了专利申请辅助、数据填报、表单提交、信息检索这类实际任务,这篇文章就从头到尾拆一遍,讲讲我是怎么选型、怎么搭建、怎么调通,以及踩过的那些坑。
1. AI操控网页这件事,本质是三层架构的协作
很多人一听到“AI操控网页”,第一反应是“这玩意儿是不是就相当于挂了个按键精灵”?说实话,早期确实有人这么干,但那个不叫AI,那叫脚本录制回放,页面结构稍微变一点点就废了。真正的AI浏览器自动化,内核是让大模型充当“大脑”,浏览器自动化框架充当“手脚”,再靠一套状态反馈机制把两者黏在一起。
1.1 视觉层、决策层、执行层怎么分工
我把这套系统拆成三个层次,理解了这个结构,后面所有代码和配置你都能看懂。
第一层是视觉感知层,也就是AI怎么“看见”网页。这里有两种主流路线。一种是把网页截图喂给多模态大模型,比如GPT-4o、Qwen-VL这类,让模型直接读图判断“这个按钮在哪、那个输入框是什么”。另一种是把DOM树、可访问性树(Accessibility Tree)或者经过精简的HTML结构转成文本,让模型阅读理解。我实测下来,截图方案对复杂页面的理解更接近人的直觉,但Token消耗高;DOM文本方案便宜且精确,但遇到渲染极其复杂的页面容易漏信息。
第二层是决策规划层,也就是AI根据当前页面状态决定下一步动作。这一层通常用ReAct模式的Agent来实现:模型观察(Observation)→思考(Thought)→执行动作(Action)→接收新状态(Observation),循环往复。每一步动作被限制在一个预定义的动作空间里,比如click、type、scroll、select_option、extract_content等。这样做的好处是模型不用“自由发挥”生成一堆非法操作,框架可以严格校验每个动作是否可执行。
第三层是动作执行层,负责把AI决策翻译成真实的浏览器操作。这一层常见的是基于Playwright或Selenium驱动真实浏览器实例,执行鼠标点击、键盘输入、页面导航等操作,并把执行后的结果返回给决策层。
1.2 为什么说纯脚本方案替代不了大模型方案
传统自动化脚本的逻辑是“死路径”:定位元素→执行操作→断言结果。它要求每一步都是确定性的,页面稍微改个class名或者加个弹窗,脚本就挂了。而AI方案的逻辑是“目标导向”:你给它一个最终目标,比如“去后台把所有待审核订单的状态抓下来,整理成表格”,它自己会拆分步骤、处理异常、调整策略。
我举一个实际测试的例子。我让脚本去一个老旧的政府申报系统填表,那个系统里的输入框没有稳定的id,很多字段的name属性还是中文夹杂拼音,传统XPath写起来极其痛苦。但用AI方案,我只要说“在项目名称里填入XXX,申报单位填YYY”,它自己就通过页面语义和相邻文本找到了对应的输入框。这就是“看懂页面”和“匹配选择器”的本质区别。
当然,也有需要注意的地方。AI方案不是万能的,它存在动作幻觉的问题,也就是模型可能“以为自己点了按钮”,但实际页面状态没变。所以整套系统里必须加入状态验证环节,比如点击后检查URL变化、检查特定元素是否出现。这一块后面我会仔细讲。
2. 工具选型实战:为什么我把browser-use当主线
工具选型是项目启动时最纠结的部分,在这条赛道上,可选的东西太多,但真正能跟大模型顺畅配合的并不多。我前后对比了Playwright、Selenium、Puppeteer、Skyvern和browser-use,说说我自己的判断。
2.1 白板方案与Agent框架的取舍
如果你就是想把Playwright跟大模型拼在一起,这条路完全走得通,很多大厂内部也是这么干的。但工作量不小,你需要自己写Agent循环、自己管上下文、自己解析模型输出、自己处理各种页面状态异常。早期我走的就是这条路,代码写了一堆,核心的循环逻辑勉强够用,但一旦遇到多步交叉验证的页面就很容易翻车。
后来我切到了browser-use这个开源项目。它是一个专门让大模型驱动浏览器的Agent框架,核心设计理念就是“让LLM像人一样使用浏览器”。它内置了Playwright驱动和一套标准化的动作接口,同时有现成的Agent循环和Prompt模板,我可以把主要精力放在任务定义和参数调优上,而不是重复造轮子。
Skyvern我也测过,它在处理验证码、表单提取这些场景上做了很多工程化设计,泛化能力不错。但对中文网页的支持细节和灵活度,目前我觉得browser-use更顺手。而且browser-use的生态更新非常快,社区活跃,遇到问题基本都能搜到解决方案。
2.2 browser-use的核心配置拆解
我用的版本是基于LangChain集成的。核心入口是Agent类,你需要传入一个大模型实例和一个包含任务描述的Prompt。下面是我跑通的一个最小示例,用来做一个简单的信息检索任务:
from langchain_openai import ChatOpenAI from browser_use import Agent, Browser, BrowserConfig import asyncio # 配置浏览器实例,我用的是本机Chrome的调试端口方式 browser = Browser( config=BrowserConfig( headless=False, chrome_instance_path="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", ) ) # 使用GLM-4.5或GPT-4o均可,这里以OpenAI兼容接口为例 llm = ChatOpenAI( model="gpt-4o", temperature=0, ) agent = Agent( task="打开百度首页,搜索‘浏览器自动化’,把搜索结果的前三条标题和链接提取出来,保存到result.json", llm=llm, browser=browser, ) async def main(): history = await agent.run(max_steps=15) print(history) if __name__ == "__main__": asyncio.run(main())这里面的几个参数我单独说一下:
headless=False:有头模式。调试阶段强烈建议开着,你能实时看到AI在浏览器里的每一步操作,排查问题非常直观。跑稳定了再切headless=True上服务器。max_steps=15:限制最大决策步数,防止Agent陷入死循环或者被某个页面拖死。这个值需要根据任务复杂度调整,简单检索10步内就能搞定,复杂的表单填报我一般给到30。temperature=0:决策任务不要给模型留太多随机性,温度必须拉低,让动作选择更确定。
2.3 为什么说动作空间设计是灵魂
browser-use最聪明的设计,是把LLM的输出约束在一套结构化的动作集合里。这意味着模型不能凭空“发明”一个点击方式,它只能在预定义动作里选。这套动作包括:
go_to_url(url):跳转click_element(index):点击某个已标记的元素input_text(index, text):输入文本scroll_down/scroll_up:滚动extract_content(selector):提取内容switch_tab(index):切换标签页open_tab/close_tab:标签页操作select_dropdown_option(index, option):下拉选择go_back:返回上一页
这套设计让我想到一个类比:如果你让一个实习生“用浏览器查资料”,他不会乱来,他知道自己只能做那些浏览器允许的操作。动作空间就是给AI画了同样的一条行为边界,让它在合法动作里做规划。这大大降低了无效操作和“幻觉动作”的概率,也方便我做操作审计——每一步都记录在案,出了问题能回溯。
3. 实操:从零搭一个“AI填表机器人”全流程
光谈概念没有用,我拿一个相对完整的案例来演示:让AI自动填写某个专利申请辅助系统的表单。这个任务包含页面登录、表单填写、附件上传、提交确认四个阶段,基本覆盖了浏览器自动化的典型场景。
3.1 第一步:定义任务和预期输出
任务描述是整个Agent行为的天花板。同样一个模型,任务Prompt写得好不好,效果差很远。我的写法遵循“目标+约束+输出格式”三段式。
任务目标:登录专利辅助系统,进入“新申请”页面,填写专利名称、申请人、技术领域、摘要描述四个字段。 字段要求: - 专利名称:一种基于边缘计算的设备状态监测方法 - 申请人:某某科技有限公司 - 技术领域:物联网 - 摘要描述:本申请涉及设备监测技术领域,公开了一种基于边缘计算的设备状态监测方法… 约束条件:登录页如果出现验证码,直接停止,不要尝试识别,报告“需要人工介入”。 输出格式:填写完成后,截图保存为apply_success.png,并返回所有填写字段的最终值。注意几个细节:我给AI设定了“验证码出现就停止”的边界,这很重要。现行很多系统都有人机校验,硬让AI去识别验证码既不道德也容易触发风控,让Agent学会“求助人工”反而更效率。输出格式明确为截图加字段回读,这方便我做结果验证,不能只让AI说“我填好了”,要有实锤。
3.2 第二步:元素定位失败时,让AI自己想办法
这个案例里最容易翻车的是登录环节。系统的登录框不是标准input,外头套了好几层div,常规的placeholder、label都不好使。browser-use的DOM序列化会把所有可交互元素编号,大模型通过元素的文本内容、位置关系、相邻元素语义来判断哪个是用户名框。
我的经验是:不要一上来就让AI盲填,先让它extract_content提取当前页面的可交互元素列表和大致布局,看一遍再动手。这个“先观察、再行动”的思路,能大幅降低误操作概率。我给Agent的Prompt里专门加了一句“在点击或输入之前,先提取当前页面的input和button列表,确认目标后再操作”。
3.3 第三步:状态机验证机制
填完表单之后不能直接提交,必须做状态检查。我的做法是:每次click动作之后,强制Agent提取当前页面的关键状态,比如URL、弹窗信息、按钮文案变化。browser-use支持在每一步之间插入自定义校验逻辑,但更简单的方式是靠Prompt约束。
在这个案例里,我让Agent在提交前先回读表单内容,与预期值逐项比对,全部一致才允许点提交按钮。这一步别嫌多余,我测试时遇到过模型“自信地”填错了字段,把专利名称填到了申请人栏,没有回读验证的话,这单申请就直接废了。
3.4 第四步:异常分支处理
这个案例我预设了三种异常分支:
- 页面加载超时:重试一次,还不行就放弃并截图报错
- 下拉选项与预期不符:读取当前选项列表,选择一个最接近的,并在报告中说明
- 遇到人机验证弹窗:停止操作,输出“需要人工介入”
# 伪代码示意:在任务中加入异常分支 task_prompt = """ ... 异常处理: 1. 如果点击后5秒内页面没有变化,重新提取页面状态,再次尝试原动作。 2. 如果下拉框里没有“物联网”选项,选择一个名称最接近的选项,并记录实际选中的值。 3. 任何环节出现无法处理的异常,直接停止,输出当前页面截图,并填写错误原因。 """把异常处理写进任务描述,是最简单也最有效的容错手段。它相当于给Agent立了规矩,让它知道“不是所有情况都要硬闯”。
4. 踩坑实录:AI操控网页最常见的五个翻车点
从开发到稳定运行,我在这套系统上踩过的坑不下十个。挑五个最典型的分享出来,这些坑几乎每个人都会遇到。
4.1 坑一:点击动作“薛定谔的成功”
这是最常见的坑。模型输出了click_element(5),执行器也确实点了,但页面没有反应。原因很多:按钮被遮挡、点击坐标偏移、按钮触发的是hover事件而不是click事件、或者页面压根没加载完。
我的解决办法是在动作执行后加一个“预期变化检查”。比如点击“下一步”按钮,预期URL变化或出现某个新元素。如果检查不通过,就触发重试逻辑:先滚动到元素可见区域再点,或者用键盘模拟Enter键。
4.2 坑二:动态渲染页面让AI变成“瞎子”
现在好多前端框架都是数据驱动渲染,页面加载完成后DOM还在变。AI第一次提取元素列表时看到一个结构,等它执行点击时页面又渲染了新内容,元素索引全变了。这导致AI“按图索骥”却扑了个空。
对策是把显式等待做足。我习惯在任务Prompt里强调“每次动作前,等待页面完全静止,再提取元素”。同时增大max_steps,给AI留出重新观察页面的次数。不要期待一次提取就永远有效,把“重新提取”当作常态。
4.3 坑三:登录态和验证码策略
很多内部系统有单点登录和定时失效机制,Agent跑着跑着登录态过期了,直接被踢回登录页。我在设计工作流时,把登录作为一个独立的阶段,登录完成后做一次Cookie持久化,让后续任务复用会话。但要注意,有些系统对Cookie有绑定检测,单纯复用Cookie会被风控拦下来。
验证码这块我的态度很明确:不要用AI去强解验证码。一是合规风险,二是成功率低。正确做法是设计一套“需要人工介入”的回退机制:检测到验证码页面,Agent自动暂停,通过邮件/钉钉通知人工处理,处理完手动放行。
4.4 坑四:多标签页和弹窗的上下文丢失
AI在多个标签页之间跳转时,偶尔会“忘记”自己之前在哪个页面。这个问题在弹窗场景下尤其明显:某个系统点击按钮后弹出新窗口,AI如果没有主动switch_tab,后续操作全部作用在旧页面上,结果完全不可控。
我的做法是在Prompt里加一条铁律:“在每次动作前,确认当前激活的标签页是否是目标页面;如果系统弹出了新窗口,必须切换过去后才能操作。”同时把max_steps余量留大一点,因为切换标签页本身就会多消耗步骤。
4.5 坑五:Token消耗失控
AI操控网页的Token消耗比普通对话高得多。每一步动作都要回传页面状态,有些状态序列化之后直接上万Token。一个复杂的填报任务跑下来,可能消耗几十万Token,成本不容忽视。
三个降本措施:一是在Agent循环里增加“状态摘要”而不是全量DOM回传,让模型只看到精简后的可见元素列表;二是任务拆小,一个大任务拆成多个小任务串行执行,避免上下文无限膨胀;三是用支持更长上下文的模型,减少因截断导致的重试次数。整体算下来,单次复杂任务成本能压到几分钱到几毛钱,还是可以接受的。
| 翻车点 | 核心原因 | 推荐对策 |
|---|---|---|
| 点击无效果 | 元素被遮挡/未加载完成 | 动作后验证状态,不通过则重试 |
| 动态渲染失明 | DOM持续变化,索引失效 | 等待页面静止,每次动作前重新提取 |
| 登录态过期 | 会话失效被踢回 | 独立登录段,Cookie持久化,人工介入回退 |
| 多标签页混乱 | 未主动切换上下文 | Prompt强制切换标签页后再操作 |
| Token消耗失控 | 全量状态回传,上下文膨胀 | 精简状态摘要,拆分任务,用长上下文模型 |
5. 进阶:从单任务脚本到可用的自动化服务体系
跑通单条Agent任务只是第一步,真正要落地,还得解决两个问题:一是怎么并发跑多个任务,二是怎么跟现有业务系统集成。
5.1 队列化与并发隔离
浏览器自动化任务不能无脑并发。每个Agent实例都会占用一个浏览器进程和一份大模型配额,并发太高会造成资源争抢,也会触发目标网站的风控。我的做法是做一个轻量任务队列,每个任务分配到独立的浏览器上下文(Context)中。Playwright本身就支持多Context隔离,Cookie、缓存互不干扰,这是天然的安全边界。
我测试过一个场景:三个Agent同时在三个电商后台抓取商品数据。每个Agent用独立的Context,互不干扰,跑了一个小时没有出现串号或者登出问题。如果共用一个Context,大概率会出现“A任务填表填到一半,B任务把页面跳走了”的惨剧。
5.2 与RPA和业务系统的关系
很多人觉得AI浏览器自动化会完全取代RPA,我不这么看。传统RPA适合规则固定、逻辑简单、量级大的任务,比如每天定时登录系统下载报表,它跑得又快又稳。AI方案适合规则模糊、页面多变、需要理解语义的任务。两者是互补关系。
我的集成方式是:优先用RPA处理固定流程,把AI方案作为“柔性环节”嵌入到RPA流程里。比如RPA跑到某个页面发现出现了意料之外的弹窗,就触发一个AI Agent来分析这个弹窗是什么、应该点哪里,分析完再交回RPA继续执行。这种混合编排兼容了RPA的效率与AI的应变能力。
5.3 模型选型的变化
最早我用GPT-4o,稳定性确实好,但价格偏高。后来测试了几款国产模型,在绝大多数中文页面上的表现已经足够好,成本下降了一个数量级。以我目前的感受,在中文场景里GLM-4.5系列表现不错,尤其是对中文表单字段的理解和页面语义的把握。如果任务涉及复杂英文文档或者多模态截图推理,GPT-4o还是有优势。
选模型时要同时考虑三个维度:一是指令跟随能力,也就是能不能严格按动作空间输出;二是上下文窗口,任务越长,越需要大窗口;三是函数调用能力,browser-use这类框架依赖结构化输出来解析动作,函数调用能力弱的模型会频繁输出格式错误。
6. 还没结束的部分:稳定可靠仍需要持续打磨
其实写到这,我脑海里已经很清楚了:这套东西真正能在生产环境发挥价值,还有很多细节要熬。稳定性要盯,成本要控,安全要守,模型要迭代。但方向是明确的,AI操控网页已经不是“能不能做”的问题,而是“怎么做得更稳、更省、更安全”的问题。
我自己下一步的计划是:把AI执行的结果可信度做分级,关键任务不仅要有输出截图,还要有核心字段的文本回读和一致性校验;再把执行日志沉淀成数据集,反过来微调或者few-shot提升特定流程的稳定性。这个方向我觉得值得长期投入。
最后分享一个建议:如果你刚接触这个东西,不要一上来就搞什么高并发、多任务编排,先找一个每天都要重复操作的网页流程,用browser-use把它跑通,感受一下AI“看懂页面并动手”的过程。等这一步稳定了,再逐步把任务做复杂、做多。这个领域门槛不高,但细节非常多,真正能让你拉开差距的,是你在实际运行中积累的那些异常case和应对策略。