AP2 (Agent Payments Protocol) — 架构与原理
30 秒导读: AP2 是 Google 主导的开放协议,解决一个新问题——当 AI agent 替你花钱时,商家/银行凭什么相信这笔钱是你授权的? 它的答案是 mandate(授权书):把「人批准了什么」写成一份密码学签名的凭证,agent 每次付款都要出示它,任何验证方都能离线核验、事后追责。
1. 这是什么(零基础也能懂)
一句话定义: AP2 是一层叠加在电商协议之上的安全协议,让 AI agent 发起的支付带上「人类确实授权过」的密码学证据。
解决什么问题 / 给谁用
想象你对一个购物 agent 说:「帮我买双红色高帮篮球鞋,200 美 元以内。」agent 跑去跟商家谈、组购物车、刷你的卡。这里有个信任黑洞:
- 商家怎么知道这个 agent 真的被你授权买这双鞋,而不是 agent 自己乱花钱或被人劫持?
- 银行 / 支付处理方怎么知道该不该放行这笔卡交易?
- 真出了纠纷,凭什么证据说清「用户当时到底批准了什么」?
传统电商假设「点付款的就是持卡人本人」。可一旦中间多了个非确定性的 LLM agent,这个假设就破了——agent 自己就可能是攻击面。AP2 就是来补这个洞的。
它能做什么(功能)
- 把用户的购买授权固化成可验证凭证(mandate),商家/银行可独立核验。
- 支持两种模式:用户在场(人亲自点确认)和用户不在场(人先设好约束,agent 自主成交)。
- 用**约束(constraints)**框住 agent 的自主权:金额上限、限定商家、限定商品、预算、执行日期……
- 用选择性披露只露出验证必需的字段,保护隐私。
- 结算后回一张收据(receipt),密码学绑回那份授权,作为纠纷证据。
- 与传输无关:示例跑在 A2A(Agent-to-Agent)和 MCP 上,但协议本身不绑定任何一种。
用起来什么样
AP2 的「核心动作」其实就三步,SDK 把它收成三个方法(code/sdk/python/ap2/sdk/mandate.py:153 MandateClient):
# 示意,非源码:一笔「用户不在场」授权的最小骨架
client = MandateClient()
# 1. 用户(经银行/可信表面)签发一张「开」mandate:只设约束,不绑具体交易
open_token = client.create(payloads=[open_payment_mandate], issuer_key=user_key)
# 2. agent 在它上面追加一跳,签出「闭」mandate:绑定到这笔具体交易
chain = client.present(holder_key=agent_key, mandate_token=open_token,
payloads=[closed_payment_mandate], nonce="tx_abc", aud="merchant")
# 3. 商家/银行验证整条链:签名对不对、约束满不满足
payloads = client.verify(token=chain, key_or_provider=lookup_user_key,
expected_aud="merchant", expected_nonce="tx_abc")
一句话直觉 / 类比
把 mandate 想成一张「带条件的授权委托书」。 用户签的「开」委托书写的是规则(「200 刀以内、任意鞋店都行」);agent 拿着它去成交,再补签一张「闭」委托书填上真实成交细节(「就这双鞋、就这家店、就 $179.99」)。验证方拿到两张一对照:闭的有没有越过开的规则?两张是不是同一条信任链上的?——全程不需要联系用户本人,纯靠密码学。
2. 顶层全景(它大概怎么转)
五种角色
AP2 把一笔 agentic 交易拆成五个职责(docs/ap2/specification.md:30-52)。一个公司可以兼任多个角色,但职责是分开的:
| 角色 | 干什么 | 是否「agentic」 |
|---|---|---|
| Shopping Agent (SA) | 主 agent:找货、组购物车、发起购买 | 预期是 agentic(LLM 驱动) |
| Credential Provider (CP) | 持有用户支付凭证,放行 token | 可 agentic / 可非 agentic |
| Merchant (M) | 提供并完成 checkout,保证库存与价格 | 可 agentic / 可非 agentic |
| Merchant Payment Processor (MPP) | 处理支付,核验凭证是否绑对了这单 | 可 agentic / 可非 agentic |
| Trusted Surface (TS) | 拿到用户知情同意、签出用户 mandate 的 UI | 必须非 agentic |
关键洞察:协议把「LLM 是潜在攻击者」当成前提(
specification.md:86-89)。所以所有验证/处理必须跑在确定性代码里,不能交给 LLM(specification.md:96-98);唯一能签发用户授权的 Trusted Surface 也强制非 agentic(specification.md:78-80)。
一张图:一笔交易怎么流
下面是「用户不在场」的高层数据流。从上到下是时间顺序,左边是人/agent 侧,右边是验证方。
用户 Shopping Agent 验证方(商家 / CP / MPP)
│ │ │
│ 1. 设任务+约束 │ │
│──────────────────────▶│ │
│ 2.(经 Trusted Surface)│ │
│ 签「开」mandate │ │
│◀─────────签名─────────▶│ │
│ 用户离场 │ │
│ │ 3. 跟商家谈、组车、拿 checkout JWT
│ │───────────────────────────▶│
│ │ 4. 用 agent 私钥追加一跳, │
│ │ 签出「闭」mandate │
│ │ 5. 出示整条链(开+闭) │
│ │──────────────────────── ───▶│
│ │ │ 验签 + 查约束
│ │ 6. 收据(reference 绑回闭 mandate)
│ │◀───────────────────────────│
主线走一遍(不进代码):
- 授权阶段 — 用户在 Trusted Surface 上批准一份「开」mandate(只含约束 + agent 公钥),用户私钥签名。这是整条信任链的根。
- 成交阶段 — agent 自主跟商家组好购物车,拿到商家签名的 checkout。
- 绑定阶段 — agent 用自己的私钥,在「开」mandate 之上追加一跳,签出「闭」mandate,把真实成交细节绑死。
- 验证阶段 — 验证方拿到整条链:先用**只信任的根(用户/银行公钥)**验第一跳,再顺着每跳的
cnf(下一跳公钥)往下验,最后逐条评估约束。 - 结算 + 追责 — 通过则回一张收据,其
reference = sha256(闭 mandate JWT),把结算结果永久绑回那份授权,作为纠纷证据。
部件一句话职责(SDK)
| 部件 | 干什么 | 在哪个文件 |
|---|---|---|
MandateClient | 对外门面:create / present / verify | code/sdk/python/ap2/sdk/mandate.py:153 |
sd_jwt | 根 SD-JWT(链的第一跳)签发与验证 | code/sdk/python/ap2/sdk/sdjwt/sd_jwt.py:23 |
kb_sd_jwt | KB-SD-JWT 委托跳(中间/终端) | code/sdk/python/ap2/sdk/sdjwt/kb_sd_jwt.py:35 |
chain.verify_chain | 顺链验证,跟着 cnf 走 | code/sdk/python/ap2/sdk/sdjwt/chain.py:121 |
constraints | 约束评估器(金额/商家/预算/配货…) | code/sdk/python/ap2/sdk/constraints.py:489 |
ReceiptClient | 收据创建与验证 | code/sdk/python/ap2/sdk/receipt_wrapper.py:18 |
3. 接下来读哪章
这个项目有两面:一套协议规范(docs/) 和 一套真实实现(code/sdk + code/samples),而且实现里还并存两代数据模型。按下面顺序读最省力:
- 01-mandates-and-roles.md — 先把「开 vs 闭 mandate」「五种角色」「人在场 vs 不在场」这几个核心概念吃透。所有人必读。
- 02-sdjwt-delegation-chain.md — SDK 的心脏:委托链怎么用 SD-JWT + KB-SD-JWT 一跳跳拼出来、验证方怎么顺着
cnf一路验下来。想读源码的从这章进。 - 03-constraints-and-receipts.md — agent 自主权的「护栏」:约束怎么逐条评估(含一个用最大流做配货匹配的巧妙实现),收据怎么把结算绑回授权。
- 04-two-model-generations.md — 诚实章:仓库里
ap2/models/(Intent/Cart/Payment)和ap2/sdk/generated/(Open/Closed Checkout/Payment)是两代设计,哪套用在哪个样例、规范站在哪一边。读懂这章才不会被「同一个仓库两套 mandate 名字」搞晕。
4. 代码地图(导航索引)
| 主题 | 文件 | 符号名 |
|---|---|---|
| 协议规范 v0.2 | docs/ap2/specification.md | (Roles / Mandates / Verification) |
| 授权框架(开/闭、委托、收据) | docs/ap2/agent_authorization.md | (Mandate Delegation / Action Authorization) |
| 两种流程示例 | docs/ap2/flows.md | (Human Present / Human Not Present) |
| 旧版 Pydantic 模型 | code/sdk/python/ap2/models/mandate.py | IntentMandate CartMandate PaymentMandate |
| W3C 支付对象 | code/sdk/python/ap2/models/payment_request.py | PaymentRequest PaymentResponse |
| SDK 门面 | code/sdk/python/ap2/sdk/mandate.py | MandateClient |
| SD-JWT 原语 | code/sdk/python/ap2/sdk/sdjwt/sd_jwt.py | create verify |
| 委托跳原语 | code/sdk/python/ap2/sdk/sdjwt/kb_sd_jwt.py | create verify |
| 链编排 | code/sdk/python/ap2/sdk/sdjwt/chain.py | verify_chain |
| 约束引擎 | code/sdk/python/ap2/sdk/constraints.py | check_payment_constraints |
| 配货最大流 | code/sdk/python/ap2/sdk/max_flow_helper.py | evaluate_line_items_max_flow |
| 收据 | code/sdk/python/ap2/sdk/receipt_wrapper.py | ReceiptClient |
| A2A 扩展 URI | code/samples/python/src/common/a2a_extension_utils.py | EXTENSION_URI |