很多团队上线 Agent 时,权限设计一句话带过:"高风险动作都加审批,让人点。"本文站在工程视角,拆穿"审批=治理"的幻觉,给出一套最小权限 + 动作矩阵 + 不可变审计 + 回滚的落地方案。
0. 一个 ¥3,800 的教训
先上结论再讲故事。我们给一家跨境客服客户做退款 Agent,第一版权限设计是这样的:
refund_agent_token:
scopes:
- orders:read
- refund:issue
理由朴素:"退款总得先读订单吧。"上线第二周,一笔不该退的 ¥3,800 退出去了。复盘发现审批人在 11 分钟点了 23 次"批准",事后说"我以为系统筛过风险了"。
问题不在人,在架构:orders:read 和 refund:issue 绑在同一个身份上,意味着任何一个拿到 token 的环节都能一气呵成完成"看 + 退"。审批按钮只是把责任从系统推给人,人疲劳了就盲签。
这就是企业 Agent 权限管理最常见的死法——用审批假装兜住了权限。
1. 最小权限原则的工程落地
最小权限(least privilege)在 Agent 场景不是哲学,是三个可验证的约束:
1.1 读 / 写 / 资金必须拆成三个独立身份
风险等级完全不同:
| 权限 | 出错代价 |
|---|---|
| 读 | 最多答错,≈0 |
| 写 | 人工可改回,一次客服 |
| 资金 | 钱出去了,实打实损失 |
拆法:
read_token: { scopes: [orders:read, policy:read] }
write_token: { scopes: [ticket:create, status:update] }
fund_token: { scopes: [refund:issue], requires: [approval, idempotency_key] }
Agent 运行时按动作类型挑对应 token,绝不让一个身份同时持有读和资金。
1.2 权限写在工具签名里,不写在提示词里
这是最关键的一点。提示词是给人看的,工具签名才是系统执行的边界。
@tool(scope="read-only", market="US")
def lookup_refund_policy(order_id: str) -> Policy: ...
@tool(scope="fund", required=["approver_id", "idempotency_key"])
def issue_refund(order_id: str, amount: float,
approver_id: str, idempotency_key: str) -> Receipt: ...
即使模型被越狱、提示词被改写,issue_refund 仍然强制要求 approver_id 和 idempotency_key,缺参直接 400。工具层的硬约束不依赖模型乖不乖。
1.3 分阶段发放 token
最稳的节奏:
- Phase 1(只读):只发
read_token,Agent 跑两周,把所有"想做"的动作记成proposed日志,不落库。 - Phase 2(受限写):逐个开
write_token,每个动作配审批档。 - Phase 3(资金):最后开
fund_token,强制双签 + 幂等。
跳过 Phase 1 直接全开,然后用审批兜底——这是后面所有事故的起点。
2. 动作分级:auto / single / dual
按"是否可逆 + 金额上限"分三档:
def tier(action):
if action.reversible and action.cap == 0:
return "auto" # 查询、草稿、建工单
if action.reversible:
return "single" # 改状态、非资金通知
return "dual" # 退款、改预算、删数据、跨市场写
一句话:做错了 5 分钟内能不能无损撤回?不能,就别自动跑。
注意改广告预算——钱不"直接飞走"但会烧。比一次退款更隐蔽:退款立刻报警,预算被悄悄改可能三天后才在报表露馅。所以资金边界不能只看"是否直接转账"。
3. 审批页必须渲染的五类证据
有效的企业 Agent 权限管理,审批页要一次性给审核人五样东西,少一样就是盲签:
- intent:哪条消息/政策触发?
- evidence:看了哪些数据,可点击溯源?
- tool_call:调哪个工具、传什么参数?
- blast_radius:动多少钱、几个订单、哪个市场?
- reversibility:点批准之后还能不能撤、怎么撤?
前端实现上,这要求把 Agent 的"思考轨迹"结构化存储,而不是只存最终动作:
{
"trace_id": "tr_8f2a",
"intent": "user asked refund for order A",
"evidence": ["order:A:status=delivered", "policy:v2025:refund_window=30d"],
"tool": "issue_refund",
"params": {"amount": 3800},
"blast_radius": {"orders": 1, "market": "US", "money": 3800},
"reversible": true,
"rollback": "reverse_refund(tr_8f2a)"
}
审核人看到的不是"是否批准",而是"基于以上证据,是否批准"。
4. 四道防线:deny / retry / rollback / audit
权限管理终点不是"批了就完",是"出事能兜住"。
def execute(action):
if not has_evidence(action): # deny
raise Denied("insufficient evidence")
if action.idempotency_key in seen: # retry-safe
return seen[action.idempotency_key]
result = call_tool(action)
seen[action.idempotency_key] = result
audit.log(trace_id=action.trace_id, actor=action.approver_id, ...) # audit
return result
def rollback(trace_id):
compensations[trace_id]() # reverse / snapshot / soft-delete
- deny:证据不足或超权限,系统直接拦,不进队列。
- retry:幂等键保证重复调用不产生二次副作用。
- rollback:退款有冲正、预算有快照、删除有软删+回收站。
- audit:每次调用带
trace_id,串起决策、参数、审批人、时间。
没有幂等键的 retry 是灾难,没有快照的 rollback 是空话,没有 trace_id 的 audit 是甩锅。三样必须和权限同设计。
5. 动作矩阵(可直接抄)
| 动作 | 分级 | 角色 | 上限 | 证据 | 审批 | 幂等键 | 回滚 |
|---|---|---|---|---|---|---|---|
| 查询订单 | 读 | Agent | 无 | 无 | 系统 | query_id | 无 |
| 生成建议 | 读(出) | Agent | 无 | 政策版本 | 系统 | draft_id | 无 |
| 创建工单 | 写 | Agent | 低 | 订单+原因 | 系统 | ticket_id | 关工单 |
| 修改状态 | 写 | Agent+1 | 中 | 原/新+依据 | 单人 | op_id | 还原 |
| 发起退款 | 资金 | Agent+2 | ≤¥500单/>¥500双 | 订单+政策+时效+确认 | 双人 | refund_id | 冲正 |
| 改广告预算 | 资金 | Agent+2 | 日预算封顶 | 旧/新+理由 | 双人 | budget_id | 快照还原 |
每周复盘:审批人离职?上限半年没调?动作从"单人"偷升"自动"?
6. 五个失效模式
- 审批疲劳:高低风险混排,真人变橡皮图章。
- 共享账号:一堆 Agent 共用 admin token,出事分不清谁。
- 不可回滚:删库、发外邮、改全局,点了不可逆。
- 日志不全:只记"调了什么",不记"凭什么、谁批的"。
- 权限漂移:业务变了权限没变,临时写权限忘了收。
四条与"审批"无关,只和"证据/边界/可逆/可审计"有关。
7. 独家观点:治理最小单位是动作,不是模型
行业谈治理总盯"模型安不安全""提示词越狱没"。但企业真正要审计的最小单位,是动作——它看了什么、调了什么、改了什么、能否恢复。
沙盒里对答如流 vs 能改你广告预算,风险不在一个量级。决定量级的是动作,不是模型。把治理下沉到动作层,每个动作配齐角色/上限/证据/审批/幂等键/回滚,模型再抽风也被框在小格子里。
8. 亚马逊场景的落地提示
运营 Agent 能碰:查 BSR、改竞价、调预算、读评论、代发邮件。建议:
- 实时数据(价格/排名/广告位/评论)交给 Amazon Data API 这类数据层提供"看"的事实;
- 任何改后台的动作走最小权限 token + 双人审批 + 幂等键 + 回滚。
很多误退、误改预算,根因是"看"的事实层和"动"的权限层混在一起。亚马逊政策随市场/季节/类目剧烈变化,外部事实统一从可信数据层拉,至少"基于哪版政策决策"可追溯,避开权限漂移。
第二现场:广告预算是怎么被"悄悄改掉"的
退款事故容易被看见,因为它立刻报警。还有一种更隐蔽的事故:预算被悄悄改。
我们见过一个案例,某团队的 Agent 有"改广告预算"权限,分级在"写"而不是"资金",理由是"它只是调个数字,又不直接转账"。结果一次策略误判,把某 ASIN 的日预算从 ¥200 顶到了 ¥2000,连续烧了三天才在周报里被发现。三天 × ¥1800 ≈ ¥5400 的无声损耗,还没算连带的转化浪费。
这个案例说明两件事:第一,资金边界不能只看"是否直接转账",任何"钱会烧"的动作都该进双签 + 回滚;第二,不可回滚的动作一旦点下,靠审批是追不回来的,必须靠快照还原在分钟级止损。把预算当"写"而不是"资金",是第二常见的权限事故源。
90 天落地节奏(可直接排期)
别想着一次到位。我们给客户排的节奏是这样的:
- 第 1–2 周(只读观察):只发 read_token,Agent 跑起来,把所有"拟执行"动作记成
proposed日志,不落库。这阶段你会看清它到底想碰什么。 - 第 3–6 周(受限写):逐个开 write_token,每个动作配单人/双签档与审批页五证据。先开"改状态""建工单"这类可逆动作。
- 第 7–10 周(资金 + 回滚):最后开 fund_token,强制双签 + 幂等键 + 回滚(退款冲正、预算快照)。同时把 trace id 串起全链路。
- 第 11–12 周(常态化审计):动作矩阵进周会,跑"权限使用记录"周审,清离职审批人、收临时写权限。
绝大多数团队把前 6 周压缩成"上线即全开",于是把事故也压缩进了前 2 周。
自检清单:上线前问自己 10 个问题
- 读、写、资金是三个独立 token 吗?
- 权限写在工具签名里,还是只写在提示词里?
- 第一阶段是不是只读?
- 每个动作的审批档(auto/single/dual)写清楚了吗?
- 审批页是否展示意图、证据、调用、影响、可逆性?
- 每个动作有幂等键吗?
- 每个可逆动作有回滚方案吗?
- 每次调用有 trace id 吗?
- 有没有不可回滚动作被放进了自动档?
- 动作矩阵这周有人复盘吗?
10 个里答不上 3 个,就先别让 Agent 碰资金。
成本账:治理 vs 不治理
还是用前面 5 万咨询量/月的运营来算。盲签导致 10% 误动作,其中 5% 变成 ¥50 投诉,就是 ¥12,500/月、¥150,000/年;再加 10 个复核人力(¥50k/人)= ¥500 万。治理的代价是一个兼职 owner + 一个周脚本。这笔账不用算第二遍——"免费"的放任,其实是最贵的方案。
五个关于权限的误区
- 误区一:"有审批就安全"——审批是责任转移,不是边界。
- 误区二:"模型乖就不会乱动"——边界必须在工具层,不靠模型表现。
- 误区三:"预算不是资金"——会烧钱的动作必须进资金档。
- 误区四:"日志记了调用就够了"——还要记证据、审批人、trace id。
- 误区五:"上线配一次永久有效"——权限会随业务漂移,必须周审。
金融等强监管行业的额外要求
做金融、医疗、政务的团队,除了上面这些,还要多两层:一是职责分离(SoD)要有书面审批留痕,审计师会逐项核;二是外部实时事实必须来自可信数据层,不能让 Agent 自己抓网页猜政策版本——这一点上,像 Amazon Data API 这种实时数据层,价值就在于把"它基于哪版政策决策"变成可举证的事实,而不是模型的一句"我认为"。
怎么衡量治理健康度
别只看"有没有审批"。真正该盯的指标:审批拒绝率(长期为 0 说明审批形同虚设)、平均审批耗时(过长说明证据不够、审核人卡壳)、不可回滚动作占比(应趋近于 0)、trace id 覆盖率(必须 100%)、权限漂移次数(周审发现的问题数)。这五个数字,比"我们加了审批"这句话诚实得多。
审批页前后对比:同一笔退款,两种页面
坏的页面:"Agent 请求退款 ¥3,800,是否批准?" 好的页面:意图(买家说货损)、证据(订单 A 已签收;政策 v2025 30 天窗口可退)、工具调用(issue_refund 3800 市场 US)、影响范围(1 单 ¥3,800)、可逆性(24h 内可冲正)。同一个动作,两种决策——坏页面产出盲签,好页面产出真实判断,也常常产出证据不足时的果断"拒绝"。
反模式清单
- 审批人写进提示词:软请求,模型可忽略。
- 共享 admin token:出事分不清谁。
- 日志只记动作名:不记证据、审批人、trace id。
- "模型拒绝了"当"安全":拒绝 ≠ 已验证边界。
- 小额定额自动批:仍在训练盲签习惯。
落地小结:治理不是按钮,是系统
把上面这些串起来,企业 Agent 权限管理就是一套可重复的机制:分级的动作、每次审批都亮证据、每个动作带幂等键、每个可逆动作有回滚、每次调用有 trace id,并且每周复盘一次。它不是一个"批准"按钮,而是一套让"批准"这两个字终于有意义的系统。做到这些,Agent 才从玩具变成能托付业务的同事。
小结
企业 Agent 权限管理治的是"责任",不是"开关"。当"批准"不再是盲签、出错一定能撤、出事查得到谁,Agent 才从玩具变同事。
系列前作:客服 Agent 拒答能力、端到端集成、Agent 不是交付单位、项目管理 Agent 系统集成、AI 转型 SOP 还是进入流程、企业 AI 知识库为什么会失效。欢迎在评论区交流你们的工具签名怎么设计。