page-agent 自定义工具开发最佳实践:Zod Schema 与 AbortSignal 协作式取消
page-agent 自定义工具开发最佳实践Zod Schema 与 AbortSignal 协作式取消【免费下载链接】page-agentJavaScript in-page GUI agent. Control web interfaces with natural language.项目地址: https://gitcode.com/GitHub_Trending/pa/page-agentpage-agent 是一个运行在网页内的 JavaScript GUI Agent用自然语言操控网页界面。本文面向新手讲透两个核心问题如何用 Zod Schema 定义自定义工具的输入参数以及如何用 AbortSignal 实现协作式取消cooperative cancellation让你的工具在用户点击停止时能立即、干净地退出。内置工具不够用先认识 customToolspage-agent 自带一组内置工具点击、输入文本、下拉选择、滚动、等待、执行 JS 等定义在 tools/index.ts 中。当你的业务需要加入购物车查知识库提交审批单这类专属动作时就通过customTools配置项扩展能力。注册方式只需一步在创建 Agent 时传入customTools每个工具由tool()辅助函数包裹包含三个要素要素作用关键点description写给大模型看的说明书决定 AI 何时调用该工具要具体、可操作inputSchema用 Zod 定义的输入参数结构必须从zod/v4子路径导入execute实际业务逻辑返回字符串结果异步工具必须响应ctx.signal一个最小示例完整示例见 types.ts 中的注释文档import { z } from zod/v4 import { tool } from page-agent add_to_cart: tool({ description: Add a product to the shopping cart by its product ID., inputSchema: z.object({ productId: z.string(), quantity: z.number().min(1).default(1), }), execute: async function (input, { signal }) { await fetch(/api/cart, { method: POST, body: JSON.stringify(input), signal, // 关键把取消信号传给网络请求 }) return Added ${input.quantity}x ${input.productId} to cart. }, })Zod Schema 定义的 3 个最佳实践1. 一律从zod/v4子路径导入page-agent 的 LLM 客户端使用 Zod 4 的z.toJSONSchema()把你的 Schema 转成大模型能理解的 OpenAPI 参数格式见 utils.ts 中的zodToOpenAITool。官方文档明确支持 Zod 33.25.0与 Zod 4但必须写import { z } from zod/v4不支持 Zod Mini。2. 用约束代替提示词大模型传参不可靠把规矩写进 Schema 比写进 description 更稳z.number().min(1).max(10)限制取值范围内置wait工具就是min(1).max(10)见 tools/index.ts.default(1)提供缺省值AI 少传一个参数也不会崩.optional()标记可选参数字段命名用简短的 camelCase降低模型出错率3. description 是AI 的行为开关Schema 决定参数长什么样description 决定什么时候调用。参考内置scroll工具的描述写法tools/index.ts先说做什么再说明有无参数的不同行为最后给出使用建议。模糊的 description 会导致 AI 在错误步骤调用工具。AbortSignal 协作式取消让任务随时可控为什么需要协作式取消用户随时可能点击停止。page-agent 为每个任务创建一个AbortController其signal会同时送达三处大模型请求、每个工具的ctx.signal、以及异步回调见 PageAgentCore.ts 中的设计注释。协作式的含义是框架不会暴力杀掉你的工具而是把signal交给你由你的代码在合适的检查点自愿退出——这正是浏览器fetch取消机制的标准玩法。工具内响应 signal 的 3 种姿势execute: async function (input, { signal }) { // ① 网络请求直接传给 fetch const res await fetch(url, { signal }) // ② 长循环每轮检查一次 for (const item of items) { signal.throwIfAborted() await process(item) } // ③ 纯等待用内置的 waitFor(seconds, signal) await waitFor(3, signal) }其中waitFor是项目内置的可取消等待工具utils/index.ts传入 signal 后一旦取消会立刻以标准AbortError拒绝 Promise而不是傻等到时间结束。内置wait工具就是标准示范tools/index.ts实验性的execute_javascript工具甚至会把signal注入到 AI 生成的脚本作用域里并要求生成代码遵守它tools/index.ts。双保险即使你忘了框架也会兜底框架在工具执行完毕后会强制再检查一次signal.throwIfAborted()PageAgentCore.ts。也就是说即使你的工具忽略了 signal 并正常返回只要期间任务被停止框架仍会中断任务。当AbortError被捕获时任务状态优雅地变为stopped历史记录里只留一条简短的 Task aborted不会污染 Agent 的记忆PageAgentCore.ts。 同理自定义onAskUser回调询问用户也必须响应signal在取消时 reject否则停止会卡死在等待用户回答上见 PageAgentCore.ts 的接口注释。进阶覆盖与移除内置工具customTools的值支持两种元操作types.ts同名覆盖用内置工具名如ask_user注册新工具直接替换其行为——例如把问用户改成问你的后端模型设为null移除如scroll: null让 Agent 永远无法滚动页面适合做安全围栏常见踩坑清单 ✅坑后果正确做法写成import { z } from zodSchema 转换报错或行为异常统一用zod/v4子路径异步工具不传signal点停止后要干等请求超时fetch必传{ signal }长循环加throwIfAborted()execute返回 undefined步骤输出为空AI 失去反馈永远返回字符串可含 emoji 状态标记description 只写一句话AI 在不该调用的步骤乱调用说明参数语义 适用场景 注意事项用setTimeout裸等待无法被取消改用内置waitFor(seconds, signal)获取源码与延伸阅读克隆仓库即可本地研读git clone https://gitcode.com/GitHub_Trending/pa/page-agent工具定义与内置工具全集packages/core/src/tools/index.tscustomTools配置说明packages/core/src/types.ts取消机制主流程packages/core/src/PageAgentCore.ts官方文档页含完整示例custom-tools 文档小结Zod Schema 负责AI 能不能传对参数AbortSignal 负责任务能不能随时停下。两者配合才能写出既聪明又可控的自定义工具。【免费下载链接】page-agentJavaScript in-page GUI agent. Control web interfaces with natural language.项目地址: https://gitcode.com/GitHub_Trending/pa/page-agent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考