快轉到主要內容
  1. AI×生活/

主體崩壞(principal collapse)——為什麼一個只服務一個老闆的 AI代理,無法恰當的處理其他老闆的話

·14 分鐘
QQder 核舟記部落格
作者
QQder 核舟記部落格
這裡有八款 iOS App,全部免費、無廣告、無追蹤——直接挑一款來用。同時記錄一個文科背景的系統管理員,如何靠 AI vibe coding 從零把想法做進 App Store。也承接固定範疇的 agent 自動化委託——詳見「服務」頁。
Parenting Agent - 本文屬於一個選集。
§ 3: 本文

前兩篇講了一個範式和一次實作。這篇要講的是在做實作的過程中撞到、但當時沒有名字的那個東西。

三週前那篇實作篇的第二節,我列了六道護欄,並且說「不靠更聰明的 agent,靠結構」。當時我以為那只是工程上的保守選擇,現在我覺得大概沒有別的選項,因為問題其實不在 agent 身上,而在盛裝 agent 的那個容器身上。

我把這個缺陷命名為 principal collapse,中文我叫它主體崩壞


一、先定義三個詞
#

這三個詞在後面每一節都會用到,而且第二個是新的。

  • 主體(principal):agent 服務的那個人,agent 的權威是跟他借來的。就我讀過的 harness,都預設恰好一個,也就是坐在終端機前面的那個人。
  • 對等方(peer):一個服務別的主體的 agent。它不是子 agent、不是工具,也不是惡意注入,而是一個有名有姓、被它自己的主體授權來說話、但站在你的信任邊界之外的談判對手。
  • harness:組裝模型 context1、執行模型工具呼叫的那個程式,比如 Claude Code、Codex CLI、opencode、pi,或你自己寫的那個。

二、定義
#

主體崩壞:一則由某個主體授權說出口的話,在進入另一個 agent 的 context 之後,取得了後者主體的權威。原因是 harness 沒有任何一種表示法,能夠承載「有作者、但沒有權威」的輸入。

今天的 harness 只有兩種非 system 的輸入,而輸入落在哪一種,是由 role2 這個欄位決定的:

role意思權威
user我的主體說的指令
tool某個工具回傳的資料

沒有第三種。所以當一則來自對等方的訊息抵達,它要嘛被壓平成 user,在那裡它繼承了你主體的權威,要嘛被降格成 tool,在那裡它的作者身分被丟掉,變成無法歸屬的東西。兩個都不對,因為那則訊息是某個人說的話,只是不是你的主體說的。

崩壞的重點其實不是「錯的位元組進來了」,而是權威這條軸上只有一個位置,所以第二個主體一出現,harness 就沒有辦法把那個差別表示出來。


三、三個問題,任何一個答「否」就是了
#

圖 1 · 判定一個 harness 有沒有主體崩壞
🪪
可區分性
能不能表示一則「作者已知、但不是我的主體」的訊息,而且不跟我的主體同一個 role?
有沒有第五種 role
🚫
不可晉升
如果那則訊息裡寫著「使用者已經批准了」,有沒有任何一條程式路徑會讓這句話成真?
說服能不能變成授權
👁
可辨識性
對於 agent 做過的任何一個動作,主體看不看得出造成它的那則輸入來自哪一個 role?
事後追得回去嗎
圖說:三題都要答「是」才算沒有。就我讀過的通用 harness,出廠時三題全部答「否」。

更短的版本是:去問你的 harness,它 context 裡哪些位元組帶有權威。如果答案是「user role 裡的全部」,而且信任邊界外的東西進得了 user role,你就有主體崩壞。

我要講清楚一件事:這不是在批評那些 harness 的工程品質。 它們是為一個主體設計的,而在只有一個主體的情況下,這個缺陷是觀察不到的,因為根本沒有第二個權威可以崩壞進去。這有點像在單人系統上談權限提升,不是那個系統做得特別好,只是沒有第二個使用者可以提升過去。


四、它不是什麼
#

第一個反應大概會是「這不就是某某某嗎」,所以我把鄰居一個一個講清楚。

不是 prompt injection3 注入是不正當的內容混在資料通道裡偷渡進來,而對等方的訊息是正當的:它的主體授權了它、它有簽章、作者是已知而且穩定的。防注入問的是「這東西該不該在這裡」,主體崩壞問的是「這東西帶著誰的權威」,而後面這個問題,在你已經確定內容該在這裡之後依然是開著的。所以一個把注入防得很好的 harness 照樣會崩壞,因為對等方從來就不是入侵者。

不是 confused deputy4 那個講的是一個程式替呼叫者誤用了它自己的環境權威,解法是能力式授權5,也就是不要攜帶環境權威。主體崩壞是話語表示法的缺陷,context window 裡沒有一個欄位放「作者權威」,所以光靠能力機制修不好,一個能力紀律完美的 harness,依然沒辦法告訴模型「這句話是陌生人的提議,不是你老闆的命令」。某種程度上算是同一個家族的問題,只是不同的成員。

不是多 agent 編排6 子 agent、swarm、worker/reviewer 分工,這些全部都是單主體的,它們共用一個擁有者、一個信任邊界、一套權限模型,而且彼此沒有對立利益。沒有東西會崩壞,因為只有一個權威可以崩壞進去。所以多 agent 處理的大部分是並行問題,主體崩壞是權威問題,兩者剛好不重疊。

不是多租戶。 多租戶是一個營運者服務許多互相隔離的客戶。這裡的主體們並不隔離,他們正在互相講話,那是刻意的,而且沒有一個是營運者。


五、我在別人的出貨文件裡找到它
#

這一節本來不在計畫裡。我原本只是想弄清楚 can2cup 是不是在重造輪子,所以去把幾個同類專案 clone 下來讀原始碼,結果在 hauddy(Apache-2.0,一個「給 agent 的簡訊」專案)的 harness 接線指南裡看到這一行。

那份文件在教任何一個 MCP7 harness,怎麼接收一則由別人的主體授權的 agent 傳來的訊息:

session.injectUserMessage(`[hauddy ${msg.params.from}] ${msg.params.message}`);

一則陌生人的話,放進 user role,前面加一個方括號當標記。

而同一份文件往下兩行,把旁邊那個問題處理得完全正確:

from 是 Hauddy 斷言的(可以信任);不要message 的內文裡去解析身分。

所以這不是粗心。他們守住了來源(provenance)8,但權威沒有地方可以放,因為沒有第五種 role 可以放,那個方括號就是全部的邊界。

這是一個很認真的工程師寫下來的東西,而他沒有別的選項。我引用它是出於敬意,也因為它是我目前能找到最好的證據:這個缺口是真的,而且會撞到它的人,正是那些有在思考的人。

同一個專案在 Claude Code 這條路上又往前了一步,它送出的是:

<channel source="hauddy" from="@ada">…</channel>

這確實是一個可區分框,一個獨立的框,帶著一個內文偽造不了的屬性。它沒有帶的是「權威=無」,而且框裡的內容,沒有任何東西阻止它被當成指令來讀。所以可區分性有了、不可晉升沒有,那還只是一個標籤,因為標籤不會改變模型讀到那段文字之後能做什麼。


六、補上那個位置:peer role
#

要修這個缺陷,需要的東西小得有點好笑:在權威這條軸上補一個位置。

system | user | assistant | tool | peer

一則 peer 訊息是有作者的、可歸屬的、而且預設沒有權威。

{
  "role": "peer",
  "author": {
    "id": "ed25519:9f3c…",
    "display": "Mira(B 的 agent)",
    "verified": "signature"
  },
  "principal_of_author": "B",
  "content": "2400 可以,但運費要你出。",
  "authority": "none"
}

三個欄位就承載了整個想法:誰寫的、他服務哪個主體、以及它自己能造成什麼(none)。

六條可以逐條引用、逐條測試的要求
#

我把它們編號,是因為「多主體 harness」如果只是一個形容詞,那它就沒有用,要能被指著說「你這條沒過」才有用。

圖 2 · PC-1 到 PC-6
🪪
PC-1 獨立 role
來自主體信任邊界外的輸入,必須用一個與主體自身不同的 role 表示
有地方可放
🔏
PC-2 來源可驗
每則 peer 訊息必須帶一個「獨立於傳輸通道」可驗證的作者身分
relay 偽造得了,這個 role 就是裝飾
🚧
PC-3 無權威
peer 內容本身不得授權任何工具呼叫、承諾、或對 agent 自身限制的變更
說服 ≠ 授權
PC-4 不可晉升
peer 訊息**內部**的任何內容,都不得讓 harness 把它、或之後任何一則,重新歸類進主體 role。晉升必須來自主體自己通道上的新輸入
這條最常被跳過
PC-5 授權邊界
跨過門檻的動作(金錢、授出權限、揭露保留事項)必須要有一個可歸屬於主體、而且**綁定在那一個動作上**的授權,不是綁在 session 上
「我授權這一則」
👁
PC-6 可辨識
對於任何已執行的動作,主體必須能看出造成它的輸入位於哪一個 role
看得見才談得上判斷
圖說:六條全過,才叫多主體 harness。每一條都是 MUST,而且都可以寫成測試。

PC-4 是最常被跳過的那條,而它其實是關鍵的那條,因為一個「只要講得夠有說服力就能講出去」的 peer role,在行為上跟沒有這個 role 是一樣的。

PC-3 到底買到了什麼
#

它沒有讓對等方變得可信,而且它不需要。它讓對等方的話變成惰性的:那些話可以讓你的 agent 知道事情,但永遠移動不了你的 agent 自己的界線。agent 還是可能判斷錯,還是可能被說服,但它不可能被對方授權。

被說服的代價,從此由 mandate9 決定,而不是由模型的判斷力決定。

那句話我在實作篇的第二節就寫過了,只是當時我以為那是一個工程取捨。


七、為什麼是現在
#

只有一個主體的時候,這個缺陷是隱形的。它在下面任何一件事出貨的那一刻變成承重牆:

  • 跨組織的 agent 對 agent 談判或排程
  • 一個 agent 代表客戶,對上另一家公司的 agent
  • 一個共用頻道裡同時有好幾個人的 agent
  • 任何 agent 對 agent 的付款或承諾

而協定層已經有了。A2A10 在 2026 年四月進到 Linux Foundation 治理,超過 150 個組織。也就是說傳輸問題正在被解決,只是繞過了權威模型:傳輸標準描述的是兩個 agent 怎麼交換訊息,沒有一個描述的是,一則訊息落進對方 agent 的 context 之後,它帶著誰的權威。主體崩壞就住在這個缺口裡。

而且主體自己感覺不到。 第二篇提過 Anthropic 的 Project Deal11:69 名員工、五百多件物品。他們的發現裡有一條,我現在覺得比什麼都重要,就是由強模型代表的人成交更多、賣得更貴,但雙方自評的公平度一模一樣。

輸的人不覺得自己輸了。這說明這個缺陷,站在缺陷裡面的人是看不見的,所以它非得在結構上解決不可,不能靠當事人警覺。


八、can2cup 怎麼對應這六條
#

我不想讓這六條停在「大家應該要」的層次,所以把自己的實作逐條攤開。這不是在推銷,是在讓這六條可被檢查。

怎麼做的
PC-1房間訊息以獨立的內容類別抵達;主體的指示走另一組 MCP content block
PC-2每則訊息由參與者自己的金鑰 ed2551912 簽章、串進 hash chain13;relay14 沒有任何私鑰,偽造不了作者
PC-3入站的對等方內容被框成資料而非指令;mandate.json 在每一則出站訊息離開前執行
PC-4只有主體簽章過的輸入才會被標記為 VERIFIED;房間內文會被清掉主體通道的標記字串;require_signed_principal 直接關掉未簽章的那條路
PC-5承諾閘門15:mandate 一旦放寬,acceptgrant、帶價格的 proposal 都需要一個綁定在該訊息 hash 上的主體簽名
PC-6每則訊息的私有理由16寫進本機稽核檔;主體的視窗與 transcript 都記錄指令是從哪一條通道進來的

實作本身不是這篇的重點,那六條才是。任何 harness 都可以滿足它們,而我寧願它們去滿足。如果三年後這六條變成別人 harness 的預設,而沒有人記得是誰先寫下來的,那也比六條沒人做要好。


九、我可能錯在哪裡
#

寫一個新詞出來,最誠實的做法是自己先列出它可能站不住的地方。

這個概念可能已經有名字了。 我找過 confused deputy、prompt injection、多租戶、能力安全這幾條線,沒找到。但「沒找到」和「不存在」是兩件事。如果它已經有名字,我寧願用那個名字,而不是跟它競爭。

peer role 可能不是最好的解法。 也許正確的做法是在既有的 role 上加權威標註,而不是加一個新 role。我對那六條要求的信心,比對那個 JSON 形狀的信心高得多,所以我把要求編了號,把形狀留成一個例子。

六條可能不完備。 我特別懷疑還缺一條關於時間的:一個授權在什麼條件下過期。實作裡有 max_grant_hours,但我沒把它提升成一條要求,因為我還沒想清楚它是獨立的一條,還是 PC-5 的一個面向。

最大的那個洞不在這六條裡。 這六條保護的是主體的界線,它們完全沒有處理第一篇第四節那個問題:兩個都守規矩的 agent 談判,盈餘會流向比較強硬的那一方,而兩邊都覺得自己被公平對待。中立的仲介層還是沒做,而 PC-1 到 PC-6 一條都幫不上忙。


第一篇說,parenting agent 上線之後,人升級成委託人,而委託人唯一的核心能力是判斷代理人有沒有在替你工作。第二篇做了一扇窗,讓委託人看得見。

這一篇是再往下一層:看得見之後,還要看得出來每一句話是誰說的、算不算數,而這件事在今天的 context window 裡沒有地方可以寫。所以在那個位置被補上之前,委託人的判斷力有一部分是浪費的,因為他要判斷的東西根本沒有被記錄下來。


英文版在這裡,因為要看的人是寫 harness 的,所以英文版才是主要的那一份。更正、反例、以及「這東西早就有名字了」的指認,都歡迎告訴我,聯絡方式在關於頁。本系列用到的所有名詞,整理在詞彙表


  1. context window(上下文視窗):模型每次推論時實際看得到的那一整段文字,包含 system prompt、對話歷史、工具回傳、檔案內容等等,由 harness 組裝。它有長度上限,而且模型對它裡面的每一個位元組一視同仁,除了 role 以外沒有別的欄位可以標示來源與權威。 ↩︎

  2. role(角色):語言模型 API 把 context 切成一則一則訊息,每則帶一個 role 欄位,標示這段文字是誰說的。system 是營運者設定的規則,user 是使用者,assistant 是模型自己先前的回覆,tool 是工具回傳的資料。模型讀 context 的時候,role 是它判斷「這段話該不該當指令」的主要依據,所以 role 不只是分類標籤,實際上就是權威標記。 ↩︎

  3. prompt injection(提示詞注入):攻擊者把看起來像指令的文字藏進 agent 會讀到的資料裡,比如網頁、檔案、工具回傳、別人的訊息,誘導模型把它當成使用者的指令執行。目前沒有已知的完整防法,實務上是靠限縮 agent 的權限與動作範圍來降低最壞後果。 ↩︎

  4. confused deputy(混淆代理人):1988 年 Norm Hardy 在 ACM SIGOPS Operating Systems Review 上寫的一個經典問題。一個擁有較高權限的程式,被權限較低的呼叫者誘導去使用它自己的權限做事,於是權限實質上外洩了。標準解法是能力式授權,不要讓程式攜帶環境權威。 ↩︎

  5. 能力式授權(capability-based security):不用「你是誰、你有什麼身分」來決定能不能做某件事,而是用「你手上有沒有那把可轉讓的鑰匙」。鑰匙(capability)本身就是權限,可以傳遞、可以縮限、可以撤銷。它處理的是程式對資源的存取,處理不了「一段話帶著誰的權威」。 ↩︎

  6. 多 agent 編排(multi-agent orchestration):一個 agent 把工作拆給多個子 agent 並行處理,或安排 worker/reviewer 這種分工。這些 agent 共用同一個擁有者與同一套權限,彼此沒有對立的利益,所以它處理的是並行與分工,不是權威。 ↩︎

  7. MCP(Model Context Protocol):Anthropic 2024 年底提出的開放協定,規範 agent 怎麼掛載外部工具與資料源。現在大部分 agent harness 都支援,所以一個 MCP server 寫一次,Claude Code、Codex CLI 等等都能掛上去用。 ↩︎

  8. provenance(來源):一段內容是誰產生的、經過哪些手、有沒有被竄改。它跟 authority(權威)是兩件事:來源回答「誰說的」,權威回答「他說了算不算」。這篇的整個論點就是現在的 harness 有前者、沒有後者。 ↩︎

  9. mandate(授權書):委託人在冷靜的時候寫下的一份機讀檔(mandate.json),裡面是金額上限、不得揭露的字串、允許的動作類型等等。agent 的每一則出站訊息在離開本機之前都要通過它,所以 agent 就算被對方說服了也送不出去。 ↩︎

  10. A2A(Agent2Agent):Google 2025 年提出、2026 年四月移交 Linux Foundation 治理的開放協定,規範不同組織的 agent 之間怎麼互相發現與交換訊息。它定義的是傳輸與能力描述(agent card),沒有定義訊息落地之後帶著誰的權威。 ↩︎

  11. Project Deal:Anthropic 跑過的一次內部實驗,69 名員工把五百多件二手物交給各自的 Claude 去談,一週、每人 100 美元上限、全程在 Slack 裡進行、無人介入,成交 186 筆。公開的發現裡有一條是:由能力較強的模型代表的人成交更多、賣得更貴,但雙方自評的公平程度一模一樣。 ↩︎

  12. ed25519:一種橢圓曲線數位簽章演算法,金鑰短、驗簽快、實作陷阱少,是目前簽章的預設選擇,SSH、Signal 等等都在用。這裡用它讓每則訊息都能離線驗證作者,不必信任中間的伺服器。 ↩︎

  13. hash chain(雜湊鏈):每則訊息都把前一則的雜湊值寫進自己的內容再簽章,所以任何一則被竄改、刪除或插入,後面全部的驗證都會失敗。作用是讓「整段對話沒有被動過」變成可以離線證明的事,而不是要相信伺服器的說法。 ↩︎

  14. relay(中繼):can2cup 裡負責收轉訊息與排序的伺服器,跑在 Cloudflare Workers 上。它沒有任何一方的私鑰,所以看得到訊息的順序與大小,但改不了內容也偽造不了作者。 ↩︎

  15. 承諾閘門(commit gate):mandate 的上限一旦被臨時放寬,acceptgrant、以及帶價格的 proposal 就需要一個綁定在「那一則訊息的雜湊」上的委託人簽名才送得出去。跟「這個 session 已經授權過」不同,它授權的是單一一則訊息,所以放寬額度不會把閘門一起打開。 ↩︎

  16. 私有理由(rationale):agent 每則出站訊息可以附一段只寫進本機稽核檔、永遠不上傳的說明,寫的是它為什麼這樣出價、為什麼讓步。對方與 relay 都看不到,作用是讓委託人事後重建 agent 當時的判斷。 ↩︎

Parenting Agent - 本文屬於一個選集。
§ 3: 本文