前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
AI 面试
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
AI 热点
开发者导航
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
AI 面试
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
AI 热点
开发者导航
返回 AI 情报前线
All News · 全部资讯6945
  • 我用AI编码一年:全流程 agent 实践复盘
  • 免费额度用调试:AI 辅助调试的高价值工作流
  • AI编码代理的令牌预算事后分析
  • 开源前端AI代码基准OpenVibeEval
  • 与其跑模型基准,不如用免费Token模糊测试自己的代码
  • AI记忆不用向量库:SQL在百万元素规模更实用
  • rag-mcp:用LanceDB+Tantivy实现本地混合搜索MCP服务
  • 一文读懂MCP、Skills与Plugins的区别
  • AI编程Agent生成PR时测试覆盖率严重不足
  • Browser Agent误读React-Select:写入可见文本却未提交实际值
  • MCP协议新路线图:五大改进方向直击生产级痛点
  • Oraclebone:让AI占卜脚本可审计,结果不由模型捏造
  • Firecrawl vs Jina Reader vs Tavily:RAG 网页抓取工具实战对比
  • Node.js 语音转文字的三段式验证架构
  • AI编程记忆系统为何仍败给文本文件
  • HTML 转 Markdown 真实压缩率:基准测试忽视的真相
  • Mistral Small 3.2 24B 实测:单 GPU 可运行的开源模型
  • AI编码Agent六小时修复412个无障碍违规的实战复盘
  • 本地LLM与官方Demo效果差异:KL散度的幕后影响
  • Chrome 扩展 MV3 工程实战:零崩溃架构与隔离上下文设计
  • Azure OpenAI PTU vs 按量付费:真实盈亏平衡表
  • OpenAI前沿模型已能发动复杂网络攻击,内部暂停部分训练加强安全
  • Python 异步代码仍在阻塞?事件循环饥饿的诊断与修复
  • AI Agent 防火墙实战:从 73 到 1600+ 测试用例的安全护栏设计
  • AI Agent 盲路由:不暴露内网拓扑的消息传递方案
  • 开源模型医疗落地:SWE-bench 80.6% 成绩与离线部署架构
  • Q Developer:一键让AI读项目、改代码、执行命令
  • AI编程 agents 遗忘症:持久记忆方案Tacit
  • 12岁少年用手机开发AI编程导师:移动端+无IDE的工程实践
  • 让AI引用你的内容:sitemap是隐形瓶颈
  • Prompt 注入绕过防护:字段拼接成盲区
  • 为AI网关构建支持定价的请求队列
  • AI可观测性:记录决策而非仅监控模型
  • C++编译失败自动分类修复Bot实战
  • 免费API限流应对:重试阶梯与熔断设计
  • Web开发者的AI工程化实践
  • 400M商品价格实时更新:MCP服务器数据新鲜度实战
  • 重试风暴:容量骤降时无预算重试如何导致 7 倍级联故障
  • 严格工具契约 vs 宽松契约:错误率相差 13 倍的实证分析
  • 免费 Kaggle GPU 跑出 28 TPS:跨 WAN 的张量并行实践
  • 已加载 40 / 6945
8.0
热点
AI SCORE
技术实践2026-08-24 00:12

Browser Agent误读React-Select:写入可见文本却未提交实际值

dev.to · AI#Browser Agent#前端自动化#调试
Editor brief · 编辑速览

团队发现自动化浏览器Agent填表时,react-select组件只写入了可见input而hidden value为空,Agent自读验证完全匹配但实际未提交,调试成本极高。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

我们运行的浏览器 Agent 会在各公司的招聘系统上填写求职申请表。其中一个 Agent 报告表单已全部填写完成。十七个字段写入,十七个确认,提交按钮已点击。

这十七个值中,零个到达了雇主端。

Agent 没有说谎。它读取了错误的东西,而那个错误的东西每一次都和它达成了一致。

那个字段是一个 react-select 组合框。你知道它的形态:上方是一个文本输入框,下方是一个选项菜单,以及一个表单实际提交时用的隐藏值。

我们的 Agent 向输入框中键入了内容,回读输入框,看到了自己的文本就躺在那里,然后标记字段为已完成。

以下是我们在一份真实职位上用真实浏览器测量的结果,用三种方式操作同一个组件:

同一组件,三种操作方式:0、0、244 个选项

react-select 在一个可信的 mousedown 事件上打开菜单。合成事件不符合条件。所以按我们的 Agent 的路径,菜单从未打开过,没有选中任何东西,隐藏值一直保持为空。

与此同时,可见输入框完美地保存着我们的文本。我们的回读是匹配的。成功。

这是一个反馈缺陷,不是填写缺陷

这个区别我们花了太长时间才搞清楚,所以我要把它说清楚。

填写从来都不是出问题的那部分。评分才是。

await fill(selector, value);
const readback = await getValue(selector);
if (loosely(readback, value)) return { success: true };  // <- 读取的是我们自己

那个条件里的每一个术语都在我们自己的控制之下。我们写入了值,我们读取了我们写入的字段,我们把自己的字符串和我们的字符串做了比较。这个检查里没有任何状态是对方产生的。只要写入工作正常它就不会失败,而且它不会仅在提交工作时才成功——而这恰恰是你对一个检查真正需要的属性。

因为字段被评分为完成,Agent 从未升级到专门的提交路径——那条会正确点击选项的路径。那条路径是存在的。它是模型可选的,所以没有任何东西替你调用它。虚假的通过比红色失败更糟糕,因为红色至少会把你路由到备用方案。

生产环境中的实际形态:

一次申请:17 个组合框写入中,0 个实际提交

另一次申请,同样的表单,同样的运行:专用路径上 3 次写入全部落地,Agent 路径上 8 次写入中 6 次发出去是空的

再一次:8 个是空的,其中一个回读出了字面占位符文本"Select…"并把它当作一个值

然后表单在提交时拒绝了,而 Agent 看不到任何错误,因为从浏览器的角度看什么都没错。必填字段只是空着。

我们后来写下的规则

永远不要在自己输入的回读上给写入评分。

要根据对方产生的东西来评分。对于组合框,这意味着要问组件它实际提交了什么:

已渲染的选中标签,而不是过滤文本 表单验证所依赖的隐藏后备输入框 库自身的已提交状态指纹

然后是让上线变得安全的那部分:

三种状态,不是两种。已提交、未提交、未知。未知不改变任何东西。

第三种状态是承重的。一个普通的 ARIA 组合框,其中键入的文本本身就可以是值——不能被一个为 react-select 构建的检查器判为失败。如果我们无法识别组件、无法解析作用域、或者任何东西抛出异常,我们就返回未知,并保持之前的判定不变。一个在陌生组件上自信地出错的检查器,是穿着旧 bug 外衣的新 bug。

我们自己的补丁中的两个 bug,就是被专门为此编写的测试捕获的:

在第一个看起来像 react-select 的元素上,在读取实际重要的隐藏输入框之前就得出未提交的结论。

把抛出异常当作失败,会让每一个我们从未见过的组件都失败。

这个模式在其他地方也同样存在

一旦你掌握了这个形态,你会到处看到它:

上传被标记为完成,因为文件输入框的 files.length 是 1,这是你自己的 DOM 写入的属性,而不是任何字节到达了服务器

保存通过重新读取本地状态来确认,而不是通过响应来确认

队列发布通过没有抛出异常来确认

指标读数为零,是因为仪器没有上锁,这和事件没有发生不是一回事

我们现在对每一个检查应用的一般化原则:

这个检查在成功场景和失败场景下,读数会不同吗?如果不是,它就不是证据,它是一面镜子。

等更久也没有用。我们试过在回读之前增加延迟,基于菜单很慢的理论。它被回滚了。根本没有什么菜单值得等。

我构建了 AI Applyd。我们在公司的自有招聘系统上投递申请,只有当他们的系统确认了之后,我们才把申请计为已发送,原因正是上面说的:我们自己的点击不是任何东西的证据。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
AI编程Agent生成PR时测试覆盖率严重不足
下一篇
MCP协议新路线图:五大改进方向直击生产级痛点