UIAM · Agent

Agent 不该拿人类的令牌干活

把一个人类用户的令牌交给 Agent,等于把一把万能钥匙交给一个你不完全理解的行为体。我们用 RFC 8693 把「谁代表谁」写进令牌里。

AI Agent 接入企业系统的第一个方案通常是:让用户登录一次,把拿到的令牌交给 Agent 用。这个方案能跑通,但它有三个无法回答的问题——Agent 用了谁的权限?用户撤销授权后 Agent 还能不能用?出事时怎么区分是人的操作还是 Agent 的操作?

Agent 是主体,不是工具

第一步是把 Agent 建模成独立主体。令牌里带 principal_type=machine,与人类用户走同一套内核但主体类型不同。Agent 有自己的凭据、自己的角色、自己的调用配额。

uiam-agent — MACHINE 主体
01// Agent 不再伪装成 USER,它有独立的 subject_type
02{
03 "sub": "agent:sales-copilot",
04 "principal_type": "machine",
05 "tenant_id": "acme",
06 "roles": ["order:read", "customer:read"],
07 "quota": { "tool_calls_per_min": 120 }
08}

委托链:权限取交集,不取并集

当 Agent 代表某个用户行动时,走 RFC 8693 Token Exchange 换一张新令牌。关键在权限计算:新令牌的权限是「Agent 被授予的应用权限」与「该用户实际拥有的权限」的交集,再按 maxPermissionLevel 裁剪上限。

这一点非常重要。如果取并集,Agent 就成了权限放大器——用户没有的权限,Agent 反而有了。取交集意味着 Agent 永远不可能比「委托它的用户」做得更多。

TokenExchangeServiceImpl — 权限交集
01val appPerms = appPermissionResolver.resolve(clientId)
02val userPerms = userPermissionResolver.resolve(subjectToken.sub)
03
04// 交集:Agent 不能比被委托的用户做得更多
05val granted = appPerms.intersect(userPerms)
06 .filter { it.level <= maxPermissionLevel }
07
08// act claim 记录委托关系,多跳场景可嵌套
09val act = ActClaim(sub = subjectToken.sub, nested = subjectToken.act)

工具级授权写在代码里

Agent 能调哪些工具,不是写在文档里靠人遵守,而是写在注解上由框架强制。agent_tools 注册表登记每个工具的归属与权限要求,调用前逐次校验。

uiam-agent — 工具级授权
01@RequiresToolPermission("order:refund")
02@PostMapping("/tools/order-refund/invoke")
03fun invokeRefund(@RequestBody req: ToolRequest): ToolResult {
04 // 到这里说明调用方持有该工具权限,且未超配额
05 return toolExecutionService.execute(req)
06}

代价是什么

  • 每个 Agent 都要先注册、配角色,不能「先跑起来再说」
  • 委托链多了一次令牌交换,链路更长、排查更复杂
  • 多跳委托的 act 嵌套需要小心处理,否则会丢失中间委托关系

这些成本换来的是:任何一次 Agent 的数据访问,都能回答「谁授权、用哪个工具、用了哪些权限」。在合规场景里,这个回答能力是准入门槛。

More Notes
Get in touch

把身份、Agent 与私域的复杂度,交给一套可治理的内核

无论你是要替换现有的 IAM、搭建 Agent 中台,还是想把企微私域真正运营起来——先从一次 30 分钟的架构沟通开始。我们会先判断问题是不是我们擅长解的那类,不合适会直接说。