1. 项目概述当浏览器学会“思考”最近在折腾AI应用开发特别是想让AI能像真人一样操作网页完成一些自动化任务。传统的RPA机器人流程自动化工具虽然强大但配置复杂不够灵活遇到网页结构一变就容易“罢工”。而单纯用大语言模型LLM写脚本又常常因为对网页环境的“理解”不够深入导致操作失败。就在这个节骨眼上我发现了browser-use这个项目。它不是一个简单的浏览器自动化库而是一个旨在让AI“理解”网页、并自主决策和执行操作的框架。简单来说它试图给大语言模型装上一双能“看”网页的眼睛和一双能“操作”的手并赋予其“思考”下一步该做什么的能力。这个项目的核心价值在于它极大地降低了构建基于AI的网页交互代理的门槛。无论是想自动填写表单、抓取特定结构的数据、进行跨页面的复杂操作还是创建一个能根据自然语言指令完成任务的智能助手browser-use都提供了一个清晰的范式。它抽象了网页交互的细节让开发者可以更专注于定义任务目标和逻辑而不是纠结于如何定位一个按钮或处理一个弹窗。对于从事AI应用开发、自动化测试、数据采集甚至是智能客服机器人开发的同行来说这无疑是一个值得深入研究的工具。2. 核心架构与设计哲学拆解2.1 从“指令执行”到“任务规划”的范式转变传统的自动化脚本无论是Selenium还是Playwright其模式都是“指令式”的开发者需要精确地告诉程序“点击ID为submit的按钮”、“在class为input的框里输入XXX”。这种模式要求开发者对目标网页了如指掌且脚本极度脆弱页面结构微调就可能导致全线崩溃。browser-use引入的是“声明式”或“目标导向式”的范式。你向AI Agent描述的是“做什么”而不是“怎么做”。例如你的指令可能是“在电商网站搜索‘无线鼠标’并按价格从低到高排序把前三个的结果标题和价格保存下来”。browser-use框架会驱动AI Agent去理解这个目标然后自主分解步骤首先它要“看到”搜索框理解那是输入关键词的地方然后输入“无线鼠标”并触发搜索接着在结果页“找到”排序筛选器选择“价格从低到高”最后“识别”出商品列表并提取所需信息。这个转变的背后是框架承担了环境感知、动作空间定义和规划决策的核心工作。它将杂乱的HTML DOM文档对象模型转化为AI能理解的结构化描述并提供了一套安全的原子操作如点击、输入、滚动供AI调用。AI的角色从“操作工”变成了“指挥官”和“决策者”。2.2 核心组件交互与工作流browser-use的架构通常围绕几个核心组件构建理解它们的协作方式是上手的关键LLM大语言模型这是系统的大脑。负责理解用户指令、解析当前网页状态、规划下一步动作、以及从网页内容中提取信息。通常需要接入OpenAI GPT、Anthropic Claude或开源的Llama等模型API。模型的选择直接决定了Agent的“智商”和成本。浏览器控制器这是系统的手和眼睛。通常基于Playwright或Selenium这类真正的浏览器自动化工具。它负责两大功能动作执行接收来自LLM的原子操作指令如click(‘button#submit’)并将其转化为真实的浏览器操作。状态捕获将当前的网页状态包括HTML、截图、可交互元素列表等进行加工提供给LLM作为决策依据。网页解析与表征模块这是系统的翻译官。原始HTML对LLM来说过于冗长且充满噪音。此模块的作用是将HTML“摘要”成一种对LLM更友好的格式。常见策略包括可访问性树提取提取语义化的元素信息角色、名称、状态更贴近屏幕阅读器的视角简洁且聚焦于可交互元素。关键元素过滤与摘要通过算法或启发式规则过滤掉装饰性元素只保留链接、按钮、输入框、重要文本块等并为每个元素生成一个简洁的描述和唯一标识符如序号。视觉感知补充有时会结合截图使用多模态模型或OCR来辅助理解纯视觉化组件。动作规划与执行循环这是系统的主循环。其流程可以概括为观察浏览器控制器获取当前页面状态经由解析模块处理后生成一份“网页状态描述”。思考将“用户指令”、“网页状态描述”和“操作历史”一起提交给LLM。LLM分析后输出两种结果之一一是下一个原子操作及操作目标二是声明任务已完成并附上最终答案。行动如果LLM输出的是操作浏览器控制器则执行它。循环操作执行后页面状态改变回到“观察”步骤开始新一轮循环直到LLM输出任务完成。这个“观察-思考-行动”的循环完美模拟了人类操作网页时的认知过程也是browser-use类项目最精髓的设计。3. 环境搭建与核心配置实战3.1 基础环境与依赖安装假设我们使用Python作为开发语言并选择Playwright作为底层浏览器驱动因为Playwright对现代Web技术的支持更好且自带浏览器无需额外安装。首先创建一个新的项目目录并初始化环境# 创建项目目录 mkdir ai-browser-agent cd ai-browser-agent # 创建虚拟环境推荐 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate # 安装核心依赖 pip install playwright browser-use openai # 安装Playwright所需的浏览器 playwright install chromium这里我们直接安装了browser-use包如果其在PyPI上。实际上你可能需要从GitHub仓库克隆并安装因为此类项目迭代很快。我们同时安装了openai库用于调用GPT模型。注意虚拟环境是Python项目管理的基石它能有效隔离不同项目的依赖避免版本冲突。务必养成习惯。3.2 初始化Agent与关键参数解析接下来我们编写一个最简单的脚本初始化一个browser-use的Agent。这里我们以假设的API为例进行说明实际调用需参考项目最新文档。import asyncio from browser_use import Agent, Browser from browser_use.browser.browser import BrowserConfig from dotenv import load_dotenv import os # 加载环境变量用于存储API Key load_dotenv() async def main(): # 1. 配置浏览器 browser_config BrowserConfig( headlessFalse, # 设为True则不显示浏览器窗口适合服务器运行 disable_securityFalse, # 一般保持False确保安全特性 viewport{width: 1280, height: 720} # 设置视口大小影响页面布局 ) browser Browser(configbrowser_config) # 2. 配置LLM以OpenAI为例 # 你需要先在环境变量中设置 OPENAI_API_KEY llm_config { model: gpt-4o, # 或 ‘gpt-3.5-turbo’4o的视觉和推理能力更强 temperature: 0.1, # 温度值设低让Agent决策更稳定、可重复 api_key: os.getenv(OPENAI_API_KEY) } # 3. 创建Agent agent Agent( task请打开百度首页(https://www.baidu.com)在搜索框里输入‘今日天气’然后点击‘百度一下’按钮。最后告诉我第一个搜索结果链接的标题是什么。, llmllm_config, browserbrowser, max_steps20 # 限制最大操作步数防止Agent陷入死循环 ) # 4. 运行Agent result await agent.run() print(f任务结果: {result}) # 5. 关闭浏览器 await browser.close() if __name__ __main__: asyncio.run(main())关键参数解读headless: 调试时强烈建议设为False你可以亲眼看到Agent的操作过程便于排查问题。在生产环境或需要并行多实例时设为True以节省资源。temperature: 这是LLM的关键参数。对于需要稳定执行动作的Agent通常设置为较低值如0.1-0.3以减少其决策的随机性。如果设得太高Agent可能会做出一些“创造性”但错误的操作。max_steps:必设的安全阀。防止Agent在某个页面上陷入“点击-返回-再点击”的循环或者因为无法理解页面而不断尝试无效操作。根据任务复杂度设置简单任务10步足够复杂任务可能需要30-50步。3.3 网页状态描述的策略选择browser-use如何向LLM描述网页是影响其性能和成本的核心。通常框架会提供几种模式DOM摘要模式通过算法提取关键元素的文本、角色和属性生成一段简洁的英文描述。例如[1. link: ‘News’, 2. button: ‘Search’, 3. text_input: ‘Enter keyword’...]。优点是文本量小API调用成本低缺点是可能丢失布局和视觉上下文。可访问性树模式提取类似屏幕阅读器使用的语义化信息。这对表单和交互控件丰富的页面特别有效因为它天生就是为描述UI而设计的。多模态模式同时提供网页的截图和DOM摘要。LLM如GPT-4V可以“看到”页面结合视觉信息做出更准确的判断尤其是对于纯图片按钮、复杂图表或验证码。这是效果最好但也是最昂贵的方式因为涉及图像传输和更大的模型上下文。在配置时你需要根据任务类型和预算进行权衡。对于标准的企业内部Web应用元素有清晰的语义化标签DOM摘要可能就够了。对于需要识别图形验证码或进行视觉验证的任务则必须启用多模态模式。# 假设在Agent配置中可以选择感知模式 agent Agent( task..., llm..., browser..., perception_modedom_summary # 可选 ‘dom_summary’ ‘accessibility_tree’, ‘multimodal’ )4. 任务定义与高级控制技巧4.1 编写清晰有效的任务指令给AI Agent下指令是一门艺术。指令不清Agent就容易迷路。以下是几个原则和对比示例原则一目标明确而非过程描述差“先点击登录按钮然后在用户名框输入‘admin’在密码框输入‘123456’再点击提交。” 这是过程Agent如果找不到“登录按钮”就会卡住。优“请使用用户名‘admin’和密码‘123456’登录系统。” 这是目标Agent会自主寻找登录入口和表单。原则二提供关键上下文和约束差“把商品加入购物车。”优“在网站‘example.com’上搜索‘蓝牙耳机’在搜索结果列表中找到‘品牌A 无线蓝牙耳机 5.3版本’这一商品并将其加入购物车。如果显示缺货则选择同品牌下最相似的型号。”原则三明确输出格式在指令末尾明确要求Agent返回什么。例如“…最后请将成功加入购物车的商品名称和单价以JSON格式返回给我例如{“product”: “xxx”, “price”: “yyy”}。”4.2 使用上下文与记忆提升效率复杂的任务往往需要多步操作和状态记忆。browser-use框架通常会维护一个会话历史包含之前的操作和页面观察结果。但有时我们需要注入更具体的先验知识。预导航与Cookie注入对于需要登录的任务可以先让Agent或直接用Playwright导航到登录页完成登录并将登录后的Cookie保存下来。在后续启动新Agent时可以注入这些Cookie使其直接处于登录状态跳过重复登录步骤。# 伪代码示例使用保存的Cookie context await browser.new_context(storage_stateauth_cookies.json) agent Agent(task..., llm..., browser_contextcontext)自定义提示词工程你可以修改或扩充框架发送给LLM的系统提示词System Prompt。例如你可以加入“你是一个专注于数据提取的助手。你应优先尝试使用页面的‘导出’或‘下载’功能如果找不到再考虑从表格中复制数据。” 这能引导Agent采用更优的策略。4.3 处理动态内容与等待策略现代网页大量使用JavaScript动态加载内容。Agent发出点击操作后新内容可能不会立即出现。内置等待好的框架如基于Playwright的会自动等待网络空闲和DOM稳定后再进行下一次“观察”。这通常足够了。显式等待指令在任务指令中可以明确告诉Agent等待。例如“点击‘加载更多’按钮然后等待新内容完全出现再继续向下滚动。”处理弹窗和确认框这是常见难点。需要在系统提示词中教导Agent识别常见的弹窗文本如“确定”、“取消”、“OK”、“Confirm”并做出正确响应。有些框架允许你注册“后置动作钩子”在每次操作后检查是否有弹窗并自动处理。5. 实战案例构建一个智能商品比价Agent让我们用一个更复杂的例子串联起上述所有知识点。目标是构建一个Agent能在两个不同的电商网站假设为Site A和Site B上搜索同一商品并返回价格对比。5.1 任务分解与Agent设计这个任务可以分解为两个基本子任务然后进行聚合。我们设计一个“主控”逻辑而非一个Agent从头跑到尾。子任务Agent (Price Fetcher)专门用于在单个网站上搜索并提取价格。主控流程依次或并行运行两个子任务Agent收集结果然后进行比较。5.2 代码实现与核心逻辑import asyncio from browser_use import Agent, Browser from browser_use.browser.browser import BrowserConfig import os import json async def fetch_price_from_site(site_name, site_url, product_name, browser_contextNone): 子任务在指定网站抓取商品价格 task_description f 请导航到 {site_url}。 在网站的搜索框中搜索商品{product_name}。 从搜索结果列表中找到第一个或最匹配的商品并提取其商品标题和当前价格。 请确保你提取的是商品本身的价格而不是运费或其他费用。 最终请严格按以下JSON格式返回信息不要返回其他任何内容 {{ “site”: “{site_name}”, “product_title”: “提取到的商品标题”, “price”: “提取到的价格字符串” }} browser_config BrowserConfig(headlessTrue) # 可以复用浏览器上下文避免重复登录如果有 browser Browser(configbrowser_config, contextbrowser_context) agent Agent( tasktask_description, llm{model: gpt-4o, temperature: 0.1, api_key: os.getenv(OPENAI_API_KEY)}, browserbrowser, max_steps25, perception_modedom_summary # 假设商品列表文字信息充足 ) print(f“开始从 {site_name} 查询 {product_name}...”) try: result await agent.run() # 尝试从Agent的返回文本中解析JSON # 注意实际中框架的result对象可能结构不同这里仅为示例 result_text result.final_result if hasattr(result, ‘final_result’) else str(result) # 简单查找JSON块实际应用应用更健壮的解析 import re json_match re.search(r‘\{.*\}’, result_text, re.DOTALL) if json_match: data json.loads(json_match.group()) return data else: return {“site”: site_name, “error”: “未能解析出价格信息”, “raw_output”: result_text[:200]} except Exception as e: return {“site”: site_name, “error”: str(e)} finally: await browser.close() async def main(): product_to_search “罗技 MX Master 3S 无线鼠标” sites [ (“电商平台A”, “https://www.site-a.com”), (“电商平台B”, “https://www.site-b.com”), ] all_results [] # 顺序执行避免并行对服务器造成压力或触发反爬 for site_name, site_url in sites: result await fetch_price_from_site(site_name, site_url, product_to_search) all_results.append(result) await asyncio.sleep(2) # 礼貌性间隔 print(“\n 比价结果 ”) valid_results [r for r in all_results if ‘price’ in r and r[‘price’]] if valid_results: # 简单清洗价格字符串提取数字实际应用需要更复杂的清洗逻辑 def parse_price(price_str): import re numbers re.findall(r‘[\d,.]’, price_str) return float(numbers[0].replace(‘,’, ‘’)) if numbers else float(‘inf’) for res in valid_results: res[‘price_num’] parse_price(res[‘price’]) print(f“{res[‘site’]}: {res[‘product_title’]} - {res[‘price’]} (解析值: {res[‘price_num’]})”) cheapest min(valid_results, keylambda x: x[‘price_num’]) print(f“\n最优惠的是{cheapest[‘site’]} 价格{cheapest[‘price’]}”) else: print(“未能成功获取任何价格信息。”) print(“详细结果”, json.dumps(all_results, indent2, ensure_asciiFalse)) if __name__ ‘__main__’: asyncio.run(main())5.3 案例中的难点与应对价格信息提取不同网站的价格格式千差万别“599”、“$59.99”、“59,99 €”、“优惠价 499”。我们的子任务Agent依赖LLM的自然语言理解能力来“读懂”并提取价格文本。更鲁棒的做法是在系统提示词中强化对价格模式的描述或者在后处理阶段使用更复杂的正则表达式或文本解析库。商品匹配搜索“罗技 MX Master 3S”结果里可能包含不同颜色、套餐的变体。我们的指令是“第一个或最匹配的”这并不精确。生产环境中可能需要更复杂的指令如“找到标题中同时包含‘MX Master 3S’和‘无线’的商品”甚至结合图像识别来匹配产品图。反爬虫机制高频访问或特征明显的自动化流量可能被网站屏蔽。browser-use由于使用真实浏览器本身比简单HTTP请求更隐蔽但仍需注意设置合理的await asyncio.sleep()间隔、使用住宅代理IP池、以及让Agent模拟人类的不规律操作节奏如随机移动鼠标、滚动。6. 常见问题、调试与优化指南6.1 Agent行为异常排查表问题现象可能原因排查与解决思路Agent卡住不动不执行操作1. LLM API调用失败或超时。2. 页面加载过慢等待超时。3.max_steps设置过小任务未完成就停止。4. Agent陷入逻辑循环如找不到元素但不断重试。1. 检查API密钥、网络、额度。查看框架日志。2. 增加浏览器操作的超时时间。检查网络环境。3. 适当增加max_steps或在任务指令中提示“如果找不到X请尝试Y”。4.开启headlessFalse观察看页面是否如预期。在系统提示词中加入“如果三次尝试同一操作均失败请停止并报告”。Agent点击了错误的元素1. 网页状态描述不准确LLM误解了元素功能。2. 页面有多个相似元素标识符不唯一。3.temperature参数过高决策随机性大。1. 切换到multimodal感知模式让AI“看到”页面。2. 检查框架生成的元素描述。有时需要自定义解析逻辑为元素添加更独特的描述如“蓝色的提交按钮”。3. 将temperature降至0.1或0.2。Agent无法处理登录/验证码1. 登录表单复杂有动态令牌。2. 遇到图形验证码或点选验证码。1. 考虑使用预登录Cookie注入绕过登录环节。2.这是当前技术的难点。可以a) 尝试多模态模型识别简单验证码b) 集成第三方打码平台APIc) 设计流程让人类在关键时刻介入人工验证。任务成功率低时好时坏1. 任务指令模糊。2. 网页结构在不同场景下有差异如A/B测试。3. LLM模型能力不足或不稳定。1.精细化任务指令这是提升成功率最有效的方法。提供例子、明确边界条件。2. 增加Agent的容错指令如“如果看到A样式的页面做X如果看到B样式的页面做Y”。3. 升级到更强的模型如从GPT-3.5升级到GPT-4o或尝试不同的模型提供商。6.2 成本控制与性能优化使用商业LLM API是主要成本来源。优化策略包括选择性价比模型对于逻辑简单、页面描述清晰的任务gpt-3.5-turbo可能就足够了。对于需要视觉理解或复杂推理的再用gpt-4o。精简网页描述确保使用的感知模式如dom_summary能提供足够信息的同时尽可能压缩文本长度。可以自定义解析器过滤掉绝对不可交互的元素。减少不必要的步骤通过优化指令让Agent路径更直接。分析日志看Agent是否走了弯路。缓存与复用对于导航到固定页面获取信息的任务可以考虑缓存该页面的描述结果短时间内重复任务时直接使用避免重新加载页面和调用LLM进行重复观察。6.3 我的实操心得从小任务开始验证不要一开始就设计一个需要操作20步的复杂流程。先从“打开网页点击某个特定按钮”这样原子级的任务开始验证整个链路是否通畅感知是否准确。日志是你的眼睛务必开启框架的详细日志记录下LLM接收到的网页描述、LLM的思考过程如果支持以及发出的每一个动作。这是调试的唯一依据。你经常会发现AI“看”到的页面和你想象的不一样。系统提示词是方向盘花时间精心设计系统提示词。明确Agent的身份“你是一个高效、准确的数据提取助手”、行为准则“优先使用最直接的方法”、“未经确认不要提交表单”和输出格式要求。这能极大规范Agent的行为。接受一定的不确定性基于LLM的Agent本质是概率模型无法达到传统脚本100%的确定性。它的优势在于灵活性和泛化能力。评估时应关注其成功率例如95%的任务能成功而非绝对可靠。对于要求100%准确的关键业务需要设计人工审核或备用方案。组合使用browser-useAgent最适合处理非结构化的、需要一定理解和决策的网页交互。对于高度结构化、重复性极高的操作如批量处理表格每一行传统的Playwright脚本可能更高效、更经济。将两者结合用传统脚本处理固定流程用AI Agent处理其中的变体和异常往往是更优的架构。
基于browser-use框架的AI网页自动化:从原理到实战
1. 项目概述当浏览器学会“思考”最近在折腾AI应用开发特别是想让AI能像真人一样操作网页完成一些自动化任务。传统的RPA机器人流程自动化工具虽然强大但配置复杂不够灵活遇到网页结构一变就容易“罢工”。而单纯用大语言模型LLM写脚本又常常因为对网页环境的“理解”不够深入导致操作失败。就在这个节骨眼上我发现了browser-use这个项目。它不是一个简单的浏览器自动化库而是一个旨在让AI“理解”网页、并自主决策和执行操作的框架。简单来说它试图给大语言模型装上一双能“看”网页的眼睛和一双能“操作”的手并赋予其“思考”下一步该做什么的能力。这个项目的核心价值在于它极大地降低了构建基于AI的网页交互代理的门槛。无论是想自动填写表单、抓取特定结构的数据、进行跨页面的复杂操作还是创建一个能根据自然语言指令完成任务的智能助手browser-use都提供了一个清晰的范式。它抽象了网页交互的细节让开发者可以更专注于定义任务目标和逻辑而不是纠结于如何定位一个按钮或处理一个弹窗。对于从事AI应用开发、自动化测试、数据采集甚至是智能客服机器人开发的同行来说这无疑是一个值得深入研究的工具。2. 核心架构与设计哲学拆解2.1 从“指令执行”到“任务规划”的范式转变传统的自动化脚本无论是Selenium还是Playwright其模式都是“指令式”的开发者需要精确地告诉程序“点击ID为submit的按钮”、“在class为input的框里输入XXX”。这种模式要求开发者对目标网页了如指掌且脚本极度脆弱页面结构微调就可能导致全线崩溃。browser-use引入的是“声明式”或“目标导向式”的范式。你向AI Agent描述的是“做什么”而不是“怎么做”。例如你的指令可能是“在电商网站搜索‘无线鼠标’并按价格从低到高排序把前三个的结果标题和价格保存下来”。browser-use框架会驱动AI Agent去理解这个目标然后自主分解步骤首先它要“看到”搜索框理解那是输入关键词的地方然后输入“无线鼠标”并触发搜索接着在结果页“找到”排序筛选器选择“价格从低到高”最后“识别”出商品列表并提取所需信息。这个转变的背后是框架承担了环境感知、动作空间定义和规划决策的核心工作。它将杂乱的HTML DOM文档对象模型转化为AI能理解的结构化描述并提供了一套安全的原子操作如点击、输入、滚动供AI调用。AI的角色从“操作工”变成了“指挥官”和“决策者”。2.2 核心组件交互与工作流browser-use的架构通常围绕几个核心组件构建理解它们的协作方式是上手的关键LLM大语言模型这是系统的大脑。负责理解用户指令、解析当前网页状态、规划下一步动作、以及从网页内容中提取信息。通常需要接入OpenAI GPT、Anthropic Claude或开源的Llama等模型API。模型的选择直接决定了Agent的“智商”和成本。浏览器控制器这是系统的手和眼睛。通常基于Playwright或Selenium这类真正的浏览器自动化工具。它负责两大功能动作执行接收来自LLM的原子操作指令如click(‘button#submit’)并将其转化为真实的浏览器操作。状态捕获将当前的网页状态包括HTML、截图、可交互元素列表等进行加工提供给LLM作为决策依据。网页解析与表征模块这是系统的翻译官。原始HTML对LLM来说过于冗长且充满噪音。此模块的作用是将HTML“摘要”成一种对LLM更友好的格式。常见策略包括可访问性树提取提取语义化的元素信息角色、名称、状态更贴近屏幕阅读器的视角简洁且聚焦于可交互元素。关键元素过滤与摘要通过算法或启发式规则过滤掉装饰性元素只保留链接、按钮、输入框、重要文本块等并为每个元素生成一个简洁的描述和唯一标识符如序号。视觉感知补充有时会结合截图使用多模态模型或OCR来辅助理解纯视觉化组件。动作规划与执行循环这是系统的主循环。其流程可以概括为观察浏览器控制器获取当前页面状态经由解析模块处理后生成一份“网页状态描述”。思考将“用户指令”、“网页状态描述”和“操作历史”一起提交给LLM。LLM分析后输出两种结果之一一是下一个原子操作及操作目标二是声明任务已完成并附上最终答案。行动如果LLM输出的是操作浏览器控制器则执行它。循环操作执行后页面状态改变回到“观察”步骤开始新一轮循环直到LLM输出任务完成。这个“观察-思考-行动”的循环完美模拟了人类操作网页时的认知过程也是browser-use类项目最精髓的设计。3. 环境搭建与核心配置实战3.1 基础环境与依赖安装假设我们使用Python作为开发语言并选择Playwright作为底层浏览器驱动因为Playwright对现代Web技术的支持更好且自带浏览器无需额外安装。首先创建一个新的项目目录并初始化环境# 创建项目目录 mkdir ai-browser-agent cd ai-browser-agent # 创建虚拟环境推荐 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate # 安装核心依赖 pip install playwright browser-use openai # 安装Playwright所需的浏览器 playwright install chromium这里我们直接安装了browser-use包如果其在PyPI上。实际上你可能需要从GitHub仓库克隆并安装因为此类项目迭代很快。我们同时安装了openai库用于调用GPT模型。注意虚拟环境是Python项目管理的基石它能有效隔离不同项目的依赖避免版本冲突。务必养成习惯。3.2 初始化Agent与关键参数解析接下来我们编写一个最简单的脚本初始化一个browser-use的Agent。这里我们以假设的API为例进行说明实际调用需参考项目最新文档。import asyncio from browser_use import Agent, Browser from browser_use.browser.browser import BrowserConfig from dotenv import load_dotenv import os # 加载环境变量用于存储API Key load_dotenv() async def main(): # 1. 配置浏览器 browser_config BrowserConfig( headlessFalse, # 设为True则不显示浏览器窗口适合服务器运行 disable_securityFalse, # 一般保持False确保安全特性 viewport{width: 1280, height: 720} # 设置视口大小影响页面布局 ) browser Browser(configbrowser_config) # 2. 配置LLM以OpenAI为例 # 你需要先在环境变量中设置 OPENAI_API_KEY llm_config { model: gpt-4o, # 或 ‘gpt-3.5-turbo’4o的视觉和推理能力更强 temperature: 0.1, # 温度值设低让Agent决策更稳定、可重复 api_key: os.getenv(OPENAI_API_KEY) } # 3. 创建Agent agent Agent( task请打开百度首页(https://www.baidu.com)在搜索框里输入‘今日天气’然后点击‘百度一下’按钮。最后告诉我第一个搜索结果链接的标题是什么。, llmllm_config, browserbrowser, max_steps20 # 限制最大操作步数防止Agent陷入死循环 ) # 4. 运行Agent result await agent.run() print(f任务结果: {result}) # 5. 关闭浏览器 await browser.close() if __name__ __main__: asyncio.run(main())关键参数解读headless: 调试时强烈建议设为False你可以亲眼看到Agent的操作过程便于排查问题。在生产环境或需要并行多实例时设为True以节省资源。temperature: 这是LLM的关键参数。对于需要稳定执行动作的Agent通常设置为较低值如0.1-0.3以减少其决策的随机性。如果设得太高Agent可能会做出一些“创造性”但错误的操作。max_steps:必设的安全阀。防止Agent在某个页面上陷入“点击-返回-再点击”的循环或者因为无法理解页面而不断尝试无效操作。根据任务复杂度设置简单任务10步足够复杂任务可能需要30-50步。3.3 网页状态描述的策略选择browser-use如何向LLM描述网页是影响其性能和成本的核心。通常框架会提供几种模式DOM摘要模式通过算法提取关键元素的文本、角色和属性生成一段简洁的英文描述。例如[1. link: ‘News’, 2. button: ‘Search’, 3. text_input: ‘Enter keyword’...]。优点是文本量小API调用成本低缺点是可能丢失布局和视觉上下文。可访问性树模式提取类似屏幕阅读器使用的语义化信息。这对表单和交互控件丰富的页面特别有效因为它天生就是为描述UI而设计的。多模态模式同时提供网页的截图和DOM摘要。LLM如GPT-4V可以“看到”页面结合视觉信息做出更准确的判断尤其是对于纯图片按钮、复杂图表或验证码。这是效果最好但也是最昂贵的方式因为涉及图像传输和更大的模型上下文。在配置时你需要根据任务类型和预算进行权衡。对于标准的企业内部Web应用元素有清晰的语义化标签DOM摘要可能就够了。对于需要识别图形验证码或进行视觉验证的任务则必须启用多模态模式。# 假设在Agent配置中可以选择感知模式 agent Agent( task..., llm..., browser..., perception_modedom_summary # 可选 ‘dom_summary’ ‘accessibility_tree’, ‘multimodal’ )4. 任务定义与高级控制技巧4.1 编写清晰有效的任务指令给AI Agent下指令是一门艺术。指令不清Agent就容易迷路。以下是几个原则和对比示例原则一目标明确而非过程描述差“先点击登录按钮然后在用户名框输入‘admin’在密码框输入‘123456’再点击提交。” 这是过程Agent如果找不到“登录按钮”就会卡住。优“请使用用户名‘admin’和密码‘123456’登录系统。” 这是目标Agent会自主寻找登录入口和表单。原则二提供关键上下文和约束差“把商品加入购物车。”优“在网站‘example.com’上搜索‘蓝牙耳机’在搜索结果列表中找到‘品牌A 无线蓝牙耳机 5.3版本’这一商品并将其加入购物车。如果显示缺货则选择同品牌下最相似的型号。”原则三明确输出格式在指令末尾明确要求Agent返回什么。例如“…最后请将成功加入购物车的商品名称和单价以JSON格式返回给我例如{“product”: “xxx”, “price”: “yyy”}。”4.2 使用上下文与记忆提升效率复杂的任务往往需要多步操作和状态记忆。browser-use框架通常会维护一个会话历史包含之前的操作和页面观察结果。但有时我们需要注入更具体的先验知识。预导航与Cookie注入对于需要登录的任务可以先让Agent或直接用Playwright导航到登录页完成登录并将登录后的Cookie保存下来。在后续启动新Agent时可以注入这些Cookie使其直接处于登录状态跳过重复登录步骤。# 伪代码示例使用保存的Cookie context await browser.new_context(storage_stateauth_cookies.json) agent Agent(task..., llm..., browser_contextcontext)自定义提示词工程你可以修改或扩充框架发送给LLM的系统提示词System Prompt。例如你可以加入“你是一个专注于数据提取的助手。你应优先尝试使用页面的‘导出’或‘下载’功能如果找不到再考虑从表格中复制数据。” 这能引导Agent采用更优的策略。4.3 处理动态内容与等待策略现代网页大量使用JavaScript动态加载内容。Agent发出点击操作后新内容可能不会立即出现。内置等待好的框架如基于Playwright的会自动等待网络空闲和DOM稳定后再进行下一次“观察”。这通常足够了。显式等待指令在任务指令中可以明确告诉Agent等待。例如“点击‘加载更多’按钮然后等待新内容完全出现再继续向下滚动。”处理弹窗和确认框这是常见难点。需要在系统提示词中教导Agent识别常见的弹窗文本如“确定”、“取消”、“OK”、“Confirm”并做出正确响应。有些框架允许你注册“后置动作钩子”在每次操作后检查是否有弹窗并自动处理。5. 实战案例构建一个智能商品比价Agent让我们用一个更复杂的例子串联起上述所有知识点。目标是构建一个Agent能在两个不同的电商网站假设为Site A和Site B上搜索同一商品并返回价格对比。5.1 任务分解与Agent设计这个任务可以分解为两个基本子任务然后进行聚合。我们设计一个“主控”逻辑而非一个Agent从头跑到尾。子任务Agent (Price Fetcher)专门用于在单个网站上搜索并提取价格。主控流程依次或并行运行两个子任务Agent收集结果然后进行比较。5.2 代码实现与核心逻辑import asyncio from browser_use import Agent, Browser from browser_use.browser.browser import BrowserConfig import os import json async def fetch_price_from_site(site_name, site_url, product_name, browser_contextNone): 子任务在指定网站抓取商品价格 task_description f 请导航到 {site_url}。 在网站的搜索框中搜索商品{product_name}。 从搜索结果列表中找到第一个或最匹配的商品并提取其商品标题和当前价格。 请确保你提取的是商品本身的价格而不是运费或其他费用。 最终请严格按以下JSON格式返回信息不要返回其他任何内容 {{ “site”: “{site_name}”, “product_title”: “提取到的商品标题”, “price”: “提取到的价格字符串” }} browser_config BrowserConfig(headlessTrue) # 可以复用浏览器上下文避免重复登录如果有 browser Browser(configbrowser_config, contextbrowser_context) agent Agent( tasktask_description, llm{model: gpt-4o, temperature: 0.1, api_key: os.getenv(OPENAI_API_KEY)}, browserbrowser, max_steps25, perception_modedom_summary # 假设商品列表文字信息充足 ) print(f“开始从 {site_name} 查询 {product_name}...”) try: result await agent.run() # 尝试从Agent的返回文本中解析JSON # 注意实际中框架的result对象可能结构不同这里仅为示例 result_text result.final_result if hasattr(result, ‘final_result’) else str(result) # 简单查找JSON块实际应用应用更健壮的解析 import re json_match re.search(r‘\{.*\}’, result_text, re.DOTALL) if json_match: data json.loads(json_match.group()) return data else: return {“site”: site_name, “error”: “未能解析出价格信息”, “raw_output”: result_text[:200]} except Exception as e: return {“site”: site_name, “error”: str(e)} finally: await browser.close() async def main(): product_to_search “罗技 MX Master 3S 无线鼠标” sites [ (“电商平台A”, “https://www.site-a.com”), (“电商平台B”, “https://www.site-b.com”), ] all_results [] # 顺序执行避免并行对服务器造成压力或触发反爬 for site_name, site_url in sites: result await fetch_price_from_site(site_name, site_url, product_to_search) all_results.append(result) await asyncio.sleep(2) # 礼貌性间隔 print(“\n 比价结果 ”) valid_results [r for r in all_results if ‘price’ in r and r[‘price’]] if valid_results: # 简单清洗价格字符串提取数字实际应用需要更复杂的清洗逻辑 def parse_price(price_str): import re numbers re.findall(r‘[\d,.]’, price_str) return float(numbers[0].replace(‘,’, ‘’)) if numbers else float(‘inf’) for res in valid_results: res[‘price_num’] parse_price(res[‘price’]) print(f“{res[‘site’]}: {res[‘product_title’]} - {res[‘price’]} (解析值: {res[‘price_num’]})”) cheapest min(valid_results, keylambda x: x[‘price_num’]) print(f“\n最优惠的是{cheapest[‘site’]} 价格{cheapest[‘price’]}”) else: print(“未能成功获取任何价格信息。”) print(“详细结果”, json.dumps(all_results, indent2, ensure_asciiFalse)) if __name__ ‘__main__’: asyncio.run(main())5.3 案例中的难点与应对价格信息提取不同网站的价格格式千差万别“599”、“$59.99”、“59,99 €”、“优惠价 499”。我们的子任务Agent依赖LLM的自然语言理解能力来“读懂”并提取价格文本。更鲁棒的做法是在系统提示词中强化对价格模式的描述或者在后处理阶段使用更复杂的正则表达式或文本解析库。商品匹配搜索“罗技 MX Master 3S”结果里可能包含不同颜色、套餐的变体。我们的指令是“第一个或最匹配的”这并不精确。生产环境中可能需要更复杂的指令如“找到标题中同时包含‘MX Master 3S’和‘无线’的商品”甚至结合图像识别来匹配产品图。反爬虫机制高频访问或特征明显的自动化流量可能被网站屏蔽。browser-use由于使用真实浏览器本身比简单HTTP请求更隐蔽但仍需注意设置合理的await asyncio.sleep()间隔、使用住宅代理IP池、以及让Agent模拟人类的不规律操作节奏如随机移动鼠标、滚动。6. 常见问题、调试与优化指南6.1 Agent行为异常排查表问题现象可能原因排查与解决思路Agent卡住不动不执行操作1. LLM API调用失败或超时。2. 页面加载过慢等待超时。3.max_steps设置过小任务未完成就停止。4. Agent陷入逻辑循环如找不到元素但不断重试。1. 检查API密钥、网络、额度。查看框架日志。2. 增加浏览器操作的超时时间。检查网络环境。3. 适当增加max_steps或在任务指令中提示“如果找不到X请尝试Y”。4.开启headlessFalse观察看页面是否如预期。在系统提示词中加入“如果三次尝试同一操作均失败请停止并报告”。Agent点击了错误的元素1. 网页状态描述不准确LLM误解了元素功能。2. 页面有多个相似元素标识符不唯一。3.temperature参数过高决策随机性大。1. 切换到multimodal感知模式让AI“看到”页面。2. 检查框架生成的元素描述。有时需要自定义解析逻辑为元素添加更独特的描述如“蓝色的提交按钮”。3. 将temperature降至0.1或0.2。Agent无法处理登录/验证码1. 登录表单复杂有动态令牌。2. 遇到图形验证码或点选验证码。1. 考虑使用预登录Cookie注入绕过登录环节。2.这是当前技术的难点。可以a) 尝试多模态模型识别简单验证码b) 集成第三方打码平台APIc) 设计流程让人类在关键时刻介入人工验证。任务成功率低时好时坏1. 任务指令模糊。2. 网页结构在不同场景下有差异如A/B测试。3. LLM模型能力不足或不稳定。1.精细化任务指令这是提升成功率最有效的方法。提供例子、明确边界条件。2. 增加Agent的容错指令如“如果看到A样式的页面做X如果看到B样式的页面做Y”。3. 升级到更强的模型如从GPT-3.5升级到GPT-4o或尝试不同的模型提供商。6.2 成本控制与性能优化使用商业LLM API是主要成本来源。优化策略包括选择性价比模型对于逻辑简单、页面描述清晰的任务gpt-3.5-turbo可能就足够了。对于需要视觉理解或复杂推理的再用gpt-4o。精简网页描述确保使用的感知模式如dom_summary能提供足够信息的同时尽可能压缩文本长度。可以自定义解析器过滤掉绝对不可交互的元素。减少不必要的步骤通过优化指令让Agent路径更直接。分析日志看Agent是否走了弯路。缓存与复用对于导航到固定页面获取信息的任务可以考虑缓存该页面的描述结果短时间内重复任务时直接使用避免重新加载页面和调用LLM进行重复观察。6.3 我的实操心得从小任务开始验证不要一开始就设计一个需要操作20步的复杂流程。先从“打开网页点击某个特定按钮”这样原子级的任务开始验证整个链路是否通畅感知是否准确。日志是你的眼睛务必开启框架的详细日志记录下LLM接收到的网页描述、LLM的思考过程如果支持以及发出的每一个动作。这是调试的唯一依据。你经常会发现AI“看”到的页面和你想象的不一样。系统提示词是方向盘花时间精心设计系统提示词。明确Agent的身份“你是一个高效、准确的数据提取助手”、行为准则“优先使用最直接的方法”、“未经确认不要提交表单”和输出格式要求。这能极大规范Agent的行为。接受一定的不确定性基于LLM的Agent本质是概率模型无法达到传统脚本100%的确定性。它的优势在于灵活性和泛化能力。评估时应关注其成功率例如95%的任务能成功而非绝对可靠。对于要求100%准确的关键业务需要设计人工审核或备用方案。组合使用browser-useAgent最适合处理非结构化的、需要一定理解和决策的网页交互。对于高度结构化、重复性极高的操作如批量处理表格每一行传统的Playwright脚本可能更高效、更经济。将两者结合用传统脚本处理固定流程用AI Agent处理其中的变体和异常往往是更优的架构。