loading

Loading

探索与发现

首页 AI 前沿

Agent 工具调用权限分级:写在代码里才作数

分类:AI 前沿
字数: (2509)
阅读: (7)
0
摘要:提示词里写“请先确认”不叫权限控制。从工具级、数据级到参数级三层拦截,forbid 优先加默认拒绝,人工确认要让人看得懂,再把步数和预算固化到代码里,这些合起来才是 Agent 权限分级的可执行版本。

给 Agent 接工具这件事,第一版通常很顺:读接口加上写接口,提示词里写一句“高风险操作前请先确认”,demo 就能跑起来。真正出问题是在上线之后。腾讯云开发者社区那篇企业 Agent 落地文章列的几条差不多是所有团队都会撞上的:提示注入一句越权调用、出了事说不清是谁让它做的、退款改配置这类动作直接执行、一个死循环把接口和预算一起烧光。

这些问题的共同点是,它们都不是模型能力问题。提示词里的“请不要”不是权限控制系统,它只是一段上下文,可以被覆盖、被忽略、被长对话挤出窗口。权限得在模型输出之后、工具真正执行之前拦住。

三层拦法:工具级、数据级、参数级

我看过不少实现只做了最外面一层:给每个工具打一个 risk 标签,read 放行、write_low 放行、write_high 转人工。这套骨架不难,腾讯云那篇里的 guard 函数就是十几行——查工具表、看风险等级是否在白名单、不在就拒绝。难的是它拦不住真正的事故。

企业场景里更高发的是第二层:Agent 逻辑完全正确,但它看到了不该看的数据。比如工单分类任务,工具调用本身合法,可它拿到的是别的部门的工单。所以 guard 里得再加一条判断,args["ticket_id"] not in ctx["visible_tickets"] 就直接拒绝。这一层的输入不是角色,是当前用户可见数据集合,需要从业务侧传进来,而不是让 Agent 自己决定。

第三层是参数级别。枚举值越界、ID 格式不对、日期范围离谱、金额为负,这些都应该在执行前拦掉。set_category 只接受四个值这一条枚举约束,一个正则就够,比事后让模型自查可靠得多。

黑白名单之外,还要处理优先级

只有一个白名单时,加一条策略就是改一次代码,很快就乱。Progent 是较早系统化处理这个问题的方案,它把策略做成可编程的表达式:每条策略带工具 ID、条件表达式、Effect(allow 或 forbid)和回退函数。调用前先筛出目标工具的策略子集,按优先级排序,优先级相同时 forbid 优先——这一条很重要,默认行为是“无任何策略匹配就阻止该工具调用并走回退函数”。

默认拒绝,而不是默认放行。安全策略写错的一端应该落在“用不了”上,而不是“什么都放行”。

forbid 优先加默认拒绝,是两个朴素的工程习惯。但要注意副作用:策略热更新失败、规则加载为空、正则写错导致匹配不到,都会直接表现为工具不可用。上线前得有一套“策略加载成功但规则为空”的告警,否则模型会不停生成长度正常的拒绝对话,你没收到任何报错。

这也是 RBAC 和 ABAC 取舍的现实:RBAC 简单,角色边界清晰的内部系统够用;一旦出现跨地域访问、晚间时段限制、资源敏感度判断,就得引入上下文属性。CSDN 那篇文章给了一个风格很直接的例子,Resource.Sensitivity == "high" 且 Location.RiskScore > 0.7 时就要求多因素认证。这种检查要放在权限服务里,不要写进工具实现,否则同一个能力分散在不同工具里,很难保证一致。

参考 Claude Code 的三段分离

Claude Code 的工具系统有一处值得借鉴的设计:权限检查被拆成三层——输入验证 validateInput 在权限检查之前单独跑,只做数据合法性判断,不关心谁能调;hasPermissionsToUseTool + checkPermissions 处理工具特定权限,不同工具粒度不同,读类工具查路径允许列表,Bash 类工具得解析命令、评估风险等级;再往后是并发调度相关的运行时属性判断,比如 isConcurrencySafe()。

把数据验证和权限策略分开做,好处是出了问题好定位。参数非法返回给模型的是“这个入参不对”,权限不足返回的是“这个动作被禁止”,两种回退的处理方式不一样,模型能不能自我修正也不一样。混在一个函数里,你就会看到日志里全是模糊的“被拒绝”,根本没法定性。

Per-tool 自定义检查这件事也别省。一张全局工具表能把读类和写类分开,但拦不住 rm -rf / 这种。高危工具要允许挂在 ACL 钩子上做更细的检查,代价是每加一个工具就多一处代码,维护成本会涨。我的建议是第一版只允许不超过 5 个工具,全部手写检查,先把边界摸清再考虑抽象。

审计和人工确认是容错的一部分

腾讯云那篇文章的审计结构给得比较完整:任务 ID、时间、模型版本、提示词版本、每一步的工具调用和参数、护栏判定结果、人工审批记录、最终输出、耗时与 token。字段多的意义在于,出事后能复现当时的上下文——换过模型版本还是改过提示词,一看就知道。

人工确认这里我见过不少走形式的产品:弹个框写“是否允许此操作”,审批人根本看不到 Agent 想做什么、依据是什么、影响范围多大,只能凭印象点同意。有效的审批界面至少要让审批人理解这三件事,否则高风险动作人审只是把风险从 Agent 挪到了更疲惫的人身上。

还有个细节容易漏:拒绝之后 Agent 怎么继续。如果你的所有 request_approval 失败都当成“工具出错”,Agent 会陷入重试循环,白白消耗步数。正确的做法是把“被拒绝”作为一种终止性语义返回给模型,让它走兜底分支转人工。

最后是预算,不是安全意识问题

步数上限、总超时、单任务预算、同一工具重复调用上限——这些很多人把它当安全问题,其实是成本控制。一条死循环路径烧掉整月额度,在我见过的团队里起码发生过两次。护栏的取值不要凭感觉定,应该按线上 P99 的实际步数往上留 30% 的余量,每次改了工具或提示词都要重新核算。

总结下来,工具调用权限分级的正面清单大致是:工具级权限、数据级权限、参数合法性、forbid 优先加默认拒绝、高危动作强制人审、每一步可审计、步数预算双上限。这七件里任何一件缺失都可能埋坑,尤其数据级权限和人工确认还原上下文这两项,最容易用“还好没出事”的方式忽视。用腾讯云那篇文章里的一句话收尾比较合适:Agent 的能力上限由工具决定,可信下限由护栏和审计决定。

转载请注明出处: 皮哈皮阿

本文的链接地址: https://blog.phpat.com/ai-frontier/643.html

手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

您可能对以下文章感兴趣
1 / 1
预览图