工作原理
natural-language task ──▶ planner (LLM, 1 call) ──▶ JSON action plan
│
trajectory cache ◀── cheap verification ◀── deterministic executor
│
└──▶ subsequent runs: zero LLM, ~1s, $0
最昂贵的部分 —— 弄清楚该执行哪些浏览器操作 —— 只发生一次,并被转化为缓存的、可验证的数据。
- 计划是数据,而非代码 —— 经过 schema 校验的 JSON;没有生成的脚本,没有条件分支。
- 廉价验证 —— 每个操作之后检查 DOM/URL 后置条件。验证失败会使缓存的计划失效,并触发一次自动重新规划。
- 站点地图 —— 每次执行都会补充一张页面与跳转的图;
windup scan在首次运行前就直接从你的源代码为这张图播种,因此规划器使用的是你应用的真实选择器,而不是靠猜。 - 片段(Fragments) —— 经过验证的操作块(例如登录),规划器通过
{ "type": "use" }组合它们,而非重新生成。 - 零硬编码的站点知识 —— 引擎懂的是各类框架和 Web 平台,从不懂你的站点。所有站点知识都作为输入(场景、配置、清单)到来,或在运行时被发现。
为什么选 Windup
手写脚本运行成本低,但维护成本高。每次运行都调用 AI 的智能体易于编写,但速度慢且不确定。Windup 各取二者之长。
| 手写脚本 | 每次运行都用 AI 智能体 | Windup | |
|---|---|---|---|
| 编写方式 | 手写代码 + 选择器 | 纯自然语言 | 纯自然语言 |
| 运行成本 | $0 | 每次运行都调用 LLM | 仅首次运行调用 LLM |
| 运行速度 | 快 | 慢(模型在回路中) | ~1s 回放 |
| 确定性 | 高 | 低 —— 每次即兴发挥 | 高 —— 每次回放都是同一份计划 |
| 应用发生变化 | 你去修脚本 | 可能悄无声息地做别的事 | 验证失败 → 自动重新规划 |
缓存买到的是 $0,而不是”瞬时”。 一次缓存命中会跳过 LLM 的规划(plan=0ms、llm_calls=0)—— 但计划中的 Playwright 动作仍然会运行,任何 depends_on 链路也仍然会执行,因此实际耗时是真实的浏览器时间,而不是一次查表。每次运行都会报告明细 —— total=… (plan=… deps=… exec=… setup=…) —— 其中 deps 是依赖链路,exec 是本场景的动作,setup 是浏览器上下文。HTML 报告将每个场景的耗时拆分为一条可对账的条形图(setup · deps · plan · nav · actions),其中 nav 是首个动作之前的 goto + 页面加载/水合 —— 通常是 SPA 中真正的时间消耗点(所以一个显示为 “3.6 s” 的 113 ms 动作,实际上是 setup + nav)。Windup 一旦页面渲染出可交互元素或网络空闲便会继续推进,因此纯展示型页面不会卡在就绪超时上。套件标题显示的是实际耗时(wall-clock,真实经过时间),而不是各场景总耗时之和 —— 后者在 --concurrency N 下会膨胀约 N×。在并发下,每个场景的剩余时间会被标注为 contention(即”争用”:该场景在兄弟场景运行时等待 CPU/浏览器槽位所花的时间 —— 空闲,而非工作),并会显示一个 active ms 数值(它自身的活跃工作量,在不同并发下大致稳定),以便各场景保持可比。最大的杠杆是会话快照:一个依赖的认证状态(storageState)只捕获一次,并在之后的回放中恢复,因此登录流程不必为每个依赖它的场景重新运行(deps≈0)。
想深入了解运行机制 —— 模块边界、数据格式、成本与安全态势 —— 参见架构与规范。