PAP协议解析:从工具调用到身份握手,Agent如何证明自己代表谁
1. 从“工具调用”到“身份握手”PAP协议到底想解决什么问题第一次看到“Person Agent Protocol”这个全称的时候我下意识把它归类成了又一个“让大模型调用外部工具”的接口规范。毕竟这两年各种Agent协议、函数调用标准、插件描述格式已经多到让人麻木光是把它们列个表就能占满一屏。但真正把PAP的设计动机和几个核心概念过了一遍之后我发现它想干的事情跟之前那些协议根本不在一个层面上——它要解决的不是“Agent怎么调用工具”而是“Agent怎么证明自己代表谁”。这个区别听起来有点抽象我举个生活化的例子你就明白了。以前的工具调用协议本质上像是一个没有门禁的公共图书馆任何人走进来报一个书名管理员就把书递给你。管理员不关心你是谁也不关心你拿书去干什么他只关心“你要的书我有没有”。而PAP想做的是给这个图书馆加上一套身份核验机制你进门要刷卡卡上写着你是谁、你能进哪些区域、你能借几本书、借了之后要承担什么责任。管理员在递书之前会先看一眼你的卡确认你有权限然后才把书给你。这个类比里“卡”就是PAP里的Person Agent概念“刷卡”就是身份握手“管理员看卡”就是权限校验。整套协议的核心就是把“Agent代表谁执行操作”这件事从一个隐含假设变成一个显式声明并且让这个声明可以被验证、被追溯、被约束。为什么这件事突然变得重要了因为Agent的自主性在快速提升。早期的Agent基本是“你问一句它答一句”所有的操作都在用户的直接指令下完成出了问题用户自己兜着。但现在越来越多的Agent开始具备长链条任务执行能力——它可以自己规划步骤、自己决定调用哪些工具、自己判断什么时候该停下来。当一个Agent能自主完成“查资料→写报告→发邮件”这一整条链路的时候“它到底代表谁”就不再是一个可以含糊过去的问题了。我试过用一个很简单的场景来理解这个痛点假设你有一个Agent帮你管理日程它需要读取你的邮件、访问你的日历、可能还要代表你给其他人发会议邀请。在传统模式下你只能给它一个“全权授权”它拿着你的凭证去操作所有事情。一旦它判断失误比如把一个不该发的会议邀请发给了错误的人你很难说清楚这到底是你的责任还是Agent的责任因为从系统角度看所有操作都是用你的身份完成的。PAP想做的就是把这个“全权授权”拆解成一个个具体的、有边界的、可追溯的授权单元让每一次操作都能对应到一个明确的身份声明上。注意PAP目前还处于早期讨论阶段不同实现方对细节的理解可能存在差异。下面我讲的内容一部分来自公开的设计讨论一部分是我基于常见Agent架构做的合理推演你在实际落地时需要以你所用平台的最新文档为准。2. 拆开PAP的三个核心概念Person、Agent、Protocol要理解PAP得先把这三个词拆开看。很多人一上来就盯着“Protocol”研究通信格式结果越看越糊涂因为协议本身只是一层壳真正决定它行为的是前面两个词的定义。2.1 Person不是“人”而是“责任主体”在PAP的语境里Person指的不是生物学意义上的人而是一个责任主体。它可以是一个自然人也可以是一个组织、一个部门、甚至另一个系统。关键在于这个主体具备两个能力第一它能做出授权决策第二它能承担授权带来的后果。这个定义听起来有点绕我换个说法你就懂了。当你用个人账号登录一个服务的时候你的账号背后对应的是一个Person因为这个账号的授权行为比如同意某个App访问你的数据是由你做出的出了问题也是你负责。但如果你在公司里用一个共享的服务账号去调用某个API这个账号背后对应的可能是一个部门而不是具体某个人那这个部门就是Person。PAP要求每个Agent在行动之前必须明确声明自己代表的Person是谁。这个声明不是随便写个字符串就完事了它需要满足几个条件可验证别人能确认这个声明是真的、可追溯出了问题能找到对应的Person、可撤销Person能随时收回授权。这三个条件缺一不可少了任何一个整套协议就退化成了一张废纸。2.2 Agent是“被授权的执行者”不是“自主决策者”这是最容易产生误解的地方。很多人看到“Agent”这个词脑子里浮现的是一个能自己思考、自己决策的智能体。但在PAP的框架下Agent的角色被严格限定为执行者——它可以在授权范围内自主选择执行路径但不能自主扩大授权范围。我用一个实际场景来说明这个边界。假设你授权一个Agent帮你处理报销流程授权范围是“读取发票信息、填写报销单、提交审批”。在这个范围内Agent可以自己决定先读哪张发票、怎么分类、用什么格式填写这些都属于执行层面的自主性。但如果它在执行过程中发现某张发票金额超标需要额外审批它不能自己决定“那我先提交了再说”而是必须停下来向Person请求扩大授权或者请求人工介入。这个边界的设计逻辑很清晰Agent的自主性应该体现在“怎么做”上而不是“能不能做”上。前者是效率问题后者是安全问题。PAP通过把授权决策权牢牢锁在Person手里确保Agent无论多智能都不会越过那条线。2.3 Protocol是“握手规则”不是“通信格式”最后说Protocol。很多人一看到这个词就开始研究消息格式、字段定义、传输层选型这其实是本末倒置了。PAP的Protocol部分核心不是定义“消息长什么样”而是定义“握手怎么发生”。什么叫握手就是Agent和Person之间建立授权关系的过程。这个过程需要解决几个问题Agent怎么向Person证明自己的身份Person怎么确认Agent的请求范围双方怎么达成一个双方都认可的授权条款授权条款怎么被记录下来供后续验证这些问题解决了消息格式反而是最简单的一部分——你用什么JSON schema、用什么传输协议都是实现细节。我个人的理解是PAP的Protocol部分更像是一套授权契约的协商流程而不是一套数据传输规范。这个定位上的差异决定了你在实现PAP的时候重点应该放在授权流程的设计上而不是消息格式的打磨上。3. 一次完整的PAP握手长什么样从请求到授权的全流程拆解光讲概念容易飘我直接用一个模拟场景把整个流程走一遍。假设你有一个日程管理Agent它需要代表你去读取某个外部系统的日历数据然后根据你的空闲时间自动安排会议。这个场景涉及跨系统访问正好能体现PAP的价值。3.1 第一步Agent发起身份声明Agent在请求访问日历数据之前首先要向目标系统发起一个身份声明。这个声明里包含几个关键信息Agent自己的标识、它代表的Person标识、它请求的权限范围、以及这个请求的有效期。这里有个细节值得注意Agent的标识和Person的标识是分开的。Agent标识用来区分“是哪个Agent在操作”Person标识用来区分“这个Agent代表谁”。为什么要分开因为同一个Person可能授权多个Agent同一个Agent也可能代表多个Person。如果把它们混在一起后续的授权管理和审计就会变得非常混乱。{ agent_id: calendar-assistant-v2, person_id: user-12345, requested_scope: [calendar.read, calendar.write], valid_until: 2025-06-30T23:59:59Z, nonce: a1b2c3d4e5 }这个声明本身不包含任何敏感信息它只是一个“我要代表谁做什么”的意图表达。真正的授权决策发生在下一步。3.2 第二步Person侧进行授权决策目标系统收到Agent的声明后不会直接信任它而是要把这个声明转发给Person侧进行确认。Person侧可能是一个授权服务也可能是一个人工确认界面取决于具体的实现。在这个环节Person侧需要做几件事验证Agent的身份是否合法、检查请求的权限范围是否在Person的授权能力之内、确认这个请求是否符合Person的当前意图。最后一项特别重要——Person可能之前授权过这个Agent读取日历但现在不想让它继续读了那Person侧就应该拒绝这个请求。我试过用一个简单的规则引擎来模拟这个决策过程如果Agent在Person的白名单里且请求的权限在Person的授权范围内且当前时间在有效期内就通过否则就拒绝或者转人工。这个规则引擎不需要很复杂但必须存在否则PAP就退化成了“Agent说什么就是什么”。3.3 第三步生成授权凭证如果Person侧批准了请求就会生成一个授权凭证返回给Agent。这个凭证是Agent后续访问目标系统的“通行证”它需要满足几个条件不可伪造通常用签名保证、不可篡改通常用哈希保证、可验证目标系统能独立验证、可撤销Person能随时让它失效。{ grant_id: grant-67890, agent_id: calendar-assistant-v2, person_id: user-12345, granted_scope: [calendar.read], issued_at: 2025-06-01T10:00:00Z, expires_at: 2025-06-30T23:59:59Z, signature: base64-encoded-signature }注意这里granted_scope和之前requested_scope的差异Agent请求了读和写两个权限但Person只批准了读。这个差异是正常的也是PAP设计里很重要的一点——Person有权缩小授权范围Agent不能因为请求被部分拒绝就拒绝执行。3.4 第四步Agent携带凭证访问目标系统Agent拿到授权凭证后就可以带着它去访问目标系统了。目标系统在放行之前会先验证凭证的有效性签名对不对、有没有过期、权限范围是否覆盖当前操作。验证通过后才执行实际的数据读取操作。这个环节的关键在于目标系统不需要直接和Person侧通信它只需要验证凭证本身。这大大降低了系统的耦合度——Person侧只需要在授权时参与一次后续的每次访问都是Agent和目标系统之间的事。3.5 第五步操作记录与审计每次Agent使用凭证访问目标系统都应该产生一条操作记录。这条记录里包含Agent标识、Person标识、授权凭证标识、操作类型、操作时间、操作结果。这些记录汇总起来就形成了一条完整的审计链路。审计链路的价值在于当出现问题时你可以沿着这条链路一路回溯这个操作是哪个Agent做的它代表谁它用的是哪个授权凭证这个凭证是谁批准的批准时的权限范围是什么这些问题都能找到答案责任归属就清晰了。提示审计记录的存储和查询本身就是一个不小的工程。如果你的Agent数量不多可以先从简单的日志文件开始如果Agent数量上来了建议尽早考虑结构化的审计存储方案不然后期排查问题会非常痛苦。4. 落地PAP时最容易踩的五个坑概念和流程讲完了接下来聊点实在的。我在模拟实现PAP的过程中踩了不少坑有些是设计层面的有些是实现层面的这里挑五个最有代表性的分享出来。4.1 坑一把Agent标识和Person标识混用这是最常见也最致命的一个坑。很多人在实现的时候图省事直接用Person的标识作为Agent的标识觉得反正都是同一个用户在操作没必要区分。结果就是审计日志里全是Person标识根本看不出是哪个Agent在操作出了问题连排查方向都没有。正确的做法是严格区分两个标识并且在所有日志和凭证里都同时记录。Agent标识用来定位具体的执行者Person标识用来定位责任主体。两者缺一不可。4.2 坑二授权范围定义得太粗另一个常见问题是授权范围定义得太粗比如直接给一个“calendar.*”的全权限而不是细分成“calendar.read”和“calendar.write”。粗粒度的授权看起来省事但实际上埋了大雷Agent一旦被攻破或者出现逻辑错误它能造成的破坏范围会大得多。我的建议是授权范围的定义粒度应该和你的审计能力匹配。如果你能精确审计到每一次读写操作那授权范围就可以细到读写级别如果你的审计只能到模块级别那授权范围最好也控制在模块级别。审计能力和授权粒度不匹配是很多安全问题的根源。4.3 坑三忘记处理授权撤销授权撤销是PAP设计里很重要的一环但在实现时经常被忽略。很多人只实现了“授权”流程没实现“撤销”流程结果就是Person一旦授权出去就收不回来了。撤销的实现有两种常见思路一种是短有效期频繁续期每次续期都是一次重新授权Person不续期就自动失效另一种是维护一个撤销列表目标系统在验证凭证时额外检查这个列表。两种思路各有优劣短有效期实现简单但会增加授权频率撤销列表实时性好但需要额外的存储和查询开销。我个人的偏好是短有效期为主、撤销列表为辅。大部分场景下短有效期就够了只有对实时性要求特别高的场景才需要引入撤销列表。4.4 坑四凭证验证逻辑写得太松凭证验证是安全链条上的最后一环也是最容易被攻破的一环。我见过不少实现只验证了签名没验证有效期或者只验证了有效期没验证权限范围。任何一个验证环节缺失都会让整个PAP的安全保证打折扣。一个完整的凭证验证至少应该包含这几项签名验证、有效期验证、权限范围验证、Agent标识验证、Person标识验证。这五项缺一不可而且验证顺序也有讲究——先验证签名防止伪造再验证有效期防止过期最后验证权限范围防止越权。4.5 坑五审计日志只记不查最后一个坑是审计日志只记录不查询。很多人把审计日志当成一个“合规摆设”记录是记录了但从来不查。结果就是出了问题之后面对海量的日志无从下手排查效率极低。审计日志的价值在于查询不在于记录。你需要在设计阶段就想清楚出了问题之后我会怎么查我会按什么维度过滤我会关注哪些字段把这些想清楚了日志的字段设计和索引设计就有了方向后续排查才能快起来。5. PAP和其他Agent协议的对比什么时候该用它聊到这里你可能会问市面上已经有那么多Agent协议了PAP到底有什么不同我什么时候该用它什么时候不该用我整理了一个对比表格从几个关键维度把PAP和常见的工具调用协议做了区分。对比维度传统工具调用协议PAP核心目标让Agent能调用外部工具让Agent能证明自己代表谁身份处理隐含在凭证里不显式声明显式声明Person和Agent两个身份授权粒度通常是全权授权细粒度、有边界、可撤销审计能力依赖底层系统的日志协议层面要求审计链路适用场景单用户、低风险操作多用户、跨系统、高风险操作实现复杂度低中到高从表格里能看出来PAP不是要取代传统的工具调用协议而是在它之上加了一层身份和授权管理。如果你的Agent只在单用户环境下运行操作的风险也不高那传统协议完全够用没必要上PAP。但如果你的Agent需要跨系统操作、需要代表多个不同的Person、或者操作本身涉及敏感数据那PAP的价值就体现出来了。我个人的判断标准是当“这个操作代表谁”这个问题变得重要的时候就是该考虑PAP的时候。如果这个问题从来没人问过那说明你的场景还没复杂到需要PAP的程度。6. 一个最小可用的PAP实现思路最后聊点实操的。如果你想在自己的项目里试试PAP我建议从一个最小可用的实现开始不要一上来就追求完整。下面是我梳理的一个最小实现思路你可以直接参考。6.1 定义三个核心数据结构第一个是身份声明包含agent_id、person_id、requested_scope、valid_until、nonce五个字段。第二个是授权凭证包含grant_id、agent_id、person_id、granted_scope、issued_at、expires_at、signature七个字段。第三个是审计记录包含record_id、grant_id、agent_id、person_id、operation、timestamp、result七个字段。这三个结构不需要很复杂但字段要齐全。特别是审计记录字段设计的时候要想清楚后续怎么查不然后期改起来很麻烦。6.2 实现两个核心接口第一个是授权接口接收身份声明返回授权凭证。这个接口的内部逻辑是验证Agent身份、检查请求范围、生成凭证、签名、返回。第二个是验证接口接收授权凭证和操作请求返回验证结果。这个接口的内部逻辑是验证签名、验证有效期、验证权限范围、返回结果。这两个接口是整个PAP的核心其他都是辅助。先把这两个接口跑通再考虑扩展。6.3 用签名保证凭证不可伪造凭证的签名可以用常见的非对称加密算法实现比如Ed25519或者RSA。Person侧持有私钥用私钥对凭证内容签名目标系统持有公钥用公钥验证签名。这样即使凭证在传输过程中被截获攻击者也无法伪造一个新的凭证因为他没有私钥。import nacl.signing # Person侧生成密钥对 signing_key nacl.signing.SigningKey.generate() verify_key signing_key.verify_key # 对凭证内容签名 credential_bytes b{grant_id:grant-67890,...} signed signing_key.sign(credential_bytes) signature signed.signature # 目标系统验证签名 try: verify_key.verify(credential_bytes, signature) print(签名验证通过) except nacl.exceptions.BadSignatureError: print(签名验证失败)这段代码只是一个示意实际实现时你还需要考虑凭证的序列化格式、签名的编码方式、密钥的管理和轮换等问题。但核心思路就是私钥签名、公钥验证、签名绑定内容。6.4 用短有效期降低撤销复杂度前面提到过授权撤销是一个容易被忽略的环节。在最小实现里我建议先用短有效期来替代复杂的撤销机制。比如把凭证的有效期设成1小时Agent每次访问前先检查凭证是否过期过期了就重新走一遍授权流程。这个方案的优点是实现简单不需要维护额外的撤销列表。缺点是授权频率会比较高如果Agent的访问很频繁可能会对Person侧造成压力。但在最小实现阶段这个缺点是可以接受的等后续有需要了再引入更复杂的撤销机制。提示短有效期的具体时长需要根据你的场景来定。如果Agent的操作是突发性的、间隔很长的有效期可以设长一点如果Agent的操作是持续的、高频的有效期就要设短一点同时考虑引入缓存机制来减少授权请求。6.5 从单Person单Agent开始验证最小实现的最后一步是先用一个最简单的场景来验证整套流程。比如一个Person授权一个Agent读取一个数据源Agent读取后返回结果。这个场景足够简单能让你快速跑通整个链路发现设计上的问题。等这个场景跑通了再逐步增加复杂度多个Agent、多个Person、多种权限范围、跨系统访问。每增加一个维度都重新验证一遍确保新增的复杂度没有破坏原有的安全保证。我个人在实际操作中的体会是PAP这类协议的价值不在于它的技术有多复杂而在于它把一些原本隐含的假设显式化了。在实现的过程中你会被迫去思考很多以前没想过的问题这个Agent到底代表谁它的权限边界在哪里出了问题怎么追溯这些问题想清楚了即使你不用PAP你的Agent系统也会变得更健壮。