别再用截图驱动浏览器了:阿里开源 Page Agent 用 DOM 脱水让大模型直接操作网页

发布时间:2026/7/5 10:39:29
别再用截图驱动浏览器了:阿里开源 Page Agent 用 DOM 脱水让大模型直接操作网页 前言做 AI Agent 落地的同学大概率都绕不开一个场景让大模型去操作一个网页——点按钮、填表单、走流程。主流做法是把 Playwright、Puppeteer、Selenium 或者 browser-use 跑在外部进程里要么喂截图给多模态模型让它看图点鼠标要么走 Chrome DevTools 协议读 DOM。这些方案能跑但有两个绕不开的成本一是要维护一个无头浏览器或驱动运行时二是看图操作这条路必须依赖更贵、更慢的多模态模型。如果你要做的是给自己产品内嵌一个 Copilot——比如让你的 SaaS 后台支持帮我提交一笔昨天的差旅报销——其实根本不需要从外面开一个浏览器去操作。阿里开源的Page Agent走了一条反常识的路它是一个纯 JavaScript 客户端库直接嵌进你的网页里把实时 DOM 当文本读让一个普通文本模型就能精准操作界面。本文会讲清楚Page Agent 和传统浏览器自动化到底差在哪、它核心的DOM 脱水是怎么把页面压成文本的、怎么用 CDN 一行或 NPM 工程化接入、以及它最大的坑API Key 暴露、单页面作用域、提示词级安全该怎么规避。项目地址alibaba/page-agentMIT 协议最新版本 v1.8.2TypeScript 优先构建在 browser-use 之上。背景或问题外部驱动的浏览器自动化到底贵在哪先把现状摆清楚。目前让大模型操作网页主流方案几乎都是从外部驱动浏览器方案运行位置读页面的方式典型用途Selenium / Playwright / Puppeteer外部进程通过 WebDriver / CDP 读 DOM脚本化端到端测试browser-use外部进程DOM 可选的视觉信息自主多站点智能体截图驱动vision 类外部进程截图喂多模态模型通用网页操作外部驱动这条路在做跨站点抓取、被锁定环境下的自动化时仍然不可替代。但如果你的目标是在自家产品里嵌一个 AI 助手它会有几个明显的累赘要单独部署运行时无头浏览器、驱动程序、有时还要一台服务器运维成本不低。看图操作贵且慢截图驱动必须用多模态模型视觉 文本调用更贵、延迟更高而且模型是在猜像素位置精度依赖分辨率和提示词。会话割裂外部浏览器和用户真实会话是两套 Cookie / 登录态要自己处理身份继承。现有校验规则失效风险如果绕过了页面本身的校验逻辑安全规则可能被破坏。换句话说在自家产品里加 Copilot和做通用网页爬虫是两个完全不同的问题强行用外部驱动方案去解前者等于杀鸡用牛刀。核心思路智能体住进网页里读 DOM 而不是看截图Page Agent 的核心定位一句话就能说清它是一个住在网页内部的 GUI Agent。你用一行 script 标签或一个 npm 包把它嵌进页面然后用自然语言下指令它就在页面里找元素、点按钮、填表单。这条路线带来三个根本变化第一它继承用户的身份。因为它就跑在用户的浏览器会话里所以用户的 Cookie、Session、登录态它天然就有不用单独写后端去维护一套机器人账号。页面里现有的前端校验、权限规则、CSRF 令牌依然生效。第二它不依赖多模态模型。它不截图而是把实时 DOM 读出来当文本喂给模型。这意味着一个足够强的纯文本模型就能胜任调用的就是普通 OpenAI 兼容端点成本和延迟都比视觉方案低。第三它是模型无关的。你通过任意 OpenAI 兼容接口自带模型换模型基本就是改baseURL和apiKey。核心机制DOM 脱水Dehydration与 FlatDomTree这一节是整篇文章技术含量最高的地方也是 Page Agent 真正的秘密武器。为什么不能直接把 HTML 塞给模型一个现代页面的 DOM 动辄几千上万个节点里面充斥着div、样式属性、广告脚本、框架运行时注入的标记。如果直接把原始 HTML 发给大模型会有两个灾难慢且贵Token 数量爆炸每次操作都要付一大笔推理费。模型迷路在一片噪音里模型很难定位到那个提交按钮到底是哪个节点。DOM 脱水只保留模型需要的关键信息Page Agent 团队管这步叫DOM 脱水Dehydration。当一条自然语言指令到达时智能体会扫描整个 DOM识别出所有可交互元素按钮、链接、输入框等给每个元素打上一个索引并提取它的角色role、标签label / aria-label、文本等关键属性。最终实时 DOM 被转换成一份叫FlatDomTree的纯文本映射——一份脱水后只保留关键内容的清单。冗余的标签、样式、脚本通通被剥掉。模型读到的不是像素、也不是原始 HTML而是这种紧凑的结构化表示。举个例子页面上一个登录按钮原始 HTML 可能长这样buttonclassbtn btn-primary mt-4 w-full focus:ring-2 focus:ring-blue-500data-testidlogin-submitonclickhandleLogin()spanclassicon icon-login/span登录/button脱水后给模型看的大概是这种形式示意非项目真实输出[index7] rolebutton name登录 inputModenone [index8] roletextbox name用户名 ... [index9] roletextbox name密码 ...模型拿到这份清单结合用户指令点击登录按钮就能精准输出操作索引 7click。精度来自读结构而不是根据像素去猜。一个循环脱水 → 决策 → 执行 → 再脱水整个执行是一个闭环updateTree()扫描 DOM生成最新的 FlatDomTree。把 FlatDomTree 用户指令发给文本模型。模型返回对索引 N 执行动作 X。clickElement(N)/inputText(N, text)/scroll(...)执行动作。页面发生变化后回到第 1 步重新脱水进入下一轮。之所以每轮都要重新updateTree()是因为页面是动态的一次点击可能让某个按钮消失、又让一批新元素出现索引也会随之变化。所以索引只在当前这一轮快照里有效不能跨轮复用——这是后面避坑的一个关键点。底层这些动作都委托给一个PageController来执行后面会贴出它的核心 API。实现步骤从一行 CDN 到工程化集成Page Agent 的接入刻意做得极低门槛官方给了两个层级一个用于快速评估的 CDN demo 脚本一个用于生产的 NPM 集成。方式一一行 CDN 脚本仅用于评估最快验证效果的方式是直接在页面里加一个 script 标签它会带上一个免费的测试用大模型!-- 全球镜像 --scriptsrchttps://cdn.jsdelivr.net/npm/[email protected]/dist/iife/page-agent.demo.jscrossorigintrue/script!-- 国内镜像访问更快 --scriptsrchttps://registry.npmmirror.com/page-agent/1.8.2/files/dist/iife/page-agent.demo.jscrossorigintrue/script这个 demo 脚本加载后会自动创建一个 demo agent你可以直接在页面上看到它的交互面板。注意官方明确说明这个 demo 端点仅供技术评估使用生产环境必须换成你自己的模型凭证。如果你不想自动初始化可以加一个查询参数手动控制scriptsrchttps://cdn.jsdelivr.net/npm/[email protected]/dist/iife/page-agent.demo.js?autoInitfalsecrossorigintrue/scriptscript// 之后用 new window.PageAgent(...) 手动实例化/script方式二NPM 工程化集成生产推荐正式项目里装包来用npminstallpage-agent然后引入并配置。最关键的是model/baseURL/apiKey三件套它们接受任何 OpenAI 兼容的服务商import{PageAgent}frompage-agentconstagentnewPageAgent({model:qwen3.5-plus,baseURL:https://dashscope.aliyuncs.com/compatible-mode/v1,apiKey:YOUR_API_KEY,language:en-US,})awaitagent.execute(Click the login button)换模型基本就是改baseURL和apiKey比如换成 OpenAI、DeepSeek、Moonshot 等任何兼容 OpenAI 接口的服务逻辑不变。PageController 的核心 API真正的 DOM 操作被封装在PageController里Agent 在底层会调用这些方法。了解它们有助于你理解执行循环也能在自定义扩展时直接用// 刷新 DOM 树生成最新的 FlatDomTree每一轮都要先调用awaitthis.pageController.updateTree()// 对指定索引的元素执行点击awaitthis.pageController.clickElement(index)// 对指定索引的输入框填写文本awaitthis.pageController.inputText(index,text)// 滚动页面awaitthis.pageController.scroll({down:true,numPages:1})注意index这个参数——它对应的是上一次updateTree()生成的索引。页面一变索引就失效了所以每次操作前都要先updateTree()不能拿着旧索引硬点。项目结构分而治之的 Monorepo源码本身是一个 Monorepo关注点拆得很细方便你按需引入或二次开发page-agent/core无头智能体的核心逻辑不含 UI。page-agent完整入口类自带交互 UI 面板。page-agent/page-controller负责 DOM 提取和元素索引并提供可选的SimulatorMask做视觉反馈就是页面上那个高亮遮罩动画。代码示例给一个内部后台加一个一句话填表助手下面是一个相对完整、贴近真实业务的例子。假设你有一个内部的费用报销后台想让它支持帮我提交一笔昨天午餐 50 元的差旅报销这样的自然语言指令。import{PageAgent}frompage-agentconstagentnewPageAgent({// 任意 OpenAI 兼容端点这里用通义千问示例model:qwen3.5-plus,baseURL:https://dashscope.aliyuncs.com/compatible-mode/v1,apiKey:YOUR_API_KEY,language:zh-CN,// 可选操作白名单限制 Agent 能做什么// 比如只允许点击和输入禁止触发删除、支付等高危动作// allowedActions: [click, input],// 可选数据屏蔽避免把密码等敏感字段发给模型// dataMasking: { selectors: [input[typepassword]] },// 可选注入自定义知识让 Agent 遵循你的业务规则// knowledge: 本系统的费用类型在「差旅」分类下金额单位为人民币元。,})asyncfunctionrunUserCommand(instruction){// 用户的一句自然语言awaitagent.execute(instruction)}// 场景用户说帮我提交一笔昨天午餐 50 元的差旅报销awaitrunUserCommand(提交一笔昨天的差旅报销类型选餐饮金额 50 元)执行时Agent 会自动完成打开报销表单 → 选择费用类型 → 填金额 → 点提交这一串动作中间每一步都会重新updateTree()来对齐最新的 DOM。如果你想在每一步关键操作前加一道人工确认生产环境强烈建议可以利用 Agent 提供的审批提示能力在提交支付这类破坏性操作前弹出确认框避免 AI 自作主张。运行结果或效果说明接入后最终用户在你的页面上会看到一个交互面板可以输入自然语言指令。一个脱水 DOM / 动作追踪的可视化区实时展示当前 FlatDomTree 和 Agent 每一步做了什么。执行时页面会有高亮遮罩SimulatorMask告诉你它正在操作哪个元素。从效果上看几个关键体感响应快因为只传文本、用纯文本模型单步决策延迟明显低于截图方案。精度高点错按钮的情况少因为它是读结构定位而不是看图猜位置。零后端评估阶段完全不用写后端生产阶段也可以前端直连模型端点但有安全前提见避坑。身份天然继承用户登录态直接可用不用再为机器人维护一套账号。横向对比Page Agent 到底该不该选把几种主流方案放到一张表里差异会非常清楚方案运行位置读页面方式设置方式最佳适用场景Page Agent页面内部客户端 JS脱水文本 DOM一个 script 标签或 npm在你拥有的应用里嵌入 CopilotSelenium / Playwright / Puppeteer外部进程驱动程序读 DOMWebDriver/CDP驱动 运行时或服务器脚本化端到端测试browser-use外部进程DOM 可选视觉Python 浏览器自主多站点智能体截图驱动vision外部进程截图 多模态无头浏览器 多模态模型通用网页操作一句话总结选型逻辑关键在于作用范围而不是速度。如果你要操作的是你自己拥有控制权、能加代码的产品Page Agent 是更轻、更省、更准的选择。如果你要做的是跨站点抓取、被锁定环境下的自动化外部驱动方案Playwright / browser-use仍然占优。Page Agent 官方也明确自我定位它是为客户端 Web 增强设计的不是用来做服务端自动化的。常见问题与避坑这一节是真正落地时会踩到的地方重点说三个。避坑一API Key 会暴露在前端生产必须走后端代理这是最容易被忽视、也最危险的一点。new PageAgent({ apiKey })这种写法apiKey 会被编译进你的客户端代码包任何用户都能在浏览器里扒出来。正确做法是在生产环境搭一个你自己的轻量后端代理前端调用你的代理由代理带上密钥去请求模型。官方也提示Agent 可以在执行每个关键操作前显示审批提示配合使用更安全。避坑二单页面作用域跨标签页要装扩展核心库的目标是单个视图内的交互它没法自己跨标签页或跨窗口移动。如果你需要多页面自动化要用官方提供的可选Chrome 扩展需要单独安装和授权。另外还有一个 Beta 版的MCP Server可以让外部 Agent 客户端比如 Claude Desktop、Copilot来驱动它。所以别指望用一个script标签就搞定跨页签的复杂流程——那是扩展的活。避坑三提示词级安全不是硬约束高危操作要服务端兜底Page Agent 支持在系统提示词里写规则比如永远不要自动提交支付表单。但必须清醒地认识到这只是引导性建议不是硬性保证。提示词可以被绕过、被绕话术诱导它不应该成为你唯一的安全措施。对于任何敏感或破坏性操作支付、删除、数据导出正确的做法是在操作白名单里直接禁止这类动作。在执行前强制人工确认HITL。在服务端保留最终校验——这才是真正可靠的防线。这个思路和我们做 Function Calling 安全护栏是一样的执行权、校验权、审计权永远要在服务端而不是交给模型的自觉性。避坑四索引不跨轮复用前面提过再强调一遍FlatDomTree 的索引只在当前这一轮快照有效。页面一变就要重新updateTree()千万不要把上一轮拿到的索引缓存下来复用否则会点错元素。总结Page Agent 给在自家产品里嵌 AI 助手这件事提供了一个很漂亮的解法它把浏览器自动化的范式从外部驱动 截图识别翻转成页面内 JS DOM 文本读取。回顾一下它的三个核心价值更低成本只传文本避免了多模态模型的调用方式和计费精度来自读结构而非猜像素。更强集成几行代码就能交付一个 AI 助手不用重写后端不用分发浏览器扩展。天然继承身份跑在用户会话里Cookie、登录态、现有校验规则都还在。但它也有清晰的边界API Key 必须用后端代理保护、核心库只管单页面、提示词级安全不能替代服务端校验。它最适合的场景是把你自己的应用变成一个能用自然语言操作的智能产品而不是用来爬别人的网站或操作被锁定的环境。如果你的项目正好是 SaaS 后台、ERP/CRM、内部工具这类表单多、流程长、用户叫苦的系统Page Agent 值得花一个下午试一下——一行 CDN 就能跑起来评估成本极低。