
browser-use 这个项目我断断续续关注了大半年直到最近才真正把它用起来。它做的事情一句话就能讲清把浏览器的控制权交给 AI Agent让大模型像真人一样去理解网页、点击按钮、填写表单、翻页抓数据而不是像传统自动化脚本那样写死一行行选择器。如果你折腾过 Selenium、Playwright应该能体会那种痛页面一改版脚本就废元素定位全靠运气稍微有点动态加载就抓瞎。browser-use 的思路完全不同它让模型直接理解页面的 DOM 结构和视觉信息再用自然语言决定下一步操作。这篇文章我把自己从安装、配置、跑通 Demo到并发调度、踩坑排查的完整过程都整理出来适合正在研究 AI Agent 落地或者想把大模型接入真实网页操作场景的开发者参考。1. 别把 browser-use 当成爬虫框架它是 Agent 的“手脚”我见过很多人一上来就问“browser-use 能不能批量抓数据”这话问得有点偏。它确实能做数据采集但它的定位从来不是爬虫框架而是给 AI Agent 补上“操作浏览器”这一环。理解这一层后面用起来才不容易走偏。1.1 传统自动化脚本为什么总在翻车先聊一个老问题。用 Selenium 或 Playwright 写网页自动化核心工作其实是两件事定位元素、等待状态。定位元素靠什么靠 CSS 选择器、XPath或者各种怪异的文本匹配。写到后面你就会发现一个按钮可能同时有十几个属性而能稳定定位它的就是那么一两个。页面结构一旦调整layout 改版选择器失效脚本直接红一大片。更麻烦的是动态页面。现在的前端框架基本都在做异步渲染数据是请求接口后动态填充的。你上午跑得好好的脚本下午发现某个步骤多等了两秒元素还没出现就报 timeout。传统的解决办法是死等、重试、加各种显式等待本质上是在跟不确定性对抗越写越复杂。还有一类问题更核心传统脚本没有“理解”能力。它只会按预设路径执行遇到弹窗、cookie 授权、验证码、二次确认就只能写一堆异常分支去兜底。页面稍微出现点没见过的情况脚本就只能原地崩溃。你想想真人上网是怎么处理的看到弹窗先关掉遇到验证码手动过不知道下一步就回退一下再试。这种“随机应变”恰恰是传统自动化最难做到的。1.2 browser-use 的本质把浏览器操作“对话化”browser-use 的做法是绕开选择器让模型直接“看”页面。它把网页的 DOM 结构、可访问性树、甚至截图一起丢给大模型模型理解当前页面有哪些可点击区域、输入框在哪、链接指向哪里然后自己规划动作序列先点这里再输入内容再按下回车最后读取结果。这意味着你写的不再是操作脚本而是一句任务描述。比如“打开 GitHub 搜索 browser-use把第一页的 star 数告诉我”Agent 会自己拆解成多个步骤去执行。每一步它都会观察页面变化调整计划。页面改版了也不怕只要语义逻辑还在模型大概率能找到新入口。GitHub 上这个项目已经有一万多 star说明确实踩中了需求。它底层用的是 Playwright 驱动浏览器但把控制层全部换成了大模型。你可以理解成浏览器是肉体Playwright 是神经大模型是大脑。1.3 适合谁来用、能做什么我实际体验下来browser-use 最适合三类人。第一类是做 AI Agent 应用开发的要把 Agent 从“聊天窗口”拉进真实业务系统比如自动操作后台系统、OA、ERP它非常合适。第二类是做数据分析的需要从多站点抓取公开信息并汇总整理可以让 Agent 自动完成搜索、跳转、抽取、落库这一整套流程。第三类是搞 Web 自动化测试的用来做探索性测试或者 UI 冒烟验证它能覆盖到很多你漏掉的边界情况。但也要说清楚它的边界。如果你只是想稳定高效地抓某个固定网站的数据写一个针对性脚本可能比 Agent 更省资源更稳定。browser-use 的价值在“灵活决策”不在“极限性能”。想明白这一条你就不会对它有不切实际的期待。2. 核心原理模型究竟是怎么“看懂”网页的用 browser-use 时你不需要写选择器不用管 xpath但理解它背后的原理仍然很重要。因为只有清楚了模型是怎么感知页面的你才知道任务描述怎么写、参数怎么调、遇到问题时怎么排查。2.1 DOM 太脏模型不需要全部 HTML你直接打开浏览器开发者工具把一段网页的 HTML 复制出来会发现 90% 的内容都是模型不需要的内联脚本、样式表、埋点标签、隐藏的弹窗模板。如果把这些一次性塞给大模型Token 瞬间爆炸而且大量无效信息会干扰模型判断。browser-use 的做法是先对 DOM 做精简保留对交互有意义的元素可见的按钮、链接、输入框、下拉框、文本段落。同时它会去掉那些屏幕上看不见的样式节点和脚本节点。经过处理之后一个复杂的页面可能只剩几百个可操作元素模型只需要在这些候选里面做选择。这里有个很关键的细节browser-use 特别依赖“可访问性树”也就是 accessibility tree。你可以把它理解为屏幕阅读器视角下的页面结构每个元素都有 role按钮、链接、输入框、name可读名称、状态是否禁用、是否选中。这个视角去掉了视觉布局的干扰模型看到的是一张更纯粹的功能清单。这也是为什么很多无头浏览器在抓取无障碍信息时效果反而比普通 DOM 解析更稳。2.2 动作空间模型能操作什么要让模型“会”用浏览器必须给它定义清楚动作空间。browser-use 提供的动作包括但不限于访问 URLgo_to_url点击元素click_element输入文本input_text滚动页面scroll切换标签页switch_tab浏览器前进/后退go_back打开新标签按键盘按键如回车、Tab获取页面文本内容保存内容到文件每一轮模型都会输出一个 JSON 格式的动作指令比如“我要点击 id 为 submit 的那个按钮”或者“我要在输入框里填入某段文字”。这个动作是结构化的不是自由文本这就保证了后续能被 Playwright 稳定执行。把动作空间限制在几十个原子操作里是我认为这个项目设计得很聪明的地方。如果让模型自由发挥写 JavaScript那等于让模型直接面对整个编程世界不可控。而现在它只有一张小菜单怎么选靠模型智力选了之后怎么执行靠 Playwright 的稳定性。2.3 ReAct 循环观察、思考、行动、反馈browser-use 的内部运行逻辑是典型的 ReAct 模式一句话描述让模型在执行过程中不断观察和调整而不是一次性把整条路走完。每一轮循环大致是这样的Agent 先观察当前页面状态精简后的 DOM 可交互元素列表然后给模型一段思考thought说明这一步为什么要这么操作。接着模型输出一个动作指令Playwright 去执行。执行完后再把新的页面状态反馈给模型开启下一轮。这个循环一直持续到任务完成、达到最大步数、或者 Token 用完为止。我把这个逻辑写成伪代码你感受一下while not task_done and step max_steps: state browser.get_state() # 获取当前页面结构 action llm.decide(state, task) # 模型输出动作 result browser.execute(action) # Playwright 执行动作 history.append(state, action, result) # 记录反馈 step 1这个循环最大的好处是模型能看到“动作的结果”。比如点击了某个链接页面跳转了那模型就知道下一步要基于新页面去决策。如果点击没反应模型也能看到页面状态没变就会调整策略可能换一个入口试试。这种试错能力是传统脚本不具备的。2.4 视觉模式和纯文本模式的取舍browser-use 还支持视觉模式也就是把页面截图一起交给多模态模型让模型直接“看”页面。这对复杂页面的理解帮助特别大尤其是那些 DOM 结构正规、但视觉位置很重要的网页。比如某些按钮没有良好的文本标签或者页面是 Canvas 绘制、完全拿不到 DOM 元素的时候视觉模式几乎是唯一解。代价是 Token 消耗暴涨。一张截图换算成 Token相当于几千到上万字。所以我的经验是能用文本模式解决的就不开视觉复杂页面再开。官方也支持一个折中方案只在特定步骤需要使用视觉时启用这个后面讲参数时再说。3. 从安装到跑通第一个 Demo理论讲完动手先跑一批最简单的任务。你可能已经装过 Playwright但是 browser-use 的环境还是有一点自己的要求最好单独开一个虚拟环境不然依赖冲突会让你怀疑人生。3.1 环境准备与安装我推荐 Python 3.10 以上版本特意避开 3.7、3.8因为项目用到了不少新的类型语法。创建虚拟环境后直接安装python -m venv agent_env source agent_env/bin/activate # Windows 上执行 agent_env\Scripts\activate pip install browser-use playwright playwright install chromium这里有一个很多人会踩的坑只执行pip install playwright是装不上浏览器的必须再跑playwright install chromium否则第一行代码就会报“浏览器可执行文件找不到”。另外如果你在服务器环境可能还需要装系统依赖命令是playwright install-deps这个命令在纯净的 Linux 服务器上尤其重要。安装过程中如果网络不好导致 chromium 下载失败你可以设置PLAYWRIGHT_DOWNLOAD_HOST指向一个可用的镜像源。这属于常规的环境配置不涉及任何额外的东西放心用。3.2 配置你的大模型browser-use 在设计上不做模型绑定你可以接 OpenAI、通义千问、智谱 GLM、DeepSeek 这些兼容 OpenAI 协议的服务也可以通过 Ollama 跑本地模型。我个人最推荐的方式是先用一个支持视觉的模型跑通比如 GPT-4o 或者 Qwen-VL 系列因为视觉模式确实能提高成功率。如果你只有文本模型比如 GPT-4o-mini 或者 DeepSeek-V3也能跑但是遇到复杂页面会吃力。代码里配置模型很简单以 OpenAI 兼容接口为例from langchain_openai import ChatOpenAI llm ChatOpenAI( modelgpt-4o, temperature0, api_key你的API密钥, base_urlhttps://api.example.com/v1, # 换成你自己的接口地址 )这里有个容易被忽略的经验temperature尽量设成 0。Agent 执行任务需要确定性模型如果总是发挥灵感同一个任务每次步骤都可能不一样后面排查问题会非常痛苦。宁可让它保守一点也不要让它自由创造。3.3 跑一个最简单的任务装好环境、配好模型之后我用一个最简单的任务验证链路是否通畅。任务描述是“打开 GitHub搜索 browser-use告诉我第一个仓库的 star 数量。”完整代码如下import asyncio from browser_use import Agent, Browser, BrowserConfig from langchain_openai import ChatOpenAI async def main(): llm ChatOpenAI( modelgpt-4o, temperature0, api_keyYOUR_API_KEY, base_urlhttps://api.example.com/v1, ) browser Browser(configBrowserConfig(headlessFalse)) agent Agent( task打开 GitHub 搜索 browser-use告诉我第一个仓库的 star 数量, llmllm, browserbrowser, ) result await agent.run() print(result.final_result()) asyncio.run(main())跑起来之后你会看到浏览器窗口自己打开光标在页面里移动模型在“思考”然后一步一步执行。第一次看到这个画面还是很震撼的像一个看不见的人在帮你操作电脑。任务完成后final_result()会返回模型整理好的最终答案。这里提醒一句第一次跑不要用 headless 模式开窗口能看到过程有利于你理解它在干嘛。等脚本稳定了、确定不会出错再改成无头模式挂服务器。3.4 让 Agent 使用你已有的登录态很多任务需要登录才能操作比如后台系统、个人工作台。browser-use 支持连接你已经打开的浏览器复用登录态这样就不用每次让 Agent 重新输账号密码。实现思路是先用调试模式启动一个 Chrome 浏览器然后让 browser-use 通过 CDP 连接它。命令如下# 先手动启动 Chrome并打开远程调试端口 chrome --remote-debugging-port9222 --user-data-dir/tmp/myprofile对应代码browser Browser(configBrowserConfig( cdp_urlhttp://localhost:9222, ))这样 Agent 会直接操作你已经打开的浏览器窗口天然带上了你的登录态和 cookie。对于需要登录的站点这是最省事的方式。我日常跑内部系统任务时就喜欢用这个模式不用每次处理验证码和账号密码。4. 实操搭一个能跑业务的中文 Agent跑通 Demo 之后就得面对真实业务了。真实业务和 Demo 最大的区别在于任务更复杂、约束更多、失败成本也更高。我拿一个具体场景演示怎么从一个模糊需求落地成一个稳定运行的中文 Agent。4.1 任务描述不是越短越好很多人以为给 Agent 的任务越简洁越好其实不是。任务描述像给实习生布置工作要说明背景、目标、约束、输出格式他才不会跑偏。比如你要它去某电商平台整理热门商品价格如果只说“帮我看看商品价格”大概率结果很乱。更好的描述是这样请打开 example.com 的数码分类页筛选出销量超过一万的商品。 对每个商品提取商品名称、当前价格、月销量。 最后以 JSON 数组形式输出字段名分别为 name、price、sales。 如果页面需要登录停下来告诉我不要尝试去破解验证码。注意几个细节给了明确范围数码分类、给了筛选条件销量超一万、给了字段结构、给了兜底策略需要登录就停。这样 Agent 每一步都有据可依出错了也能知道是卡在哪一步。4.2 关键参数怎么调browser-use 的 Agent 构造函数里有一批重要参数直接决定任务的成败和成本。我整理成一张表参数作用我的建议max_steps最大执行步数防止模型无限循环简单任务给 20复杂任务给 50别超过 100max_costToken 成本上限超了就停止按单任务预算设置避免跑飞use_vision是否启用视觉模式复杂页面开简单页面关headless是否无头模式调试时 false生产时 trueallowed_domains允许访问的域名白名单强烈建议设置防止模型跳到莫名其妙的地方browser浏览器实例对象需要登录态时用 CDP 模式allowed_domains这个参数我最推荐大家用。你任务里只要用到某个站点就把域名加进白名单模型就不会突然去搜索一个无关页面既能省 Token 又能降低风险。另外max_steps别设太大。模型在一个循环任务里如果 20 步还没完成说明它可能已经迷路给它更多步数只会增加 Token 消耗不会提高成功率。正确的做法是让它停下来你检查一下中间过程调整任务描述或页面状态再重跑。4.3 结构化输出到文件或数据库Agent 跑完任务后默认输出是一段文字。真实业务里我们往往要的是结构化数据所以我会在任务描述里强制要求 JSON 格式然后用代码解析结果。一个常用的做法是让 Agent 把最终结果保存到文件然后主程序再读取result await agent.run() # final_result() 可能是纯文本如果是 JSON 字符串直接解析 final_output result.final_result() data json.loads(final_output) # 注意做好异常处理但更稳妥的方式是在 task 里要求“将结果保存为 result.json并告诉我已经完成”然后任务代码里直接读这个文件。因为模型输出 JSON 字符串时偶尔会多解释几句、或者把 JSON 包在 Markdown 代码块里直接解析很容易失败。让它写文件再读文件稳定性高很多。4.4 验证码和登录态怎么处理落到真实业务验证码是绕不开的话题。我的原则很简单不要让 Agent 去“智斗”验证码。滑块、点选、短信验证码这类东西模型操作成功率不高而且容易触发风控。browser-use 本身没有自动解验证码的能力需要靠外部方案。最常见的是保留人工任务执行中如果页面弹了验证码Agent 停下来你在浏览器窗口里手动过一下然后让它继续。另一种方案是尽量复用 CDP 登录态只要登录态没过期就很少会遇到验证码。把验证码问题作为任务预留字段写清楚比如“遇到滑块验证码就停下来等待人工处理”比让模型自己硬闯要靠谱得多。5. 并发问题AI Agent 到底怎么扛流量项目跑顺之后很多人接下来就问“AI Agent 怎么扛并发” 这也是最近社区里讨论很多的热点。我自己在把 browser-use 接入生产系统时也被并发问题折磨过一阵。5.1 browser-use 天然不适合“传统并发”先认清一个事实browser-use 本质上是一个 Agent 逻辑框架不是一个高并发爬虫引擎。每个 Agent 实例会持有一个浏览器上下文占用大量内存每一步都需要调用大模型接口响应时间是秒级多个 Agent 如果同时操作同一个页面状态还会有上下文互相污染的风险。所以它根本不适合用线程池硬怼。我试过一口气开十几个 Agent 实例内存直接飙升到 10GB 以上大模型接口也被限流任务失败率显著增加。结论是并发一定需要队列和限流而不是无脑多开。5.2 实用并发模型任务队列 多实例 并发控制我目前在用的方案是“异步任务队列 多浏览器上下文 信号量限流”。browser-use 的 Agent 支持异步调用可以直接跑在asyncio里用Semaphore控制同时执行的 Agent 数量。一个最简单的并发模型如下import asyncio from browser_use import Agent semaphore asyncio.Semaphore(5) # 最多 5 个并发 async def run_one(task): async with semaphore: agent Agent(tasktask, llmllm) result await agent.run() return result.final_result() async def main(): tasks [run_one(f查询第 {i} 个关键词的搜索结果) for i in range(20)] results await asyncio.gather(*tasks, return_exceptionsTrue) print(results) asyncio.run(main())这个方案的好处是收放自如。你只需要调整Semaphore的数值就能控制并发度。但注意这里的并发重点是“任务级别的并发”每个 Agent 持有一个浏览器实例。如果机器内存不够可以把并发数调小或者考虑复用浏览器上下文。更深一点的优化是“浏览器连接池”。因为浏览器上下文创建很贵可以只启动 1 个浏览器进程提前创建多个上下文Agent 运行的时候从池子里取一个空闲上下文用完归还。这个思路和数据库连接池一模一样能省下不少启动时间。5.3 Token 成本和接口限流并发一上来最先打爆的不是内存而是 Token 预算和大模型接口的 QPS。browser-use 每次动作都要调一次模型一个 30 步的任务至少就是 30 次调用。20 个任务同时跑瞬时请求量非常大。我用两个手段控制成本。第一是在Agent里设置max_cost比如单个任务 token 成本预算为 0.5 美元超过就自动终止避免失控。第二是给接口调用加限流不要asyncio.gather一把梭而是用信号量控制并发数后接口压力自然就降下来了。另外还可以考虑把模型换成更便宜的文本模型。纯文本模式加上 DeepSeek 或 GLM 这类模型成本能降到 GPT-4o 的十分之一以下。对于大多数网页操作任务文本模型配合 DOM 描述已经能覆盖很大比例只有在确实理解不了页面时才用视觉模型。5.4 稳定性设计日志、快照、重试、监控并发环境里失败是常态设计时一定要预留观察窗口。browser-use 自带登录日志和浏览器回放能力我建议每次任务执行时开启日志保存记录每步动作、Token 数、耗时。任务失败后第一步不是改代码而是看日志找到模型是在哪一步判断错了。任务队列建议持久化。如果用的是 Redis任务状态放在队列里失败后自动放回重新投递。这样即使某个 Agent 崩溃其它实例也会接着处理不会丢任务。还有一个指标值得记录单任务的 Token 消耗和步数。这两个指标能直接反映任务描述的质量。如果某个任务平均步数特别高说明任务描述不够清晰页面可能过于复杂。你可以针对性优化。5.5 别忘了合规这道红线做网页自动化合规问题必须讲清楚。至少要遵守这么几条尊重目标站点的 robots.txt明令禁止的路径不要碰控制请求频率不要对目标站点造成压力只采集公开或你有权限访问的数据遇到验证码、异常风控提示立即停止不要尝试绕过收藏夹、登录态等敏感信息不要上传给模型把这些约束写进任务描述和代码逻辑里是一个成熟 Agent 应用的基本素养不仅保护对方站点也保护你自己的服务稳定性。6. 常见问题排查实录接下来这部分都是我实际跑出来的坑。看一遍能帮你省掉至少一个下午的排查时间。6.1 Playwright 装不上 Chromium最常见也最好解决。执行playwright install chromium没有反应或者报错基本是网络问题。方案是指定下载源例如设置环境变量PLAYWRIGHT_DOWNLOAD_HOSThttps://npmmirror.com/mirrors/playwright/这类镜像地址再重试安装。装完之后用命令行验证一下playwright install --dry-run能正确显示安装路径就说明环境没问题。如果运行时报浏览器找不到多半是环境变量指向了旧的缓存路径清一下~/.cache/ms-playwright重新安装即可。6.2 元素找不到、点错按钮这是 Agent 运行中最常见的问题原因往往是页面状态和模型预期不一致。排查思路开视觉模式让模型直接看截图通常能大幅提高理解准确率。任务描述里补充说明页面特征比如“页面上方橙色导航栏里的搜索按钮”。把max_steps略微调大给模型一点试错空间但不要超过 30。确认页面是否加载完成有些页面里有 iframe模型默认看不到 iframe 内的元素要换策略。6.3 中文输入乱码或输入失败browser-use 在中文输入框里偶尔会丢字或乱码尤其是遇到一些重开发的富文本编辑器。一个有效缓解办法是改用“粘贴输入”方式绕过键盘事件。可以在任务描述里明确要求“使用粘贴方式输入”或者在代码里直接指定输入方式为input_typepaste。另外尽量用 Playwright 的最新版本老版本在处理中文输入时确实有不少 bug。6.4 任务跑一半就超时或步数耗尽max_steps耗尽最常见的原因是模型在某个页面里反复尝试同一个无效动作陷入了循环。解决办法不是单纯调大步数而是检查这个页面的状态。比如登录弹窗挡住页面模型点不到目标元素就会反复尝试。这时候你需要在任务描述里加一句“如果检测到弹窗先关闭再继续”。如果任务特别长超过了模型上下文窗口可以考虑让 Agent 在中间生成阶段小结把必要信息带入下一步。这点 browser-use 有内置的历史压缩机制但你可以在任务描述里主动要求“每完成一个阶段把关键信息记录到 notes 文件里”效果更好。6.5 headless 模式下表现和有人看着时不一样这个坑很隐蔽。有些网站在 headless 模式下会返回不同的 HTML或者前端检测到无头浏览器就禁用某些功能。如果 headless 模式总是失败但开窗口就能跑通大概率是目标站点做了自动化检测。我的建议是优先用 CDP 连接现实的浏览器进程既能复用登录态又能降低被识别风险。如果一定要无头模式检查 User-Agent 和浏览器指纹配置必要时手动指定一个常浏览器的 UA。6.6 本地小模型跑不动复杂页面如果你用 Ollama 跑本地模型会遇到上下文不够或者推理速度慢的问题。browser-use 对模型的推理能力要求其实很高小模型连基本的思考链都走不稳。我的建议本地模型只用来处理非常简单的任务比如固定表单填写、固定页面跳转。要处理复杂页面老实调用云端模型。本地模型最大的价值是隐私和成本不是能力别指望它能顶替 GPT-4o 级模型的判断力。7. 几个让项目更实用的个人经验这些经验不涉及代码但比代码更能决定你项目的成败。7.1 先固定站点再谈泛化我见过不少新手一开始就想做一个能处理所有网站的通用 Agent结果什么网站都搞不定。正确的路线是选三五个你日常最常访问的站点把任务描述打磨到极其精准先让这五个场景稳定跑通。等积累足够多的站点特征和任务模板后再慢慢扩大覆盖面。泛化的基础是足够的样本不是更强的模型。7.2 把浏览器配置和登录态固化真实业务里登录态是贵重金属。我建议把常用的浏览器用户目录user-data-dir固定下来不要每次临时创建。这样 Agent 下次启动时Cookie、存储、偏好设置都在大部分站点不需要重新登录。把这个目录纳入备份体系丢了等于又得人工重新登录一遍。7.3 任务结果一定要落库很多人跑完 Agent 只是print(result.final_result())然后就没有然后了。真实业务需要把结果持久化到数据库或文件并且设计好幂等逻辑。同一个任务如果跑 10 次数据应该更新而不是重复插入。我习惯给每个任务加一个 run_id把原始结果、清洗结果、状态一起存下来后面问题排查和数据分析都方便。7.4 后续还能扩展什么browser-use 目前已经支持多浏览器、多 Agent、任务状态持久化但它更多还是解决“单个 Agent 如何操作浏览器”的问题。下一步值得尝试的是把多个 Agent 组织成工作流一个 Agent 负责采集一个负责清洗一个负责生成报表中间用消息队列串联这样就已经摸到了“Agent 中台”的雏形了。我目前就在用这套方案跑一个小型的数据同步任务每天固定时间自动打开几个后台页面抓取关键数字写入数据库再推一条提醒消息到群里。整个链路每天稳定运行省掉了很多重复劳动。browser-use 不算完美但按照它现在的迭代速度未来网页自动化这个领域大概率会有更多基础设施级别的产品出现。早一点踩坑早一点积累经验是一件值得的事。