3085 字
约 10 分钟
16
S22-A11 · Agent 的权限模型:它能做什么、谁批准

给 Agent 开了数据库写权限,第二天它批量更新了三万行——不是它"想作恶",而是它在完成一次"清理脏数据"的任务时,把 WHERE 条件理解宽了,并且没有任何一步拦住它。

传统服务账号的权限设计假设三件事:调用者固定、行为可预演、错误有界。Agent 三条都不满足。所以它需要一套分层的、带审批点与影响上限的权限模型,而不是一把更大的 key。


1. 与传统服务账号的三个差别

维度 服务账号 Agent 直接后果
调用者 确定(某个服务) 不确定(同一次会话内意图会漂移) 无法按调用方静态授权
行为 代码固定,可预演 由计划与上下文生成,不可预演 白名单要按"能力"而非"语句"划
错误 失败即停,影响面有界 会连续放大(循环调用、批量重放) 必须设影响范围与熔断

结论:服务账号靠最小权限就够;Agent 要在最小权限之上再加影响上限、时间窗、审批三层。

2. 权限的四层结构

层 控制什么 典型实现位置 缺这一层会怎样
L1 工具白名单 能用哪些能力 Agent 注册表 / 工具清单 它能调用未授权的工具
L2 参数约束 参数取值与形状 工具 schema + 服务端校验 能拼出越界查询
L3 影响范围 一次操作能碰多少数据 服务端配额与事务边界 一次误判改三万行
L4 时间窗与批次 什么时候、分几次做 调度器 / 审批网关 深夜批量写无人察觉
// 工具声明:四层写在同一处,避免散落在提示词里
tool: db_update
capabilities: [write]
params:
  table:  { enum: ["orders", "tickets"] }        // L2 参数约束
  filter: { required: true, min_length: 8 }      // 禁止无条件全表
limits:
  max_rows_per_call: 200                          // L3 影响范围
  max_calls_per_task: 5
window:
  allowed_hours: "09:00-19:00"                    // L4 时间窗
  requires_approval_above_rows: 50

关键点:这些约束必须在服务端可执行。写在提示词里的"请勿全表更新"是建议,不是权限。

3. 读、写、删必须分级

级别 语义 默认策略 典型例子
R0 公开读 无副作用、无隐私 免审批 查文档、读配置
R1 受限读 含个人数据或商业秘密 记录审计,必要时脱敏 查用户资料、读工单
W1 幂等写 重复执行结果一致 配额限制 打标签、写缓存
W2 不可逆写 覆盖、批量更新 需审批 + 影响预估 批量改状态、发通知
D 删除 不可恢复或难恢复 单独一级,强制人工确认 删记录、删索引、删文件

"删"不能和"写"共用一级,因为两者的恢复成本差一个量级:写错了可以再写一次覆盖回去,删错了只能靠备份。恢复成本决定审批成本。

4. 审批点:哪些必须人确认,确认时展示什么

审批的设计目标不是"多一道门",而是让人在 30 秒内判断该不该放行。所以确认界面必须带四样东西:

展示项 作用 缺失后果
意图摘要(一句话) 判断是否符合任务 只能凭参数猜目的
精确参数与目标对象 判断影响面 无法发现范围过宽
影响预估(行数/金额/对象数) 判断代价 只能盲批
可撤销性(能否回滚、多久内) 判断风险 一律拒绝或一律通过
// 审批请求:机器生成,人只需看 impact 与 reversible
{
  "intent": "把超时未支付的订单标记为关闭",
  "tool": "db_update",
  "params": { "table": "orders", "set": {"status": "CLOSED"},
              "where": "created_at < NOW() - INTERVAL 7 DAY AND status = 'PENDING'" },
  "impact": { "estimated_rows": 1280, "tables": ["orders"], "irreversible": false },
  "reversible": { "window": "30m", "method": "backup_snapshot" },
  "requester": "agent:session-7f2a", "approver_policy": "oncall"
}

必须人确认的判据可以写死成三条:不可逆、影响超过阈值、触碰生产数据。其余走自动放行 + 事后审计,否则审批会变成噪音。

5. 确认疲劳会让审批形同虚设

症状 机制 修正
通过率极高且审批耗时极短 人在机械点击 提高阈值,减少低价值审批
审批请求集中在同一类操作 阈值定得过低 该类改自动放行 + 抽样复核
出现"批量批准"入口 审批量超过人的处理能力 按影响降级为异步审计
审批人长期是非相关角色 责任错配 换成能判断影响面的人

6. 幂等与重试:同一条指令被重放

Agent 的重试比服务间重试更危险:它可能重新生成参数再发一次。

重试形态 风险 处理
同参数重发(网络失败) 重复副作用 幂等键 = 任务 id + 工具 + 参数哈希
重新生成参数再发 两次不同操作 只允许原样重试,禁止重新规划后自动重发
超时后不确定是否成功 状态未知 先查询再决定,不做"再写一次"
批量任务部分失败 半完成状态 记录进度点,支持从断点续做
// 幂等键由意图内容决定,不由调用次数决定
key = sha256(f"{task_id}:{tool}:{canonical(params)}")
if seen(key) and seen(key).status == "DONE":
    return seen(key).result          // 重放直接返回原结果
execute_once(key, lambda: call(tool, params))

参数需键序归一后再哈希。

7. 沙箱与真实环境的边界

边界 沙箱允许 生产允许 常见错误
数据范围 合成或脱敏数据集 真实数据 沙箱脚本直接指向生产库
写操作 可自由写 需审批与配额 把演练用的宽权限复制过去
删除 常开放 单独审批 沙箱养成"随手删"的习惯
凭据 独立测试账号 单独签发、可即时吊销 一套凭据两处用

**"演练环境的权限不能顺手复制"**是这条边界最贵的一课:权限一旦复制,约束也随之失效,而习惯已经养成。

8. 审计要记录什么

字段 为什么必须有
意图(自然语言摘要) 事后判断"它当时想干什么"
参数(归一化后的完整值) 复现与举证
结果(成功/失败/影响行数) 判断实际发生了什么
发起人(人 + Agent 会话 id) 责任落点
审批人与其看到的视图版本 判断批准是否知情
时间与工具版本 对齐发布与配置变更
// 审计事件:只追加,不允许 Agent 自己改写
{ "ts": "2026-11-09T10:00:00Z", "actor": "agent:session-7f2a",
  "human": "USER_ID", "tool": "db_update", "params_hash": "HASH",
  "impact_rows": 1280, "approved_by": "ROLE_A", "result": "OK" }

审计的价值不在合规,而在归因:没有意图字段,日志只能告诉你"改了什么",不能告诉你"为什么"。

9. 提权路径必须显式,不能由推理产生

Agent 遇到权限不足时,自然的反应是"找个有权限的路径"。这条路径要么被显式设计,要么它自己发明一条:

// 唯一的提权入口:申请、审批、限时、记名
escalation:
  request: { reason: required, scope: [tool, params, rows], ttl: "2h" }
  approve: { roles: ["ROLE_A"], max_ttl: "8h" }
  effect:  { grant: temporary, revoke_on: [task_end, ttl_expiry] }
  audit:   [requester, approver, grant_scope, expiry]

禁掉的形态要明确写出来:不允许 Agent 修改自身工具清单、不允许通过写配置文件扩展权限、不允许复用他人凭据。

10. 人机责任划分

情形 责任落点 依据
Agent 按批准的范围执行 批准者 批准时可见影响预估
Agent 超出批准范围 权限模型设计者 约束未在服务端生效
Agent 理解错意图 指令下达者 意图未被写成可验证的判据
未经审批的自动操作出事 策略配置者 阈值与放行规则由其设定
审计缺失导致无法归因 平台方 审计字段不完整

"Agent 做了什么不该由 Agent 负责"——它没有资产、没有判断力、也没有拒绝的能力。把它拟人化成责任主体,等于让真正的责任方隐身。

11. 度量

指标 口径 异常信号
高权限操作数 W2 + D 级调用次数 突增或集中在单一会话
审批通过率 通过 / 请求 接近 100% 且耗时刻度极短
越权尝试数 被 L1–L3 拦下的调用 上升说明工具描述误导
回滚次数 执行后回退的操作数 上升说明影响预估不准
平均影响行数 单次 W2 操作的影响量 超出阈值却未触发审批

12. 排错:五种"权限配了还是出事"

现象 原因 处理
一次改了三万行 只有白名单,没有影响上限 补 L3 配额与服务端事务边界
审批全部通过、无人细看 阈值过低导致疲劳 提高阈值,只留不可逆与大影响
重试后数据被改两次 无幂等键或键含调用序号 幂等键用参数哈希,重放返回原结果
出事后无法归因 审计无意图与审批视图 补意图摘要与审批快照
权限不足时它自己绕过 未定义提权入口 显式提权通道 + 禁用自改权限

13. 边界:什么时候可以只做工具白名单

情形 可压缩到 理由
纯只读场景 L1 白名单 + 审计 无副作用,影响面为零
输出由人复核且不落库 L1 + L2 人有最终拦截点
影响可即时撤销(草稿、临时文件) L1 + 幂等键 恢复成本接近零
单用户本地工具 L1 调用者、被执行者、受害者同一人
高影响且不可逆(资金、删除、外发) 四层全开 + 强制审批 恢复成本决定审批成本

判据始终是同一条:这次操作的恢复成本有多高。恢复成本低,权限可以宽;恢复不了,就必须有人先看一眼。


14. 自测

  1. Agent 与服务账号的三个差别中,哪一条直接决定了白名单要按能力划分?
  2. 四层权限里,哪一层缺了会导致"一次误判改三万行"?
  3. 为什么"删"不能与"写"共用同一权限级?
  4. 审批界面必须展示的四项信息,缺哪一项会让人只能盲批?
  5. 幂等键为什么不能包含调用序号或重试次数?
  6. 什么情形下权限模型可以只保留工具白名单一层?
S22-A11 · Agent 的权限模型:它能做什么、谁批准
https://www.clxhxhhr.top/posts/6294/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。