PACT 協定拆開看:personal agent 替你問商家,Trust 與 Consent 為什麼拆成兩層
你的 personal agent 要替你問商家客服:那張訂單到哪了?
最直覺的做法,是商家的客服 agent 像在聊天視窗那樣自己驗證你,問訂單編號、問 email,personal agent 把你的答案轉述過去。能動,也不需要任何新協定。麻煩出在下一步:你想讓它幫你改地址、幫你退貨,客服 agent 憑什麼相信這個 agent 真的是你派來的,又憑什麼只讓它做你准許的那幾件事?
PACT(Personal Agent Consent & Trust Protocol)想回答的就是這一段。Decagon 在 2026 年 10 月 6 日發了公告,原話是 “Today, we’re open-sourcing the Personal Agent Consent & Trust Protocol (PACT).” 並說它 “Built on the Agent2Agent protocol and OAuth 2.0.” repo 在 openpactprotocol/openpactprotocol,授權是 Apache-2.0。我拆的方式是照同一個動作,看舊做法在規格裡變成什麼、疊上去的新東西又多了什麼。
底線:只有身分,沒有授權
規格把聊天視窗式的驗證留成底線,叫 PACT Identity。它只管一件事:商家那端的 Provider 要知道,是哪個 personal agent 在呼叫。
做法是 personal agent 用自己的金鑰簽一個 JWT,Provider 去它公開的 JWKS 驗。規格寫得很乾脆:”No shared secrets.” alg 只能是 ES256 或 RS256,其他一律拒絕。sub 要穩定、不透明、每個使用者一個,而且 “MUST NOT contain personal data.”。exp 最多是 iat 之後 300 秒,reference signer 實際用 120 秒。時鐘偏差容忍 30 秒。jti 是 MAY,規格甚至說 “Providers need not track replay.”
這層證明的範圍,規格自己劃得很窄:「That a known personal agent is calling for someone it calls sub. Not that sub owns a Brand account.」所以 sub 是誰、是不是帳號主人,這層完全不碰。沒有第二層的時候,Brand 的 agent 還是得自己問訂單編號和 email,帳密 “never pass through the personal agent.”
這個版本沒有「授權」這個概念。使用者准許 agent 做什麼,在這層裡沒地方放。
疊一層:登入搬到商家那邊
第二層叫 PACT Delegated,規格標成選配。§5 的開頭說得直白,身分那層(§2 到 §4)沒有它也能運作,不提供的 Provider 只要在 Agent Card 裡省略 §5.1。
同一個「替你改地址」的動作,在這層變成五步:personal agent 先挑 scope,拿到登入連結,你在商家那邊登入並勾選核准,Provider 發一張 delegation token,之後每次送訊息都帶著它。底下是每次請求要帶的兩個 header,規格原文:
1 | Authorization: Bearer <pa-jwt> |
兩張 token 證明的東西不同,我整理成表(欄位值都照規格原文):
Authorization(PA JWT) |
X-A2A-User-Delegation |
|
|---|---|---|
| 誰簽 | personal agent 自己的金鑰 | Provider |
| 證明什麼 | 一個已知的 personal agent 在替 sub 呼叫 | 使用者在這個 Brand 核准了哪些 scope |
| 壽命 | exp 最多 iat 後 300 秒 |
“Lifetime SHOULD be ≤ 1 h.” |
| 綁定 | aud 是 Provider 指派的單一字串 |
aud 是 Brand 的 interface URL,”One Brand per token.” |
登入發生的順序我覺得是整份規格最聰明的地方。規格寫 “Login comes first so the grant is bound to a verified account.”,意思是你先在商家登入,同意頁才出現,同意頁上每個 scope 一個可以取消勾選的 checkbox。personal agent 拿到的是 verification_uri_complete,規格要求它 “MUST NOT proxy, frame, or observe the login.”,也就是不得代理、嵌框或旁觀這次登入。
我拿飯店來比喻。你在櫃檯自己出示證件,櫃檯給管家一張房卡,只能開你勾選的那幾道門。管家能帶著房卡走,卡上的權限他自己改不了,規格原句是 “The personal agent carries it but cannot change it.”
房卡上還有一道綁定:delegation token 的 client_id “MUST equal the iss of the personal-agent JWT sent with it.”。卡是發給哪個 agent 的,寫在卡上,別的 agent 撿到也不能用。另一個細節是 token 回應裡的 scope 是你實際核准的,”which may be less than requested. The personal agent MUST read it.”,也就是你可能只勾了其中幾項,agent 不能假設自己拿到的是全部。
缺一個 scope 的時候
使用者核准了「查訂單」,然後 agent 想改地址。這時 Provider 怎麼辦,規格的答案是 “If a turn needs a scope the token lacks, the Provider MUST NOT fail it.”
不准失敗。Provider 要回 task 狀態 TASK_STATE_AUTH_REQUIRED,metadata 裡帶 pact.missingScopes 和 pact.verificationUriComplete,對話保持開著。personal agent 重走一次取得 token 的流程,拿到新 token,用同一個 contextId 重送。
我喜歡這個設計。缺權限是個很自然會發生的狀況,直接讓它失敗,我猜使用者就得從頭解釋一遍。把「缺什麼、去哪補」寫進狀態,等於承認授權是一路追加的,不是一次講完。這是我的讀法,規格沒有這樣自述。
對話也有鎖。同一個 context 一旦以某個 sub 跑過,換成別的 sub 的 token 會回 INVALID_PARAMS。context 還要屬於這個 Brand 和這組 (personal agent, sub),否則同樣 INVALID_PARAMS,而且不透露它是否存在於別人名下。規格那句 “contextId is state, not a credential.” 是這一整塊的註腳:對話編號不是通行證。
規格寫了,誰守著它
讀這份規格時,最讓我停下來的是這一段。repo 建立於 2026-10-01,我在 2026-11-01 讀的時候,公開的討論裡有好幾條,是在問同一件事:這些 MUST 有沒有東西在守。以下全是提交者自述,我沒有 clone repo,也沒有重現任何一條。
Issue #55 說 §5.5 的 client_id 比對沒有測試覆蓋,原話是 “Deleting that one comparison leaves pnpm test 79/79 and pnpm e2e 19/19 green.” 前面講的房卡綁定,正是那一行比對。
Issue #57 更直接:它說 CI 的 ci.yml 跑 lint、typecheck、pnpm test、format:check 和兩個 build,”It never runs pnpm e2e”。提交者自述把 metadata key 打成 pact.reciept,所有檢查全綠,而它提議加的 e2e job 會失敗。README 寫 e2e 目錄是 conformance tests,可以用 E2E_PROVIDER=any 對任何 Provider 跑。照 #57 的說法,測試是有的,只是 CI 沒呼叫它。ci.yml 我沒有自己打開核對。
2026-10-30 開出來的 PR #61 要加一個選配的 contexts/v1 擴充,補對話歷史和 callback。PR 內文自己列了三件事,我覺得寫得很誠實:reference Provider 沒有實作這個擴充,新的 e2e 測試對它是跳過的,”have not run against a live implementation”;callback 用 HMAC 簽,但沒有 timestamp,可以重放,文件把它列為 open risk;另外目前已出貨的 handoff 回應是空的 parts,PR 說 “So the current parts: [] ack is not A2A-conformant.”。這個 PR 的狀態是 open,沒有合併。
還有兩條是缺口也是提案。Issue #58 指出 PA JWT 只說得出「哪個 agent 在呼叫」,原話是 “It says nothing about which build of that agent is calling.”,提議加一個 agent_manifest claim。Issue #60 則提議在任務終態回一個 task 層級的 Scope Receipt,把整串 §5.6 receipt 綁在一起;它目前 0 則留言。
§5.6 的現行規格是每個回覆一張收據:”Every message:send served under a delegation token MUST include in the reply’s metadata a receipt signed with the same keys as the token”,key 是 pact.receipt,裡面有 scopesUsed 和 actions。收據只到單一訊息層級,#60 想補的就是這個空缺之上的那一層。
這條死路,我下次會跳過:讀協定時只盯 MUST 清單,就當作它們有人守。#55 和 #57 自述的是反過來的情況:規則寫得清楚,改掉那行判斷卻沒有測試會紅。下次我會先問兩件事,一個是 conformance 套件有沒有進 CI,一個是最關鍵的那條規則有沒有對應的負向測試。
兩層要分開決定
我的立場是:先決定商家要不要第二層,再談要不要用 PACT。只要商家的需求是「知道哪個 agent 在叫」,§3 一層就夠,而且規格明講身分那層沒有 §5 也能運作,Provider 不提供就省略 §5.1。要讓 agent 真的替使用者動手改東西,才值得上 §5,並把「缺 scope 時不准直接失敗」當成設計重點。
什麼會讓我改變想法?第一,如果 ci.yml 真的把 e2e 納進去、#55 那種比對補上負向測試,我會收回「規格還沒被守住」這個保留。第二,如果出現任何真實 Brand 部署 PACT 的回報,我對它能不能在正式環境站得住,會比現在有信心得多。目前這兩件事我都沒有證據:公告只提到 Muse、dots 是 personal agent,沒有說有沒有上線,我也沒查。
資料基準日是 2026-11-01:114 顆星、11 個 fork,沒有 GitHub Release,也沒有版本 tag。main 分支只有 5 筆 commit,最後一筆是 2026-10-06 的 “deps: clear pnpm audit –prod (#39)”,之後沒有新的。10 月 6 日之後的動靜都在還沒合併的 PR 和 open 的 issue 裡,所以我不會說它在快速演進,我只能說它的討論還在長。規格自己寫 “This is PACT 1.0.”,兩個 profile 有破壞性變更就會改這個數字。
本文只讀了公告、docs/spec.md(main 分支)、README 和 repo 的 issue 與 PR,沒有跑過 pnpm install、pnpm test、reference provider,也沒簽過任何 JWT 或走過 device code 流程。規格引用 A2A 的部分,我沒有回 A2A 的規格逐項核對,所以不寫 A2A 本身規定了什麼。名字相撞的另一份 IETF draft,我只看到標題,沒讀內文。來源:Decagon 公告、repo、規格。
以前問的是「你是誰,你轉述的答案對不對」,現在多問一句:這張許可是誰簽的,你拿著它能不能自己改。










