AI エージェントを企業システムにつなぐ最初の案は、たいていこうです。ユーザーに一度ログインさせ、取得したトークンをエージェントに渡して使わせる。動くことは動きますが、答えられない問題が三つ残ります。エージェントは誰の権限を使ったのか? ユーザーが認可を取り消した後も、エージェントはまだ使えるのか? 問題が起きたとき、それが人の操作なのかエージェントの操作なのか、どう区別するのか?
エージェントは主体であって、道具ではない
最初のステップは、エージェントを独立した主体としてモデル化することです。トークンには principal_type=machine を持たせ、人間ユーザーと同じカーネルを通しながら、主体の型は別にします。エージェントには自分の資格情報、自分のロール、自分の呼び出しクォータがあります。
01// Agent 不再伪装成 USER,它有独立的 subject_type02{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}委任チェーン:権限は積集合を取り、和集合は取らない
エージェントが特定のユーザーに代わって動くときは、RFC 8693 Token Exchange で新しいトークンに交換します。肝は権限の計算です。新しいトークンの権限は、「エージェントに付与されたアプリの権限」と「そのユーザーが実際に持っている権限」の積集合で、さらに maxPermissionLevel で上限を切り詰めます。
この点が非常に重要です。和集合を取ると、エージェントは権限の増幅器になります —— ユーザーが持っていなかった権限を、エージェントが代わりに持ってしまう。積集合を取るということは、エージェントは「委任したユーザー」以上のことは決してできない、ということです。
01val appPerms = appPermissionResolver.resolve(clientId)02val userPerms = userPermissionResolver.resolve(subjectToken.sub)0304// 交集:Agent 不能比被委托的用户做得更多05val granted = appPerms.intersect(userPerms)06 .filter { it.level <= maxPermissionLevel }0708// act claim 记录委托关系,多跳场景可嵌套09val act = ActClaim(sub = subjectToken.sub, nested = subjectToken.act)ツールレベルの認可はコードに書く
エージェントがどのツールを呼べるかは、ドキュメントに書いて人の遵守に頼るのではなく、アノテーションに書いてフレームワークに強制させます。agent_tools レジストリは各ツールの所属と権限要件を登録し、呼び出しの前に毎回検証します。
01@RequiresToolPermission("order:refund")02@PostMapping("/tools/order-refund/invoke")03fun invokeRefund(@RequestBody req: ToolRequest): ToolResult {04 // 到这里说明调用方持有该工具权限,且未超配额05 return toolExecutionService.execute(req)06}代償は何か
- すべてのエージェントは先に登録し、ロールを設定する必要がある。「まず動かしてから考えよう」は許されない
- 委任チェーンにはトークン交換が一回増え、経路は長くなり、切り分けは複雑になる
- 多段委任の act のネストは注意深く扱わないと、途中の委任関係が失われる
これらのコストの見返りはこうです。エージェントによるどんなデータアクセスも、「誰が認可し、どのツールを使い、どの権限を使ったのか」に答えられる。コンプライアンスが絡む場面では、この「答えられる力」こそが参入の条件です。