把模型当”超管用户”配权限,是 Agent 系统最常见的灾难。工具权限控制必须按”身份可识别 → 范围可收敛 → 凭据短效 → 高危操作审批 → 全量审计”五层同步推进;缺任何一层,prompt injection 或一次意外的写库调用都可能让整个生产数据裸奔。下文把权限分层、场景差异、审批门控与一段可复用代码逐项拆开。
一、Agent 权限控制的五层模型
把 Agent 当成”会说话的脚本用户”是错误起点。OWASP 在 LLM Top 10(2025 版)里把 excessive agency(LLM06)单列为风险项,意思是模型被赋予了超出它完成本职所需的工具和数据访问能力。工业实践里通常把权限切成五层,缺一不可:
| 层级 | 关注问题 | 典型实现 |
|---|---|---|
| 身份(Identity) | 谁在调用?代表谁? | OAuth、M2M Token、Entra Agent ID |
| 范围(Scope) | 每个工具的最小权限 | 工具 manifest、显式 allow/deny 列表 |
| 凭据(Credential) | 短效、不可落地 | 10 分钟 JWT、动态签发、托管 Vault |
| 审批(Approval) | 写库/对外发消息/扣款必须人审 | HITL 门控 + 强认证 |
| 审计(Audit) | 出事能查、行为可追溯 | 不可篡改的事件日志 |
把 Agent 的身份和人类用户身份解耦是近年共识。Microsoft Entra Agent ID、WorkOS Connect 都提供”Agent 作为一等公民”的注册方式——Agent 拿到自己的 client_id,而不是借用某个服务账号。
二、不同场景的工具权限差异
权限设计不是”一套打天下”。按工具的”读/写、可逆性、影响半径”分类,差异极大:
| 工具类型 | 风险级别 | 处理方式 | 典型示例 |
|---|---|---|---|
| 只读信息查询 | 低 | 自动放行 + 日志 | 知识库检索、订单详情查询 |
| 内部状态变更 | 中 | 自动执行 + 可回滚 | 创建工单、CRM 草稿 |
| 对外通信 | 高 | 强制审批 + 强认证 | 发送邮件、Slack 通知 |
| 资金/权限变更 | 极高 | 多因素 + 职责分离 + 限额 | 转账、删除数据、修改 RBAC |
| 不可逆写 | 极高 | 必须人在环路、逐次确认 | drop_table、强制 push、撤销证书 |
经验上,”中”级别是工程上最容易被忽视的:很多人以为”创建工单”是只读,但工单一上线就触发下游分单、写 IM、写邮件——一个看似无害的”中”风险操作,影响半径可能横跨三个系统。
三、最小权限与工具 manifest
最小权限(Least Privilege)不是口号,要落地到具体的工具 manifest 描述里。每条工具声明都应明确”它能做什么”和”它不能做什么”——后者用”默认拒绝 + 显式允许”实现,而不是反过来。OpenAI 的 function schema 只描述入参,不限制行为;所以真实的权限控制必须在应用层做。
权限 manifest 落地有 5 个必做步骤,顺序不能乱:
- 枚举工具清单:把所有可用工具列出来(哪怕只是临时调试用的),每条配 name、description、scope、tier 四个字段;
- 逐条标记风险等级:按”读/写、可逆性、影响半径”三类属性给 tier 赋 low / medium / high / critical;
- 声明高危操作的审批要求:needsapproval、approverrole、mfarequired、amountlimit_cents 等必须显式写;
- 配置执行器侧的 scope 校验:每次工具调用前用
set(manifest["scope"]).issubset(set(agent_scopes))做白名单匹配; - 接入审计与告警:把”被拒绝”和”被审批放行”两类事件送到监控,关键事件触发即时告警。
from typing import Literal, List
# 工具权限 manifest:与工具 schema 解耦,由执行器加载
TOOL_MANIFEST = {
"kb.search": {
"scope": ["read:kb"],
"tier": "low",
"needs_approval": False,
"rate_limit": "60/min",
},
"crm.create_ticket": {
"scope": ["write:crm"],
"tier": "medium",
"needs_approval": False,
"rate_limit": "30/min",
"rollback_supported": True,
},
"email.send": {
"scope": ["write:mail"],
"tier": "high",
"needs_approval": True,
"approver_role": "team_lead",
"mfa_required": True,
},
"billing.transfer": {
"scope": ["write:billing"],
"tier": "critical",
"needs_approval": True,
"approver_role": "finance_admin",
"mfa_required": True,
"amount_limit_cents": 1_000_00, # 单笔上限 1000 元
},
}
def authorize(tool_name: str, agent_scopes: List[str], context: dict) -> dict:
"""每次工具调用前都过这一道闸。"""
manifest = TOOL_MANIFEST.get(tool_name)
if manifest is None:
return {"allow": False, "reason": "tool_not_in_manifest"} # 默认拒绝
# 1. scope 校验
if not set(manifest["scope"]).issubset(set(agent_scopes)):
return {"allow": False, "reason": "scope_missing"}
# 2. 审批门控:高危/极高必须走 HITL
if manifest["needs_approval"]:
approved = request_human_approval(
tool=tool_name, args=context["args"],
approver_role=manifest["approver_role"],
mfa_required=manifest.get("mfa_required", False),
)
if not approved:
return {"allow": False, "reason": "human_rejected"}
# 3. 限速与金额阈值
rate_limiter.hit(tool_name, manifest["rate_limit"])
if "amount_limit_cents" in manifest:
if context["args"]["amount_cents"] > manifest["amount_limit_cents"]:
return {"allow": False, "reason": "amount_exceeds_limit"}
return {"allow": True, "tier": manifest["tier"]}
代码块展示了三件事:① 默认拒绝(未列入 manifest 的工具直接拒);② scope 与审批分两步走,避免”scope 通过就放行”;③ 金额、速率等业务阈值作为单独维度叠加,不会被单一 scope 覆盖。真正部署时,agent_scopes 应来自短期 JWT,由 AgentCore、AuthKit 等控制平面动态签发,而不是写在 prompt 里。
四、Human-in-the-Loop 审批的最佳实践
审批不是”每步都问人”,而是”按风险分级”。高危操作(发邮件、转账、删数据)必须经过人审,且审批必须绑定具体的参数快照——避免 Agent 改完参数复用上次同意。Powercode Group 提出的”action preview”模式值得借鉴:审批界面同时展示操作名、目标、影响记录、关键参数、数据来源、模型给出的理由。审批者点”通过”后,该授权仅对本次调用有效,参数变化即作废。
五、审计日志与零常驻权限
审计是事后追责的最后一根稻草。每条工具调用都应记录:发起用户、Agent 身份、工具名、参数、policy 决策、审批人、最终结果。Microsoft、Permit.io 等都在推”零常驻权限(zero standing permissions)”模式:Agent 启动时不持有任何长期凭据,每次任务开始时按 tier 和 task 申请短效 grant,任务结束或超时自动回收。这与”长期 PAT + RBAC”思路是根本不同的设计——后者一旦被 prompt injection 击中即全线失守。
到这里,工具权限从分层、场景差异、manifest 设计到审计的链路就完整了。
常见问题(FAQ)
Q1:Agent 权限和用户权限是一回事吗?
不是。Agent 应有独立身份与 scope,只继承它完成任务所需的最小能力。
Q2:所有高危操作都强制人审吗?
对,转账、删数据、对外发消息都应强制审批,参数变更需重新审批。
Q3:最小权限写在 prompt 里能生效吗?
不能。权限必须由运行时执行器校验,模型无法真正限制自己。