4.3 自定义动作与扩展:给军械库添自造装备


文档摘要

4.3 自定义动作与扩展:给军械库添自造装备 本节摘要:框架的注册表是开放的:用装饰器把任意 Python 函数登记成模型可调用的动作,参数靠 Pydantic 模型声明。自定义动作有两个高价值用途——接入业务专属能力(查内部接口、做格式校验)和给高危操作加人工确认闸门。本节给出注册模板、参数模型与闸门示例。 从一次"聪明反被聪明误"说起 有人让智能体"下单前先核对库存",模型自己发明了走法:把商品加进购物车看报不报缺货——页面操作绕了个大弯,还留下一堆脏数据。正确做法是给它一件正经武器:一个直接查库存的自定义动作。这件事暴露了武器库章的核心判断:凡是能用一次函数调用解决的事,就别让模型用五步页面操作去模拟。自定义动作不只是"扩展",更是把模型的创造力往正道上引的缰绳。

4.3 自定义动作与扩展:给军械库添自造装备

本节摘要:框架的注册表是开放的:用装饰器把任意 Python 函数登记成模型可调用的动作,参数靠 Pydantic 模型声明。自定义动作有两个高价值用途——接入业务专属能力(查内部接口、做格式校验)和给高危操作加人工确认闸门。本节给出注册模板、参数模型与闸门示例。

从一次"聪明反被聪明误"说起

有人让智能体"下单前先核对库存",模型自己发明了走法:把商品加进购物车看报不报缺货——页面操作绕了个大弯,还留下一堆脏数据。正确做法是给它一件正经武器:一个直接查库存的自定义动作。这件事暴露了武器库章的核心判断:凡是能用一次函数调用解决的事,就别让模型用五步页面操作去模拟。自定义动作不只是"扩展",更是把模型的创造力往正道上引的缰绳。

注册一件武器

登记表格式很朴素:一个函数加一个装饰器。装饰器里的字符串是动作名,会出现在模型的动作清单里(3.2 的输入四),所以命名要写得像给人看的说明——模型挑动作全靠这份描述。

from typing import Type from pydantic import BaseModel from browser_use import Controller, Agent controller = Controller() class 库存参数(BaseModel): 商品编号: str # 商城后台的商品 SKU 编号 仓库: str = "华东一仓" # 缺省查华东一仓 @controller.action("查询指定商品的实时库存", param_model=库存参数) def 查库存(params: 库存参数): # 这里接真实业务:示例用假数据代替内部接口 mock = {"SKU-001": 42, "SKU-002": 0} 数量 = mock.get(params.商品编号, -1) if 数量 < 0: return f"查询失败:编号 {params.商品编号} 不存在" return f"商品 {params.商品编号} 当前库存 {数量} 件" # 返回文本会进入模型下一拍的情报

两处设计值得留意:参数不是散装字典而是 Pydantic 模型——模型填错类型会被合同打回,这与 4.2 的提取合同是同一个思想;返回值是给模型读的一句话,写清结论("库存 42 件")而不是丢一个原始数据结构让它猜。

把军械库挂上 Agent 就能用了:

agent = Agent( task=( "对商品 SKU-001 执行下单前检查:先调用查询库存的动作," "库存为零则直接报告缺货,不为零再打开商城商品页核对页面售价" ), llm=llm, browser=browser, controller=controller, # 挂上自造装备 )

预期轨迹示意:第一拍就出现"调用查询库存"而不是任何页面点击——动作清单里有了这件武器,模型会优先选直路。

闸门:把危险操作锁在人工手里

自定义动作更深的一层用法是收权。智能体带着登录态能做你做的一切(2.3 立过这条边界),那删除、支付这类操作的开关就该收回人手里。做法:把危险动作定义成必须人工敲确认码才执行的自定义动作,其他删除路径则从动作空间里禁掉。

from browser_use import Controller from pydantic import BaseModel controller = Controller() class 下单参数(BaseModel): 商品编号: str 数量: int 人工确认码: str # 模型不知道这个码,必须向人要 @controller.action("提交订单(需人工确认)", param_model=下单参数) def 提交订单(params: 下单参数): if params.人工确认码 != "今日口令66": # 口令来自值班人,不写进任务单 return "确认码错误,订单未提交" # 模型拿不到口令,闸门就锁得住 return f"订单已提交:{params.商品编号} x {params.数量}" # 同时把页面里现成的下单按钮从动作空间里屏蔽掉,防止绕闸 @controller.exclude_actions(["点击元素"]) # 示意写法:生产环境按真实动作名配置 def 仅示例(): pass

上面最后一段的屏蔽在真实项目里用 Controller 的排除参数配置,思路不变:加一道带口令的闸门,同时封掉绕行的路。模型会试探,闸门必须两头都锁。

什么时候别自定义

三种情况把手缩回来:页面操作本来就能表达的事(点击、填表)——再造一个"帮我点击"的动作是重复建设;需要高频调用的重逻辑——自定义动作的返回会进模型情报,大段输出既费 token 又稀释注意力,重活该在动作内部算完只回结论;以及想把整个业务流程写成一个"超级动作"——那样模型的观察与决策拍就形同虚设,不如直接写脚本(回 1.3 的口诀)。

动作描述的写作要点

模型挑动作全看描述文字,这段描述值得当任务单一样打磨。三个要点:动词开头("查询库存"优于"库存查询接口"),写清参数含义(参数模型里的字段注释会一并进入动作说明),写明返回什么("返回库存件数"让模型知道拿到的是什么)。对比一下:"do_query"和"查询指定商品的实时库存,返回件数"——后者被选中的概率天差地别。

再答一个高频问题:**自定义动作里能操作浏览器吗?**技术上可以拿到页面上下文,但强烈不建议——动作里一旦混入页面操作,动作与循环的职责边界就糊了,排错时你分不清哪步是模型决策、哪步是动作内部行为。让自定义动作只做"页面之外的事"(接口、计算、校验、通知),页面的事交还给指挥循环。

调试自定义动作的一个小技巧

动作没被调用时,先别怀疑注册,先用任务单点名:"优先使用查询库存动作完成任务"——点名的动作若还是没出现,才是注册真的出了问题(没挂上 Agent、装饰器没执行、名字冲突)。这个二分法能把"注册问题"和"选择问题"一分钟切开,比翻源码快得多。

闸门口令的管理

确认闸门的口令管理决定闸门是真门还是装饰。三条最低要求:每日轮换(固定口令泄漏一次就永久失效);不落日志(口令校验失败可以记,校验成功的口令值必须脱敏);不经模型(口令由人在动作触发时提供,任务单与历史轨迹里都不能出现)。做到这三条,闸门才配得上"最后防线"四个字。顺便提醒:口令校验动作本身也要写返回语义——失败时返回"确认码错误,订单未提交",让模型明确知道该停,而不是再试几个口令碰运气(若发现模型反复尝试口令,立即停车,这属于危险信号)。

武器库收官。第 5 章三个战役开打:制式装备、提取合同、自造武器将同场亮相。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U