你的智能体记住的浏览器选择器
上周二,你的 computer-use 智能体表现出色。它登录了供应商门户,点击了五层嵌套菜单,导出了报告,将其附加到工单中,并在不到两分钟内完成了任务。你保存了轨迹。你赞美了模型。你发布了工作流。然而,在那个成功的轨迹中,智能体记住了一个信息:“导出 CSV”操作位于 div.toolbar > div:nth-child(2) > button.btn-secondary:nth-child(4)。
到了周五,供应商推送了重新设计。工具栏现在是一个 flex 容器,次要按钮被放进了下拉菜单,而“导出”这个动作被一个下载图标取代了。你智能体记下的路径现在指向空——或者更糟,它指向了一个现在显示为“删除账户”的按钮。智能体无法分辨其中的区别。两者都是按钮。两者都在同一个选择器位置。周二留下的轨迹不再是记忆,而是一颗地雷。
这是那种没人会写进复盘报告的故障模式,因为没人会记录诱因。智能体完成了工作。网站发生了变化。智能体重新运行了工作。智能体做了些可怕的事情。连接这三个事件的线索贯穿了一种记忆形态,这种形态比你系统中任何其他知识老化得都快,而大多数团队从未给它命名。
Web 是世界上最动荡的 API
后端 API 有版本、弃用策略和 SLA。一个毫无预警就挂掉的 REST 端点是违反合同的。删除字段的模式迁移有六个月的弃用窗口。整个生态系统都建立在一个假设之上:你的客户端耦合的表面明天还会存在。
DOM 则完全相反。DOM 是一种渲染。它是团队本季度发布的任何前端框架的输出,经过任何构建工具压缩类名,由他们刚刚采用的任何组件库进行注水。按钮不是按钮——它是按钮当前的渲染结果。CSS 类 btn-primary-v2 不是标识符——它是构建产物的哈希值,在下次部署时就会变得不同。
行业数据在大规模层面上证实了这一点。长期维护跨多站点爬虫的团队,通常有 30% 到 40% 的工程时间花在维持选择器的可用性上。在某些行业,10% 到 15% 的爬虫每周都需要仅仅因为 DOM 变动而进行修复。据估计,失效的爬虫、维护开销和错失的数据机会每年造成的损失高达数十亿美元。这些摩擦并非来自数据本身,而是来自数据渲染方式的摩擦。
你的智能体在记住 CSS 路径时,也就踏上了同样的维护跑步机——只不过,周一早上发现故障的不是人类,而是智能体会充满自信地操作错误的解析器,并产生一个错误的结果,而在轨迹记录中,这看起来却像是一个成功的动作。
两种故障形态,一个诱因
第一种故障形态很简单:选择器解析为空。智能体点击了一个空路径,页面没有响应,超时触发,监控系统记录下“找不到元素”的错误。这是你的团队最终能抓到的版本,因为它会产生明显的、可观测的失败,并触发错误仪表盘。
第二种故障形态是危险的:选择器解析到了不同的元素。以前是“导出”的 nth-child(4) 现在变成了“删除”。以前是搜索的表单字段 input[name='q'] 现在变成了隐藏的追踪输入。以前是“确认”的 div.modal > button.primary 按钮现在变成了模态框的关闭按钮——而智能体的成功标准(定义为“点击返回且未报错”)显示为绿色。智能体报告任务完成。智能体原本打算导出的数据,实际上被删除了。
选择器不是合同。它们是智能体无法控制的坐标系中的坐标。当坐标系发生偏移时,坐标不会变得无效——它们会变得错误。智能体无法区分“这是我想要的元素”和“这只是刚好占据了我记忆位置的元素”,因为在路径字符串查找看来,两者是一模一样的。
这就是为什么选择器衰减(selector-decay)不是重试就能解决的问题。更努力地重试点击错误的元素并不会让它变成正确的元素。需要告诉智能体这个元素 是什么,而不是它 在哪里。
语义锚点优于句法锚点
弥补这一差距的模式是停止按树路径索引页面,转而按含义索引页面。现代自动化框架已经趋向于这一理念,那些在网站重构中幸存下来 的生产级智能体也都遵循这一原则。
Playwright 的 getByRole 是一个典型例子。你不再使用 button.toolbar-export,而是通过其可访问角色(accessible role)和名称来定位按钮:一个可访问名称匹配“导出”的按钮。无障碍树——浏览器向屏幕阅读器展示的结构——比 DOM 树持久得多,因为受法律无障碍要求和对辅助技术的承诺驱动,网站最有压力去保护这一契约。一个将类名重命名为 btn-v3-export-primary 的网站,不太可能同时剥离按钮的可访问名称。
同样的逻辑也适用于定位器堆栈。getByText 通过可见标签寻找元素,这追踪的是用户的心理模型,而非工程团队的类分类法。getByLabel 通过关联的标签寻找表单字段,这与视力正常的用户的导航锚点相同。这些方法中的每一步都更接近“用户认为这个元素是什么”,而远离“工程师今早恰好把这个元素放在了哪里”。
对于智能体来说,这意味着要改变成功运行后存储的内容。不要存储 div.toolbar > button:nth-child(4)。要存储“报告工具栏中标记为‘导出 CSV’的按钮”。前者是坐标。后者是描述。前者在渲染改变的瞬间就会失效。后者在功能被移除之前都能存活。
基于视觉落地的回退与重新规划
即使是语义锚点也不是万无一失的。网站确实会重命名按钮。标签确实会改变。语言确实会本地化。下一层防御是承认页面不再是智能体(agent)记忆中的那个页面,并根据意图重新 推导路径。
生产环境中的计算机使用(computer-use)智能体趋向于采用一种混合模式:当 DOM 与记忆一致时,解析 DOM 以获取速度和结构;当 DOM 不一致时,回退到视觉方案。视觉过程会拍摄截图,询问“我打算执行的操作在哪里”,并从当前的渲染中生成新的落地(grounding),而不是使用存储的路径。这比 DOM 查找更慢、更昂贵,但它是从智能体从未见过的布局中优雅恢复的唯一机制。
架构层面的承诺是:选择器失效不是可重试的失败,而是规划失败。智能体不会更努力地重试相同的路径;它会放弃该路径,重新读取页面,并重新推导操作所在的位置。自愈自动化框架已将此循环直接构建到其运行时中。“愈合智能体”(Healing Agent)模式在重试后主要目标定位失败时,会启用语义回退——在宣布元素缺失之前,二级和三级定位方法会带着各自的落地逻辑接管工作。
这对你智能体的记忆层意味着存储的选择器需要一个明确的衰减策略。每个存储的路径都应该带有新鲜度时间戳、置信度分数,以及在执行任何关键操作之前针对实时 DOM 进行的重新验证步骤。超过 72 小时未验证的选择器应被视为提示(hint),而非坐标。对于当前页面修订版本验证次数为零的选择器,永远不应被用于执行破坏性操作——只能用于引导视觉过程以确认实际位置。
评估漂移,而不仅仅是成功率
这种失败模式之所以在生产环境中依然存在,是因为团队用来评估计算机使用智能体的基准测试(benchmarks)奖励的是在评估时智能体所见页面上的任务完成情况。WebArena、VisualWebArena 和类似的评估工具运行在快照环境中,在智能体的训练和评估运行之间,DOM 不会发生变化。现实世界的基准测试(如 BrowserArena)已开始揭示只有当智能体遇到动态页面时才会出现的失败模式——验证码解析、弹窗关闭、重定向处理——但选择器衰减(selector decay)本身很少被衡量。
能及早捕捉选择器衰减的评估方法是对抗性的:获取目标网站的副本,以真实重新设计可能发生的方式扰动其 DOM(重命名类名、将 div 换成 button、重新排序子元素、延迟加载片段),并针对扰动后的版本运行智能体。成功的指标不是智能体是否完成了任务,而是智能体是否检测到了漂移并进行了恢复或询问,而不是自信地点击了错误的元素。
一个有益的补充是对智能体自身的操作流进行插桩,以记录每个操作中哪种定位方法取得了成功:是语义锚点起作用了,还是智能体回退到了视觉方案?是存储的选择器触发了,还是重试路径被激活了?汇总一周的生产流量后,这些遥测数据会告诉你技术栈中哪些部分老化最快,以及智能体在哪些地方操作了不应信任的记忆。
存储训练数据也有一个推论。智能体将脆弱坐标提交到记忆中的成功追踪(traces)实际上并不是训练信号——它们是债务。智能体学到了一条在六周内就会出错的路径。通过追踪清理(trace-curation)步骤,将存储的路径重写为语义描述,或者丢弃路径字符串仅保留意图,可以防止你的回放缓冲区(replay buffer)变成过时渲染图的博物馆。
是渲染图,而非 API
这背后的架构认知是:Web UI 不是接口(interfaces)——它们是渲染图(renderings)。API 暴露的是契约;渲染图暴露的是当前状态。契约是生产者承诺的内容。状态是生产者在你观察那一刻恰好发出的内容。将两者混淆是导致选择器衰减如此容易上线的原因。
将 DOM 视为 API 的智能体会记住坐标,将其编码到提示词(prompts)或微调(fine-tunes)中,并逐渐积累一堆指向虚无的指针。将 DOM 视为渲染图的智能体会编码意图——用户想要的操作、用户阅读的标签、元素扮演的角色——并在每个关键操作上重新推导路径。第一种智能体在第一天看起来更快。第二种智能体是唯一能在第九十天仍在运行的。
智能体记住的每个选择器都是对一个它无法控制的渲染决策的赌注。渲染图的生产者会根据与你的路线图无关的时间表重新设计页面。如果团队发布计算机使用智能体却不点明这一事实,就是在其关键路径上安装了一个贬值资产——而且这种贬值是无声的,因为解析到错误元素的损坏选择器仍然会报告成功。
修复方法不是一个更智能的选择器引擎。修复方法是缩短智能体记忆与世界之间的契约:少存储,多验证,并将每个页面都视为智能体第一次遇到的页面,即使 URL 没有改变。
- https://playwright.dev/docs/aria-snapshots
- https://www.browserstack.com/guide/playwright-getbyrole
- https://testdino.com/blog/accessibility-tree
- https://proofsource.ai/2026/01/agent-browser-the-accessibility-first-approach-to-browser-automation/
- https://groupbwt.com/blog/challenges-in-web-scraping/
- https://extralt.com/blog/state-of-web-scraping-2026
- https://techstackups.com/comparisons/browser-use-vs-claude-computer-use/
- https://arxiv.org/abs/2510.02418
- https://medium.com/@kavianrabbani/the-hidden-danger-of-hardcoded-data-testid-in-testing-8ec9e671955e
