前一阵业界放出了不少关于"个人代理"的消息,很多朋友第一反应是"又一个大模型功能"。功能层的东西其实不难做,真正难的是让代理与代理之间、代理与真实人类之间,有一套可以共同遵守的交流规则。PAP(Person Agent Protocol)这个名字出现在这个节点上,我认为它讲的不是某一个模型,而是"当AI代理代表真实的人去做事时,整个交互链路该怎么设计"。
先说清楚,我在这里聊的"代理"都是AI智能体(Agent),是替用户去执行任务、调用工具、跟别的系统协作的软件实体,跟网络代理没有任何关系。PAP这套思路的核心,是把"代理替人办事"这件事从临时拼装的API调用,变成一种有身份、有授权、有状态、有审计的标准通信方式。
我看过不少讨论,大部分停留在"它是个协议"这一层,有点可惜。PAP真正值得拆开看的是它背后的设计取舍:身份怎么锚定、权限怎么委托、会话怎么续接、能力怎么被发现、出了问题怎么追溯。这篇文章就按这几个维度展开,把我认为这类协议必须具备的核心逻辑、落地时需要补的组件,以及真实工程里容易踩的坑都过一遍。正在做AI Agent、智能体编排,或者想给自己的产品加一套"代理间互操作"能力的人,应该能从里面找到一些可以直接用的思路。
另外提前说明:下面所有分析是基于公开技术趋势和协议设计的通用逻辑做的拆解推演,不是照着某份官方文档复刻。协议具体叫什么、字段名怎么写,不同版本可能有差异,但需要解决的问题和设计上的权衡是相通的。
1. 从"代理各说各话"到PAP:协议要解决的第一个问题
1.1 现在的Agent生态,问题不在模型,在"对话规则"
我最近和几个做智能体的朋友聊天,大家都有同一个感受:单看一个Agent,能力已经很能打了,能写代码、能查资料、能调工具;但一旦让两个Agent协作,立刻会进入"鸡同鸭讲"的状态。A系统用一套JSON格式描述任务,B系统用另一套XML结构表达结果;A说"帮我订个会议室",B理解成"查找会议室列表",两边全靠开发者写胶水代码来回翻译。
这不是模型能力不够,而是缺少公共语义层。每个Agent内部可以有自己私有的prompt规范、工具调用格式、任务描述语言,但一旦要跨出系统边界,就必须有一个大家都认的"信封"和"信纸"格式。PAP想做的就是这个公共语义层:它不管Agent内部怎么想,只管Agent对外怎么说话。
这个场景其实很像互联网早期。HTTP能成功,不是因为它把"超文本传输"这个概念讲得多完美,而是因为它定义了一个足够简单的请求-响应模型,让任何人都能基于它搭服务。PAP要做的,就是把"代理替人做事"这个高频动作标准化:我是谁的代表、我要做什么、我有什么权限、进展到哪一步了、结果是什么。
1.2 三个核心痛点:身份缺失、上下文断裂、责任不明
看现在主流的Agent协作方式,最常见的还是"一个Agent把prompt塞给另一个Agent"。这里面藏着三个问题:
第一个是身份缺失。当服务端收到一个来自Agent的请求,它看到的只是一段文本或一次API调用,无法确认"这个Agent代表的是谁"。是张三让他来的,还是李四?如果是一个被注入恶意指令的Agent发出的请求,它代表的是用户本人还是攻击者?没有身份锚定,后续的权限控制、数据隔离、责任追溯都无从谈起。
第二个是上下文断裂。一次真实的用户任务,比如"帮我安排下周去某地的出差",往往会拆成订机票、订酒店、约会议室、准备材料好几个子任务,由不同的Agent分头执行。如果每个子任务都从零开始,不知道"这是同一个人的同一个行程",就会出现航班时间和酒店入住日期对不上、会议室预订和行程冲突这类低级错误。
第三个是责任不明。任务成功时大家抢功劳,任务失败时没人认账。机票订错了,是主Agent理解错了,还是订票Agent执行错了,还是用户自己给的信息有歧义?没有统一的任务ID和动作日志,出了问题只能翻聊天记录,效率极低。
1.3 PAP想做的事情:把"代理替人办事"变成一个标准动作
如果把上面三个痛点翻译成设计目标,PAP大概要承担四件事:
- 身份:让每个请求都清楚"谁在代表谁"。
- 授权:让接收方知道"这个代表能做哪些事,做到什么时候为止"。
- 状态:让一次跨代理的协作有统一的进度视图,可暂停、可恢复、可取消。
- 审计:让每一个关键动作都能回溯到具体的发起人和授权记录。
听起来不复杂,但真要做成可落地的协议,每一件都需要掰开揉碎地设计。身份不是简单加个用户ID,授权不是发个API Key,状态不是靠数据库硬扛,审计不是记几行日志就完事。接下来的几个章节,我就按这条主线逐个拆。
2. PAP的基石:身份锚定与授权委托链
2.1 为什么不能给代理一张"长期通行证"
很多人做Agent工具调用时,习惯性的做法是把用户的API Key存起来,Agent需要调服务时直接带上这个Key。这种做法在Demo阶段没问题,但放到真实生产环境,马上会遇到几个坎:
第一个坎是永久有效。API Key一旦发出去,就等于给了一张长期通行证。用户的权限变了,Key不会自动跟着变;用户离职或取消授权了,Key可能还在服务商的数据库里躺着。
第二个坎是无法表达"替谁办"。一个家庭场景里,用户可能授权"我的助手可以帮我查账单,但只有家长角色能确认支付"。API Key没法区分"这个请求是替家庭里的谁发起的",它只能告诉你"有权限"或"没有权限"。
第三个坎是无法精细控制动作范围。API Key的粒度通常到服务级别,能查,就能删;能读,就能写。但真实委托往往是"只允许查本周的账单,不允许删任何记录"这种细粒度需求。
PAP这类协议解决这个问题的思路,是把"授权"从一张静态凭证,变成一个动态的、有时限的、可撤销的委托链。
2.2 委托链:人—主代理—服务代理
我理解的PAP授权模型,核心是一条委托链。
最顶端是真实的人。人是信任的源头,一切授权最终都能追溯到某个具体的个人。人不直接跟每个服务打交道,而是把一部分权限委托给自己的主代理(Personal Agent)。主代理拿到委托后,为了完成一个具体任务,又把其中更小范围的权限委托给下游的服务代理(比如订票代理、支付代理、日历代理)。
这样一层层传下去,就形成了一个树状的授权结构。它的好处是:每一层都只拥有完成自己任务所需的最小权限,而且每一层的授权都能单独撤销。
举个例子:用户让主代理安排出差。主代理先向日历代理发起"查下周二是否有空"的请求,这时候需要的权限很小,只要"读取日历";确认有空之后,再向订票代理发起"预订某航班"的请求,这时候需要的权限是"预订机票,金额不超过5000元,且限本人乘坐"。两个请求的授权范围完全不一样,都由主代理根据任务需要动态生成。
这里的关键设计是:代理不能自己给自己授权。主代理的权力来自用户的委托,服务代理的权力来自主代理的委托。任何一环的授权都要能逐级回溯到用户本人,这才叫锚定。
2.3 关键字段的设计意图与实操建议
如果让我设计一份委托授权的最小数据结构,大概会包含这几个核心概念:
| 概念 | 含义 | 设计理由 |
|---|---|---|
| actor | 发起动作的实体 | 明确"谁在操作",可以是人,也可以是代表人的Agent |
| subject | 被代表的人 | 一切权力的源头,最终责任归属者 |
| action | 允许的操作 | 如read、write、book、pay,粒度要明确到动作级 |
| resource | 操作对象 | 如"日历中的某个时间段"或"支付账户中的某个额度" |
| constraint | 约束条件 | 金额上限、时间窗口、次数限制、终端限制 |
| delegation_id | 委托关系编号 | 用于撤销、续期、审计定位 |
| expires_at | 委托失效时间 | 强制最短有效周期,避免长期凭证泛滥 |
这套字段看上去像OAuth的加强版,但区别在于它把委托链显式地建模出来了:每个delegation_id都有一串父级关系,撤掉父节点,子节点的授权也就跟着失效。
实操上有几个建议:
第一,所有委托默认给最短时效。比如订票任务完成后,对订票代理的委托立刻失效,而不是让它一直保持"可以帮你订票"的状态。第二,每个委托独立ID,不要复用用户主令牌。第三,服务的访问日志必须记录delegation_id,而不是记录"哪个用户调用了接口",否则就没法做链式追溯。
有人会问:这会不会太重了?每次调用都要生成一个新委托,性能开销不小。实际权衡下来,对高频低风险的读操作可以做缓存,对高频低风险的读操作可以做缓存,对支付、修改、删除这类高风险操作就不要贪这个性能。安全性和性能的取舍本来就应该按动作风险分级,而不是一刀切。
3. 会话与人工介入:代理通信不只是"接口调用"
3.1 一次代理协作中的完整状态流转
如果只做"请求-响应"这种一次性交互,PAP没有存在的必要,HTTP就够了。真实的代理协作是长周期的:一个任务可能需要几分钟、几小时,甚至几天才能完成,中间涉及多轮确认、多次工具调用、多个人工介入点。
我拿一次完整的差旅安排举例,体会一下状态流转:
- 用户对主代理说:"安排下周三到周四去某地出差。"
- 主代理发起一个任务,生成task_id,状态为"待确认"。
- 主代理向日历代理查询用户的时间安排,状态变为"查询中"。
- 日历代理返回"周三上午有空",状态变为"已确认日程"。
- 主代理向订票代理发起机票预订请求,状态变为"等待预订确认"。
- 订票代理返回"某航班有票,价格为2800元",主代理发现这超过了用户预设的"单笔不超过2500元"约束,状态变为"需要人工批准"。
- 主代理向用户推送一条确认消息,用户点击批准后,状态变为"预订中"。
- 订票代理完成出票,状态变为"已完成";同步更新日历,向用户发送最终行程。
在这个过程中,如果PAP只支持"请求-响应"语义,主代理在第6步就必须一直同步阻塞等用户回答,或者干脆自作主张把票订了。这两种体验都很糟糕。所以协议必须支持异步会话、状态持久化、人工介入和恢复。
3.2 异步、回调与轮询的取舍
异步是代理协作的默认方式,因为代理任务的不确定性和耗时远超普通API请求。但异步通信具体怎么实现,有好几条路:
回调查询最简单,调用方发起任务后,等着服务方通过回调地址通知结果。缺点是要维护一个可公网访问的回调端点,对内部系统来说部署成本较高。
轮询就是调用方每隔一段时间主动问一次"好了没",实现简单,但会有延迟,也会浪费请求。
WebSocket/长连接适合单机部署的两个代理实时通信,但跨机构、跨网络时就不好穿透。
事件总线适合大规模部署,问:事件总线是不是也要引入消息中间件,会不会太重?PAP在设计上可以不强绑具体传输方式,而是定义一个标准的事件对象:task_id、status、actor、timestamp、payload。至于这个事件怎么从A传到B,走Kafka也好,走Webhook也好,走HTTP轮询也好,协议不关心,每套系统自己实现就行。这里的不强绑其实很重要,协议刚推出来时,传输层越简单,接入门槛越低。
我自己的习惯是:初始版本优先支持"轮询+Webhook回调"两种模式,跑通了再加事件总线,不要在第一天就把架构搞复杂。
3.3 人工介入:权限不足不等于任务失败
现在的Agent编排框架普遍缺一个状态:"我做不了主,需要问人"。
在PAP的语义里,人工介入不应该被设计成异常分支,而应该是正常流程的一个环节。代理碰到权限超限、信息冲突、成本超预算、目标模糊这四类情况时,都应该主动发起"需要人确认"的信号,而不是自作主张或直接失败。
人工介入的设计难点有两个:
第一个是如何准确地描述问题。如果只是丢给用户一句"出错了",用户根本没法决策。协议里的人工介入请求应该结构化:当前目标是什么、已经进行到哪一步、遇到了什么冲突、有哪些可选方案、每个方案的后果是什么。我推荐用一个类似"decision_request"的消息体,包含context、options、deadline,让用户一屏看完就能选。
第二个是如何安全地暂停和恢复。用户说"等我出差回来再说",任务就进入挂起状态;用户说"按方案A做",任务从挂起状态恢复。这要求代理在挂起期间持有会话上下文,不能被GC清掉,也不能在恢复时重新从头算。实际工程里这个状态往往要落库,不能只放在内存里,这也意味着协议层的事务设计要考虑幂等和恢复的语义。
注意:人工介入的入口一定要具备"用户身份再验证"能力。很多系统图省事,把确认接口做得跟普通接口一样,结果别的Agent拿到回调链接就能替用户点头,这就等于把授权链最顶端的人变成了一个可以被滥用的"确认按钮"。
4. 能力注册与发现:让代理知道"谁擅长做什么"
4.1 从硬编码API到能力发现
PAP解决"代理之间怎么说话",但要真正协作起来,还有一个前置问题:一个代理怎么知道另一个代理能做什么。
现在的常见做法是硬编码,把"订机票找A系统,查日历找B系统"写死在配置里。这在系统少、角色固定的时候没问题,但一旦代理多了、角色动态变化了,硬编码就变成灾难。比如有两个日历系统,一个主打个人日程,一个主打团队会议室调度,按理说应该根据具体任务特点选择调用者,硬编码就没法做这种运行时决策。
所以PAP这类协议要和微服务里的服务注册中心结合起来。我理解PAP在能力发现这一层的设计,是每个代理启动时向注册中心上报自己的能力描述;调用方发起请求时,先通过能力发现找到合适的服务方,再通过委托授权发起调用。
这跟DNS有点像。DNS把域名解析成IP,能力发现则是把"我的目标"解析成"哪个代理擅长做这件事"。
4.2 能力描述需要哪些元数据
能力描述不能只写一行自然语言"我可以帮忙订机票",必须机器可读、可比较、可筛选。我给一套能力描述建议,虽然各家协议的名字可能不同,字段设计是相通的:
- 能力ID:全局唯一的标识,比如"flight-booking-v3"。
- 能力类型:一类是"事务型",一次调用出结果;一类是"流程型",需要多轮交互才能完成。
- 输入Schema:描述需要哪些参数、参数类型、必填性,如果涉及日期时间,最好明确时区。
- 输出Schema:结果数据结构、状态码定义,方便调用方解析。
- 适用条件:比如"仅限中国大陆航线"或"支持国际机票但需额外证件信息"。
- QoS信息:平均响应时长、成功率、价格区间(如果涉及计费)。
- 信任评级:认证等级、审计等级、是否有SLA承诺。
用JSON示意大概是这样:
{ "capability_id": "flight-booking-v3", "capability_type": "process", "input_schema": { "origin": { "type": "string", "required": true }, "destination": { "type": "string", "required": true }, "date": { "type": "string", "format": "date", "required": true }, "max_price": { "type": "number", "required": false } }, "output_schema": { "flight_no": { "type": "string" }, "price": { "type": "number" }, "status": { "type": "string", "enum": ["confirmed", "pending", "rejected"] } }, "constraints": { "region": "china_mainland", "id_required": false }, "qos": { "avg_latency_ms": 1200, "success_rate": 0.998, "price_range": [500, 8000] } }这个Schema看起来很基本功?但很多人做多Agent协作时恰恰把这一步省了,直接让两个Agent对着prompt互猜,结果就是千奇百怪的解析错误。能力发现的本质是为了减少"猜"。
4.3 服务代理的选择与信任评级
有了能力描述之后,调用方怎么选服务方?我见过不少方案,最靠谱的是"规则过滤+信任权重"。
规则过滤是先排除掉不满足硬性条件的,比如不支持指定区域的、成功率低于阈值的、QoS不达标的。信任权重解决的是"多个候选都能做,优先用谁"。这个可以做成加权打分:QoS得分、历史完成率、调用方与提供方的历史合作次数、安全评级。信任权重不能一步到位,早期可以用 Qos数据硬编码,随着日志累积逐步改为动态评分。
这里特别提醒一点:能力发现的协议层和实际的调用层要解耦。也就是"找到"是一个动作,"调用"是另一个动作,中间隔着一个授权步骤。找到不代表可以随便调用,必须创建独立的委托授权之后才能发起实际请求。这个机制能防止代理拿着服务目录当通讯录乱拨电话。
5. 隐私边界与审计追溯:协议可用的前提
5.1 数据最小化与大字段脱敏
代理替人做事,意味着它要替人看数据、传数据。隐私问题在协议设计里不是"尽量遵守法规"那么轻描淡写,而是直接决定协议能不能被信任。
我在实际设计里反复强调一个原则:能力边界不等于数据边界。一个代理可以有能力"查询订单",但不代表在每一次协作里都有必要看到完整的订单信息。比如订票代理需要知道乘客姓名,但它用不着知道用户的历史订单、积分余额和银行卡号。
PAP在这块的设计思路,应该是在每次授权请求里显式声明"本次交互需要哪些数据字段",服务方被要求尽量返回最小集,并通过协议层面的脱敏标识来区分"完整字段"和"脱敏字段"。
打个比方:你要住酒店,前台只需要知道你的名字和身份证号,不需要知道你昨晚和谁吃饭、今天账户里有多少钱。Agent协作也应该这样,每次传递的数据都按任务需求裁剪。
5.2 跨域协作时,数据边界怎么表达
更复杂的是跨域场景:两个不同机构的代理协作时,数据会从一个域流向另一个域。比如用户的个人主代理在私有化服务器上,调用的酒店预订代理在另一个公司运营的公有云上。这个过程里,哪些数据可以流出、流出后怎么被处理、是否允许被第三方代理再传递,协议必须能表达清楚。
我理解的做法是给数据块附加"传播策略"标签,类似"notice"(使用前告知)、"consent"(使用前需获得同意)。每次代理收到一个带标签的数据,都必须按标签声明的方式使用和转发,否则就拒绝处理。这套机制在浏览器里叫CSP策略,在PAP里应该升级成"数据使用策略"。
这里涉及一个容易被忽视的开销:跨域数据合规校验。两个代理协作时,如果都严格执行对方的数据策略,解析和校验的成本会上升,延迟也会增加。所以设计上要有"可信域"的概念:同一个可信域内的数据流转,可以走简化校验;跨可信域才走全量策略检查。这样能在安全性和性能之间取得平衡,不至于因为过度合规检查导致代理响应慢得没法用。
5.3 审计日志怎么设计才真正可追溯
协议的最后一个底层能力是审计。我见过太多团队做Agent时,日志系统还停留在"打印几行debug信息"的水平,问题排查全靠猜。PAP如果要支持真实的商业场景,审计日志必须具备字段一致性全链路追踪能力。
一个完整的审计记录至少应该包含:
- request_id:一次任务或请求的唯一标识,贯穿整条链路。
- auth_id:授权记录id,关联到具体的委托链。
- actor_id:发起动作的代理或用户。
- subject_id:被代表的人。
- action:具体操作,如create/read/update/delete/book/pay。
- resource:操作对象,最好是结构化的(如calendar:2025-06-10:0900-1000)。
- timestamp:UTC时间戳。
- client_ip和user_agent:网络层的来源信息,留下至少能追溯到调用方的线索。
- decision_request_id:如果该操作需要人工确认,关联到对应的确认请求,让人工批准的记录也能对得上。
日志格式建议直接用JSON写,方便喂给日志分析系统。举例:
{ "log_id": "log_8f8e6c2a7b1d4e90a5f6c3d2b1a0f9e8", "request_id": "req_20250610_001", "auth_id": "auth_88f3a1b2-77d1-4e6b-8a1c-1f2b3d4e5f6a", "actor_id": "agent_flight_booking_v3", "subject_id": "user_12345", "action": "book", "resource": "flight:CA1234", "timestamp": "2025-06-10T08:30:00Z", "decision_request_id": "dr_6601" }有了这套日志,追溯一个"机票订错"的问题就变得很直接:拿到request_id,沿时间线把所有相关日志拉出来,看看是哪个环节传错了参数,是哪个授权ID允许了超范围的操作,人工确认请求是哪条Decision记录。没有这条链路,出了事就只能是多方扯皮。
6. 落地时最容易翻车的几个细节
6.1 超时与重试不能照搬HTTP
PAP是异步的,但真实的底层传输往往还是依赖HTTP。问题就来了:很多人习惯性用HTTP的超时和重试策略来约束代理调用,会出大问题。
代理动作分为"级联的确定性调用"和"异步的业务型任务"两个类型。前者比如查询日历,几百毫秒就有结果,用等特超时没问题,超时重试也相对安全。后者比如发起支付、预订航班,这类动作不能盲目设一个5秒或10秒的超时,更不能在超时后自动重发,否则就可能出现"同一张机票被订了两次"的事故。
我的经验是设计两层超时:
- 传输层超时:短一些,比如10-30秒,只负责"确保请求送到并得到初步受理",只要收到"已受理(task_id已创建)"的响应,就不再关心连接是否保持。
- 任务层超时:长一些,按业务类型单独设置,订票任务可以设10分钟,涉及人工审批的可以设24小时。
重试策略上,只在收到"明确失败"或者"传输超时且请求是幂等"时才重试。为了支持幂等,请求里一定带上一个由调用方生成的idempotency_key,服务方按这个key去重,才能保证重试不重复执行。这一步不做,整天提心吊胆。
6.2 会话恢复与幂等设计
代理协作过程中,某个节点可能因为网络抖动、进程重启、版本发布而中断。恢复机制怎么做,是决定系统可用性的关键。
我推荐的做法是:任务状态机事件持久化。也就是把task的每次状态变更都记录到一个事件列表里(可以用数据库表,也可以走消息队列),新的接管节点只要从事件列表里重放到最后一个状态,就能干净地接管。
举个例子,主代理把"预订机票"任务发给订票代理后,自己进程崩了。重启后,它从事件存储里读到"任务已受理,状态:等待确认",于是继续发起能力发现或检查之前确认请求的状态,而不是把这个任务当成新任务重新发起。如果没有事件持久化,用户就会经历"刚让订票,又让你重新输入一遍日程"这种分裂体验。
幂等设计的另一个重点是状态变更只允许单向转移。比如从"已确认"不能回退到"待确认",除非显式发起一个"撤回"动作并记录原因。这个单向性原则能有效防止重放事件时状态倒退,导致下游误判。
6.3 权限膨胀与定期收敛
做分布式系统久了都知道,权限会像房间里的杂物一样越堆越多。PAP这类授权模型尤其容易膨胀,因为每个任务都会生成新的委托ID,时间一长,可能一个用户名下挂着几百条未过期的委托链。
我的建议是至少做两件事:
第一,默认缩短委托有效期。除非业务明确要求,到期时间不要超过任务周期的两倍。任务搞定了,委托就应该尽快失效。
第二,定期做委托链审计。每周或每个月跑一次脚本,筛选"过期但仍未被撤销"的委托,标识"授权后从未被使用"的委托,把这些数据提交给管理员或者用户本人确认回收。不要等到某个委托被滥用、捅了篓子才发现权限早就发超了。
注意:撤销委托本身也要记录审计日志,并且最好与任务状态联动。如果某个任务已经进入"人工审批中",把相关的委托撤销了,会导致审批通过后无法继续执行。设计时要在"可撤销性"和"任务连续性"之间做权衡,通常做法是撤销前先挂起相关任务,再回收权限,等任务终止或重建委托后才能恢复流程。
6.4 版本兼容与灰度升级
协议落地最难的不是写代码,而是升级。PAP一旦真正铺开,参与方很多,不可能所有节点同步升级,所以必须在第一天就想好版本兼容策略。
最直接的两个做法是:语义化版本号和字段容错。协议层的大版本升级,比如从v1升到v2,允许不兼容,但必须让旧节点感知到"对方是v2,我按v1解析不了",并返回结构化错误,而不是一屏乱码。小版本升级要保持向后兼容,新增字段不能影响旧客户端解析。字段容错就是"客户端忽略未知字段、服务端只校验必填字段",这个习惯能省掉无数升级纠纷。
灰度升级的顺序也有讲究,我会先在一个内部域里升级两三个可控节点,验证日志兼容、状态机正常,再逐步扩大。千万不要第一天就全网强制升级PAP版本,没出事是运气,出事是必然。
我在实际做类似项目时,最大的体会是:协议本身不产生价值,只有被大家真正用起来才能产生价值。PAP这类协议如果真的要普及,依赖的不是某一家厂商的强势推广,而是有没有足够清晰的文档、足够简单的接入示例、足够低的上手门槛。我建议所有想试水的人,先搭一个小闭环:一个用户、一个主代理、两个服务代理,用最小化的方式把"委托、调用、返回、审计"跑通,再慢慢加人工介入、加能力发现、加跨域策略。复杂系统都是从最小闭环长出来的,一上来就要支持全量功能,通常撑不到上线那天。