首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >工具层治理:Schema 版本、权限边界与破坏性操作的闸门

工具层治理:Schema 版本、权限边界与破坏性操作的闸门

原创
作者头像
Archive
发布于 2026-10-13 09:30:36
发布于 2026-10-13 09:30:36
520
举报
文章被收录于专栏:Agent 架构Agent 架构

工具层失控的三种典型形态

工具定义通常是整个 Agent 里最不被重视的一环——它看起来只是一段 JSON,写完就丢进请求里。但它其实是模型与外部系统之间唯一的契约,契约一出问题,表现会非常分散:

  • 模型偶尔选错工具,看起来像"模型不行"
  • 同一个工具昨天能用今天不能用,看起来像"服务抖动"
  • Agent 把一条本该审批的操作直接执行了,看起来像"权限配置漏了"

这三种现象对应工具层的三个治理面:Schema 契约、权限边界、破坏性闸门。它们各自独立,但共同的根因是同一个——把工具定义当配置,而不是当接口。

Schema 是契约,要有版本

先说一个容易忽略的前提:工具定义会变,而且必须能变。加一个参数、改一个枚举值、调整返回值结构,都很正常。

问题在于,大多数人是在原地改。改完之后,历史任务的回放变了、评测基线失效了、缓存的前缀哈希变了——因为工具定义往往在稳定前缀里。

所以工具定义要有 schema_version,而且变更分两类:

  • 兼容变更:新增可选参数、放宽枚举、返回值增加字段。原地升版本号即可。
  • 破坏性变更:删参数、改语义、返回值结构变化。另起一个工具名(比如 create_ticket_v2),新旧并存一段时间,旧的在观测里确认没有流量后再下线。

原地改破坏性变更是最常见的坑。它造成的现象是"某天开始,这个工具的调用成功率掉了一半",而排查时没人会想到是定义改了。

描述是写给模型看的文档

工具定义里的 description 和参数说明,读者是模型,不是人。

这一点决定了它的写法跟 API 文档不一样。API 文档写给会认真读的人,工具描述写给"只会扫一眼"的模型。所以:

  • 要写"什么时候用",更要写"什么时候不要用"。后者比前者更有价值——模型选错工具,多数是不知道该排除谁。
  • 参数边界写在描述里,而不是靠参数名暗示。amount 暗示不出"单位是分还是元"。
  • 工具之间的边界要显式说明。search_orders 和 list_orders 的区别,光看名字模型猜不出来。

有个很常见的省 token 做法是:把 description 砍短、把 enum 去掉。这笔账基本是亏的——省下的是每次请求几十个 token,多出来的是调用错误率上升带来的重试、误操作和人工介入。

参数要校验两次

模型按 schema 生成参数,但它不保证合规。缺字段、类型错、枚举值编一个出来、必填项填 None,都会出现。

所以服务端要有第二次校验,而且校验失败要返回结构化的错误给模型(字段名 + 原因 + 期望类型),而不是抛一个异常让整个任务失败。前者模型下一轮能自己修,后者只能重试。

返回值的形状也要稳定。模型对返回结构的依赖,其实比对返回内容的依赖更强——同一个工具今天返回 {"data": {...}},明天返回 {...},模型会开始瞎猜字段路径。

权限:按任务临时给,不是按人长期给

工具权限最容易做成"这个 Agent 能用哪些工具"的静态清单。这不够,因为它回答不了"这次调用该不该被允许"。

更可用的模型是三维求交:

代码语言:c
复制
允许集合 = 工具声明的 scope ∩ 当前用户的权限 ∩ 当前任务被授予的临时权限

第三个维度是关键。最小权限不是"少给权限",是"按任务临时给权限"。一个对账任务需要读订单、写调整单,不需要发消息;任务结束后这些权限就该收回。

凭据的位置同样重要。工具调用的 token 不应该出现在模型的上下文里——它会被写进日志、被回放、被评测数据集带走。正确做法是模型只输出"调什么工具、传什么参数",由执行层在真正发起调用时注入凭据。

这条和状态持久化那一篇是同一个思路:模型负责决策,执行层负责边界。

破坏性操作:按影响面分档,不按工具名

给工具分级时,很多人按工具名分:delete_* 是高危,get_* 是安全。这个分法会漏掉一半情况,因为影响面取决于参数,不取决于工具名。

update_price 改一个 SKU 的价格和批量改一万个 SKU,危险程度差三个数量级,但它们是同一个工具。

所以闸门要参数化。判断条件应该是这样的形式:

  • 金额:amount > 阈值
  • 范围:count > N 或缺少筛选条件(等于全量)
  • 外部性:涉及对外发送、对外可见、影响第三方
  • 不可逆性:没有撤销接口的操作

按这三个维度打分,落到三档:

  1. 自动执行:读操作、幂等写、影响面在阈值内
  2. 二次确认:影响面中等、可撤销。确认由发起人完成,不打断任务流
  3. 人工审批:影响面大或不可逆。这一档必须支持异步

第三档为什么要异步?因为审批人可能十分钟后才看到。如果同步等待,任务会持有连接、超时、然后被重试——重试一次就可能把待审批的操作变成重复提交。正确做法是把任务状态置为"待审批",把上下文快照存下来,审批通过后从断点续跑。

这里和持久化那篇直接接上了:待审批本质上是一种特殊的"不确定态",恢复时要靠回查而不是重放。

工具数量是个需要管理的指标

工具越多,模型选择越容易出错。这个关系不是线性的——较少的时候几乎不影响,超过某个点之后错误率会明显抬头。

所以有两件事要做。

一是定期清理。上线后调用量为零的工具,多数是模型根本没理解它的用途,或者它解决的问题已经不存在了。留着只会稀释选择准确率。

二是分组或路由。当工具数量确实压不下来(比如接了多个业务域),就不要把所有工具一次性给模型,而是先让它判定业务域,再给该域的工具子集。这一步相当于在工具层前面加了一层检索。

一个反对意见

我不建议把所有工具统一包一层网关然后无差别限流。

工具的价值和风险差异很大:一个高频的只读查询和一个低频的批量删除,放在同一个配额池里,结果是前者把配额吃掉、后者排队。按影响面分级治理,让只读工具走快通道、破坏性工具走慢通道并带闸门,比"统一入口"更实用。

统一网关的价值在审计和凭据注入,不在限流。这两件事可以分开做。

落地顺序

  1. 给工具定义加 schema_version,并定下破坏性变更的规则(另起名字)。
  2. 重写 description:补"什么时候不要用"和参数边界。
  3. 服务端加第二次参数校验,返回结构化错误。
  4. 建权限三维求交,凭据从模型上下文里挪出去。
  5. 按影响面给工具分档,第三档改成异步审批 + 断点续跑。
  6. 最后做清理和分组路由——这一步要等有调用数据支撑。

收尾

工具层治理的目标不是"管住 Agent",而是让每一次外部调用都能回答三个问题:这次调用符合契约吗、它有权这么做吗、它的影响面被评估过吗。三个问题都能答,工具层就算站住了。


同系列:

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 工具层失控的三种典型形态
  • Schema 是契约,要有版本
  • 描述是写给模型看的文档
  • 参数要校验两次
  • 权限:按任务临时给,不是按人长期给
  • 破坏性操作:按影响面分档,不按工具名
  • 工具数量是个需要管理的指标
  • 一个反对意见
  • 落地顺序
  • 收尾
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档