ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

构建AI驱动的网页自动化智能体:从LLM规划到Playwright执行

2026/8/20 23:54:37 拓冰建站 浏览量
构建AI驱动的网页自动化智能体:从LLM规划到Playwright执行 在实际项目中我们常常需要让AI模型能够访问实时网络信息或与网页应用交互比如自动抓取数据、填写表单、监控网页变化等。传统的做法是手动编写爬虫脚本或使用浏览器自动化工具但这类工作往往需要开发者持续维护且难以处理复杂的、动态变化的网页逻辑。将大型语言模型与浏览器环境结合构建一个能够自主理解网页、执行任务并学习的AI Agent正成为解决这类问题的新思路。本文将以一个概念性的“给Codex装浏览器”项目为引深入探讨如何构建一个具备网页自动化能力的AI Agent系统。我们将从核心概念讲起逐步完成环境搭建、基础功能实现、核心逻辑开发并最终实现一个能够理解指令、操作浏览器并完成简单任务的智能体。文章适合对AI应用开发、自动化脚本和Web技术有一定了解的开发者目标是提供一个可复现、可扩展的技术实现方案。1. 理解AI Agent与浏览器自动化的结合点在深入代码之前我们需要厘清几个核心概念以及它们如何组合成一个能“自己上网干活”的系统。1.1 什么是AI AgentAI Agent智能体通常指一个能够感知环境、自主决策并执行行动以实现目标的软件实体。在本文语境下我们构建的是一个基于大型语言模型的Agent。它的核心工作流程是接收一个自然语言描述的任务例如“查看今日科技新闻头条”然后将其分解为一系列可执行的步骤打开浏览器、导航到新闻网站、定位头条元素、提取文本最后调用相应的工具如浏览器控制模块来执行这些步骤并根据执行结果决定下一步行动。1.2 为什么选择浏览器作为环境浏览器是现代信息交互的核心入口。一个能控制浏览器的Agent相当于获得了与绝大多数Web服务交互的能力。这与单纯调用API不同浏览器自动化可以处理动态内容应对由JavaScript渲染的页面。模拟用户操作完成点击、输入、滚动等真实用户行为。绕过API限制直接操作那些未提供开放接口的网站。具备通用性一套逻辑理论上可适配于任何网站尽管实际需要针对不同站点进行优化。1.3 核心架构设计我们的系统将采用分层架构确保各模块职责清晰任务理解与规划层LLM核心接收用户指令理解意图并将其分解为具体的、序列化的浏览器操作指令。这是系统的大脑。浏览器控制层自动化驱动提供一套稳定的API用于执行诸如打开网页、查找元素、点击、输入文本、获取页面内容等底层操作。这是系统的手和眼睛。执行与协调层Agent逻辑连接大脑和手脚。它调用规划层生成指令再调用控制层执行指令并处理执行过程中的异常如元素未找到、页面加载超时决定重试或调整策略。记忆与状态管理层记录当前任务进度、已访问的页面、获取到的信息等为后续步骤提供上下文。2. 环境准备与核心工具选型构建此类项目工具链的选择至关重要。我们需要一个强大的浏览器自动化库和一个能够进行任务规划的LLM接口。2.1 开发环境与依赖假设我们使用Python作为主要开发语言这是目前AI和自动化领域最流行的选择。首先创建项目并安装核心依赖。我们选择Playwright作为浏览器自动化工具因为它支持多浏览器Chromium, Firefox, WebKit且API现代、性能优异。对于LLM我们使用OpenAI的API兼容OpenAI API的本地模型亦可。# 创建项目目录并初始化虚拟环境 mkdir ai-browser-agent cd ai-browser-agent python -m venv venv # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate # 安装核心依赖 pip install playwright openai python-dotenv # 安装Playwright所需的浏览器 playwright install chromium项目根目录下创建requirements.txt文件记录依赖playwright1.40.0 openai1.12.0 python-dotenv1.0.02.2 工具选型对比与说明为什么是Playwright而不是Selenium或Puppeteer工具优点缺点适用场景Playwright跨浏览器、自动等待、网络拦截、移动端模拟、录制功能强大。相对较新某些极端场景社区方案可能较少。本文推荐。适合需要稳定、功能全面的现代浏览器自动化。Selenium生态成熟、社区庞大、支持语言多。配置稍复杂处理动态页面等待需要更多代码。企业级测试、需要多语言支持Java/C#的项目。Puppeteer与Chrome DevTools协议深度集成性能好。主要支持Chrome/Chromium。专注于Chrome生态的爬虫或生成PDF等。对于LLM我们使用OpenAI的gpt-3.5-turbo或gpt-4模型它们擅长理解和生成结构化指令。如果考虑成本或离线运行可以替换为通过litellm等库兼容的本地模型如Qwen、DeepSeek等。2.3 配置文件与密钥管理永远不要将API密钥硬编码在代码中。我们使用.env文件来管理敏感信息。在项目根目录创建.env文件OPENAI_API_KEYsk-your-openai-api-key-here # 可以设置其他配置如模型选择、超时时间等 OPENAI_MODELgpt-3.5-turbo REQUEST_TIMEOUT30同时创建.gitignore文件确保.env和虚拟环境目录不会被提交到版本库venv/ __pycache__/ *.pyc .env .playwright/3. 构建浏览器控制层Playwright驱动这是Agent的“手脚”必须稳定可靠。我们将封装一个BrowserController类提供高层级的操作方法。3.1 基础控制器实现创建browser_controller.py文件import asyncio from playwright.async_api import async_playwright, TimeoutError as PlaywrightTimeoutError import logging logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) class BrowserController: 浏览器控制核心类封装Playwright操作 def __init__(self, headless: bool False): 初始化控制器 :param headless: 是否无头模式不显示浏览器界面 self.headless headless self.browser None self.context None self.page None self.playwright None async def start(self): 启动浏览器和上下文 try: self.playwright await async_playwright().start() # 使用Chromium可更换为 firefox 或 webkit self.browser await self.playwright.chromium.launch(headlessself.headless) # 创建上下文可以设置视窗大小、用户代理等 self.context await self.browser.new_context( viewport{width: 1920, height: 1080}, user_agentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ) self.page await self.context.new_page() logger.info(浏览器启动成功) except Exception as e: logger.error(f启动浏览器失败: {e}) raise async def goto(self, url: str, timeout: int 30000): 导航到指定URL try: await self.page.goto(url, timeouttimeout, wait_untilnetworkidle) logger.info(f已导航至: {url}) return True except PlaywrightTimeoutError: logger.warning(f页面加载超时但可能已部分加载: {url}) return True except Exception as e: logger.error(f导航到 {url} 失败: {e}) return False async def get_page_content(self, simplified: bool True) - str: 获取当前页面内容 :param simplified: 是否简化内容去除脚本、样式等 if simplified: # 执行JavaScript获取页面的主要文本内容这是一个简单示例 content await self.page.evaluate( () { // 移除脚本和样式标签 const elementsToRemove document.querySelectorAll(script, style, nav, footer, iframe); elementsToRemove.forEach(el el.remove()); // 获取body文本或特定内容区域 const main document.querySelector(main) || document.querySelector(article) || document.body; return main.innerText; } ) else: content await self.page.content() return content[:5000] # 限制返回长度避免上下文过长 async def find_and_click(self, selector: str, timeout: int 5000): 查找元素并点击 try: await self.page.click(selector, timeouttimeout) logger.info(f已点击元素: {selector}) return True except Exception as e: logger.error(f点击元素 {selector} 失败: {e}) return False async def find_and_type(self, selector: str, text: str, timeout: int 5000): 查找输入框并输入文本 try: await self.page.fill(selector, text, timeouttimeout) logger.info(f已在元素 {selector} 中输入文本: {text}) return True except Exception as e: logger.error(f在元素 {selector} 中输入文本失败: {e}) return False async def wait_for_selector(self, selector: str, state: str visible, timeout: int 10000): 等待特定元素出现 try: await self.page.wait_for_selector(selector, statestate, timeouttimeout) return True except Exception as e: logger.warning(f等待元素 {selector} 失败: {e}) return False async def stop(self): 停止浏览器释放资源 if self.browser: await self.browser.close() if self.playwright: await self.playwright.stop() logger.info(浏览器已关闭)3.2 关键操作解析与常见坑启动参数headless开发调试时设为False可以看到浏览器操作过程便于排查问题。在生产环境或服务器运行时应设为True以节省资源。等待策略wait_untilpage.goto中的wait_until参数至关重要。‘networkidle’表示等待网络空闲适合大多数SPA单页应用。如果页面加载过慢可考虑使用‘domcontentloaded’DOM加载完成或自定义等待逻辑。元素选择器Playwright支持CSS选择器、XPath、文本选择器等。page.click(‘text登录’)可以点击包含“登录”文本的元素。但文本选择器在动态内容中可能不稳定优先使用CSS选择器或具有># 错误做法直接点击可能因元素未加载而失败 await page.goto(‘https://example.com’) await page.click(‘#submit-btn’) # 可能失败 # 正确做法加入等待 await page.goto(‘https://example.com’, wait_until‘networkidle’) await page.wait_for_selector(‘#submit-btn’, state‘visible’) await page.click(‘#submit-btn’)常见坑2获取的内容包含无关噪音直接获取page.content()会得到完整的HTML包含大量脚本、样式和广告代码不利于LLM理解。我们提供的get_page_content(simplifiedTrue)方法通过执行JavaScript来提取主要文本内容是一个简单的净化步骤。对于复杂页面可能需要更精细的提取策略。4. 构建任务规划层LLM驱动这是Agent的“大脑”。我们将设计一个TaskPlanner类其核心功能是将用户的自然语言指令解析成一系列标准的、可被浏览器控制器执行的原子操作。4.1 定义操作指令集首先我们需要定义一套Agent能理解的有限指令集。这类似于给LLM规定一套“语法”。创建actions.py文件from enum import Enum from pydantic import BaseModel, Field from typing import List, Optional class ActionType(str, Enum): 可执行的操作类型枚举 NAVIGATE navigate # 导航到URL CLICK click # 点击元素 TYPE type # 输入文本 EXTRACT extract # 提取内容 WAIT wait # 等待 SCROLL scroll # 滚动 DECISION decision # 决策点如判断是否登录成功 class BrowserAction(BaseModel): 单个浏览器操作的模型 action: ActionType Field(description要执行的操作类型) target: Optional[str] Field(defaultNone, description操作目标如URL或CSS选择器) value: Optional[str] Field(defaultNone, description操作值如输入的文本) description: str Field(description该步骤的人类可读描述) wait_after: Optional[float] Field(default1.0, description操作后等待的秒数用于页面稳定)4.2 实现基于LLM的任务规划器创建task_planner.py文件。我们将使用OpenAI的Function Calling或工具调用能力让LLM根据我们的指令集来规划步骤。import os import json import logging from openai import OpenAI from dotenv import load_dotenv from actions import BrowserAction, ActionType from typing import List load_dotenv() logger logging.getLogger(__name__) class TaskPlanner: def __init__(self, model: str None): self.client OpenAI(api_keyos.getenv(OPENAI_API_KEY)) self.model model or os.getenv(OPENAI_MODEL, gpt-3.5-turbo) # 定义LLM可用的“工具”即我们的操作指令集 self.tools [ { type: function, function: { name: plan_browser_actions, description: 将复杂的自然语言任务分解为一系列具体的浏览器操作步骤。, parameters: { type: object, properties: { actions: { type: array, items: { type: object, properties: { action: {type: string, enum: [at.value for at in ActionType]}, target: {type: string}, value: {type: string}, description: {type: string}, wait_after: {type: number} }, required: [action, description] }, description: 按顺序执行的浏览器操作列表 } }, required: [actions] } } } ] def plan(self, user_task: str, current_context: str ) - List[BrowserAction]: 根据用户任务和当前上下文规划行动步骤 :param user_task: 用户指令如“搜索OpenAI的最新新闻” :param current_context: 当前页面或任务上下文信息 :return: 规划好的浏览器操作列表 system_prompt 你是一个专业的网页自动化助手。你的任务是将用户用自然语言描述的任务分解成一步步具体的、可执行的浏览器操作。 可用的操作类型包括 - navigate: 导航到一个新的URL。target应为完整的URL。 - click: 点击一个页面元素。target应为CSS选择器或文本描述如‘text登录’。 - type: 在输入框中输入文本。target为选择器value为要输入的文本。 - extract: 从当前页面提取信息。description应说明提取什么。 - wait: 等待一段时间或等待某个条件。target可以是选择器或秒数。 - scroll: 滚动页面。 - decision: 根据页面内容做出判断如‘检查登录是否成功’。 请确保步骤逻辑清晰、顺序正确并考虑到页面加载时间适当添加wait_after。 如果用户指令模糊请基于常识做出合理假设例如搜索使用Google。 user_prompt f用户任务{user_task}\n if current_context: user_prompt f当前上下文{current_context}\n user_prompt 请规划浏览器操作步骤 try: response self.client.chat.completions.create( modelself.model, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt} ], toolsself.tools, tool_choice{type: function, function: {name: plan_browser_actions}}, temperature0.1 # 低温度确保输出稳定 ) # 解析LLM的响应 tool_call response.choices[0].message.tool_calls[0] arguments json.loads(tool_call.function.arguments) actions_data arguments.get(actions, []) # 将字典转换为BrowserAction对象 planned_actions [] for act in actions_data: # 确保action是有效的ActionType act[“action”] ActionType(act[“action”]) planned_actions.append(BrowserAction(**act)) logger.info(f任务‘{user_task}’规划完成生成{len(planned_actions)}个步骤) return planned_actions except Exception as e: logger.error(f任务规划失败: {e}) # 返回一个保守的默认计划打开Google搜索 return [ BrowserAction( actionActionType.NAVIGATE, targethttps://www.google.com, description导航到Google首页 ) ]4.3 规划逻辑解析与提示工程系统提示词System Prompt这是指导LLM行为的关键。我们明确限定了它的角色、可用操作集以及输出格式要求。清晰的约束能大幅提高输出结果的稳定性和可用性。工具调用Tool Calling我们使用了OpenAI的tools参数。这比让LLM直接输出JSON更可靠因为API会强制LLM按照我们定义的函数签名来生成结构化数据。温度Temperature设置为较低的0.1是为了让规划结果尽可能确定和可重复避免LLM的随机性导致步骤混乱。错误回退在except块中我们提供了一个最保守的默认计划打开Google。在实际项目中可以根据错误类型设计更复杂的重试或降级策略。常见坑3LLM规划出不可执行或模糊的步骤LLM可能会生成“click the login button”这样的描述但target字段是空的或者给出“button.login-btn”这样在目标页面上不存在的选择器。缓解策略1在系统提示词中严格要求target字段必须为有效的CSS选择器或文本描述。缓解策略2在后续的Agent执行层加入验证和修复逻辑例如如果target为空可以尝试用description中的关键词重新生成选择器或者让LLM根据当前页面HTML重新规划。5. 构建执行与协调层AI Agent核心现在我们将“大脑”TaskPlanner和“手脚”BrowserController连接起来并赋予其处理异常和做出简单决策的能力。创建ai_agent.py文件。5.1 基础Agent实现import asyncio import logging from browser_controller import BrowserController from task_planner import TaskPlanner from actions import BrowserAction, ActionType logger logging.getLogger(__name__) class BrowserAgent: AI Agent核心协调类 def __init__(self, headless: bool False, model: str None): self.controller BrowserController(headlessheadless) self.planner TaskPlanner(modelmodel) self.context # 存储当前任务上下文如页面摘要、提取的信息等 self.max_retries 2 # 单个操作最大重试次数 async def initialize(self): 初始化Agent启动浏览器 await self.controller.start() async def execute_task(self, user_task: str) - str: 执行用户任务的主入口 :param user_task: 自然语言描述的任务 :return: 任务执行结果摘要 logger.info(f开始执行任务: {user_task}) final_result # 步骤1规划 planned_actions self.planner.plan(user_task, self.context) if not planned_actions: return 任务规划失败无法执行。 # 步骤2按顺序执行规划好的动作 for i, action in enumerate(planned_actions): logger.info(f执行步骤 {i1}/{len(planned_actions)}: {action.description}) success await self._execute_single_action(action) if not success: logger.warning(f步骤‘{action.description}’执行失败尝试重新规划或终止。) # 简单策略失败后停止整个任务 final_result f任务在执行步骤‘{action.description}’时失败。 break # 步骤执行成功后更新上下文例如记录页面内容变化 await self._update_context_after_action(action) # 操作后等待让页面稳定 await asyncio.sleep(action.wait_after or 1.0) # 步骤3收集最终结果 if not final_result: final_result await self._collect_final_result(user_task) logger.info(f任务执行完毕。结果: {final_result[:100]}...) return final_result async def _execute_single_action(self, action: BrowserAction) - bool: 执行单个浏览器动作包含重试逻辑 for retry in range(self.max_retries): try: if action.action ActionType.NAVIGATE: return await self.controller.goto(action.target) elif action.action ActionType.CLICK: # 如果target是‘textxxx’格式需要特殊处理这里假设planner已生成正确选择器 return await self.controller.find_and_click(action.target) elif action.action ActionType.TYPE: return await self.controller.find_and_type(action.target, action.value) elif action.action ActionType.WAIT: if action.target and action.target.isdigit(): await asyncio.sleep(int(action.target)) else: # 假设target是选择器等待元素出现 await self.controller.wait_for_selector(action.target) return True elif action.action ActionType.EXTRACT: # 提取操作获取页面内容并存储到上下文 content await self.controller.get_page_content() self.context f\n[提取信息]: {action.description}\n内容摘要: {content[:1000]}\n return True elif action.action ActionType.SCROLL: await self.controller.page.evaluate(window.scrollBy(0, 500)) return True elif action.action ActionType.DECISION: # 决策操作可以获取当前页面内容让LLM做简单判断 logger.info(f决策点: {action.description}) return True else: logger.error(f未知的操作类型: {action.action}) return False except Exception as e: logger.warning(f动作执行失败 (重试 {retry1}/{self.max_retries}): {action.description}, 错误: {e}) await asyncio.sleep(2) # 失败后等待2秒再重试 return False # 重试多次后仍失败 async def _update_context_after_action(self, action: BrowserAction): 执行动作后更新上下文例如记录页面URL或标题 try: title await self.controller.page.title() url self.controller.page.url self.context f\n[步骤‘{action.description}’后] 页面标题: {title}, URL: {url}\n except: pass async def _collect_final_result(self, user_task: str) - str: 收集任务最终结果例如获取当前页面关键信息 try: # 简单实现返回页面标题和前500字符内容 title await self.controller.page.title() content await self.controller.get_page_content(simplifiedTrue) return f任务‘{user_task}’执行完成。最终页面: 《{title}》。内容摘要: {content[:500]} except Exception as e: return f任务执行完成但收集结果时出错: {e} async def close(self): 关闭Agent释放资源 await self.controller.stop()5.2 运行一个完整示例创建main.py作为程序入口import asyncio import sys from ai_agent import BrowserAgent from dotenv import load_dotenv load_dotenv() async def main(): # 初始化AgentheadlessFalse便于观察 agent BrowserAgent(headlessFalse, modelgpt-3.5-turbo) try: await agent.initialize() print(AI Browser Agent 已启动。输入任务指令输入‘quit’退出:) while True: user_input input(\n ).strip() if user_input.lower() in [quit, exit, q]: break if not user_input: continue print(f执行任务: {user_input}) result await agent.execute_task(user_input) print(f结果: {result}) except KeyboardInterrupt: print(\n程序被用户中断。) except Exception as e: print(f程序运行出错: {e}) finally: await agent.close() print(Agent已关闭。) if __name__ __main__: # 处理Windows上asyncio的事件循环策略 if sys.platform win32: asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) asyncio.run(main())现在运行程序并尝试一个简单任务python main.py在提示符后输入“打开百度搜索‘人工智能最新进展’然后点击第一个搜索结果。”你将看到浏览器自动启动导航到百度输入搜索词点击搜索按钮然后尝试点击第一个结果链接。这就是你的AI Agent在“自己上网干活”。5.3 执行层的关键设计原子操作映射_execute_single_action方法将抽象的BrowserAction映射到具体的BrowserControllerAPI调用。这是连接规划与执行的关键桥梁。重试机制网络波动、元素加载稍慢都可能导致单次操作失败。简单的重试2-3次往往能解决问题。上下文管理self.context变量记录了任务执行过程中的关键信息如页面标题、URL、提取的内容。这个上下文会在规划下一个任务或步骤时反馈给LLM使其具备“记忆”能力做出更连贯的决策。同步与等待每个操作后都有wait_after等待时间这是对网络和渲染延迟的简单补偿。更复杂的做法是等待特定元素出现或网络请求完成。6. 常见问题排查与优化策略一个原型能跑起来只是第一步要让它在复杂真实场景中稳定工作需要处理大量边界情况。6.1 典型问题与解决方案问题现象可能原因检查与解决思路浏览器启动失败1. Playwright浏览器未安装。2. 端口冲突或无头模式在服务器环境缺少依赖。1. 运行playwright install chromium。2. 服务器环境需安装系统依赖playwright install-deps。页面加载超时1. 网络慢或目标网站不可达。2.wait_until策略过于严格。3. 网站有复杂前端框架如Next.js需要更长时间。1. 增加goto的timeout参数。2. 将wait_until改为‘domcontentloaded’。3. 添加自定义等待如page.wait_for_function(‘window.nextReady’)。元素找不到或点击失败1. 选择器错误或页面结构已变。2. 元素在iframe内。3. 元素被遮挡或未处于可交互状态。1. 使用浏览器开发者工具重新确认选择器。可让LLM根据当前页面HTML重新生成选择器。2. 使用page.frame_locator()定位iframe内元素。3. 使用page.click(selector, forceTrue)强制点击或先滚动到元素处。LLM规划步骤不合理1. 提示词不够清晰。2. 任务过于复杂或模糊。3. 模型能力限制。1. 优化系统提示词提供更具体的示例。2. 要求用户给出更明确指令或让Agent先澄清问题。3. 升级到更强大的模型如GPT-4或引入“反思”步骤让LLM检查上一步结果再规划下一步。被网站识别为机器人1. 请求头、指纹过于标准。2. 操作速度过快、过于规律。1. 在new_context中设置更真实的user_agent、viewport甚至启用ignore_https_errors并加载特定指纹插件需谨慎。2. 在操作间加入随机延迟模拟人类操作。6.2 增强Agent的健壮性引入反思与修复上述基础Agent在步骤失败后会直接停止。一个更智能的Agent应该能尝试自我修复。我们可以修改_execute_single_action失败后的逻辑async def _execute_single_action(self, action: BrowserAction) - bool: # ... 原有的执行逻辑 ... except Exception as e: logger.warning(f“动作执行失败: {action.description}, 错误: {e}”) # 尝试修复获取当前页面HTML让LLM分析失败原因并生成新动作 if retry self.max_retries - 1: # 最后一次重试前尝试修复 html_snippet await self.controller.page.content() new_action await self._replan_failed_action(action, html_snippet, str(e)) if new_action: logger.info(f“已重新规划步骤: {new_action.description}”) action new_action await asyncio.sleep(2) return False需要实现一个_replan_failed_action方法将错误信息、当前页面片段和原动作发送给LLM请求其分析原因并给出修正后的动作。这构成了一个简单的“感知-决策-执行”闭环。7. 生产环境最佳实践与扩展方向将实验性项目转化为可用的生产组件还需要考虑更多因素。7.1 安全与合规考量遵守Robots协议在robots.txt中检查目标网站是否允许爬取。控制访问频率在操作间添加随机延迟避免对目标网站造成负载压力。数据隐私如果处理用户数据或敏感信息确保符合相关法律法规如GDPR。API密钥管理使用安全的密钥管理服务而非硬编码在环境变量文件中。7.2 性能与可维护性优化浏览器上下文复用对于连续任务不要频繁启动关闭浏览器复用BrowserContext可以提高效率。操作超时配置化将各类超时时间加载、点击、等待提取为配置项便于针对不同网站调整。日志与监控记录详细的操作日志和错误日志便于回溯问题。可以集成像Sentry这样的错误监控平台。任务队列对于大量任务引入消息队列如RabbitMQ, Redis进行异步处理Agent作为Worker从队列消费任务。容器化部署使用Docker封装整个应用确保环境一致性。注意在Dockerfile中安装Playwright的系统依赖。7.3 扩展功能方向多模态输入结合视觉模型如GPT-4V让Agent能“看到”页面截图从而处理无法通过HTML解析的复杂UI如Canvas图表、验证码。工具扩展除了浏览器Agent可以集成其他工具如调用外部API、读写本地文件、执行命令行命令成为一个更通用的自动化助手。长期记忆将执行历史、成功经验、网站结构信息存入向量数据库使Agent能积累知识越用越聪明。人机协同在Agent不确定时如遇到验证码能够暂停并请求人类干预形成人机协作流程。通过以上步骤我们完成了一个具备基础网页自动化能力的AI Agent从概念到实现的完整过程。它虽然简单但清晰地展示了如何将大语言模型的规划能力与浏览器自动化工具的执行能力相结合。在实际应用中你需要根据具体场景不断迭代规划提示词、增强错误处理逻辑、优化浏览器操作策略。这个项目的核心价值在于提供了一个可扩展的框架你可以在此基础上构建出真正能替你处理复杂、重复性网页任务的智能助手。