跳到主要内容

webwright — 本课题摘录

读了哪几篇: 01-agent-loop(中央 agent 循环)、04-completion-gate(完成门禁与自我校验)。 其余两篇(两种环境与代码即动作、模型后端)本轮没读。

这一家在本课题里的位置:它是"什么时候停"这一问里唯一一个说"模型说了不算"的。

它对本课题回答了什么

决定四:完成门禁 —— 把"做完了"变成一个可核对的磁盘事实

它先把问题点破:模型很爱"幻觉式完成"——没真正做完就宣称做完了。 后果是评测分数虚高、实际失败。

它的答案:模型想说"我做完了",必须先满足三件事,而且三件事都是磁盘上能查到的:

① 把任务拆成若干条「可独立验证的约束/筛选/动作」,写进一个计划文件

② 写一个最终脚本,真跑一遍,产出逐条对应的证据 + 动作日志

③ 跑一个「自我校验」裁判,写出结果文件,里面的判定必须是「通过」


只有第 ③ 步的文件真的存在、且判为通过,循环才放行「完成」

(依据:前沿库 · Webwright · 完成门禁与自我校验 —— 模型想 done=true 必须先把任务拆成 critical points 写进 plan.md、跑 final_script 产出逐条截图与动作日志、再跑 self_reflection 裁判写出 predicted_label=1 的结果文件,门禁检查这个文件才放行)

"把完成变成一个磁盘事实"这句话是这一篇的核心。 其它家的收工判据都在内存里(模型不再调工具 / 调了完成工具 / 停止条件谓词为真),只有它把判据放到了循环之外、放到了一个别人也能查的地方。

裁判本身是两阶段的

阶段 1(并行,每条证据一次调用)
每条证据 ──► 让模型打一个分 + 写一段理由
(解析失败重试至多三次,仍失败记零分)

▼ 收集所有理由
阶段 2(一次聚合调用)
把「每条证据的理由编号列表」+「动作日志」+「全部证据」一起给模型


回复必须以「状态:通过」或「状态:失败」结尾


解析末尾那一行 ──► 通过 / 失败 / 解析不出来当失败

(依据:前沿库 · Webwright · 完成门禁与自我校验 —— self_reflection 是两阶段——阶段1并行地对每张截图让模型打 1-5 分并写理由(解析失败重试≤3、仍失败记0分),阶段2把所有理由+动作日志+全部截图一起聚合成一次调用,要求回复以 Status: success/failure 结尾)

三个可抄的实现细节:

细节为什么
解析很宽容先用正则抠两行,抠不到再退回当 JSON 解析;而且提示词明确要求"只返回这两行,别返回 JSON"
只认最后一个"状态"行模型可能在中间提到"状态",取最后一处;缺失或畸形一律当失败
证据自动发现不显式传时自动找编号最大且有证据的那次运行,agent 不用手动列清单

(依据:前沿库 · Webwright · 完成门禁与自我校验 —— 裁判解析先正则抠 Score/Reasoning 两行抠不到再当 JSON 解析;最终裁决只认最后一个 Status 行,缺失或畸形一律当 FAIL)

"缺失或畸形一律当失败"这个默认方向是对的。 判定"成没成"的地方,不确定就该判没成。 对比 fara 的"步数耗尽也标成完成"——同一个位置,一个默认失败,一个默认成功,后者出了问题。

决定四补充:退出的唯一信号是一条消息

循环里没有布尔标志、没有返回值判断——退出的唯一方式是往消息列表尾部塞一条"退出"角色的消息。 (依据:前沿库 · Webwright · 中央 agent 循环 —— DefaultAgent 的 while True 里,退出的唯一信号是消息列表最后一条的 role 等于 "exit",不是异常也不是返回值)

这跟 mini-swe-agent 一模一样(那边也是"最后一条消息是不是退出角色")。两家独立收敛,而且都配了"异常自带该追加什么消息"的机制。

这条设计的好处:"为什么停的"和"停了"用同一个数据结构表达。 退出消息里可以带原因、带最终答案,不需要另开一个字段。

决定一:循环体只有一行,复杂性全挂在外围

它把这条说得最干脆:循环体只有一行——"查模型,执行它给的动作";所有复杂性(退出、压缩)都挂在循环外围。 (依据:前沿库 · Webwright · 中央 agent 循环 —— 循环体只有一行 step()=execute_actions(query()),所有复杂性(退出、压缩)都挂在循环外围;每一步都在 finally 里落盘轨迹)

每一步都在最终块里落盘轨迹——哪怕中途崩了,轨迹也已经存下来了。(跟 mini-swe-agent 一样。)

每 N 步压缩一次历史,压缩不在循环体里,在循环外围。

它没回答什么

  • 工具调用怎么解析——它走的是"严格 JSON 动作 + 代码即动作",细节在本轮没读的那两篇。
  • 多工具并发——它每步一个动作。
  • 循环状态怎么存下来续跑——只有轨迹落盘,没有"从中断处精确续跑"。

坑与代价

  • 这套门禁很贵。 想收工要先写计划、跑脚本、留证据、再调一次(甚至 N+1 次)模型当裁判。一次收工可能要花掉十几次模型调用。

    判断(无锚): 我们的最小原型不上完整门禁,但应该抄它的方向:至少让"完成"这件事有一个循环之外的判据,哪怕只是"最后一次工具执行的返回码为 0"。 如果错,会错在: 如果第一批任务是"回答一个问题"这类没有外部可验证产物的,那就根本没有磁盘事实可查,只能回到"模型说完了就是完了"。那时这条方向对我们无效。

  • 裁判用的是同一个模型。 让模型给自己的产出打分,存在共谋风险——它靠"看证据而不是看自述"来削弱这一点,但没有消除。
  • 模板注入用的是字符串格式化,所以提示词里任何字面花括号都得转义。 它的配置里专门警告了这一点。这是"用格式化拼提示词"这条路的通病。