- 人工智能
- AI Agent
- 浏览器控制
- 代码智能体
【免费下载链接】CUAWright
A simple SWE style browser+desktop agent framework that achieves SOTA results on long horizon web tasks.
本文基于cuawright-web技能中的 CLI 工具模式(CLI tool mode)命令 craft.md,系统讲解如何把一次性的网页自动化任务(搜索、筛选、表单填写、多步流程、数据抽取)抽象为一个可反复调用的参数化final_script.py:包括参数识别、# Parameters规划表、Google 风格 docstring 的可复用函数、argparseCLI 包装、导入安全(import-safety)与无参复现验证。读完本文,你将掌握在 CUAWright 框架内从"跑通一次"到"交付一个可持续复用的命令行工具"的完整方法,并能对照仓库源码理解其底层契约。
一、两种模式的分工:one-shot 与 CLI tool
在cuawright-web技能(总纲见 SKILL.md)中,Webwright 的浏览器自动化产出物都是final_script.py,但根据使用意图分成两种模式:
- 默认一次性模式(one-shot):由普通提示词或
/cuawright:run <task>触发(见 run.md)。final_script.py只针对用户给出的字面值完成任务,跑完即止。 - CLI 工具模式(CLI tool mode):由
/cuawright:craft <task>触发,或当用户提出"make it reusable""parameterize""turn this into a CLI""I want to call this again with different X"等意图时自动激活。此时final_script.py是一个可复用的参数化 CLI 工具:同一个脚本可以在之后用不同的参数值重复运行,完成同一类任务。
完整契约见 cli_tool_mode.md。该契约源自仓库中 crafted_cli.yaml 的 "Final-Script Shape (CLI Tool, MANDATORY)" 章节,并做了本地化改造:原本依赖 OpenAI 的image_qa与self_reflection门控,被替换为 Agent 自己对plan.md关键点(Critical Points)的逐一核对,全程无需任何模型 API Key。
二、一次性环境准备
从 CUAWright 仓库根目录执行(见 SKILL.md 的 Prerequisites 一节):
pip install -e . playwright install firefox- 本技能不需要任何 API Key:浏览器为本地 Playwright Firefox,视觉验证由 Agent 直接用
Read读取 PNG 截图完成。 - 浏览器引擎选择 Firefox 而非 Chromium 是有原因的:部分站点(如 cars.com 等 Akamai 防护站点)在 Playwright Chromium 下会因 TLS/H2 指纹问题报
ERR_HTTP2_PROTOCOL_ERROR,而 Firefox 可以正常加载(依据 playwright_patterns.md)。 - 不要额外
pip/apt安装任何包:playwright、httpx、pydantic等依赖已预装(SKILL.md 的 Hard Rules)。
三、第一步:识别参数,划定"可变"与"固定"的边界
craft的起点是 craft.md 的第 1 步:提取用户可能变动的每一个需求点。可参数化的候选包括:
- 搜索关键词(search terms)
- 地点(locations,如出发/到达机场、城市)
- 日期与时间(dates)
- 筛选值(filter values:品牌、年份区间、价格区间、颜色等)
- 排序方式、数量、单位等一切用户下次可能换掉的输入
而对站点而言真正固定的东西不是参数,必须硬编码:
- 起始 URL(start URL)
- 站点名称
- 选择器策略(selector strategy)
以 crafted_cli.yaml 中的官方示例为例:"Search for a red Toyota Corolla from 2018 to 2023 on CarMax",可参数化为Make、Model、min_year、max_year、color五个参数;而 CarMax 的入口 URL 与页面选择策略保持硬编码。仓库中真实的飞行任务轨迹也印证了这一分工:在 lax_ord/final_script.py 中,Google Flights 的启动 URL 与get_by_role选择器全部写死,而航线、日期等作为输入。
四、第二步:在 plan.md 中追加# Parameters参数表
在写脚本之前,先在plan.md中、在常规的# Critical Points清单之外增加# Parameters表格,这是 CLI 模式的硬性要求(cli_tool_mode.md):
# Task <verbatim task description> # Parameters | name | type | source phrase from task | default | allowed / format | |---------|------|-------------------------|-------------|-------------------------| | <arg_a> | str | "..." | "<value>" | <format / allowed set> | | <arg_b> | int | "..." | <value> | <range or units> | | <arg_c> | str | "..." | "<value>" | <format> | # Critical Points - [ ] CP1: ... - [ ] CP2: ...参数表规则(三条缺一不可):
# Parameters中每一行都必须同时成为(a)可复用函数的参数,和(b)argparse的一个--flag,且默认值使用表中列出的 default。- 真正固定于站点的项(起始 URL、站点名、选择器策略)不列入参数表,保持硬编码。
- 默认值必须精确复现原任务:
python final_script.py(不带任何参数)运行的结果必须与原任务完全一致。
同时,# Critical Points清单仍然保留,它是对照截图/日志逐条验收的契约。每个 CP 必须能独立地从一张截图或一行日志得到验证。
五、第三步:final_script.py 的强制形状
craft的核心产出物需要满足六项形状要求,缺一不可。这里逐项展开。
5.1 一个以任务领域命名的可复用函数
函数名体现任务领域,例如:
def search_<domain>(arg_a, arg_b, ...): ...(如search_cars(Make, Model, min_year, max_year, color))def lookup_<entity>(query, filters): ...
5.2 Google 风格 docstring
docstring 必须包含摘要、完整的Args:块和Returns:。每个Args:条目要说明:参数名与类型、在任务领域中的含义、可接受的格式/单位/取值范围、默认值(与# Parameters表保持一致):
def search_<domain>(arg_a: str, arg_b: int, arg_c: str) -> dict: """<One-line summary of what this tool does on the target site>. Args: arg_a: <what it represents>; <format / allowed values>. Default: "<value>". arg_b: <what it represents>; <range / units>. Default: <value>. arg_c: <what it represents>; <format>. Default: "<value>". Returns: dict with keys ``<key1>`` (<type>), ``<key2>`` (<type>), """5.3 argparse CLI:flag 与函数参数一一对应
在if __name__ == "__main__":下用argparse包装。每个函数参数都有对应的--<arg>flag,type=与 docstring 一致,help=直接取自 docstring,default=等于原任务的具体值:
if __name__ == "__main__": import argparse parser = argparse.ArgumentParser( description=search_<domain>.__doc__.splitlines()[0]) parser.add_argument("--arg-a", dest="arg_a", type=str, default="<value>", help="<copied from docstring>") parser.add_argument("--arg-b", dest="arg_b", type=int, default=<value>, help="<copied from docstring>") parser.add_argument("--arg-c", dest="arg_c", type=str, default="<value>", help="<copied from docstring>") args = parser.parse_args() result = asyncio.run(_run(**vars(args))) print(result)注意dest=将--arg-a映射回arg_a,保证 CLI 参数名与函数签名严格对齐,这正是 crafted_cli.yaml 中 "Every function argument MUST have a matching--<arg>flag" 的实现方式。
5.4 导入时零副作用(side-effect-free at import time)
模块顶层不得启动浏览器、发起网络请求或写文件。可复用函数必须可以被另一个 Python 进程 import 而不触发任何运行——真正的执行只发生在if __name__ == "__main__":之下。这是为了支持后续的"导入安全冒烟测试"以及把该函数作为库被其他程序引用。
5.5 动作日志的第一行必须是step 0 params: ...
日志重置后写入的第一行必须列出全部解析后的参数,格式为name=value对,例如:
step 0 params: arg_a=<value> arg_b=<value> arg_c=<value>这样任何验证环节(包括外部 judge)都能直接看到本次运行实际生效的输入。
5.6 与默认模式相同的仪器化(instrumentation)
仪器化要求与一次性模式完全一致(playwright_patterns.md):
- 视口固定
viewport={"width": 1280, "height": 1800}; - headless 本地 Firefox(
playwright.firefox.launch(headless=True)); - 禁止
page.screenshot(full_page=True)(探索、调试、终跑截图一视同仁); - 截图保存为
final_runs/run_<id>/screenshots/final_execution_<step>_<action>.png; - 最终数据(final datum:价格、代码、中选者、报价等)追加写入
final_script_log.txt末尾。
5.7 一个真实的仪器化脚本参考
仓库中 lax_ord/final_script.py 是 Google Flights"最早直飞航班"任务的完整执行脚本,展示了核心仪器化模式:
RUNS = WORKSPACE / "final_runs" RUNS.mkdir(exist_ok=True) existing = [int(p.name.split('_')[-1]) for p in RUNS.glob('run_*') if p.name.split('_')[-1].isdigit()] run_id = max(existing, default=0) + 1 RUN_DIR = RUNS / f"run_{run_id:03d}"即:每次干净执行都自动落到新的、递增的final_runs/run_<id>/文件夹,互不覆盖;随后LOG.write_text('')重置日志,next_step()写step <n> action: ...,snap()以final_execution_<step>_<action>.png命名截图,最后把答案写入agent_response.json并追加到日志。CLI 工具模式在其基础上把入口从"写死的任务值"换成"argparse 解析的参数"。
六、第四步:无参数复现原任务
在全新的final_runs/run_<id>/目录中执行:
cd final_runs/run_<id> && python final_script.py要求整条链路端到端成功,并产出预期的截图与step 0 params: ...日志行。这一步验证"默认值 = 原任务值"的承诺确实成立。
七、第五步:导入安全冒烟测试(import-safety smoke test)
从任意其他目录加载该模块,确认不启动浏览器、不触发运行,并能打印出可复用函数名(cli_tool_mode.md 给出的标准命令):
python -c "import importlib.util, pathlib; \ spec = importlib.util.spec_from_file_location('fs', 'final_runs/run_<id>/final_script.py'); \ m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m); \ print([n for n in dir(m) if not n.startswith('_')])"该命令必须瞬间完成(无浏览器启动)并打印出可复用函数的名称,证明模块可以安全地被其他代码引用。
八、第六步:自验证(替代 self_reflection)
CLI 模式的自验证在默认模式的"逐条核对plan.md"基础上(详见 workflow.md)增加了三项:
- 无参复现:如上第 6 节,
python final_script.py在final_runs/run_<id>/内端到端成功。 - 导入安全冒烟测试:如上第 7 节。
- 可选第二次运行:用不同的参数值在
final_runs/run_<id>_alt/中再跑一次,用实际结果证明参数化生效(仅当备选值在目标站点明确不可用时才可跳过)。
随后对plan.md中每个 CP,在保存的截图与动作日志中找到对应证据并逐条勾选。证据必须不含歧义:
- 筛选 chip / 选中状态可见(而不是藏在已关闭的抽屉里);
- 数值 / 日期精确匹配(没有被放宽);
- 排序确实通过站点的控件应用(而非由结果顺序推断);
- 提交 / 搜索 / 应用等必需动作被可见地执行;
- 最终数据清晰可读地展示。
若任一 CP 失败,定位具体问题(错误的筛选值、缺失的控件、被遮挡的 chip、放宽的范围、缺失的确认、缺失的截图),修复final_script.py(保持 CLI 形状不变:可复用函数 + 任务值默认值的 argparse flags),在下一个final_runs/run_<id+1>/中重跑并重新验证。空结果集在"正确应用了筛选"的前提下可接受。
九、第七步:展示--help并交付
最后一步必须向用户展示:
python final_runs/run_<id>/final_script.py --help并同时报告**最终数据(final datum)**与--help输出,让用户清楚知道以后如何用不同参数再次调用该工具。
十、CLI 模式的完成门槛(Completion Gate)
只有当以下全部为真时才能宣告任务完成(cli_tool_mode.md):
plan.md同时包含# Parameters(name、type、source phrase、default、allowed/format)与# Critical Points两份清单;final_script.py定义恰好一个可复用函数,Google 风格Args:docstring 覆盖每个参数;# Parameters中每个条目与函数参数、argparse--flag一一对应,且 flag 默认值等于原任务具体值;- 脚本通过导入安全冒烟测试;
python final_script.py(无参)在final_runs/run_<id>/内复现了任务,全部 CP 依据截图与动作日志验证通过;final_script_log.txt中存在step 0 params: ...行;- 用户已经看到最终数据与
--help输出。
任一条件不满足,就不得宣告完成——应诊断、修复脚本(保持 CLI 形状)、在下一个run_<id+1>/重跑并重新验证。这一"修复-重跑-复验"的闭环,与 crafted_cli.yaml 中"preserving the CLI shape — reusable function + argparse flags with task-value defaults"的强制要求一致。
十一、底层支撑:浏览器契约与表单交互要点
CLI 工具模式与默认模式共享同一套浏览器契约(base.yaml 中environment.browser_mode: local即为本地 Playwright 模式,与 Browserbase 云会话模式二选一):
- 每次运行都是全新会话:无持久浏览器状态,脚本从起始 URL 开始重建全部状态;
- 交互式表单填充优先于深链 URL:当任务需要参数化搜索(地点、日期、筛选、查询词)时,应像真人一样驱动页面控件,而不是把参数拼进 URL。深链的脆弱性在于:站点会静默丢弃无法解析的参数、URL 解析随地区/A-B 桶/登录态变化、一个输入集下可用的深链无法证明另一输入集也能填充。正确姿势是:用
get_by_role/aria-label选择器(避免脆弱的 CSS 类)、输入后等待 suggestion listbox 再点选包含规范 token 的选项、成对字段(日期范围、步进器组)在同一个 modal 内打开后用 Tab 切换而不是逐一点击输入框(避免被 modal 遮罩挡住)、显式点击提交控件而非依赖自动提交,最后重新读取表单状态逐条断言 CP1..CPn; - 角色定位模式:
page.get_by_role("button", name="Filters").click()、page.get_by_role("checkbox", name="BMW").check(),并对控件的父节点打印aria_snapshot()观察兄弟选项。
十二、从 CLI 工具到技能库的延伸
参数化的最终形态不止于"单次任务的复用"。仓库中 examples/README.md 展示了一条进阶路径:三份从零求解的"最早直飞航班"轨迹(SEA→JFK、SFO→BOS、LAX→ORD)经过learn蒸馏为一份含5 个提升参数(origin_city、origin_code、destination_city、destination_code、date)的skill.py模板,并在未见过的航线 SEA→DEN 上以约 10 步、约 40 秒、无需模型的方式独立运行成功(meta.json中verified: true, grade: executable)。这与craft共享"参数化 + 默认值复现 + 可独立调用"的思想,但把复用单元从单个脚本升级为可检索、可路由的技能库。相关的test_learned_example.py、test_recommend.py等测试位于 tests/skill_factory 目录,可作进一步参考。
十三、常见踩坑清单
综合 craft.md、cli_tool_mode.md 与 workflow.md 的硬规则,CLI 工具模式最常出现的失败点:
- 把固定项也参数化:起始 URL、站点名、选择器策略不应成为 flag,否则 CLI 表面被无意义地膨胀;
- 函数参数、docstring、argparse flag 三者脱节:任一参数在 docstring 或 CLI 中缺失即不满足完成门槛第 2、3 条;
- 顶层副作用:模块 import 即启动浏览器或写文件,冒烟测试将直接暴露;
- 日志缺
step 0 params::验证环节无法确认实际生效参数; - 默认值 ≠ 原任务值:无参运行无法复现任务;
- 用搜索结果代替筛选控件:站点提供专门控件时,搜索框查询永远不能满足显式筛选/排序/样式/属性要求;排名语言(cheapest、best-selling、most reviewed、highest-rated、lowest、latest)必须锚定在站点真实的排序/筛选控件上,而不是自己重排结果;
- 数值/日期/数量/单位约束被放宽:这些约束必须精确,站点没有更精确的控件时才允许更宽泛的默认;
- 选中状态在抽屉/手风琴/弹窗/下拉关闭后被隐藏:必须重新打开控件或先截取可见的 chip/摘要,再认定状态已生效;
- 对声称的阻塞(Access Denied、控件不可用)过早放弃:只有反复从真实站点 UI 取证后才允许停止。
掌握上述要点后,/cuawright:craft便能稳定地产出"可复制、可运行、可复用、可被他人通过--help直接调用"的 Webwright CLI 工具,这正是 CUAWright 将浏览器自动化从一次性脚本升级为工程化资产的核心理念。
- 人工智能
- AI Agent
- 浏览器控制
- 代码智能体
【免费下载链接】CUAWright
A simple SWE style browser+desktop agent framework that achieves SOTA results on long horizon web tasks.
相关推荐
CUAWright CLI Tool Mode 实战指南:用 `/cuawright:craft` 把一次性 Web 任务脚本改造成可复用、参数化的命令行工具
CUAWright CLI Tool Mode 实战指南:用 /cuawright:craft 把一次性 Web 任务脚本改造成可复用、参数化的命令行工具 这篇
人工智能AI Agent浏览器控制代码智能体CUAWright 浏览器技能(cuawright-web)实战指南:用单条 bash 命令驱动本地 Playwright 完成可验证的 Web 任务自动化
CUAWright 浏览器技能(cuawright web)实战指南:用单条 bash 命令驱动本地 Playwright 完成可验证的 Web 任务自动化 本
人工智能AI Agent浏览器控制代码智能体CUAWright Webwright 一次性 Web 任务执行指南:`/cuawright:run` 命令的 Playwright 代码即操作工作流
CUAWright Webwright 一次性 Web 任务执行指南: /cuawright:run 命令的 Playwright 代码即操作工作流 CUAWr
人工智能AI Agent浏览器控制代码智能体
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考