工程说明 —— Windup 背后的技术

对那些让自然语言测试既确定又廉价的方法的总结:

  • 规划一次,免费回放。 LLM 每个场景恰好使用一次(外加应用变更时的自动重新规划)。它的输出是一份经过 schema 校验的 JSON 操作计划 —— 数据,而非代码:没有生成的脚本、没有条件分支、没有运行时即兴发挥。回放以零模型调用执行缓存的计划。
  • 确定性执行。 计划在 Playwright 上运行,配合原生可操作性检查和可信输入事件。每个操作都携带一个明确的后置条件(expect:元素可见 / URL glob / 输入值),并无需 LLM地验证 —— 验证的成本是一次 DOM 查询,而非 token。
  • 自愈缓存。 轨迹以场景 + 起始 URL 的路径为键缓存(可在 dev/staging/CI 主机间移植)。验证失败会使计划失效,把陈旧条目保留为证据,并以失败作为上下文触发一次重新规划。
  • 结构化页面签名。 页面由其规范化交互元素的 SHA-256 标识 —— 不含文本、不含数据 —— 因此环境噪声不会拆分身份,且起始页面的漂移会在回放时被(宽松地)检测到。
  • 分层的站点知识。 一张站点地图图为规划器提供真实的路由和选择器,由三个来源以严格优先级构建 —— 运行时观察 > 静态源码扫描 > 受限的 LLM 辅助。知识是缓存,而非真理:任何陈旧的东西都降级为运行时发现。
  • 提示词预算纪律。 规划提示词保持近似恒定的大小(~32k 字符):页面树、地图切片、片段目录和清单各有硬性字符预算。长提示词会可测量地拖累小模型 —— 预算是一项正确性特性,而非优化。
  • 机械式规范化胜过对提示词的指望。 模型输出被确定性地清洗:丢弃空字段、id 重新编号、wait_forexpect 归一化、去重片段回声操作、从编写的场景中清除凭据。跨提供商的 A/B 测试表明,单靠提示词指令无法在各模型间站稳 —— 代码才有最终决定权。
  • 两级重试。 语义失败(无效计划)获得一次携带校验错误的短重试;瞬时的 API 异常(token 循环退化、网络)以不同的随机种子重新调用。避免全提示词重试 —— 它们会可靠地再次触发退化。
  • 可组合的构建块。 片段是精选的、已提交的子轨迹(例如登录),计划按 id 引用它们 —— 更新一次,处处传播,在运行时展开。项目清单把团队知识(约定、账户、术语)注入每一份计划。
  • 按引用管理密钥。 凭据值存在 .env.local/CI 密钥中;已提交的文件只携带账户 → ENV 名称的映射。计划使用 value_ref,在执行时解析 —— 密钥从不抵达 LLM、缓存或 git。
  • 与提供商无关的 LLM 边界。 一个接口,Google 和 OpenAI 两种实现(OpenAI 客户端是纯 REST —— 没有 SDK 负担),可按次运行选择。更换浏览器引擎和增加一个提供商各是一处单文件改动 —— 这些边界就是架构本身。
  • 可审计的成本。 每个 LLM 触点都有明确上限,并落入一份带 token、模型和提供商的按次运行账本;windup costs 从一张带日期的价格表重新计算,因此随着价格变动,历史依然准确。