ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Agent-Reach:让大模型真实操作网页的可达层设计与工程实践

Agent-Reach:让大模型真实操作网页的可达层设计与工程实践 1. 为什么我需要一个“可达层”而不是继续拼 API做 AI Agent 相关项目有一段时间后我遇到一个非常典型的瓶颈模型的理解能力已经足够强但“够不着”真实世界。你让 Agent 订机票、填表单、查后台报表它知道该干嘛但真正执行的时候往往卡在拿不到数据、点不到按钮、看不清页面状态这三个问题上。最开始我的方案很笨——遇到一个网站就单独写一套自动化脚本用 Selenium 硬点用接口直接调。但很快就会发现这种“逐个击破”的方式根本无法规模化每个站点的 DOM 结构不一样每个系统的登录态和交互逻辑也不一样脚本写多了以后光是维护选择器就能消耗大量精力更别提不同模型的 token 窗口限制根本塞不下整个页面的 HTML。所以我开始做 Agent-Reach 这个工具。它的定位很简单在 AI 模型和真实网页之间加一层专门为 Agent 设计的“可达层”。所谓“可达”包含两层含义第一信息可达Agent 需要能看懂页面里到底有什么第二操作可达Agent 需要能安全、稳定、可靠地执行点击、输入、选择、拖拽等动作并且能确认动作是否真的生效。这篇文章我会把 Agent-Reach 的整体设计思路、核心模块拆解、以及我在真实项目中踩过的坑都写出来。如果你正在做类似的 Web Agent、浏览器自动化、或者任何需要让 LLM 操控真实网页的项目这篇内容应该能帮你少走不少弯路。需要说明的是文中涉及的具体数据、模块划分和实现方案是我在多次迭代后总结出的相对可靠做法不代表唯一解。每个项目的上下文不同大家参考思路即可。2. Agent-Reach 的架构拆解把网页翻译给大模型听Agent-Reach 的整体架构一句话概括就是浏览器端做采集和动作执行服务端做语义处理和路由决策。这听起来像传统的“浏览器自动化”但关键区别在于Agent-Reach 的数据流向不是脚本驱动的而是模型驱动的。2.1 浏览器端模块的三个核心职责浏览器端我拆成了三个子模块采集器、动作执行器、状态监控器。采集器的职责是把当前页面的信息转成 Agent 能消化、大模型能理解的结构化快照。注意这里不是直接把document.body.innerHTML丢给模型。200KB 的 HTML 塞进上下文里既浪费 token又会让模型注意力涣散。采集器要做的是抽取、精简、语义化。动作执行器的职责是把模型返回的自然语言动作或结构化指令翻译成可执行的 DOM 操作。这一层我做过两个版本第一版是微软 Playwright 风格的 selector 定位第二版是坐标加语义双重定位。后面会专门展开讲。状态监控器用来在每次动作执行后记录页面变化。这个模块一开始我没太在意后来发现它才是整个系统能不能长期稳定跑的基石。因为大模型对“现在页面长什么样”的感知完全依赖于监控器回传的增量信息而不是每次重新全量抓取。2.2 服务端模块如何做决策服务端部分Agent-Reach 包含三个核心模块语义快照引擎、指令路由器和记忆管理单元。语义快照引擎接收浏览器端采集器回传的紧凑快照通过 LLM 或规则模板将页面结构转成一组语义卡片。比如一个登录页面在快照里可能被表达成[Form] username_input / password_input / submit_button这个层级描述就是 Agent 要做的上下文。指令路由器负责把 Agent 提出的目标比如“查询上周的订单数据”翻译成浏览器端的操作序列。这个模块有两种模式完全模型决策的自动模式和半人工确认的监督模式。生产级场景里我会强烈建议用监督模式原因会在后面安全性章节展开。记忆管理单元负责跨步记忆。Agent 操作网页是典型的长链路任务动辄几十步每步之间页面状态变化巨大模型如果没有记忆管理很容易迷失方向。Agent-Reach 会维护一个“任务进展摘要循环队列”每步结束之后把当前目标达成度、剩余步骤、重要状态回传并压缩避免上下文持续膨胀。3. 关键设计一DOM 压缩与语义卡片映射这一步省掉了 80% 的 token 开销DOM 压缩和语义映射是我觉得整个项目里性价比最高的一块。它的核心思路就是把模型需要感知的页面范围尽量缩小同时把缩小的结果转成模型真正能“看懂”的语言。3.1 为什么直接抓 HTML 是行不通的直接抓 HTML 喂给大模型看起来是最“无损”的路径但实际跑起来问题很多Token 开销太大。一个中等复杂度的电商页面HTML 轻松上 200KB换算成 token 接近 5 万意味着单次交互成本可能就是一块多几十步任务跑完成本直接失控。模型容易迷失。HTML 里大量标签是为了浏览器渲染服务的div套div的层级、内联样式、跟踪脚本对模型来说是纯粹的噪声。有用信息被淹没在噪声里模型的指令跟随质量会肉眼可见地下降。定位不精准。如果模型直接基于一段混乱的 HTML 提出操作目标很容易出现选择器错误或语义歧义这一步错了后面全错调试成本极高。3.2 Agent-Reach 的压缩流程三层筛选我设计的压缩流程分三层每层都有明确目标。第一层是结构清洗。用 TreeWalker 遍历 DOM去掉不可见节点display:none、visibility:hidden、宽高为零的元素、去掉脚本和样式标签只保留对交互有意义的节点。这一层通常能把原始 HTML 体积压掉 60% 以上。第二层是兴趣区域提取。页面上往往只有一小块区域是当前任务相关的其他部分对完成目标没有帮助。例如登录页只看表单区域数据分析页只看图表和筛选器。Agent-Reach 会把页面按元素密度和交互性切分成若干区域通过预训练的简单分类器判断哪些区域更可能与用户指令相关只压缩这些区域。第三层是语义卡片生成。把剩下的节点转成标准化的 JSON 卡片{ text: 用户名, role: textbox, hint: 请输入手机号/邮箱, constraints: {maxlength: 30}, id: el_7K3P2 }每张卡片只保留四个维度文本内容、控件角色、辅助提示、约束条件。模型拿到这个结构后几乎不需要额外推理就能理解页面在说什么也不再依赖完整的 HTML 上下文。3.3 实测数据与边界情况在几个真实站点上跑过之后我统计到一个比较典型的数据原始 HTML 200KB 的场景经过三层压缩后语义卡片大概只有 3-5KBtoken 开销降到了原来的 5% 左右而任务完成率反而提升了约 20%。原因很简单——噪声少了模型的注意力更集中。但这套逻辑也有边界。页面里有些信息虽然视觉上看不见却是理解任务的关键例如 aria-label 属性、隐藏的表单校验提示、通过 CSS 伪元素渲染的说明文字。所以压缩流程里我特意保留了一个“保留标签”白名单把aria-*系列属性和>task_state { session_id: AR-20250214-001, goal: 整理竞品价格报表, subtasks: [ {agent_type: crawler, status: done, output_ref: s3://.../raw.json}, {agent_type: analyst, status: running, task_id: cp_analysis_01}, {agent_type: reporter, status: pending} ], shared_memory: { target_urls: [...], extracted_schema: {...} } }通过这个总线三个 Agent 之间不需要知道彼此的实现细节只需要约定好读写格式。我在实际开发中最深的一点体会是Agent 之间的协议设计比 Agent 自身的提示词设计更重要。提示词写得再好接口不对齐也是白搭。5.2 状态回传的“推送 快照”双通道Agent 状态回传我采用了双通道机制。推送通道负责实时进度WebSocket 或 Server-Sent Events 把每步结果即时推给前端或下游消费者。快照通道则负责可审计性每完成一个阶段就生成一份完整快照存到对象存储里。这样既保证实时性又能在出现问题时回溯“某个时间点系统到底处于什么状态”。早期版本只用了推送通道结果线上出问题的时候根本查不到当时的完整上下文只能凭日志猜。加入快照通道后排障效率提升了不止一个量级。5.3 失败迁移与任务抢占跨 Agent 协作里Agent 挂掉是必然的不是概率问题是时间问题。所以任务总线必须支持失败迁移。我在实现里用了租约机制每个子任务被某个 Agent 认领后写入租约时间定时续租。如果某段时间没有续租其他空闲 Agent 可以抢占任务重新执行。这个机制的效果是即使个把采集 Agent 因为无头浏览器崩溃而退出整个任务流不会被中断新的 Agent 会基于最近一次快照继续跑。对于常驻在后台的长任务来说这个设计让我能安心睡个好觉。6. 实测表现与最值得说说的避坑经验到目前为止Agent-Reach 在内部已经迭代了四个大版本服务过三类典型场景信息采集与监控、表单代填与操作类任务、以及面向多 Agent 的数据分析流水线。我挑几个有代表性的实测数据和踩坑教训分享出来。6.1 三类场景的实测表现信息采集类任务每天定时抓取 20 个站点告警信息跑了一个半月任务成功率在 96% 以上。失败的基本都是目标站点改版导致的语义快照结构完全变化需要人工重新标注一次后面才能恢复。表单代填类任务代填 8 类常见业务表单包括登录、注册、申请、预约等的成功率大约在 88%。剩余的失败案例集中在两类滑块验证码以及需要文件上传但页面用了非标准拖拽交互的场景。滑块验证码代理无法绕过这是预期的短板拖拽上传则是可以通过扩展动作白名单优化的。多 Agent 数据流水线任务端到端稳定性比单 Agent 要好不少因为子任务挂了会自动抢占重跑。但在 Agent 数量超过五个之后总线瓶颈开始显现单条会话消息量过大导致响应延迟上升。目前我通过增加分片存储缓解了一部分但还没有彻底解决高并发会话下的性能问题。6.2 最值得分享的三条避坑经验第一条选择器别用固定路径。这个前面提到过但我必须再强调一次。现代前端框架普遍用动态渲染元素路径里带随机 ID、数字索引的情况太常见了。如果你还在用//div[2]/div[3]/form/input[1]这种 XPath趁早换成“语义标签 可见文本 稳定性哈希”的组合定位方式。第二条异步渲染等待策略不要想当然。对 SPA 或者大量使用 AJAX 的页面元素出现时间完全不可预测。Agent-Reach 里我强烈依赖 Playwright 的auto-waiting机制但光靠它也并不可靠尤其是在元素存在但内容还没渲染完整的情况下。后来我加了一个自定义的 waitForStable 函数本质是轮询 DOM 变化直到连续两次快照一致才继续执行实测对异步渲染场景的稳定性提升非常明显。第三条模型上下文窗口再大也扛不住几十步任务累积。早期我尝试把历史操作记录全量保留在上下文里让模型有足够信息做决策。效果并不好——步骤越往后模型越容易被早期的不相关信息干扰。Agent-Reach 的记忆管理单元采用“阶段性压缩摘要”策略每五个步骤把前面的操作压缩成一条简短摘要只保留核心状态和剩余目标上下文窗口永远保持在一个健康水位。7. 一些准备继续打磨的方向Agent-Reach 目前还称不上成熟有几块我觉得未来的空间很大。第一个是语义快照和模型之间的对齐方式。现在语义卡片是固定结构模型需要花一点理解成本去读。下一步我会尝试把快照直接转成接近模型偏好的自然语言描述比如“页面的左侧栏有筛选条件右上角有导出按钮底部表格展示了最近二十条告警记录”减少结构化 JSON 对模型推理的干扰。第二个是动作执行器的学习能力。目前动作白名单是人工维护的站点特殊操作只能靠扩展脚本解决。可以设计一个“操作模板学习模块”让系统在人工演示一次新操作类型后自动生成该操作的动作模板后续同类页面可以直接复用。第三个是离线环境下语义理解能力的降级方案。当前整个链路依赖云端大模型做语义解析一旦网络环境受限Agent-Reach 会退化成纯规则模式智能度大幅下降。我打算引入一个本地的轻量级意图识别模型至少保证“登录、查询、翻页、点击”这类高频操作在离线时也能稳定执行。做这类项目有一点体会越来越深Agent 的能力上限很大程度不取决于模型本身而取决于中间这层工具怎么设计。把真实世界的混乱信息过滤成干净的语义输入把模型意图翻译成安全可控的真实动作这个领域值得投入的时间和精力比想象中多得多但每一分投入都会直接反映在任务的稳定性和可用性上。
返回列表