Skip to content
🔧 进阶手册第 5 / 8 节

性能解读:7.073 秒是怎么测出来的 ​

上一课你亲眼看着 agent 用 7 秒搜完了航班。这一课把秒表拆开——7.073 秒不是广告词,是一次带完整测量边界的实录:官方不仅给了报告,还把原始测量 JSON 一起放进了仓库,里面连源码哈希和浏览器版本都带着。把 Jev Ultrafast 性能数据读明白,你不仅能复现它,还能照抄这套方法去测自己的 agent。

本课的数字主要出自你 clone 的 jev-ultrafast 仓库里三个文件:docs/performance.md(报告正文)、docs/flights-measurement.json(实录数据)、docs/full-speed-measurement.json(对比实验数据)。

学完你能做什么 ​

  • 说出 7.073 秒的计时口径:从首次预测起表、到接受 DONE 停表,表内五项、表外三项各是什么
  • 拆开实录账单:17 次决策请求(中位 178 ms、合计 3,720 ms)、2 次文本生成、11 个动作,以及每个动作在第几秒执行
  • 读懂 9.450 → 7.092 秒对比实验的设计,并解释官方为什么自己说「3 对太少,不是通用基准」
  • 说清优化砍掉了什么:浏览器协议调用 1,092 → 101,其中 828 次 DOM.resolveNode 直接清零
  • 用 examples/flights.py 的 trace 对齐同一口径,测出你自己的秒数

你现在的困境 ​

  • 「官方说 7 秒,我跑出来 12 秒——这数字怕不是挑了最好的一次?」不知道口径,比了也是白比
  • 想在汇报里引用这组 ultrafast 速度数字,被一句「怎么测的」追问就心虚
  • 想给自己做的浏览器 agent 跑性能对比,但不知道要控制哪些变量:模型?网络?浏览器?想抄个作业都找不到范式

什么时候用这一招 ​

当你需要:

  • 转述或引用 Jev Ultrafast 的性能数字,并且经得起「怎么测出来的」一句追问
  • 自己给 browser agent 做性能对比,需要一套现成的测量范式(口径、独立验证、样本量声明)照抄
  • 判断这组数字适不适合你的场景:它是单任务、live 网络、小样本

而且不想:

  • 把单次运行的秒数当成稳定指标到处引用
  • 拿不同口径的数字互相比较(inspector 开截图 vs 脚本无截图;jev-1.13 vs jev-1.14)

🎒 开始前的准备 ​

  • 完成了 跑通 Google Flights:至少跑过一次 examples/flights.py,见过 "passed": true 的验证 JSON 和 artifacts/flights/latest/
  • 记得 Jev Ultrafast 原理的「一次往返双决策」——本课的 17 次请求,每一次都是这个结构
  • (可选)把 jev-ultrafast 仓库开着,对着 docs/performance.md 和两个测量 JSON 读,本课每个数字都能在里面找到
  • 一杯水——本课以读为主,动手在「进阶技巧」

核心思路 ​

官方对性能数字的态度,可以压成三句话:

  1. 每个数字都带口径——7.073 秒从哪一毫秒起表、到哪一毫秒停表、什么算表内什么算表外,文档写得一清二楚
  2. 对比要控制变量——新旧版本交替各跑 3 次,同任务、同模型、同预算、同独立验证
  3. 主动声明局限——样本量、live 网络、单任务,官方自己先说了,不等人来戳

本课要拆的四组官方数字:

数字官方口径出处
7.073 s首次预测 → 接受 DONE;含模型调用、文本生成、浏览器操作、stale 决策、加载docs/performance.md、flights-measurement.json
9.450 → 7.092 s6 次交替运行取中位数,双方 3/3 通过独立验证docs/full-speed-measurement.json
1,092 → 101同一对比实验的浏览器协议调用中位数docs/full-speed-measurement.json
$0.00006272仅两次文本 helper 的 OpenRouter 计费,不含 TypeSafedocs/performance.md

还有一件事先记住:这组数字全部出自同一个组合——决策模型 jev-1.13.0 + 文本模型 inception/mercury-2.5(走 OpenRouter,关闭推理)。测量 JSON 里 TYPESAFE_MODEL 是 null,也就是用代码默认的 jev-latest(jev_ultrafast/model.py 第 108 行),当时它解析到 1.13.0;如今 jev-latest 已指向 jev-1.14.0。你今天复现,模型就不一样,秒数自然有差异。

💡 为什么这一课值得细读

比记住 7.073 这个数更有用的,是「口径 + 账单 + 样本量声明」这套范式。你自己测任何 agent 的性能——不管是 Ultrafast 还是别的——都能照抄。

跟我做 ​

第 1 步:对齐计时口径——官方秒数从哪一毫秒起表 ​

为什么:比较任何两个秒数之前先对齐口径,否则全是无效比较。你自己跑出 9 秒还是 12 秒,第一步都是搞清楚官方的表是怎么走的。

官方口径,一张表说清:

项目内容
起表初始首页观察之后的第一次预测
停表接受 DONE 的那一刻
表内模型调用、文本生成、浏览器操作、stale 决策(作废重来的预测)、加载等待
表外浏览器启动、初始导航、跑完后独立的 verify() 验证

这个口径在代码里对得上(jev_ultrafast/agent.py):

  • started_at 在第一次 predict 时才设置——所以初始页面观察在表外
  • DONE 在 act 里被接受时更新 elapsed_ms——这就是停表点
  • 预测过期(StalePage)会丢弃决策、重新观察、重新预测——作废的时间留在表内

视频也是同一口径:1× 原速播放、无开场停顿、结尾只加 0.5 秒停顿;186 帧连续录屏加 1 张初始截图(JSON 里 source_frames: 187),只裁掉了顶部 64 px 的账号/导航条——没有掐头去尾的剪辑。

你应该看到:docs/performance.md 的计时段落与上表逐条对应——"begins at the first prediction after initial homepage observation and ends at the accepted DONE choice",表内表外一个词都不差。

  • 能说出表内五项、表外三项

第 2 步:拆开 7.073 秒的账单——17 次请求都花在哪 ​

为什么:官方把这次实录的每个数字都写进了 docs/flights-measurement.json,账单可以直接抄。总账:

指标数值
总耗时7,073 ms
决策请求17 次
决策延迟中位 178 ms,合计 3,720 ms
执行动作11 个(10 次交互 + 1 次显式 WAIT)
文本生成2 次(Zurich 581 ms、London 346 ms)
token90,558 输入 + 6,325 输出
决策模型jev-1.13.0

时间去向(前两行是官方 JSON 的原始字段,第三行是本页推算:7073 − 3720 − 927):

去向时间占比
17 次决策请求3,720 ms≈ 53%
2 次文本生成927 ms≈ 13%
浏览器执行、观察、页面加载≈ 2,426 ms≈ 34%

17 次请求不等于 17 个动作:11 个动作加 1 次被接受的 DONE,一共 12 次预测「花在刀刃上」;其余 5 次在执行前被新鲜度检查拦下——页面指纹变了,基于旧快照的决策作废重来,这就是口径里的 stale decisions,它们的时间同样计入总秒数。(5 = 17 − 11 − 1,本页依据 agent.py「每次预测恰好消费一次、作废即重测」的循环逻辑推算,官方未单独公布 stale 次数。)

11 个动作在时间轴上的位置(executed_ms,出自实录 JSON 的 actions 数组):

时刻动作
0.336 sCLICK Change ticket type. Round trip
0.640 sCLICK One way
1.595 sTYPE_TEXT Where from? → Zurich(文本生成 581 ms)
1.930 sCLICK Zürich, Switzerland(选中自动补全建议)
2.748 sTYPE_TEXT Where to? → London(文本生成 346 ms)
3.053 sCLICK London, United Kingdom
3.452 sCLICK Open Departure
3.769 sCLICK Sunday, September 20, 2026
4.097 sCLICK Done. Search for one-way flights…
5.217 sCLICK Search(官方原话:搜索在第 5.217 秒执行)
5.587 sWAIT 等页面更新
7.073 sDONE 被接受,停表

前 5.2 秒在填表提交,后 1.9 秒在等结果并确认完成。WAIT 执行在 5.587 秒、DONE 接受在 7.073 秒——最后这约 1.49 秒,官方解释是结果页加载、状态变化和完成决策。两次文本生成各造成约 0.3–0.6 秒的「打字停顿」,这就是视频里输入框「想了一下才出字」的原因。

你应该看到:flights-measurement.json 顶层的 elapsed_ms、decision_requests、decision_median_ms、decision_total_ms 四个字段,和 actions 数组里 11 个条目的 executed_ms——上面的时间线就是从这个数组里抄的。

  • 能说出 17 次请求里几次变成动作、几次是 stale、几次是 DONE

第 3 步:读懂 Jev Ultrafast 性能对比实验:9.450 → 7.092 秒 ​

为什么:单次 7.073 秒只是实录;「快了 25%」这个结论出自另一组对照实验。它的设计决定了结论能说多大。

实验设计(performance.md「Matched runtime comparison」一节):

  • 6 次运行、交替进行:基线一次、优化版一次,共 3 对;同一个任务、同一个现成 Chrome profile
  • 两个 arm 用完全相同的:自然语言目标、独立结果检查器、1120×780 视口、jev-1.13.0、mercury-2.5(关推理)、动作与请求预算
  • 初始导航两边都不计时;每次运行自己开自己关 tab;6 次全部计入,没有丢弃,无供应商或验证失败
  • 基线 arm 冻结在 commit 68c077bf…;两边都用 Mercury,避免「换文本模型」和「改代码」两个变量混在一起

结果:

对基线优化版验证
111.214 s6.964 s双方通过
28.984 s7.913 s双方通过
39.450 s7.092 s双方通过
中位9.450 s7.092 s各 3/3

三个中位数变化:任务时间 −25.0%、TypeSafe 请求 22 → 17、浏览器协议调用 1,092 → 101。优化版在三对里都更快。

但官方紧接着自己给了三条免责声明:

  1. 3 对太少,双侧符号检验 p = 0.25,撑不起强统计结论
  2. 这是受控小样本对比,不是广泛的 agent benchmark
  3. Google、网络响应、路由、浏览器缓存都是活的,没有被控制

⚠️ 引用这组数字的正确姿势

「在同一任务、同一模型、同一浏览器的 3 对交替运行里,优化版每次都更快,中位数快 25%」——这是有依据的说法。「Jev Ultrafast 比某某 agent 快 25%」——没有依据,官方没做过跨 agent 对比。

你应该看到:performance.md 的对比表就是上面 3 对数字加一行加粗中位数;"p = 0.25" 和 "not a broad agent benchmark" 都在原文里。

  • 能说出实验控制了哪些变量、没控制哪些

第 4 步:找到时间去向——1,092 → 101 次协议调用砍掉了什么 ​

为什么:「快了 25%」的原因全在浏览器协议调用上。官方在 measurement JSON 里存了每次运行完整的 CDP(Chrome DevTools Protocol)调用明细,这是全课最硬的一组证据。

旧循环的三个负担(performance.md「Where the time went」):

  1. 每次 DOM 变化——包括动画——都作废决策,反复重新预测
  2. 反复读取整棵无障碍树(Accessibility.getFullAXTree)
  3. 解析数百个 DOM 节点(DOM.resolveNode)

新循环的做法(performance.md「Where the time went」+ README):

  • 一次浏览器调用读完常见 HTML/ARIA 控件——不再反复读树、逐个解析节点
  • 点击守卫只比对目标、邻近上下文和文档/表单状态;几何与命中测试仍在输入前做
  • combobox 事件等待:自动补全建议先到(README:上限 200 ms;其他交互至多两个动画帧或 50 ms)再问 Jev
  • 原生文本替换显式发出浏览器的 select-all 命令

CDP 调用明细(三次运行逐个列出,出自 full-speed-measurement.json 每个 run 的 cdp 对象):

协议方法基线(3 次)优化版(3 次)
DOM.resolveNode828 / 828 / 8280(键不再出现)
Accessibility.getFullAXTree30 / 30 / 300
Runtime.callFunctionOn40 / 40 / 400
DOM.getBoxModel + DOM.getNodeForLocation10 + 10 / 10 + 10 / 10 + 100
Runtime.evaluate158 / 146 / 14875 / 77 / 71
Input.dispatchMouseEvent / KeyEvent / insertText20 / 4 / 2(每次相同)20 / 4 / 2(不变)
合计1102 / 1090 / 1092(中位 1,092)101 / 103 / 97(中位 101)

读表的两个洞察:

  • 「看页面」的方式变了,「点页面」没变——鼠标、键盘、插入文本三类输入调用两边完全一致,砍掉的全是观察类调用
  • 请求也少了(中位 22 → 17):决策不再被动画频繁作废,重新预测自然就少

💡 这就是「一次快照一次浏览器调用」的量化证据

原理课讲过 README 的设计原则「One browser call per snapshot」。落到数字上:Runtime.evaluate 从约 150 次降到约 75 次,DOM.resolveNode 从 828 次清零。架构说法和测量数据对上了。

你应该看到:full-speed-measurement.json 里基线三次 run 的 cdp 明细中 DOM.resolveNode 都是 828 次;优化版三次 run 的 cdp 明细里根本没有这个方法。

  • 能说出砍掉的三类观察类调用是什么、为什么输入类调用不变

第 5 步:算清成本——token、文本 helper 与官方没报的价 ​

为什么:性能解读不能只看秒数,还要看这一趟花了多少钱。官方报了一半,另一半可以自己推。

官方报的:

  • 实录全部请求合计 90,558 输入 token + 6,325 输出 token
  • OpenRouter 对两次文本调用计费 $0.00006272(Zurich $0.0000293 + London $0.0000334)
  • 官方明确声明:这只是文本 helper 的费用,不是任务总成本——TypeSafe 响应里只有 token 数、没有美元账单,浏览器成本也不在内

官方没报、可以自己推的(本页推算,非官方数字):

按 TypeSafe 官方价目($42 / B 输入 token,输出免费),90,558 个输入 token ≈ $0.0038。推算过程:90558 × 42 ÷ 10⁹ ≈ 0.0038 美元。加上文本 helper 的 $0.00006272,这一趟 7 秒的任务,模型总成本大约 0.4 美分。

一个波动实例(都在 full-speed-measurement.json 里):同样是生成 London,实录那次 346 ms、94 个 completion token($0.0000334);对比实验第 2 对的优化版那次 1,137 ms、511 个 token($0.0000961)——单次文本调用延迟能差 3 倍多,这类波动全部会进总秒数。

你应该看到:performance.md 里 "$0.00006272" 那段写着「text-helper charge, not total task cost」;两次调用的单价在 flights-measurement.json 的 text_calls 里(2.93e-05 + 3.342e-05)。

  • 能说清 $0.00006272 包含什么、不包含什么

检查点 ✅ ​

  • 能完整说出计时口径:起表点、停表点、表内五项、表外三项
  • 能报出实录账单四个关键数:17 次请求、中位 178 ms、11 个动作、搜索在第 5.217 秒执行
  • 能解释 9.450 → 7.092 秒的实验设计,并说出官方自己的三条免责声明
  • 能说出协议调用 1,092 → 101 里被清零的三类调用
  • 能说清 $0.00006272 只是文本 helper 费用、TypeSafe 账单要按价目另算

踩坑提醒 ​

❌ 拿自己的秒数直接质疑官方数字 ​

现象:你跑出 9 秒、12 秒,觉得 7.073 秒有水分。

原因:至少四个口径差异——① 模型不同:测量用的是 jev-1.13.0,今天 jev-latest 已指向 jev-1.14.0;② 网络是活的:官方优化版自己三次就分布在 6.964–7.913 秒;③ inspector 开着截图,本来就不是计时跑法(上一课讲过);④ 你的运行可能撞上更多 stale 决策。

正确做法:用 examples/flights.py(无截图)跑,读 artifacts/flights/latest/state.json 顶层的 elapsed_ms——这才是和官方同口径的数字;比较前先对齐模型、URL 和目标。

❌ 把「快 25%」说成跨 agent 结论 ​

现象:「Jev Ultrafast 比某某浏览器 agent 快 25%。」

原因:官方对比的是自己新旧两个版本——基线是冻结在 commit 68c077bf… 的旧实现,不是任何别的 agent;而且 3 对样本 p = 0.25,官方自己都说是受控小样本。

正确做法:引用时带上限定语:「同一任务、同一模型的 3 对交替运行,新版比旧版中位快 25%」。

❌ 以为官方一次就调到了 7 秒 ​

现象:看到 7.073 秒,以为性能是顺理成章调出来的。

原因:performance.md 保留了完整开发记录:旧版通过过一次 9.302 s;两个无障碍树方案 9.395 s、10.157 s;第一个直接 DOM 方案 8.697 s,但独立验证失败(名称/值提取不完整);修复后 8.051、8.631、8.395、8.385、7.741 s 一路爬,Mercury 诊断 7.559 s。更早还有 11.387 s 的录像和 12.898 s 的策略回归。

正确做法:把「8.697 s 但 verify 失败」当成提醒——秒数再好看,独立验证不过就不算过。官方敢把失败尝试全写进文档,恰恰说明可复现比好看重要。

❌ 拿 7 秒套所有网站 ​

现象:「Flights 7 秒,那我那个复杂后台也该 7 秒。」

原因:官方只公布过三个任务的秒数:Flights 7.073 s、Wikipedia 打开哥德尔不完备定理 2.798 s、本地酒店任务 1.896 s——后两个官方明说是「冒烟检查,不是匹配对比」。DOM reader 只支持常见 HTML/ARIA 控件,shadow DOM、canvas、上传等不支持。

正确做法:拿自己的站点、自己的目标实测;先对照 Ultrafast 排错的不支持清单,把不适用的页面排掉。

进阶技巧(可选) ​

测你自己的口径。 上一课的 uv run --env-file .env python examples/flights.py --keep-open 跑完后,打开 artifacts/flights/latest/state.json:顶层 elapsed_ms 就是这一轮的官方口径秒数;history 里每个动作带 executed_ms、latency_ms、text_latency_ms,decisions 是每次预测,text_calls 是文本 helper。官方测量 JSON 就是把这些字段加工成的报表。跑三轮取中位数,比单次有说服力。

逐字段复核本课数字。 docs/flights-measurement.json(实录)和 docs/full-speed-measurement.json(对比实验)带全部原始数据:源码哈希、token 数、每次文本调用的费用;对比实验的 6 次运行还各自带浏览器版本(Chrome/152.0.7977.83)与完整 CDP 明细。想核对本文任何一个数字,去这两个文件。

注意测量后的代码变动。 performance.md 记录:计时和录像完成之后,原生 SELECT 的中断处理被收紧(结果不确定时停下,不再当作可重试的 stale 读取);Flights 不触发原生 SELECT,所以计时与录像哈希保持不变。你 clone 下的代码比测量时新一点,这是正常的。

选文本 helper 时看看官方怎么挑的。 官方拿两次真实航班字段做探针,试了 Gemini 2.5 Flash Lite、Gemini 3.1 Flash Lite 和 Mercury 2.5,全都返回了正确值;更早的探针否掉过一个把出发地/到达地写反的模型,还否掉过一个不输出合法 JSON、输出评论的模型。教训:换 TEXT_MODEL 别只看延迟,拿真实字段做正确性探针再上。

本课小结 ​

✅ Jev Ultrafast 性能数字分三组:实录 7.073 秒(口径:首次预测 → 接受 DONE)、对比实验 9.450 → 7.092 秒(6 次交替、取中位数、双方 3/3)、协议调用 1,092 → 101(同一实验)。

✅ 实录账单:17 次决策请求(中位 178 ms、合计 3,720 ms,约占总时间 53%)、2 次文本生成(927 ms)、11 个动作、90,558 + 6,325 token;搜索在第 5.217 秒执行。

✅ 17 次请求 = 11 个动作 + 1 次被接受的 DONE + 5 次 stale(预测在执行前因页面变化作废,时间照算)。

✅ 变快的原因是「看页面」的方式变了:DOM.resolveNode 828 → 0、全量无障碍树 30 → 0、Runtime.evaluate 约 150 → 约 75;输入类调用两边不变。

✅ 引用时带限定语:单任务、3 对交替、live 网络、p = 0.25——官方自己把局限写在数字旁边,你也这么转述。

关键数字回顾:

指标官方数字口径
实录耗时7.073 s首次预测 → 接受 DONE
决策请求 / 中位延迟17 次 / 178 ms实录
搜索执行时刻5.217 s实录,11 个动作之一
对比中位耗时9.450 → 7.092 s(−25.0%)3 对交替运行
协议调用中位数1,092 → 101同一对比实验
文本 helper 费用$0.00006272仅 2 次文本调用(OpenRouter)
TypeSafe token90,558 输入 / 6,325 输出实录全部请求

下一课预告 ​

数字看完了,下一课 写自己的浏览器任务:Agent 库实战把 Ultrafast 变成你自己的工具。你会学到:

  • Agent(url, goals) 的完整用法:goals 可以是字符串或列表,run() 逐步拿到 state
  • state 里每个字段怎么用:history、decisions、text_calls、status、elapsed_ms——就是本课账单的数据来源
  • 换一个 URL 和一句目标就是新任务,以及什么时候该配你自己的独立验证
  • 文本模型怎么换:DeepSeek、GLM 等 OpenAI 兼容端点的配置方法

附录:源码参考 ​

点击展开查看源码位置

更新时间:2026-11-04(仓库 github.com/browser-use/jev-ultrafast,本地信息源 sources/jev/repo-ultrafast/)

功能文件路径关键位置
性能报告正文docs/performance.md计时口径(Timing begins…);实录账单(17 请求 / 178 ms / 5.217 s / 7.073 s / 90,558+6,325 token / $0.00006272);对比实验表与 p=0.25;Where the time went;Other checks(2.798 s / 1.896 s);Development attempts;Limits
实录测量数据docs/flights-measurement.jsonelapsed_ms 7073;decision_requests 17;decision_median_ms 178;decision_total_ms 3720;actions 数组 11 条的 executed_ms 时间线;text_calls(581/346 ms 与 $2.93e-05/$3.342e-05);tokens 90558/6325;video(187 帧 / 1× / 0 开场停顿 / 500 ms 结尾停顿 / 裁 64 px);timing 字段即口径原文
对比实验数据docs/full-speed-measurement.jsonsummary(9450/7092、1092/101);runs 6 条(每对的 elapsed_ms、decision_requests、cdp 明细、源码哈希、tokens、text_calls);scope(3 对、1120×780、live 未控);baseline_commit 68c077bf…
README 摘要README.md「Evidence and limits」:7,073 ms 口径、3/3 通过、25%、协议调用 1,092 → 101、2.798 s / 1.896 s、DONE 需独立验证
计时起点与 stale 处理jev_ultrafast/agent.pyL68–69 started_at 首次 predict 设置;L93–99 DONE 接受时更新 elapsed_ms;L55–64 StalePage → 丢弃决策、重新观察;L75–76 模型调用预算 MAX_STEPS×2;L102–104 动作预算
默认模型jev_ultrafast/model.pyL108 os.environ.get("TYPESAFE_MODEL", "jev-latest")
trace 保存字段examples/flights.pyL50–52 打印 elapsed_ms/status;L54–56 state.json = agent.snapshot() + verification(含 elapsed_ms、history、decisions、text_calls)
设计原则原文README.mdL98「One browser call per snapshot」;L100 combobox 建议等待上限 200 ms、其他交互两个动画帧或 50 ms
Jev 价目(成本推算依据)TypeSafe 官方文档 docs/models.md(本地 sources/jev/docs/models.md)$42 / B 输入 token、输出免费;别名 jev-latest 当前指向 jev-1.14.0
搞懂AI关于我们怎么写隐私说明

独立的第三方教程,与文中提到的任何产品及其公司没有隶属或合作关系;产品名称和商标归各自所有者。价格和政策以官方页面为准。