news 2026/10/21 7:19:55

CUAWright cuawright-web 技能实战:用 /cuawright:craft 将一次性网页任务参数化为可复用 CLI 工具

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CUAWright cuawright-web 技能实战:用 /cuawright:craft 将一次性网页任务参数化为可复用 CLI 工具
  • 人工智能
  • AI Agent
  • 浏览器控制
  • 代码智能体

【免费下载链接】CUAWright

A simple SWE style browser+desktop agent framework that achieves SOTA results on long horizon web tasks.

项目地址:https://gitcode.com/gh_mirrors/web/CUAWright
点击查看免费下载

本文基于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: ...

参数表规则(三条缺一不可):

  1. # Parameters中每一行都必须同时成为(a)可复用函数的参数,和(b)argparse的一个--flag,且默认值使用表中列出的 default。
  2. 真正固定于站点的项(起始 URL、站点名、选择器策略)不列入参数表,保持硬编码。
  3. 默认值必须精确复现原任务: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)增加了三项:

  1. 无参复现:如上第 6 节,python final_script.py在final_runs/run_<id>/内端到端成功。
  2. 导入安全冒烟测试:如上第 7 节。
  3. 可选第二次运行:用不同的参数值在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):

  1. plan.md同时包含# Parameters(name、type、source phrase、default、allowed/format)与# Critical Points两份清单;
  2. final_script.py定义恰好一个可复用函数,Google 风格Args:docstring 覆盖每个参数;
  3. # Parameters中每个条目与函数参数、argparse--flag一一对应,且 flag 默认值等于原任务具体值;
  4. 脚本通过导入安全冒烟测试;
  5. python final_script.py(无参)在final_runs/run_<id>/内复现了任务,全部 CP 依据截图与动作日志验证通过;
  6. final_script_log.txt中存在step 0 params: ...行;
  7. 用户已经看到最终数据与--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.

项目地址:https://gitcode.com/gh_mirrors/web/CUAWright
点击查看免费下载

相关推荐

上一篇:OpenPencil CLI 导出实战指南:从终端生成 PNG、SVG、PDF、PPTX、HTML 与 JSX
下一篇:Shell变量作用域性能优化终极指南:gh_mirrors/sh1/sh中的高效缓存策略 🚀

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 19:40:11

Carp 标准库文档完全指南:在线查阅、本地副本与一键重新生成

编程语言编译器 【免费下载链接】Carp A statically typed lisp, without a GC, for real-time applications. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ca/Carp 点击查看 免费下载 Carp 是一个无 GC、静态类型、面向实时应用场景的 Lisp 方言&#xff08;参见仓…

作者头像 李华
网站建设 2026/10/14 2:40:35

PMIC+MCU协同电源管理:PCA9422与MKV46F256VLH16实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/16 14:16:53

UWB定位算法仿真包:6种算法+实测数据+Matlab工程

简介&#xff1a;本资源是一套面向通信与定位算法学习者的UWB高精度定位仿真代码包&#xff0c;聚焦卡尔曼滤波在超宽带室内定位中的建模、实现与优化&#xff0c;适用于高校研究生、嵌入式定位开发工程师及物联网定位方向实践者。包内共12个文件&#xff0c;含9个MATLAB核心算…

作者头像 李华