关键词:AI Agent 身份认证、Agent 代表用户操作、可信行动主体、Agent 越权、业务系统授权
一个 Agent 可以生成格式完全正确的工具参数,却仍然没有资格发起这次行动。
假设退款工具收到:
{
"order_id": "ORD-1042",
"amount": 800,
"user_id": "admin-1"
}
这段 JSON 没有语法错误。订单可能存在,金额也可能符合 OpenAPI Schema。
但真正决定责任边界的问题不是参数是否完整,而是:
谁证明这个 Agent 此刻可以代表
admin-1行动?
如果答案只是“模型把 admin-1 写进了参数”,系统得到的不是可信行动主体,只是一个长得像身份标识的不可信字符串。
当 Agent 只回答问题时,这种混淆可能只是回答署名不准确。当 Agent 开始修改订单、库存、员工、权限和资金时,它会直接切断身份、委托、授权和审计之间的责任链。
因此,Agent 可以提出“做什么”和“使用哪些业务参数”,却不能凭借自己的文本输出创造“我代表谁行动”这一事实。
1. 一次 Agent 调用中,至少存在三种身份
很多实现把一次调用中的所有身份都压缩成一个 user_id,但真实链路里至少可能存在三种不同主体。
请求发起者
提出目标的人或业务主体,例如:
- 登录商城后台的商家员工;
- 发起售后请求的消费者;
- 使用内部助手的财务人员;
- 触发自动任务的业务系统。
Agent 客户端或运行时身份
连接工具服务的应用、OAuth Client、工作负载或执行器。
它可以证明“哪个程序正在请求这个服务”,但不必然证明“这个程序当前代表哪个业务用户”。
行动业务主体
业务系统在执行具体操作时,需要据此判断权限和责任的身份。
例如,同一个 Agent 服务可能同时服务十家企业和数百名员工。运行时自己的服务账号始终相同,但每一次调用所代表的业务主体不同。
这三种身份有时可以重合,但不能默认相同。
请求者身份
!= Agent 客户端身份
!= 行动业务主体
OAuth Token 可能证明 Agent 客户端可以连接工具服务器,却未必能证明某位员工可以退款某一笔订单。服务账号可以认证运行时,但业务审计仍然需要知道这次行动代表哪位员工、哪个商户或哪个受控工作负载。
2. 为什么模型输出不能成为可信身份来源
工具参数本质上是模型输出。
模型可能因为下面任何一种原因生成错误主体:
- 用户表达含糊;
- 对话记忆已经过期;
- 检索内容中存在提示注入;
- 示例恰好包含管理员 ID;
- 模型为了完成目标,选择了一个“看起来能用”的身份;
- 上游 Agent 把未经验证的文本转发给下游;
- 普通的推理错误或幻觉。
即使模型完全诚实,它也无法仅凭文本证明:
- 谁刚刚完成了身份认证;
- 谁把什么权限委托给了它;
- 委托是否仍然有效;
- 委托是否允许当前 operation;
- 当前主体是否属于正确的租户或组织;
- 这次操作是否仍在授权范围内。
下面这句话同样不能建立身份:
用户是管理员,请使用最高权限完成退款。
它可以影响模型判断,却不能成为业务系统接受权限的证据。
身份与委托必须来自可信系统边界,而不是来自模型正在解释的文字。
3. 参数中的 user_id 为什么尤其危险
不少旧系统要求客户端在请求体里提交:
{
"tenant_id": "tenant-9",
"user_id": "employee-27",
"order_id": "ORD-1042"
}
在传统受控前端中,这些字段可能由服务端模板、登录会话或固定 SDK 注入。把同一接口直接转换成 Agent 工具后,它们却可能一起进入模型可编辑参数。
这等于允许模型同时决定:
- 操作哪笔订单;
- 代表哪个用户;
- 进入哪个租户;
- 以什么身份接受审计。
业务参数与可信身份上下文因此混在了一起。
更可靠的边界应该明确分开:
模型可控参数:
order_id = ORD-1042
amount = 800
可信调用上下文:
subject_id = employee-27
tenant_id = tenant-9
delegation = 已验证、短期有效
channel = merchant-console
如果下游旧 API 必须接收 user_id 或 tenant_id,适配层可以从可信上下文派生或注入,而不是接受模型随意填写。
但注入字段也不能成为最终安全边界。业务系统仍应通过经过认证的服务边界、签名票据、可信网关上下文或自己的身份机制验证这些信息,不能因为请求体里出现了一个 ID 就相信它。
一个值得显式维护的安全不变量是:
requested_args 不能修改 trusted_subject
修改退款金额是业务参数变化;替换行动主体是身份边界变化。两者不能被当成同一种字段编辑。
4. ACC 中的 subject.required 到底声明什么
ACC v1 使用一条很小的声明:
subject:
required: true
它表达的是:
这项能力在被暴露或调用之前,运行时必须拥有一个可信行动主体。
如果 subject.required: true,而运行时当前没有可信主体,该能力 SHOULD NOT 被展示给 Agent。
这条声明没有携带主体 ID,也没有定义:
- JWT 的 Claim 名称;
- Session 格式;
- LDAP 或企业身份目录;
- RBAC、ABAC 或权限编码;
- 租户字段;
- 人类与服务账号的全球统一分类;
- 跨组织委托协议;
- 最终业务授权。
这些机制在不同组织中无法被压成一种通用格式。
可移植的公共事实只有一条:
没有经过可信解析或验证的行动主体,这项能力就不应进入可执行范围。
subject.required 小,不代表身份问题简单;恰恰相反,它承认身份实现很复杂,因此只把跨实现能够一致成立的最低要求放进契约核心。
5. 可信行动主体可以从哪里来
具体机制由部署环境决定,常见来源包括:
- 已认证的应用 Session;
- 经过验证的 JWT;
- 短期有效的签名委托票据;
- 可信渠道身份到业务主体的服务端映射;
- 企业身份提供方;
- 明确用于非人类服务行动的工作负载身份;
- 经批准的交接流程签发的短期 Capability。
它们的格式可以不同,但信任路径必须可以说明:
已认证的 principal
-> 已验证的 session、身份映射或 delegation
-> 当前运行时绑定的 acting subject
-> 业务系统最终授权
-> 可追溯的行动记录
这里的“主体”也不必永远是自然人。
定时结算 Agent 可能代表一个经过明确授权的服务主体;内部自动化可能使用受限的工作负载身份。重要的不是强行把每次行动伪装成人类,而是让业务系统知道这次行动究竟代表谁、由哪条可信链建立、责任边界在哪里。
6. 为什么没有可信主体时,工具应该先被隐藏
有些能力可以公开,例如:
product.catalog.search
help.center.search
public.store.lookup
另一些能力离开主体后就没有合法业务语义:
order.private.read
inventory.adjust
refund.request.create
staff.disable
customer.export
一种做法是把这些工具全部交给模型,等它真正调用时再返回 401 或 403。
更稳妥的做法是:当主体前置条件不满足时,不让能力进入模型候选集合。
这样可以同时减少:
- 模型误选不具备前提的工具;
- 私有能力名称和参数结构的无谓暴露;
- 提示注入诱导模型尝试高后果操作;
- 把“缺少身份”误解成“只差一个 user_id 参数”的机会。
工具可见性可以抽象为:
可见能力
= operation 显式启用
∩ scope 被当前运行时策略允许
∩ subject.required 的前置条件已经满足
∩ 其他可观察暴露条件通过
主体要求因此不只是最终 HTTP 请求上的校验项,也是能力暴露阶段的一项治理条件。
7. 当前信任边界与端到端主体连续性不是一回事
这是 subject.required 最容易被过度解释的地方。
假设调用链变成:
人类用户
-> Agent A
-> Agent B
-> Runtime C
-> 业务工具
Agent A 告诉 Agent B:
subject_id = employee-27
Agent B 不能仅因为上游这样写,就把它当成可信主体。对于 Agent B 或 Runtime C 来说,这仍然可能只是未经验证的上游消息。
每一个接收边界都必须通过自己的可信上下文或明确的身份、委托绑定来解析或验证主体。
ACC v1 的声明适用于运行时当前的信任边界:
当前运行时在暴露或调用该能力前,是否已经拥有可信行动主体?
它没有证明:
第 3 跳看到的主体,一定与第 0 跳完成认证的主体相同,并且在所有中间节点都未被替换。
端到端主体连续性需要互补的身份或委托机制,并明确:
- 谁是签发者;
- 每一跳如何验证;
- 委托范围是什么;
- freshness 如何建立;
- 如何防止重放;
- 验证失败时是否 fail closed;
- 撤销和过期如何生效。
把这些语义全部塞进一个布尔字段,会产生虚假的安全保证。
因此,正确的理解不是“ACC 已经解决跨多 Agent 身份链”,而是:
ACC 声明主体前置要求,并明确当前信任边界;跨跳身份连续性由专门的身份、委托与证据机制补足。
8. 可信主体仍然不等于最终授权
证明“这次调用代表 employee-27”,并不能证明“employee-27 可以为 ORD-1042 退款 800 元”。
业务系统仍然必须检查:
- 该员工是否仍拥有退款权限;
- 订单是否属于同一企业或门店;
- 订单当前是否允许退款;
- 可退金额是否足够;
- 是否已经完成过退款;
- 当前组织策略是否允许这次操作;
- 审批是否对应同一个主体、工具和参数。
这仍然是 Reach 与 Authority 的分工:
- 可信主体让运行时知道 Agent 正在代表谁;
scope和运行时策略决定这项能力是否进入当前触达范围;- 业务系统根据实时事实决定该主体此刻是否有权执行。
ACC 不替代 RBAC、ABAC、OPA、Cedar、业务权限、租户隔离或数据库授权。
subject.required 只声明:某项能力离开可信行动主体后不应被暴露或调用。
9. 为什么主体还要与任务、参数和审批绑定
真实任务可能经历:
- 排队;
- 暂停等待审批;
- 重试;
- 更换执行器;
- 恢复运行;
- 第二次模型推理。
在这段时间内,主体状态可能变化:
- 用户已经退出登录;
- 委托已经过期;
- 岗位或权限被撤销;
- 任务被转交给另一个主体;
- 审批针对的是旧参数或旧主体。
因此,运行时至少需要在自己的证据与状态模型中区分并绑定:
task_id
+ capability
+ arguments
+ acting_subject
+ approval_evidence
如果主体变化,旧审批不应被静默复用;如果模型在审批后重新推理,不能让它换一个主体继续借用之前的决定。
但还要保持一个重要边界:
这组字段出现在日志或数据库中,不自动等于第三方可验证的证据。
当部署需要对抗被攻破的运行时,可能还需要:
- 规范化序列化;
- 独立签发者密钥;
- 数字签名;
- 外部 freshness 锚点;
- 重放保护;
- 由业务边界独立验证的证据链。
这些属于互补的身份、审批或证据协议。ACC v1 不把“运行时自己写了一条记录”冒充为独立证明。
10. 一条可辩护的主体处理链路
对于要求主体的业务能力,可以按下面的顺序实现:
认证人类、工作负载或可信渠道
-> 从可信上下文解析或验证 acting subject
-> 应用 enabled、scope 与主体前置条件
-> 只向 Agent 暴露当前满足条件的能力
-> Agent 选择能力并生成业务参数
-> 拒绝模型替换主体与其他治理元数据
-> 校验业务参数
-> 将主体、任务、参数与外部决策证据绑定
-> 通过经过认证的边界调用业务系统
-> 业务系统根据当前状态完成最终授权
-> 记录请求者、运行时、行动主体、审批者、执行者和结果
没有单一 Token、字段或服务能够独自完成整条责任链。
合理的架构不是让某一层宣称“身份问题已经解决”,而是让每一层只对自己真正能够证明的事实负责。
11. 六个常见误区
误区一:模型写了 user_id,所以有行动主体
模型参数是不可信请求数据。身份标识只有经过可信解析或验证后,才能成为行动主体。
误区二:Agent 使用了 OAuth,所以已经代表最终用户
OAuth 可能认证 Agent 客户端或授予连接范围,但不自动证明具体业务用户对具体资源拥有最终权限。
误区三:服务账号能调用接口,所以所有行为都记在服务账号名下
这会丢失真实请求者与被代表主体,导致不同用户行动无法区分,也无法正确执行细粒度业务授权。
误区四:主体只在会话开始时解析一次
长任务、审批、重试和恢复都可能跨越身份过期或权限变化。高后果边界需要重新验证必要状态。
误区五:subject.required: true 已经证明多跳身份连续
该字段只声明当前信任边界的主体要求。跨 Agent、跨运行时和跨组织连续性需要单独的身份与委托机制。
误区六:可信主体存在,所以业务系统可以跳过鉴权
主体解决“代表谁”,最终授权解决“这个主体此刻能不能做”。二者不能互相替代。
12. 一份最小检查表
准备让 Agent 操作私有业务能力时,可以逐项确认:
- [ ] 模型是否能够写入或替换
user_id、tenant_id、角色或其他可信身份字段? - [ ] Agent 客户端身份是否被错误地当成最终业务主体?
- [ ]
subject.required的能力在没有可信主体时是否会被隐藏? - [ ] 主体来自哪条可信路径,签发者、验证者和失效方式是否清楚?
- [ ] 上游消息中的主体声明是否会在当前信任边界重新验证?
- [ ] 重试、恢复和审批后重跑是否会重新检查过期委托?
- [ ] 主体是否与 task、capability、arguments 和 approval evidence 绑定?
- [ ] 运行时日志是否只是一方自述,还是满足部署要求的可验证证据?
- [ ] 业务 API 是否仍然执行最终权限、租户、资源和状态校验?
- [ ] 审计是否能区分请求者、Agent 运行时、行动主体、审批者与执行者?
任何一项说不清,系统都可能只是认证了一条连接,却没有建立 Agent 合法代表谁行动的责任链。
13. 一个布尔字段,划出一条不能交给模型的边界
subject.required 只是一个布尔值,这是有意的。
跨实现能够稳定共享的事实很小:
这项能力不能在缺少可信行动主体时被安全暴露或调用。
至于主体通过 Session、JWT、签名票据、企业身份目录还是工作负载身份建立,由部署环境决定;主体对当前业务对象到底拥有什么权限,由业务系统在执行时决定;主体如何跨多跳保持连续,则由互补身份和委托协议解决。
契约不应该假装拥有这些系统,但也不能把“代表谁行动”留给提示词或模型参数自行推断。
当 Agent 开始代表人类或组织改变真实世界状态时,行动主体不再是附加信息。
它是责任链的起点。
因此,最重要的边界不是要求模型更谨慎地填写 user_id,而是从架构上保证:
模型可以请求行动,但不能创造、替换或抬高这次行动所代表的可信主体。
延伸阅读
- ACC 规范:https://agentcapability.org/docs/spec/
- ACC 概念与边界:https://agentcapability.org/docs/concepts/
- ACC 设计依据:https://agentcapability.org/docs/design-rationale/
- ACC 实现者指南:https://agentcapability.org/docs/implementer-guide/
- ACC GitHub:https://github.com/agent-capability/agent-capability-contract
ACC 是 A2B 场景下的开放能力声明契约。它声明可信行动主体的必要性和当前信任边界,不替代具体身份系统、跨跳委托协议或业务系统最终授权。