Poppy 把「这个智能体属于谁」反了过来——而这次反转的全部代价,落在你的会话模型上,不在那个 JSON 文件上。
过去一年半里发布的每一个智能体协议,问的都是「买方的智能体怎么付你钱」。而由 Sierra 与 Meta 在 2026 年 10 月 6 日公布的个人智能体协议——Poppy——问的是商家集成从未需要回答的一个问题:一个陌生人的智能体,要如何以你某位客户的身份登录进来?回答它的代价是:一个开场时里面没有任何人、在半途才获得身份的会话;一个你在结构上被禁止与任何其他公司对接的化名;以及一处再也不能放在你原先位置上的授权检查。那个发现文件花你一个下午,会话模型才是整个项目。
步骤 1到底发布了什么,以及它仍在多快地变。
Sierra 与 Meta 在 2026 年 10 月 6 日公布 Poppy,并在 10 月 9 日发布了规范草案,同时带来一批设计伙伴,第三方追踪者数到约 35 家公司。它是草案,而且正以草案的速度前进:日期为 10 月 18 日的 SDK 发布自称面向草案 0.2,而已公开的示例里 protocol_version 已经写到了 0.3。截至 2026 年 10 月下旬,这些数字全都只有一个月的寿命,而当你读到这段时,其中至少有一个已经是错的。
这不是抱怨,这是第一条工程指令。一个处在第一个月的协议没有可供你编码对准的稳定版本号,所以就不要去对准它。Poppy 自己给出的答案——也正是本文把它看作一份设计良好的草案而非一份未完成品的理由——是:关于「一家公司支持什么」的权威陈述,是它自己提供的那份发现文档,而不是你恰好读到的那版规范里的修订号。在请求时读取这份文档,按它实际包含的字段分支,并把一个无法识别的 protocol_version 当作重新读取的理由,而不是中止的理由。这与 能力发现与协商里讲的特性探测纪律是同一回事,而 Poppy 是迄今为止支持这条纪律的最强论据:这是一个版本号在九天里跳了两次的协议。
步骤 2这个 well-known 文件的朝向是反的。
一家支持 Poppy 的公司,在 /.well-known/poppy.json 发布一份 JSON 文档。它声明智能体如何开启一个会话、这家公司提供哪些登录方式与权限范围,以及哪些通路可用——一个对话式端点、一组 API,或者一个由智能体直接驾驶的网站会话。
把它和智能体生态原本就有的那个 well-known 文件对照着看。A2A 在 /.well-known/agent.json 的智能体卡片说的是我是一个智能体,这是可以让我做的事——见 智能体卡片与发现。而 Poppy 的文档说的是我是一家公司,这是别人的智能体可以代表我的某位用户在这里行动的方式。广告的朝向反了过来,而正是这一处反转,使 Poppy 成为另一种标准,而不是同一种标准的另一个方言。智能体卡片是一份服务说明,而一份 poppy.json 是一份准入政策。
这个区别会立刻体现在你如何给它做版本管理上。服务说明可以大方一点,因为把一项能力吹过头,最坏的结果也就是一次调用失败。而一份吹过头的准入政策是一条安全发现:你在那份文件里列出的每一条通路,都是一个第三方将带着你自家客户的权限去驾驶的通路。只列出你确实已经加固过的那个最窄集合,并把「往那个文件里加一条通路」当作需要与上线一个公开 API 同等审查的变更——因为从你发布它那一刻起,它就是一个公开 API。
步骤 3会话开场是未登录的,而这正是那处承重的决定。
下面这个机制会重新组织你的后端。在 Poppy 里,智能体先开启会话,此时还没有任何人证明过自己是谁;登录是在之后,把一个公司账户挂到这个已经在跑的会话上。智能体可以作为匿名访客浏览、询问、问价、做计划,然后——如果用户批准——在同一段对话中途变成一位已知客户。
你此前造过的几乎每一个需要鉴权的 API 做的都是反过来的事:在建立连接时鉴权、签出一个编码了主体的令牌,然后让下游每一个处理函数都假定主体一定存在,因为没有主体连接根本建不起来。Poppy 恰好在这条假定唯一承重的地方把它打破了:你的授权检查不能放在会话构造处,因为在会话构造的那一刻,根本没有人可供授权。
# the shape Poppy forces: principal is a property of the turn, not the socket session = poppy.open(company="acme.example") # no user yet. legitimately. session.ask("do you ship to Lisbon?") # anonymous route: must work grant = session.sign_in(scopes=["poppy:read"]) # identity arrives mid-session def handle(action, session): # WRONG: session.user was captured when the socket opened # RIGHT: re-read the principal and the grant on every action principal = session.principal_now() if principal is None and action.needs_identity(): raise NeedsSignIn(action.required_scopes) return policy.check(principal, grant, action).run()
做错这件事会引出两个 bug,而它们朝相反的方向失败。把主体只捕获一次,那么在登出之后——或者在同一个会话上换了另一个账户登录之后——执行的动作就会带着一个过期的身份跑起来;这正是 混淆代理所描述的形状。而如果你在登录之前拒绝提供任何服务,你就破坏了这个协议的全部前提:匿名阶段恰恰是个人智能体完成大部分工作的地方,而用户也没有任何理由为了问一句送货时间就把账户交出来。
步骤 4两个权限范围、一个保留前缀,以及它为何把风险推到动作这一层。
Poppy 的标准权限词汇小得刻意:poppy:read 与 poppy:write。登录授予其中用户批准的那些,而 poppy: 这个前缀是保留的——你不可以自造 poppy:refunds 或 poppy:transfer。更细的东西,公司要用自己命名下的自定义 scope 来表达,公开示例正是这么做的:把 poppy:read 与一个业务 scope(例如 addresses)配在一起。
这里值得把「两个取值的标准词汇能承载什么、不能承载什么」说准,因为人很容易把它读成一处疏漏。它不是。一套标准 scope 必须在每一家发布它的公司那里含义相同,而「写」已经是能在一家零售商、一家银行与一家航空公司同时含义相同的上限了。任何想把 poppy:purchase 标准化到这三者身上的尝试,要么会含糊到无法审阅,要么会具体到对其中两家都是错的。
它真正意味着的是:授权无法表达风险,所以动作必须表达。一个 poppy:write 同时覆盖「改一个收货地址」和「取消一项订阅」,而批准它的用户只被展示了一个勾选框。如果你的策略层读到 scope 就停下,你就把你最危险的那个写操作的上限,发给了每一个写操作。解法正是本站一贯主张的那条:给操作打分,而不是给授权打分,再让分数决定它是直接执行、需要一次确认,还是干脆被拒——按风险打分的权限与自动批准与允许清单在一个粗粒度授权之上都照样奏效,而粗粒度授权正是你唯一会拿到的那种。
对一个已有产品,有个好用的自审问题:把你公开面上暴露的每一个变更操作列出来,然后问自己,哪些你愿意仅凭一个写着「允许该智能体做出更改」的勾选框就放它跑。所有让你不舒服的那些,都需要在 scope 检查下面再有一道自己的门——而且在 Poppy 出现之前,它们就已经需要了。
步骤 5按公司隔离的化名是一项隐私特性,也是一张工程账单。
一个 Poppy 会话携带的用户标识,在一家公司内稳定,在其他每一家公司都不同,于是两家公司无法通过比对各自智能体递来的标识,发现它们面对的是同一个人。这是一处真实而少见的隐私设计——它让跨公司关联成为协议在结构上就不提供的东西,而不是一份政策文件请求大家别做的事。
它同时也删掉了一个你很可能正在用的键。三个系统会以可预料的方式坏掉。身份归并:你不能把智能体一侧的标识当作全局客户键,因为它根本不是;它只与你自己的账户相连,而且只在登录之后。欺诈与滥用打分:关于某个具体终端用户的跨商家信誉信号,在这条通路上由构造决定地不可获得,这意味着你的频次检查与设备信号必须扛起原本由共享身份承担的重量。客服与争议处理:当一位客户打来问「我的地址为什么被改了」,把一个人和一次动作连起来的那件产物是登录事件,而不是会话——所以请把授权、它的 scope、它的时间,以及在它名下发生的动作 id 都记下来,做法见受委派访问与同意记录。
还有一处值得点名的不对称,因为人很容易感觉自己比实际更受保护。化名阻止的是各家公司之间互相关联同一个用户,它完全没有阻止智能体去关联——因为智能体恰恰是那个同时握着全部化名、并且知道它们属于哪个人的唯一一方。Poppy 把这次关联从商家侧搬到了智能体侧;这是不是一种改进,完全取决于你认为它该由谁握着,而那是委托代理问题所讨论的事,不是一份规范能裁定的事。
步骤 6它没有支付的部分,而这恰恰是线索。
草案覆盖身份、登录、会话与权限范围,支付被列为未来工作。把它和被归在一起的那些协议并排读,这处缺席就是整份文档里信息量最大的东西。
一个商务团队如今被要求评估的四个标准里,有三个讲的是支付工具。Agentic Commerce Protocol(OpenAI 与 Stripe,2025 年 9 月 29 日以 Apache 2.0 发布,带版本号的规范为 2026-04-17)带有一份 Delegated Payment Spec:签出一个一次性令牌,令牌上写着可扣款的最高金额与过期时间,再交给商家。Universal Commerce Protocol(Google 与 Shopify,2026 年 1 月 11 日公布)让商家发布自己的能力,并伸手去取 AP2 的 mandate。而 AP2 本身根本不是一个商务协议,而是一个把意图、购物车与支付建模为可验证凭证的授权层——见 AP2 与智能体商务。它们每一个都必须回答「谁可以被扣款、最多扣多少」,因为它们每一个都假定智能体是买方。
Poppy 没有答案,因为它从不做这个假定。它是四者中唯一一个让智能体充当用户的受托人、而非平台的买方的协议,而一个受托人本来就没有自己的支付工具可以出示。支付那块空白不是一章没写完,而是这个协议在一个需要「谁持有支付工具」的问题边缘上、正确地停了下来。四方的分层地图,以及先实现哪一个的决定,是「其中三个回答的是智能体怎么付钱」一文的论点。
如果你在决定这个季度要做什么:把 poppy.json 放到最后发,而不是最先发。先按顺序做完它会把你暴露给的那三件事——让每一条读取通路在未鉴权的会话下也能工作;把授权检查从会话建立处挪到单个动作上;在 poppy:write 底下放一道风险门,好让一个被批准的勾选框碰不到你最危险的那个变更操作。做完这三件事的公司,距离支持 Poppy 只差一个文件;而且在面对那些根本不用任何协议、已经在以你用户身份登录的第三方智能体时,它也确实更安全了。