最近在折腾多Agent协同的时候,我盯上了一件事:各家模型和框架都在疯狂堆Agent数量,但Agent之间的通信方式却还停留在“你给我发个JSON,我给你回个JSON”的裸奔阶段。某头部AI团队低调放出了一套协议,名字叫PAP(Person Agent Protocol),全称非常直白,就是“人-智能体协议”。我花了两周时间在模拟项目X里做了接入和压测,这篇文章不聊PPT,只聊这套协议到底拆开来看是什么、怎么用、坑在哪。
先说结论:PAP不是又一个MCP式的工具调用协议,它管的是Agent的“身份、权限和对话边界”。如果你正在做多Agent编排、AI工作流、或者企业内部助理类系统,这套协议值得仔细看。它解决了一个很实际的问题——当Agent不再是“你的一个函数”,而是“一个替你办事的数字员工”时,协议层必须有“人”的位置。
1. PAP协议的定位与设计思路
1.1 没有“人味”的Agent通信是个大问题
现在很多Agent系统互相调用,本质上就是HTTP请求加一个API Key。两个Agent之间对话,A问B要数据,B根本不知道对面是谁在操控,也不知道这次请求允许做什么。问题在单个Agent里不明显,一旦变成十几个Agent协作的复杂系统,就会出现三种混乱:
- 身份混乱:不知道“谁”在发起请求,是用户本人、用户授权的Agent,还是另一个偷偷跑起来的Agent。
- 权限混乱:很多Agent拿到一把很宽泛的钥匙,比如能读整个日历,那它顺带读个通讯录也就没人发现。
- 审计混乱:出事之后,你根本没法回答“这个操作到底是哪个Agent在哪条指令链路上做的”。
我见过某公司的内部流程自动化项目,助理Agent调用报销Agent,因为权限模型没做,助理Agent居然能直接改报销单金额。这已经不是技术问题,是治理问题了。PAP的思路,是把“人”这个角色显式地建模进协议里——每个Agent背后都有一个Person(用户或者责任人),每次通信都必须声明这个Person是谁,以及这次会话被授予了哪些权限。
1.2 PAP的三层模型:把“人”装进协议
PAP的核心设计可以拆成三层,我习惯叫它“身份层-能力层-会话层”:
- 身份层:解决“你是谁”的问题。每个Agent和人都有自己的去中心化标识(类似DID风格),并且人和Agent之间要有可验证的绑定声明。也就是说,Agent不能自己声称“我是某某人的助手”,必须能拿出一份由那个人的身份私钥签过名的凭证。
- 能力层:解决“你能做什么”的问题。每个Agent都会暴露一组能力声明,比如“可以读日历”、“可以写待办”,但调用之前必须经过策略引擎检查。能力描述不是自由文本,是结构化机器可读的,方便策略引擎做判断。
- 会话层:解决“这次对话的边界在哪”的问题。每次交互都发生在一个有生命周期的会话(Session)里,会话里携带上下文ID、权限集(Scope)、过期时间。会话一旦关闭,所有令牌自动失效。
这套设计把“永久授权”改成了“临时会话授权”。以前是Agent拿到一个长期有效的Key,现在是每次任务来了临时开一条会话,给最小权限,用完就销毁。从治理角度看,这个思路非常正。
1.3 和现有工具协议的关系:不是替代,是叠加治理
很多人一看PAP就问:这是不是要替代MCP、Function Calling?我实测下来的理解是:两者根本不在一个层次。
现有工具协议解决的是“Agent怎么调用一个工具”,PAP解决的是“Agent怎么在合法的身份和权限框架下被允许调用这个工具”。你可以把PAP理解成一层“外交护照+签证系统”,MCP理解成“高速公路”。你出国必须带护照签证,但开车上的还是高速公路。实际接入时,PAP通常作为通信骨架,工具调用仍然走原有协议,只是外面套了一层身份和策略校验。
这个定位意味着:如果你的项目已经用某种工具协议接了一堆工具,不需要推翻重来,只需要在入口处加一层PAP网关做身份验证和策略仲裁,就能逐步迁移,工程成本可控。
2. PAP协议核心机制拆解
2.1 可验证身份声明:Agent的“数字身份证”
PAP里每个参与者都有一个身份标识,格式上类似did:pap:agent:{id}或者did:pap:person:{id}。仅有一个标识没有意义,关键是必须要有“可验证的绑定关系”。
具体机制是这样的:一个用户(Person)在自己的客户端里生成一对公私钥,私钥自己持有,公钥可以公开。当这个用户想要授权一个Agent替他办事时,用户用私钥对一条声明做签名,声明内容大致是:“我,这个Person,确认这个Agent从此刻起代表我,有效期到某天为止”。签完名的声明就是一份可验证凭证,Agent在发起任何请求时必须携带这份凭证。
接收方收到请求后,会做三件事:验签(确认这份声明确实是那个Person签的)、查状态(确认这份凭证没有被吊销)、核对身份层级(确认这次请求里的“人-代理”关系链完整)。任何一个环节失败,请求直接拒绝。
我在国内某实验室的智能助理项目里做过类似实现,最深的体会是:所有的身份麻烦,都比不过“密钥放哪里”麻烦。服务器端Agent持有用户私钥,是方便,但泄密等于用户身份被拿走。更稳妥的方案是用硬件安全模块或者操作系统钥匙串托管私钥,Agent只拿临时签发的会话令牌,不直接碰长期私钥。
2.2 会话信封:一次对话就是一个受控通道
PAP把Agent之间的每一次交互都封装在会话里,和“无状态调用”相比,多了一层关键的控制能力。一次标准请求长这样:
{ "protocol": "pap", "version": "0.9.0", "session": { "id": "sess_8f2a1c", "created_at": "2025-06-14T08:30:00Z", "expires_at": "2025-06-14T08:35:00Z", "scope": ["calendar:read", "calendar:write:own"] }, "from": "did:pap:agent:assistant-01", "to": "did:pap:agent:calendar-service", "delegation": { "person": "did:pap:person:alice", "certificate_ref": "vc_20250614_001" }, "payload": { "intent": "list_events", "params": {"date": "2025-06-14"} } }注意几个字段设计的用意:
expires_at:会话必须有过期时间,这个不是可选项。我见过有人为了省事把过期时间设成7天,结果Agent令牌泄露后整整一周关不掉权限。最合理的做法是过期时间不超过单次任务预估时长的两倍。scope:声明这次会话能做什么。策略引擎最终按这个字段来仲裁,而Agent实际能调用的工具范围只会小于等于这个scope。delegation:这是PAP最关键的部分,显式声明背后的人。接收方不仅可以验证Agent身份,还能验证“这个Agent确实被这个人授权了”。
会话机制带来的一个额外好处是“可撤销”。以前要封禁一个失控Agent,只能改配置文件重启服务。有了会话之后,直接吊销会话ID,所有拿着这个ID的请求立刻失效,不需要动Agent本身。
2.3 授权级联与人工介入:权限只能收缩,不能膨胀
PAP的授权模型有一个非常值得借鉴的设计:权限在做“人→主Agent→子Agent”的链条传递时,每一级只能做减法,不能做加法。
用户授权给主Agent的scope如果包含calendar:read, 主Agent再派发给子Agent的scope只能是calendar:read的子集,比如缩小到calendar:read:team-a,而绝对不能扩展成calendar:write。这个约束是在协议层面强制的,不是靠程序员自觉。我试过故意在子Agent请求里写大权限,网关直接返回校验错误,这比老式OAuth的模式严格多了。
另一个设计是“人工介入点”。对于高风险操作,比如“发送邮件”、“修改订单”、“对外付款”,PAP策略引擎可以配置成必须回到对应Person那里做二次确认。流程是:Agent请求高风险动作 → 网关挂起这个请求 → 向Person推送一条待确认通知 → Person确认后,请求才放行。
我在项目里第一天就配了“邮件发送必须人工确认”的策略,一周内拦下了四次子Agent误触发的群发操作。这个机制对于给Agent上生产环境的人,真的能保命。
2.4 审计信息:整个交互过程可回放
PAP协议在信封里强制携带session_id、request_id、delegation信息,这些字段不是给程序看的,是给审计系统看的。日志系统可以通过这些ID把一次完整操作串起来,形成一条链路:用户请求 → 主Agent决策 → 子Agent执行 → 工具调用 → 返回结果。
有一次我们排查故障,定位到一个Agent半夜在调用另一个Agent的导数据接口,就是因为策略日志里完整记录了request_id的链路:用户A在下午4点启动了周期性任务,任务调度器在半夜以用户A的名义发起了数据导出请求。如果没有这套审计字段,这种问题很难快速复现。
3. 从零接入PAP:实操记录
3.1 初始化身份和凭证
我在模拟项目X里用的是一套开源的PAP参考实现,整个接入流程比预期顺畅。第一步是初始化身份:
pap init --identifier assistant-production \ --key-type ed25519 \ --output ./credentials执行完会生成一对密钥,同时生成一个身份标识文件。随后把公钥注册到身份注册中心:
pap register \ --did did:pap:agent:assistant-production \ --public-key ./credentials/pub.pem \ --resolver https://identity.example.internal注意,这里注册的不是简单的“把公钥存一下”,注册中心会返回一条“身份注册证明”,后面Agent对外通信时,对方可以拿这个证明去验证。如果你们公司已经有内部的公钥基础设施,PAP身份注册完全可以挂在现有体系上,不需要另起炉灶。
实操里有个容易忽略的点:Agent的私钥文件最好单独用一个服务账号去读,不要放在普通业务代码能访问的目录里。我把私钥放到专门的密钥服务后,CFT扫描和日志泄露的担子轻了很多。
3.2 建立会话与请求响应流程
初始化完成后,接入方需要实现“建立会话”这个动作。参考实现里提供了Python客户端,代码很简洁:
import pap client = pap.PAPClient( identity="did:pap:agent:assistant-production", credential_path="./credentials" ) # 发现目标Agent的能力 target = client.discover("did:pap:agent:calendar-service") print(target.capabilities) # 以Person Alice的授权身份建立会话 session = target.connect( person="did:pap:person:alice", scope=["calendar:read"], ttl=300, certificate=alice_credential ) resp = session.send({ "intent": "list_events", "params": {"date": "2025-06-14"} }) session.close()这里面scope=["calendar:read"]的选择很关键,它决定了这次会话的权限边界。我一开始图省事,把该Agent可能用到的所有权限都写进了scope,结果策略引擎每次都是放行,虽然功能正常,但完全失去了权限控制的意义。后来改成按需申请的最小权限,每次任务只申请本任务需要的权限,安全性改善非常明显。
3.3 策略文件怎么写得稳
PAP的策略文件用YAML编写,挂在网关上做仲裁。下面是一个我调试了多次才稳定的最小策略示例:
version: 0.9 name: calendar-policy targets: - did:pap:agent:calendar-service rules: - id: allow-read-own effect: allow actions: ["calendar:read"] resources: ["did:pap:person:alice"] condition: time: between: ["09:00", "18:00"] - id: deny-event-overlap effect: deny actions: ["calendar:write"] condition: expression: "resource.calendar.busy == true"写策略文件有几点经验:
- 规则顺序很重要。策略引擎采用“先匹配拒绝,再匹配允许”的顺序会更安全。我踩过坑:先写了宽泛的allow,后写的deny根本没生效。许多实现里同一条规则冲突时是按顺序先到先得,防呆做法是给每个允许规则都加严格的资源限定。
condition字段支持时间窗、资源状态判断。我建议至少加一个工作时段限制,不要允许Agent在凌晨三点任意改线上数据。- 策略文件一定要纳入版本管理。我见过直接把网关策略文件改在服务器上、没有任何评审流程的团队,那是等着出事。
3.4 工程落地的几个配置细节
接入过程中有几个参数配置直接影响实际体验,列出来供参考:
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| 会话TTL | 300秒 | 单次Agent任务内多个调用够用,太长容易扩大泄露面 |
| 凭证有效期 | 24小时 | 配合刷新机制,不推荐长期凭证 |
| 吊销缓存 | 60秒 | 吊销后最多60秒内旧凭证还能用,可以接受 |
| 最大scope数 | 10 | 超过就报警,基本能发现Agent权限膨胀的趋势 |
| 高风险操作二次确认 | 开启 | 写操作类全部开启,宁可多一步确认 |
这里推荐“会话TTL=300秒”,很多人觉得短,但Agent在几分钟内完成工具调用链绰绰有余。如果需要跑长任务,可以走“会话续期”流程,而不是一开始就给很长的时间窗口。
4. 踩坑记录:常见问题与排查思路
4.1 身份校验失败,先查时钟
接入PAP后我遇到的第一个线上问题是“身份验证签名无效”。代码和配置检查了一遍都没问题,最后发现是两台服务器之间的系统时间偏差超过了30秒。PAP的签名里带了时间戳,接收方校验时会检查时间窗,偏差过大就会判定无效。这个问题的隐蔽性在于,不是每次都失败,而是一会儿好一会儿坏。
解决办法也很简单:在所有运行PAP的节点上统一启用时间同步服务,并在协议SDK层面对系统时间做启动时检查。我后来养成了习惯,凡是Agent身份校验报错,第一件事就是看各节点时间差。
4.2 权限配置了但不生效
另一个高频问题是“策略文件里写了allow,但Agent调用还是被拒绝”。排查到最后,大部分情况是scope传递出了问题:用户给Agent的scope是calendar:read,但Agent在子调用时用的scope写成了calendar:read:tmp,这个子集在策略引擎里无法匹配任何规则。
PAP的scope匹配是精确匹配加前缀匹配,不是模糊包含。写策略时最好把自己用的scope清单完整列出来,不要想当然。用“最小够用原则”逐条列出,每加一个工具调用就补一条策略,反而比一次性写一大堆稳定得多。
4.3 调试协议的最佳路径
PAP协议刚接入时,排查问题会比较痛苦,因为涉及身份、会话、策略三个层次。我发现最好用的调试手段是“结构化回放”:把一次失败的请求完整打印出来,包括信封头、scope、证书引用,然后逐层检查。
另外,大多数PAP实现都有pap debug命令,可以模拟一次请求做本地校验。我在网关前部署了这个工具,每次策略调整后先跑一遍本地校验,确认没有问题再同步线上,基本把“改了策略反而搞挂服务”的概率降到了零。
4.4 几个值得记下来的经验
踩过几次坑之后,我总结了几条感受:
- 会话凭证不要写死在配置文件里,用动态签发、动态刷新的方式。
- Agent越多,权限膨胀越快,要定期做“最小权限审计”,看看哪些Agent实际持有的权限超过了日常工作所需。
- 线上环境记录策略变更日志,每次改动要能追溯到人和时间。
- 多Agent协作场景里,每个Agent尽量用独立身份,不要共用一个服务账号,否则出了问题很难界定责任。
5. PAP协议带来的连锁反应
5.1 多Agent协作的秩序问题
如果Agent生态继续野蛮生长,我觉得协议层迟早会成为比模型能力更关键的基础设施。PAP这类协议把“身份、权限、会话、审计”四件套做成标准后,多Agent协作才真正谈得上“有秩序”。
我之前设计多Agent系统的时候,最头疼的不是Agent不会干活,而是不敢让它们互相能调用。一旦允许A调用B,你就必须回答A能对B做什么、有效期多久、出事怎么追溯到源头这些麻烦问题。PAP相当于把“能调用”和“有权限调用”拆开,系统设计清晰很多。
5.2 我们项目里的实际变化
模拟项目X接入PAP后,最大的变化不是性能,而是安全审查效率。以前每周做权限复核要翻一堆日志,现在直接在策略台账上按Agent查已经授予的scope,一眼就能看出谁权限过大。另一个变化是跨团队协作容易了:两个团队各自维护自己的Agent,只要双方都暴露了标准的PAP接口,不需要互相给对方开数据库账号,也不需要共享密钥,各自签发的身份凭证就能建立信任关系。
5.3 后续值得关注的方向
我个人比较关注三个方向:一是PAP与现有云平台身份体系的融合,如果和单点登录打通,企业接入成本会大幅下降;二是跨组织Agent通信的可信市场,未来也许会出现“Agent按身份互相开放能力”的生态;三是协议对“人机协作回路”的支持深度,目前的人为确认机制还比较粗粒度,更细腻的人工介入方式值得期待。
最后分享一个我实际操作中的体会:协议刚出来的时候,很多人纠结“要不要等生态成熟了再上”。我的建议是,先在内部小范围试一个非核心链路,把身份签发、会话、策略这三条基本链路跑通一遍,比讨论十遍架构都管用。PAP这样偏“治理”的协议,越早引入,后面需要重构的地方就越少,等Agent规模大了再补这层,才是真正的伤筋动骨。