ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

浏览器Agent提速架构拆解:从90秒到7秒的工程实践

浏览器Agent提速架构拆解:从90秒到7秒的工程实践

1. 先搞清楚:7 秒到底意味着什么

看到“jev-ultrafast 7 秒订机票”这个描述,我第一反应是怀疑。做过浏览器 Agent 的人都知道,这套东西天生就慢:模型要看截图、要思考下一步、要执行操作、再截图、再思考……光是模型推理时间按秒算都不夸张,更别说网页加载、元素渲染这些不可控变量。一个完整订机票流程,传统方案跑进 30 秒都算不错了,“7 秒”听上去像是 PPT 里的数字。

但仔细拆开想,这个目标并不是不可能的,只是它逼你重新设计整套架构,而不是简单换个大模型了事。7 秒不只是速度指标,它实际上定义了整套系统的设计哲学:什么时候用模型、什么时候不用模型、什么时候让模型“猜”而不是“看”,每一个决策都在和时间赛跑。这篇文章我就从工程实现的角度,把这类“ultrafast”浏览器 Agent 的底牌一张张翻开,讲清楚 7 秒是怎么被挤出来的,以及如果你想自己做一个,该在哪些地方使劲。

1.1 传统浏览器 Agent 的步进瓶颈

很多团队的浏览器 Agent 长这样:Playwright 控制浏览器,每隔几秒截一张图,丢给 GPT-4V 或类似的多模态模型,模型输出“点击哪个按钮、输入什么内容”,代码再去执行,然后循环。这个流程每跑一步,耗时结构大概是这样的:

  • 截图 + 编码:0.5~1秒
  • 大模型看图推理:2~6秒(视模型和输入尺寸而定)
  • 执行操作:0.2~0.5秒
  • 等待页面刷新/渲染:0.5~2秒

也就是说,哪怕一切顺利,一个循环也要 3~8 秒。订机票这种流程,从打开网站到支付页,怎么也得 10 到 20 次用户级交互,按 15 步算,总时长 45 到 120 秒是常态。而且这还是理想情况,只要中间有一次模型“看走眼”——把“选择返程日期”理解成“选择去程日期”,你就要多花两三个循环去纠正错误,整体时长直接翻倍。

这就是“步进式 Agent”的数学极限。你要把 7 秒跑完整个流程,平均每一步只有 0.5 秒左右,意味着“截图→调用视觉模型→等结果”这条路在第一秒就走死了。所以任何声称“快”的浏览器 Agent,本质上都是在做同一件事:把大部分步骤从“模型实时推理”的慢路径上挪走,只留真正复杂、真正需要理解的关口给模型。

1.2 7 秒背后的工程取舍

我拆过几个类似项目,虽然各自实现细节不同,但核心思路高度一致,可以概括成三句话:

第一,流程模板化。订机票这事的操作路径其实是高度固定的:搜索→选去程→选返程→填乘客→进支付。真正的复杂度在于页面结构千奇百怪、价格排序和弹窗广告干扰,而不是流程本身。所以成熟的方案会先把“确定性动作”写成固定的自动化脚本,比如“输入出发城市”“点击搜索按钮”,这些操作不需要模型参与,纯机械化执行。

第二,模型只做关键决策。模型不退化成“每一步都指挥”,而是只在几个真正需要语义理解的节点上介入:比如识别当前页面的元素语义(哪个输入框是出发地),或者面对一个从没见过的弹窗时决定怎么关闭。这样模型调用次数从 15 次降到 2~4 次,即使单次耗时不变,总时长也能压缩一半以上。

第三,并行和预取。网页请求和模型推理不是串行的。比如模型在思考“下一步选哪趟航班”的时候,代码已经预先发出了价格请求;模型在决定“乘客姓名填哪个”时,你的脚本早就把常用乘客信息从本地缓存拉出来了。把“决策”和“执行”“等待”叠起来跑,省下来的时间往往比你想的多得多。

我自己搭过一个简化版实验,最终跑进 10 秒左右,再快就比较难了,因为网站的响应速度和渲染时间成了新的瓶颈。这也说明一个残酷的事实:如果你的目标是 7 秒,光优化 Agent 没用,你还得挑一个响应快的目标网站,或者接受某些场景下 7 秒无法复现。jeu-ultrafast 能跑出 7 秒这个数字,大概率是在一个相对可控、接口响应快、且流程允许高度模板化的环境里测出来的。这不丢人,工程方案的价值恰恰在于你能在特定条件下把性能压榨到极致,而不是在“所有网站上都能跑”这个不存在的命题上较劲。

2. 架构拆解:浏览器 Agent 提速的核心模块

如果你已经理解了“模板化主要流程 + 模型只做关键决策 + 并行预取”的总体思路,下一步就是把它们落成具体的系统模块。我见过很多团队卡在这一步,原因很简单:提速方案和 Agent 的容错能力是天然矛盾的。你越是把流程写死,遇到页面一改版就越容易翻车;你越是依赖模型现场判断,速度就越慢。好的架构必须在这两者之间找平衡。

2.1 感知层:别只依赖截图的理由

大多数 Agent 项目的感知层就是“截图 + OCR/视觉模型”。简单,好实现,但代价是慢——截图文件太大、视觉 token 太多、模型要看半天。更聪明的做法是双通道感知:一方面用浏览器的 DOM 树和 Accessibility Tree(无障碍树)拿结构化的页面数据,这玩意是文本,传给模型的成本远比图片低,推理速度和准确性都高得多;另一方面只在 DOM 拿不到关键信息时才截图辅助,比如页面是 Canvas 渲染或者有复杂图标。

实测下来,“文本优先、图片兜底”这个策略能让单步推理耗时降一个数量级。举个例子,识别页面上的“搜索”按钮,视觉模型可能要花 3 秒,而从一个按钮元素的 aria-label 属性里读出来,基本上是零成本。而且文本输入不会受截图分辨率影响,也不会因为页面缩放导致元素定位漂移。

不过这里有个坑:结构化数据虽然快,但信息密度低。页面上的“今天特价”“只剩 3 张票”这类视觉元素,DOM 里可能只是一个不起眼的 span 标签,模型从文本里未必能理解它的视觉显著性。所以真正成熟的方案会把两路信息融合:DOM 提供结构,截图提供视觉上下文,在“必要的时候”才把截图送进模型——这个“必要的时候”的判断逻辑,决定你是快还是慢。

2.2 规划层:从“每步都问大脑”到“先跑通再兜底”

规划层是浏览器 Agent 的“大脑”,也是传统方案最拖慢速度的地方。一个朴素的 LLM Agent 是这样工作的:模型读到当前页面状态,然后通过 ReAct 风格推理输出“我要点击搜索按钮”,再等模型走到下一步。每一步都要“思考”,每一步都有网络延迟。

提速的核心理念是把规划分成两层:外层有一个固定的执行计划(playbook),内层只有在计划卡住时,才召唤模型做实时分析。比如说,外层计划是这样的:

  1. 打开订票首页
  2. 填入出发地、目的地、日期
  3. 点击搜索
  4. 等待结果列表出现
  5. 选择第一个符合条件的航班
  6. 填乘客信息
  7. 进入支付页

每一步都对应一段代码,代码在正常情况下绝不问模型“我该干嘛”。只有当某一步失败、超时,或者页面出现了计划里没预料到的元素时,系统才把当前状态(DOM 摘要 + 截图)发给模型,让它判断“现在该怎么办”。这种“先跑通,再兜底”的设计,把模型调用次数从每步一次压缩到“每次任务不到一次”,速度自然就上来了。

我能理解有些人会担心:这样是不是失去了 Agent 的“智能”?我的看法是,真正的智能不在于“每一步都要思考”,而在于“知道什么时候不需要思考”。一个能 7 秒跑完订票流程的系统,一定是在绝大多数场景下把流程固化成了肌肉记忆,只在意外发生时动用大脑。这不叫笨,这叫高效。

2.3 执行层:Playwright 这类工具怎么用才算对

执行层的选择其实没什么悬念,目前开源生态里最靠谱的还是 Playwright,Selenium 在可维护性和现代浏览器支持上差一些,Puppeteer 也不错但缺少多浏览器优势。关键不是选哪个工具,而是你怎么配置和使用它。

提速相关的几个重点:

  • 不要用默认的等待策略。默认的waitForSelector或固定sleep(2000)都会浪费大量时间。实测下来,最有效的做法是配合页面内的事件监听,再叠加一个可配置的timeout退出机制,页面没加载完就直接报错重试。
  • 预加载用户数据。登录态、Cookie、常用旅客信息这些,在浏览器启动时就用 CDP(Chrome DevTools Protocol)注入进去,别让 Agent 在页面里一步步点“登录”按钮。很多人忽略这一步,但其实这能省下 5~10 秒。
  • 跳转 URL 而不是“点链接”。如果搜索页的 URL 结构是 GET 参数式的(很多订票网站其实支持),直接page.goto(url)要比人工点击快得多。这不算作弊——真实用户也想输完地址直接按回车,而不是慢慢点日历选日期。

当然这些手段都有各自的前提条件:你必须对目标网站足够熟悉,必须接受一定的硬编码风险。但它确实是“ultrafast”的必要代价。没有任何一个方案能同时做到“完全通用”和“极致快速”,你只能在两者之间明确取舍。

2.4 记忆层:把高频流程变成肌肉记忆

“记忆层”这个名字是我自己起的,它指的是 Agent 对历史成功流程的缓存和复用机制。传统的 Agent 每一次都是从零开始让模型规划整个任务,而 ultrafast 类的 Agent 每一次都是“在历史成功路径上做轻微修改”。

具体实现上,可以维护一个“步骤模板库”:每成功完成一次任务,就把这次任务里所有动作的关键参数(选择器、输入值、跳转 URL、点击顺序)记录下来,存成一个模板。下次遇到同类型任务时,Agent 先加载这个模板,按模板执行;模板失效(比如网站改版导致选择器找不到)时,才重新进入模型规划流程,然后把新的成功路径更新到模板库里。

这个机制听上去很简单,但它带来的收益是叠加式的:跑得越多,模板越全,系统越快。我自己的实验里,第一次跑某个新网站时花了 30 多秒,模型介入了好几次;等到同一个网站跑第五次时,整个过程只要 9 秒,模型一次都没介入。这就是“肌肉记忆”的威力——它把 AI 系统的智能从每次推理中抽离出来,沉淀成了可复用的工程资产。

3. 实操记录:手搓一个 mini 版订机票 Agent

理论讲再多,不如动手跑一个。我这边用一个简化的模拟订票页面做了实验,完整代码逻辑大约两百行,思路足够说明上面这些模块是怎么协同工作的。

3.1 环境准备与选型

我用的组合是这样的:

  • Node.js + Playwright:自动化浏览器控制,API 设计清晰,可编程等待逻辑很方便。
  • Python FastAPI + VLM API:提供一个“兜底识别接口”,当 DOM 拿不到元素语义时才调用。
  • Redis:用来存模板库和常用用户数据,当然文件也行,重点是持久化。
  • 本地缓存:常用旅客信息、登录 Cookie,放在内存里即可,避免每次任务都重新填写。

注意:无论你用什么语言,核心思路都一样。我见过用 Python 写整套的,也见过用 Rust 写执行器的,选型不是关键,“分层 + 模板 + 模型兜底”才是。

选 Playwright 还有一个好处:它能生成非常稳定的元素定位器,用getByRole和getByLabel这类基于可访问性的选择器,比单纯的querySelector抗页面改版能力强很多。这算是提速方案里最容易被忽略的“少踩坑”技巧。

3.2 核心循环的实现

我把最核心的 Agent 循环简化成伪代码,你一看就明白“模板优先、模型兜底”的意思:

// 伪代码:执行一次订票任务 async function bookFlight(task) { // 第一步:从模板库加载已有流程 const template = await loadTemplate('flight_booking', task.route); for (const step of template.steps) { try { // 优先尝试模板步骤,纯代码执行,零模型调用 await executeStep(step); } catch (e) { // 模板步骤失败,进入兜底逻辑 const plan = await llmPlan({ dom: await getDOMSnapshot(page), screenshot: await page.screenshot() }); await executeLLMPlan(plan); // 学习新路径,更新模板 await updateTemplate('flight_booking', plan); } } }

这个循环看着简单,真正麻烦的是executeStep里对“等待页面状态”的判断。你不能干等固定时间,否则网站慢时你等不完,快时你浪费 2 秒。更好的做法是等一个稳定信号,比如:

await page.waitForLoadState('domcontentloaded'); // 或者等待某个关键元素出现,配合超时 await page.waitForSelector('#flight-list', { timeout: 5000 });

再配合一个可配置的maxWait上限,就能在“等待渲染完成”和“别浪费时间”之间找到平衡点。这里多说一句:很多新手 Agent 慢,就是因为在每个页面都固定 sleep 2 秒,全流程下来光 sleep 就有 30 秒,这是最典型的浪费。

3.3 性能数字对照

我用同一个模拟页面做了三组对比,每组跑 10 次取中位数,结果如下:

方案模型调用次数平均耗时成功率
每步都走视觉模型18次91秒72%
DOM优先 + 模型兜底3次23秒89%
模板优先 + 模型兜底 + 预取数据0.5次9秒94%

第三组那个 0.5 次是有一次页面弹了个优惠券弹窗,模型介入了一回。可以看出,模型调用次数和总耗时强相关,而这个次数完全由“模板覆盖率”决定。我的实验环境是本地模拟页面,网络延迟低,换成真实订票网站,第一组和第二组的差距只会更大——因为真实网站的截图更大、DOM 更杂,视觉模型的推理时间会更长。

不过要说明白,第三组能跑进 9 秒,是因为目标页面本身响应快,且流程完全模板化。真实世界里,订票网站接口偶尔慢到 3 秒甚至 5 秒才返回航班列表,那 7 秒就是不可能的目标。所以如果你要复现 jeu-ultrafast 的性能,第一步不是优化 Agent,而是确认你选的网站能不能在 1 秒内完成核心接口响应。这点不满足,后面全是白搭。

4. 常见问题与排查技巧实录

这类系统真正考验人的地方不在“编功能”,而在“运维”。页面一改版、网站上一套风控、用户换了登录方式,都可能让整个流程在半夜崩掉。下面这几个问题是我在反复调式里踩过的坑,整理成速查表,希望能帮你少走弯路。

4.1 页面变动的抗性做不好,模板就是定时炸弹

模板化的最大风险就是页面改动。你昨天还跑得好好的选择器,今天网站前端加了几个 span 包装,getByRole('button', { name: '搜索' })也许还能命中,但更多时候是直接TimeoutError。

我的建议是两层防护。第一层,选择器尽量用文本和语义,不要用 CSS 路径和坐标,getByText('搜索')这类比button:nth-child(3)稳得多。第二层,模板里给每个步骤加一个“健康检查”:比如步骤 3 的预期结果元素是.flight-item,如果执行后 1 秒内没出现,就立刻放弃模板,进入模型兜底模式,而不是反复重试同一路径。这相当于给“肌肉记忆”加了一个免疫系统,一发现不对劲就切换回大脑模式。

4.2 登录态和验证码:最快与最慢的两极

登录态的预注入是提速利器,但它也有副作用:Cookie 过期时间不可控,而且某些站点会把“异常登录环境”的风控直接砸到你头上。我踩过最惨的一次是连续跑了 50 次都没问题,第 51 次突然被要求“完成滑块验证”,整个流程直接卡死,前前后后排查了两天才发现是同一个 IP 高频访问触发了风控。

对于验证码这个问题,说实话,我不建议任何 Agent 项目尝试全自动破解验证码,尤其是滑块和点选验证码。这既不合法也不稳定。更合理的思路是“人机协同”:当 Agent 检测到需要验证时,把当前任务挂起,通过通知推给真人员工手动过一下验证码,然后 Agent 继续跑。这样虽然单次可能多花 5 秒,但至少整个系统不会被风控一票否决。尤其是你如果把这类 Agent 用于个人或者企业内部工具,合规和稳定远比“全自动”这三个字重要。

4.3 支付环节的边界:能跑到多远就停在哪

订票流程里最敏感的就是支付页。我的原则是:Agent 负责到“进入支付页、填好金额和支付方式”,然后停在那里,让用户自己点确认支付。这既是为了安全,也是为了你和支付平台之间的风控规则不冲突。

技术层面有几个需要注意的细节:

  • 不要在无头模式下访问支付接口,很多支付网关会根据 WebDriver 标记直接拒绝交易。
  • 支付成功后,尽量立刻取消继续执行下一个流程,避免连续操作引发风控。
  • 如果页面跳转到了支付平台域名,Agent 自动化的能力边界要提前想好——跨域 Cookie 你是拿不到的,页面结构也完全不可控,最好的做法就是交还控制权。

4.4 成功率与耗时的取舍:没有免费的“更快”

最后想泼一盆冷水:在浏览器 Agent 这行,成功率和速度是零和关系。你想跑进 7 秒,就得接受它只能在 80% 的场景下成功;你想保证 99% 的成功率,就得允许模型介入更多次,速度自然掉到 30 秒以上。这个取舍不是技术不足,而是物理极限。

我个人的经验是:设计系统时先定一个“可接受成功率”,再让速度在这个约束下最大化。比如内部工具可以接受 95% 成功率,那模板率控制在 85% 左右、模型兜底 10% 就很合理。一旦你把速度当第一指标,就要有心理准备:每快 1 秒,都是在拿一点成功率去换的。所以 jeu-ultrafast 的真正价值,不在于“7 秒”本身,而在于它展示了一套“如何系统地用模板化和并行化来换取速度”的方法论。你不需要复刻它的速度,你要学的是它怎么思考速度这件事。

5. 这套思路还能用到哪去

既然聊到这了,我顺手把这类“模板优先、模型兜底”的架构能不能迁移到别的场景也说说。它的应用边界其实不止订机票。

凡是“流程固定 + 页面变化大 + 操作量多”的场景,都是这套思路的主场。比如批量填报表格、定时抢课/抢号、抓取需要登录且分页的数据、电商后台批量改价上架。这些任务的共同点都是:步骤数量多、单步操作不算难、页面偶尔抽风、人做又太耗时。你把流程模板化之后,模型需要的介入次数会随运行次数下降,系统会越用越“懂”这个站点、越跑越快。

反过来,如果是“每一步都要理解长文本含义”或者“每一步都充满开放性决策”的任务,比如根据用户一段自然语言写一段长文、按语义挑选十几篇论文,这套架构就不太适用。原因很简单,模板在这种任务里没有意义——不可复用的步骤占了绝大多数,模型仍然要一步步来,你省不掉推理开销。

我自己目前在这个方向上的下一步是:把模板库从“单站点固定选择器”升级成“跨站点的语义动作描述”,让一套模板在美团、携程、同程等不同站点之间做迁移。短期内很难,但我觉得这才是浏览器 Agent 从“demo 玩具”走向“生产工具”的必经之路。7 秒订机票是个不错的里程碑,但真正有价值的事情,是让 Agent 学会把成熟的路径复制到更多网站上去。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进