最近社区里讨论最多的话题,一个是MCP,另一个就是PAP。PAP全称Person Agent Protocol,个人代理协议,是某头部AI公司最近放出来的一个开源协议。第一眼看上去它和MCP很像,都是给AI智能体之间"说话"用的,但仔细看完整个设计,你会发现它的切入点完全不一样:MCP管的是AI和外部工具、数据源怎么连接,PAP管的是AI怎么安全地读取"用户这个人"的上下文。这篇文章我把PAP的定位、架构、实操和坑都过一遍,适合正在做智能体应用、AI助理产品或AI基础设施的开发者参考,也适合产品经理和技术决策者拿来做选型判断。
1. PAP协议要解决什么问题,和MCP有什么本质区别
1.1 智能体的"人设割裂"问题
先说一个让人头疼的实际场景。我在某个出行App里告诉AI助手"我不吃香菜,口味偏清淡,出差订酒店一定要有健身房",它记住了,推荐得挺准。但切到另一个办公助手,或者同一个公司里的另一个智能体,它完全不记得这些事,又从零开始问我一堆基础问题。这种感觉就像家里请了一个很聪明的管家,但每次换一个人进门,管家都会失忆一次。
所有做过智能体应用的人应该都有同感:单点智能体的能力提升已经很快了,模型越来越强,工具调用越来越顺,但用户的个性化体验一直卡在一个地方——用户数据被锁在一个个App的孤岛里。我在A应用里建立的偏好画像,B应用看不到;我在C设备上产生的记忆,D设备上无法同步。这就是我理解的"人设割裂",也是PAP协议出现之前最想解决但一直没人系统解决的问题。
PAP的思路很直接:把用户的画像、偏好、历史记忆从各个应用中抽出来,放到一个用户自己能控制的数据层里,然后所有AI智能体通过一套标准协议去读写。用户只需要授权一次,之后所有接入PAP的智能体都能拿到"同一个你",不再需要重复交代。
1.2 为什么现有协议解决不了
很多人第一反应是问:MCP不是已经在做智能体互联吗,为什么还要再来一个PAP?这里需要把两者分清楚。MCP,也就是Model Context Protocol,解决的是智能体"怎么调用外部工具和资源"的问题。一个MCP Server可以挂数据库、文件系统、外部API,智能体通过MCP客户端去调用这些能力。它让AI从"只会聊天"变成了"能动手干活"。
但MCP有一个盲区:它不关心"用户是谁"。举个例子,MCP给智能体提供了一个读取日历的工具,但智能体不知道该用哪个日历账号、该按什么时区显示、用户对会议时间的偏好是上午还是下午。这些信息不在MCP的模型里。MCP处理的是"世界上下文",PAP处理的是"人的上下文"。一个管工具,一个管人设,两者不是竞争关系,而是互补关系。
我把两者的边界整理成一张对照表:
| 对比维度 | MCP | PAP |
|---|---|---|
| 核心对象 | 工具、资源、外部服务 | 用户个人数据 |
| 解决问题 | 智能体如何调用外部能力 | 智能体如何理解用户 |
| 数据归属 | 服务端提供,与应用绑定 | 用户本人控制 |
| 典型场景 | 读数据库、调API、操作文件 | 读偏好、读记忆、跨App同步上下文 |
| 与用户关系 | 不关心具体用户 | 核心就是用户身份与授权 |
实际项目里,两者常常一起出现:PAP负责告诉智能体"用户是谁、他喜欢什么",MCP负责帮智能体"把用户想做的事真正执行掉"。
1.3 PAP协议带来的几个关键能力
把PAP放到具体工程里,它至少提供三个其他方式很难替代的能力。
第一,一次授权,多处可用。用户在某一个应用里完成授权后,其他被授权的应用可以通过同一套协议读取同一个人设信息。这对做应用矩阵的公司来说价值非常大,用户在一个产品里积累的偏好,可以无缝复用到另一个产品。
第二,任务交接。智能体A在处理用户需求的过程中,如果发现自己搞不定,需要把任务转给智能体B,这时候可以通过PAP把用户上下文一起带过去。B不需要用户重新描述一遍自己的情况,直接接着A的思路往下做。
第三,用户可撤销。用户随时可以在授权管理页里吊销某个Agent的访问权限。吊销之后,该Agent持有的令牌立即失效,数据读取能力被切断。这一点对于隐私合规和用户信任来说,比任何技术承诺都更实在。
1.4 哪些人应该现在就开始关注
如果你只是做一个单机版的聊天机器人,PAP暂时和你没关系。但如果你正在做以下事情,建议尽早研究:做跨App智能体的应用矩阵,做带长期记忆的AI助理,做个性化推荐系统的上下文层,或者做企业级AI Agent平台的技术选型。
对开发者的意义尤其直接:PAP定义了"用户上下文"的标准API,意味着未来我们不需要为每个应用单独设计一套用户画像存储和授权逻辑。它把过去散落在各个业务系统里的脏活累活,收敛成一个可以复用的基础设施。对产品经理来说,理解PAP也很有价值,因为以后设计个性化功能时,不用再画一堆"数据打通"的PRD,而是直接调用一套协议。
2. PAP协议的技术架构拆解:组件、数据模型与交互流程
2.1 核心组件到底有哪些
如果只看官方文档,PAP不是单个API,而是一组配套组件组成的协议体系。我实际梳理下来,核心是四个东西。
第一个是Person Agent Service,也就是协议的核心API服务,负责Agent的注册管理、Token签发、Person Data的读写、Command的任务调度。可以理解成整个协议的"控制中枢"。
第二个是Person Data Store,用户个人数据的存储层。它按用户ID做数据隔离,同一个用户的数据会集中存放在一起,并按数据分类管理。注意这里不是简单的KV存储,它对外暴露的是"Person Data Scheme"这样一个半结构化的数据模型。
第三个是Person Agent Gateway,网关层。它承担OAuth授权、令牌校验、请求限流和审计日志。所有对Person Data的访问请求都要经过Gateway,AI应用永远不会直连存储层,这样权限控制和审计就可以收敛到一个点上。
第四个是Person Agent CLI,一个本地调试工具。它可以列出当前有哪些Agent、某个用户授权了哪些Agent、最近的Person Data变更记录,也可以直接发起一次数据读写。对开发调试来说,这个CLI比反复写curl方便很多。
这几个组件的职责划分很清晰:Service管业务逻辑,Store管数据,Gateway管安全和接入,CLI管调试。对开发者来说,日常打交道最多的是Gateway暴露的HTTP API,以及CLI提供的调试能力。
2.2 核心数据模型:Profile、Preferences、Memory
PAP里的Person Data不是一坨大而全的用户JSON,而是被拆分成了三类:Profile、Preferences和Memory。这个分类设计我觉得非常聪明,它对应了用户数据的不同生命周期。
Profile是相对静态的基础资料,比如用户的显示名称、常用语言、所在时区。这类数据变化频率低,授权之后基本可以长期缓存。
Preferences是用户的偏好设置,比如提醒方式、行程风格、信息详细程度、界面语言等。它和Profile的区别在于会更细,而且会随用户当前状态变化。比如"旅行时偏好休闲行程"和"出差时偏好高效行程"都属于Preferences,但可能针对不同场景发生变化。
Memory是动态记忆,它从用户与AI的对话、以及用户的行为操作中抽取出来,带时间戳、来源标记和置信度。比如"用户A对猫毛过敏"、"用户最近在关注某城市的租房市场"。这类数据变化最快,也是智能体实现"越来越懂用户"的关键。
在实际调用的返回体里,这三类数据是放在同一个Person对象下的:
{ "person": { "profile": { "display_name": "用户A", "locale": "zh-CN", "timezone": "Asia/Shanghai" }, "preferences": { "language": "中文", "travel_style": "休闲", "notification": "daily_digest" }, "memory": [ { "id": "mem_001", "content": "用户A对猫毛过敏", "category": "health_constraint", "timestamp": "2025-05-12T08:30:00Z", "source": "chat" } ] } }一个重要设计是:PAP里存的不是原始聊天记录,而是从聊天和行为中抽取出来的"结构化人设信息"。这样做有两个考虑:一是隐私最小化,AI应用不需要看用户的原始对话,只需要知道"用户不能吃花生"这个结论;二是性能,结构化的Fields比大段文本更容易做权限控制和增量同步。
2.3 交互流程:从授权到数据读写
我把一次完整的交互流程拆成六步,你可以对照着自己跑一遍。
第一步,开发者在Person Agent Service上注册Agent,声明自己需要哪些权限范围,配置回调地址。第二步,用户在App里发起绑定,重定向到授权页,选择允许该Agent访问哪些Person Data。第三步,用户同意后,Agent拿到授权码,在后台通过Gateway兑换access_token和refresh_token。第四步,Agent携带access_token调用Person Data API,读取或更新用户数据。第五步,当数据发生变化时,Gateway通过事件流主动推送变更通知给已经订阅的Agent。第六步,如果Agent需要触发具体业务动作,比如预订酒店或发送提醒,就通过Command机制发起。
这里我想强调第五步事件流的重要性。PAP不是纯请求响应模型,它引入了事件订阅机制。这带来的一个直接好处是:多个Agent可以同时感知到用户偏好的变化,而不需要各自轮询。比如用户在当前App里更新了"以后出差不要红眼航班",另一个App里正在给用户规划行程的Agent会立刻收到变更事件,重新生成方案。
2.4 为什么选择JSON事件流而不是gRPC
很多后端同学看到协议设计时都会问:为什么PAP不用gRPC或更高效的二进制序列化,而是选择JSON加事件流?这个问题背后其实是工程权衡。
PAP处理的场景有一个特点:单次传输的数据量不大,但请求频率不低,实时性要求高。Profile和Preferences这类数据通常只有几百字节,用JSON完全够用,而且JSON自描述、跨语言、调试方便。在浏览器端、服务端、移动端都能无脑接入,这对协议推广很重要。
事件流部分走的是SSE或WebSocket。SSE实现简单,基于普通HTTP,不需要额外的连接协议,对防火墙友好;WebSocket则适合需要双向通信的场景。相比之下,gRPC虽然有性能和强类型约束的优势,但接入门槛高,需要生成客户端代码,对很多轻量应用来说完全是过度设计。
技术选型没有绝对的对错,只有是不是适合场景。PAP选择JSON事件流,本质上是把"易于接入"放在"极致性能"前面,这是个人数据交换场景下很务实的决定。
3. 实操:5分钟跑通一个PAP智能体应用
3.1 注册Agent并拿到开发者凭证
空谈架构没有意义,我直接带你走一遍实际接入流程。第一步是在开发者控制台里注册你的Agent。
打开控制台,创建一个新Agent,申请权限范围。我以"旅行助手"为例:
curl -X POST "https://person-agent.example.com/api/person-agent/agents" \ -H "Authorization: Bearer <developer_token>" \ -H "Content-Type: application/json" \ -d '{ "name": "travel-assistant", "description": "旅行行程与偏好助手", "capabilities": [ "profile.read", "preferences.read", "preferences.write", "memory.read" ], "callback_url": "https://example.com/callback" }'响应会返回agent_id和app_secret。注意app_secret只在创建时完整展示一次,之后只能重置。我在测试环境里因为没保存好,不得不重新生成过一次,多花了不少时间。
capabilities字段要和实际业务严格对应。比如我的旅行助手需要读取用户偏好来推荐行程,所以申请了preferences.read;用户如果能在App里直接设置偏好,还需要preferences.write。千万不要图省事把所有权限都申请了,既难通过审核,也会让用户在授权页感到不安,转化率会很难看。
3.2 走一遍用户授权和Token获取
Agent注册好之后,还不能直接访问用户数据,必须让用户走一次授权流程。把用户引导到授权页,URL长这样:
https://person-agent.example.com/oauth/authorize?client_id=agent_xxx&redirect_uri=https://example.com/callback&scope=profile.read+preferences.read+memory.read&state=xyz123用户在那个页面确认授权后,浏览器会带着一个临时code回调到你配置的地址。拿到code之后,在服务端换Token:
curl -X POST "https://person-agent.example.com/api/person-agent/tokens" \ -H "Content-Type: application/json" \ -d '{ "client_id": "agent_xxx", "client_secret": "app_secret_xxx", "code": "auth_code_xxx", "redirect_uri": "https://example.com/callback" }'响应:
{ "access_token": "pat_live_xxx", "expires_in": 3600, "refresh_token": "pat_refresh_xxx" }这里有两个点需要特别留意。第一,access_token的有效期通常只有一小时,过期后要用refresh_token去刷新。我一开始以为access_token有效期会很长,结果在联调时频繁遇到401,排查了半天才发现是Token过期而不是权限配置问题。第二,refresh_token一定要放在服务端保存,绝对不要下发到前端,否则用户数据等于裸奔。
3.3 读写用户Person Data
拿到Token之后,读写用户数据就非常直接了。读取:
curl "https://person-agent.example.com/api/person-agent/users/me/person-data" \ -H "Authorization: Bearer pat_live_xxx"如果你需要写入数据,比如用户在旅行助手场景里设置了新偏好,用PUT:
curl -X PUT "https://person-agent.example.com/api/person-agent/users/me/person-data" \ -H "Authorization: Bearer pat_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "person": { "preferences": { "travel_style": "商务", "seat_preference": "靠窗" } } }'这里需要注意一个行为差异:PAP的PUT是做深度合并,而不是整体覆盖。也就是说,你只传了preferences里的字段,其他preferences项以及profile、memory都不会被清空。这个设计对增量更新非常友好,但也容易让人产生"我以为已经覆盖了"的错觉。最稳妥的做法是:写入之前先GET一次,确认当前数据状态,再构造完整期望的数据发PUT。
3.4 用Command触发智能体动作
有些场景不只需要读写数据,还需要让Agent触发一个具体动作。比如用户说"帮我查一下去某城市的机票",旅行助手需要把这个需求转成一次业务查询或预订。PAP里通过Command机制来实现。
发送命令:
curl -X POST "https://person-agent.example.com/api/person-agent/users/me/commands" \ -H "Authorization: Bearer pat_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "command": "search_flights", "arguments": { "destination": "某城市", "date": "2025-07-01" } }'返回一个job_id,然后轮询任务状态:
curl "https://person-agent.example.com/api/person-agent/jobs/<job_id>" \ -H "Authorization: Bearer pat_live_xxx"用轮询而不是长连接来拿任务结果,主要是为了降低客户端实现复杂度。这种设计在异步任务场景里比较常见,适合大多数业务系统。
3.5 订阅Person Data的变更事件
被动读取之外,还有一个很实用的能力:订阅用户的Person Data变更事件。当用户在其他App里更新了偏好或产生了新记忆,你的Agent可以通过SSE实时收到推送。这样就不需要自己定时轮询数据是否有变化。
curl -N "https://person-agent.example.com/api/person-agent/users/me/events" \ -H "Authorization: Bearer pat_live_xxx"收到的事件格式大概是:
{ "event": "person_data_changed", "user_id": "user_xxx", "changed_paths": ["preferences.travel_style"], "timestamp": "2025-06-10T12:00:00Z" }接入事件流之后,我的建议是不要傻乎乎地全量刷新本地缓存。事件里带了changed_paths,你只需要更新对应字段就行,这样既能减少请求量,也能避免并发情况下覆盖掉刚写入的数据。
4. 权限模型、隐私设计与安全注意事项
4.1 权限范围与最小授权原则
PAP的权限模型借鉴了传统的OAuth2.0,但在scope设计上做了更细的拆分。权限不是粗粒度的"可读""可写",而是按数据类别和操作拆分。我建议的常用权限组合如下:
| 使用场景 | 建议scope组合 |
|---|---|
| 只做个性化推荐 | profile.read, preferences.read, memory.read |
| 允许用户在应用里更新偏好 | 再加上 preferences.write |
| 需要给用户写长期记忆 | 再加上 memory.write |
| 需要触发业务动作 | 额外申请对应Command能力 |
实际接入时我总结出的经验是:scope越细,越容易通过审核,用户的授权意愿也越高。如果你告诉用户"这个AI助手只能读取你的偏好设置",大多数人是愿意授权的;如果你告诉用户"这个助手可以读写你的全部个人数据和记忆",大部分人会犹豫甚至拒绝。
4.2 数据脱敏与存储边界
PAP可以用来存放用户偏好和记忆,但它不适合也不应该成为强敏感数据的存放点。身份证号、银行卡号、医疗记录、支付信息这类数据,建议不要写入Person Data Store。
这不是技术限制,而是安全和合规层面的边界。PAP的数据会被多个Agent共享,授权链条变长了,敏感数据暴露面也会变大。如果业务确实需要处理这类信息,更稳妥的做法是在Agent自己的服务端加密存储,并通过Command机制做一次性传递,而不是落进公共的Person Data里。
另外,即使是一般数据,也建议遵循"只存结论,不存原文"的原则。比如"用户A对猫毛过敏"这个结论可以存,而"用户A在聊天里说了什么"这段原文不应该存。这样即使被事件流推送到多个Agent,泄露的影响面也可控。
4.3 我在安全配置上踩过的坑
接入PAP的过程中,我在安全配置上踩过几个印象很深的坑,写出来帮你避雷。
第一个坑是回调URL没有做精确匹配。一开始我配置的回调地址是前缀匹配,想着方便测试,结果发现从任意域名回跳都能通过校验,这是一个很明显的开放重定向风险。修改成精确匹配之后才安心。
第二个坑是refresh_token没有做轮换。默认情况下,如果客户端没有主动发起刷新,旧refresh_token会一直有效。我在内部测试环境里甚至看到有一个多月没变过的refresh_token。后来做了一个策略:每次刷新Token时同时轮换refresh_token,旧值立即失效。
第三个坑是日志打印了完整Token。排查问题的时候为了方便,顺手把Authorization头打进了日志,结果日志系统被安全审计扫出大量敏感信息。正确的做法是只打印Token的后四位,或者完全脱敏。
第四个坑是scope申请过宽。最初图方便,所有的Agent都申请了profile.read、preferences.read、memory.read、preferences.write、memory.write。结果用户授权页上显示一大串权限,转化率肉眼可见地下降。后来按业务场景裁剪scope,情况立刻好转。
4.4 用户撤销授权的处理流程
用户撤销授权是PAP里必须妥善处理的场景。当用户在授权管理页里点击"解除绑定",该Agent立即失去访问能力。表现是:后续API调用返回401,已建立的事件流连接被断开,refresh_token也失效。
应用侧要做的事情有两件。第一,监听授权失效状态,一旦发现401且刷新失败,立刻清理本地缓存的用户Person Data,不要继续保留一套"过期"的用户画像。第二,给用户一个明确的提示,说明需要重新授权才能继续使用个性化功能。很多应用在这一步处理得很草率,用户明明已经撤销了授权,App还在假装能提供服务,最后用户数据展示异常,体验非常糟糕。
5. 常见问题与排查技巧实录
5.1 问题速查表
我在调试PAP接入时,把遇到的问题整理成了一张速查表,分享出来供收藏:
| 错误现象 | 可能原因 | 解决方法 |
|---|---|---|
| 401 Unauthorized | access_token过期或已被吊销 | 用refresh_token刷新,失败则重新走授权 |
| 403 Forbidden | 当前Agent的scope不足 | 检查创建Agent时的capabilities,重新发起授权 |
| 404 Not Found | agent_id错误或API路径拼错 | 核对路径,用CLI列出当前Agent信息 |
| 授权页打开直接报错 | redirect_uri不一致 | 确保注册回调与授权请求中的回调完全一致 |
| 数据读取为空 | 用户还没有任何Person Data | 先用PUT写一条数据,再GET验证 |
| 事件流收不到推送 | 没有正确建立SSE连接 | 检查网络代理、Token是否有效、事件路径是否正确 |
| 写入后数据被覆盖 | 并发更新且没有做合并 | 先GET再PUT,依赖深度合并而不是整体覆盖 |
| 刷新Token报错 | refresh_token被轮换,旧值失效 | 保存最新refresh_token,只在服务端使用 |
5.2 我在实际调试中踩过的坑
除了安全配置那些坑,联调阶段也有一些很琐碎但很耗时间的问题。
我曾在本地起了一个HTTP回调服务,结果授权服务器一直拒绝回调。折腾了很久才发现,授权服务器要求回调地址必须走HTTPS,本地HTTP地址直接被拦了。后来用内网穿透工具把本地端口映射成一个临时HTTPS地址,才顺利把流程跑通。如果你只是做二次开发,可以直接在控制台把回调地址配置成一个临时公网URL,把code打印出来人工复制到命令行去换Token,也能绕过这个限制。
还有一个很常见的低级错误:用curl调试PUT请求时,忘记加Content-Type: application/json,服务器返回415,我愣是看了半天没反应过来。这种问题发生的频率比想象中高,建议你在调试脚本里固定带上这个Header,或者直接用HTTPie这类自带JSON类型的工具。
CLI工具也有一点需要注意:多环境切换时,一定要指定profile参数。我有一次在本地调试一个功能,折腾了半天数据总是不对,最后发现CLI默认连的是沙箱环境,而我一直在操作生产环境的Agent,两边数据完全不是一回事。
5.3 几个能提升效率的小技巧
有些技巧不是文档上会写的,但实际能帮你省很多时间。
第一,用HTTPie替代curl做日常调试。语法更简洁,JSON响应会自动高亮,读起来舒服很多。比如上面的PUT请求,用HTTPie写是这样:
http PUT "https://person-agent.example.com/api/person-agent/users/me/person-data" \ "Authorization: Bearer pat_live_xxx" \ person:='{"preferences":{"travel_style":"商务"}}'第二,写一个统一的Token管理模块。把获取、刷新、缓存Token的逻辑封装成一个小库,所有Agent应用共用。千万别在每一个业务函数里单独调Token接口,否则后续做Token轮换时会改到怀疑人生。
第三,在控制台开启审计日志。每次授权、Token签发、数据读写、Command执行都会有记录。排查"某个Agent为什么读不到数据"这类问题时,审计日志比逐一打印调试信息快得多,直接能看到这次请求带了哪些scope、命中了哪个数据路径。
第四,接入事件流时,先用CLI或SSE客户端在本地订阅一遍,确认事件格式和推送频率符合预期,再写业务代码。贸然把事件流接进业务后,一旦事件格式理解偏差,调试成本会成倍增加。
第五,特别注意state参数的校验。授权流程里带state参数是为了防止跨站请求伪造,回调时一定要校验state和发起授权时保存的是否一致。这个小细节很容易漏,但漏掉之后安全隐患非常大。
5.4 关于PAP后续扩展的个人观察
PAP这协议后续的走向,我个人比较关注的是跨Agent任务交接。当前版本里数据和命令都已经标准化了,但真正让两个不同开发者开发的Agent互相移交任务,还需要语义标准的进一步收敛。比如Agent A说"我把用户的需求转给你",这句话本身要有一个标准化的表达结构,而不是仅仅传递一段JSON数据。
另外,用户数据的可迁移性也是一个我觉得会越来越重要的方向。如果用户从一家服务商的生态迁到另一个生态,他的Person Data应该能跟着走。协议本身具备这个能力,但落地到产品层面,还需要更多平台愿意开放和接受外部数据导入。
还有一点是权限模型的演进。现在scope已经比传统OAuth细很多了,但我猜测未来会出现基于数据字段级别的授权,比如"用户可以单独允许某个Agent读取memory里的某一条,而不是全部记忆"。这样用户对数据的控制力会更精细,也会让AI个性化服务的用户信任度上一个台阶。
我个人在实际调试PAP时最大的体会是,它的价值不在于提供一个新API,而在于把"用户上下文"从应用里抽出来,变成一种可编程的资源。第一次接入的人容易把它当成普通的用户配置中心,但真正用它做跨App智能体交接之后,才会意识到这套协议的目标是让AI的学习成果跟着人走。如果你正准备做长期记忆或个性化智能体,建议尽早接入,趁数据模型还没被业务逻辑污染的时候就把边界划清楚。