定位:Agent ↔ Agent 的互通協定
MCP 篇把「Agent 怎麼接工具」講清楚了;本篇換一層——當兩個(或多個)Agent 要彼此委派工作時,它們要講什麼共同語言。
《Model Context Protocol(MCP)深度解析》解決的是 M 個 Agent × N 個工具 的插拔問題:每個應用講 MCP、每個工具用 MCP server 暴露,整合成本從 M × N 收斂成 M + N。但真實系統很快會碰到下一層爆炸——不是「Agent 接工具」,而是「Agent 委派給另一個 Agent」:客服 Agent 要把訂單爭議丟給帳務 Agent、研究 Agent 要把法規審核丟給合規 Agent、編排 Agent 要把跨系統流程拆給多個專責 Agent。
若每一對 Agent 都各自約定 API、狀態碼與回報格式,成本又會逼近 K × K(K 個可互操作 Agent)。Agent-to-Agent Protocol(A2A)就是為這一層設計的開放標準:讓不同框架、不同語言、不同供應商做出來的 Agent,能用同一套「發現能力 → 委派任務 → 追蹤狀態 → 取回產物」的契約協作。它由 Google 於 2025 年提出並開源,後續移交 Linux Foundation 維護;核心承諾同樣一句話:
兩套協定不互相取代,而是疊在不同邊界。一個 Agent 對外部工具/資料源用 MCP;對另一個 Agent用 A2A。對方 Agent 內部怎麼推理、怎麼用自己的 MCP tools,委派方完全不必知道——它只透過 A2A 看到「這個 Agent 有哪些 skills、任務現在什麼狀態、結果 artifact 是什麼」。把兩層拆開,才能同時享受「工具生態」與「Agent 生態」的插拔,而不把兩邊的關注點揉成一團膠水。
同一條業務流程裡兩層常同時出現:編排 Agent 用 A2A 委派給專責 Agent;專責 Agent 內部再用 MCP 呼叫工具。本篇只展開 A2A 那一層。
| 常見誤解 | 實際上 | 那是誰的守備 |
|---|---|---|
| A2A 是另一套 MCP | 不是。MCP 標準化「接工具」;A2A 標準化「委派給另一個 Agent」——邊界、單位、生命週期都不同 | 本篇全文 |
| A2A 是一個 Agent 框架 | 不是。它不規定 Agent Loop、不規定記憶體、不規定用哪個 SDK;它只規範 Agent 對外可互通的契約 | 編排/Runtime → Agent 編排篇、Agent Runtime 篇 |
| 有了 A2A 就不用自己做狀態機 | 不是。A2A 定義的是任務狀態的互通表示;每個 Agent 內部怎麼跑、怎麼重試,仍是自己的 runtime 責任 | Agent Runtime 篇 |
| A2A 取代了訊息佇列 | 不是。長任務仍可掛在 MQ/workflow 之上;A2A 是 Agent 之間的語意契約,不是底層 broker | 基礎設施選型 |
先記住這四條「不是」:A2A 是對等 Agent 之間的發現與委派協定,一層薄契約,專門解「跨框架、跨廠商怎麼一起做事」。
Agent Card:自我描述與 Discovery
在委派之前,你得先知道對方是誰、能做什麼、怎麼連。Agent Card 就是這張「對外名片」。
A2A 的入口是一份 JSON 中繼資料,稱為 Agent Card。習慣上掛在可預測的 well-known 路徑(常見為 /.well-known/agent.json 或同等的 Agent Card URL),讓呼叫端只要知道對方的網域或 Card URL,就能拉回這份自我描述。它扮演的角色,很像 REST 世界的 OpenAPI:不執行工作本身,但把「能做什麼、怎麼認證、端點在哪」講清楚。
| 欄位群 | 典型內容 | 為什麼重要 |
|---|---|---|
| 身分 | name、description、version |
人類可讀的定位;版本用於相容判斷 |
| 端點 | 服務 URL/JSON-RPC 入口 | 後續 message/send 等呼叫要打哪裡 |
| Skills | 可委派的能力清單(id、說明、輸入輸出型態) | 呼叫端據此決定「這件事該不該丟給你」 |
| Auth | 支援的認證方案 | 沒談妥認證,後面的 Task 根本送不出去 |
| Capabilities | 串流、推播、多模態等協定能力 | 決定用同步回覆、SSE 串流,還是 webhook 推狀態 |
{
"name": "compliance-agent",
"description": "審核合約條款是否符合內部政策",
"url": "https://agents.example.com/compliance",
"version": "1.2.0",
"skills": [{
"id": "review-contract",
"description": "對合約 JSON 做政策檢查,回傳 pass/fail 與理由",
"inputModes": ["application/json"],
"outputModes": ["application/json", "text/plain"]
}],
"authentication": { "schemes": ["bearer"] },
"capabilities": { "streaming": true, "pushNotifications": true }
}
真實 Card 欄位會依規格版本更細;重點是「可被機器讀取的自我描述」,不是給人類看的 README。
A2A 的健康路徑幾乎永遠是:取得 Card → 對齊 skill/auth/capabilities → 再送第一則委派訊息。跳過 Card 直接硬打端點,等於放棄動態發現:對方改了 skill 名稱、關掉串流、換了認證方案,你都會在執行期才爆。Card 也可以由 registry/目錄服務彙整,但語意上仍是同一份文件——只是取得管道從「打 well-known」變成「查目錄」。
well-known 路徑降低了發現成本,也把攻擊面攤開:攻擊者可以掛一份假 Card,把流量導向惡意端點。生產環境應把 Agent Card 納入既有的信任鏈(TLS、簽章 Card、允許清單、內部服務網格等),協定本身給你互通格式,不自動給你信任。這點與 MCP「協定 ≠ 安全機制」是同一類提醒。
Task Lifecycle:委派工作的狀態機
A2A 把每一次跨 Agent 工作包成一個有明確狀態的 Task——這是它與「打一次 RPC 就結束」最大的差異。
在 A2A 裡,互動的單位不是「一次 request/response」,而是一個有 id、有狀態、可長跑的 Task。呼叫端送出委派後,遠端 Agent 回的是 Task(或其串流事件),狀態沿一條定義好的狀態機前進。這讓「查一下天氣」與「審核一份要跑兩天的合規流程」能共用同一套契約。
stateDiagram-v2
state "auth-required" as authReq
state "input-required" as inputReq
[*] --> submitted
submitted --> working: 開始執行
submitted --> authReq: 需授權
submitted --> rejected: 拒收
authReq --> working: 補授權
working --> working: 進度/產出
working --> inputReq: 缺資料
inputReq --> working: 補資料
working --> completed: 交卷
working --> failed: 失敗
working --> canceled: 取消
completed --> [*]
failed --> [*]
canceled --> [*]
rejected --> [*]
看兩個地方:authReq/inputReq 都有一條回到 working 的箭頭——它們是可恢復的中斷,不是終態;而四個終態只出得去([*]),沒有任何箭頭回到中間態,這就是「終態不可變」的圖形化寫法。
| 狀態 | 類型 | 意義 |
|---|---|---|
submitted |
進行中 | 任務已被接受,尚未開始實質處理 |
working |
進行中 | 遠端 Agent 正在執行 |
input-required |
可恢復中斷 | 缺資料/缺確認;呼叫端補訊息後可繼續(同 taskId) |
auth-required |
可恢復中斷 | 需要額外授權才能繼續 |
completed |
終態 | 成功結束;結果通常以 Artifact 呈現 |
failed / canceled / rejected |
終態 | 失敗、被取消、或一開始就被拒絕;終態後 Task 不可變 |
一旦進入 completed/failed/canceled/rejected,這個 Task 就鎖死了——不能再塞訊息「修一下結果」。若要在既有結果上 refinement,規格的做法是:用同一個 contextId 開新的 Task,延續對話脈絡,但不破壞舊 Task 的不可變性。這對審計與重放極重要:你永遠能指出「當時那次委派的最終狀態是什麼」。
狀態如何回報?A2A 支援幾種模式,呼叫端依 Agent Card 的 capabilities 選擇:
| 模式 | 適合 | 行為 |
|---|---|---|
| 同步回覆 | 短任務 | 一次 message/send 就拿到接近終態的 Task |
| SSE 串流 | 需要過程可見 | 先回 Task,再串流 TaskStatusUpdateEvent/TaskArtifactUpdateEvent |
| Push/Webhook | 長跑、呼叫端不想掛連線 | 遠端在狀態變更時主動推通知 |
三種模式共用同一套 Task 狀態語意;差在「狀態怎麼送到呼叫端」,不是另一套生命週期。
submitted → working,可經 input-required/auth-required 中斷恢復,終態為 completed/failed/canceled/rejected 且不可變。同步、SSE、push 只是回報通道,狀態語意相同。
委派與回報:Message、Parts、Artifact
狀態機告訴你「走到哪」;真正承載工作內容的,是 Message 與最終的 Artifact。
跨 Agent 交換的內容被拆成幾個清晰物件:
| 物件 | 角色 | 常見內容 |
|---|---|---|
| Message | 一輪對話/指令 | 使用者或 Agent 發出的請求、補充、澄清;帶角色與 parts |
| Part | 訊息的型別化片段 | TextPart(自然語言)、DataPart(結構化 JSON)、檔案/多模態等 |
| Task | 工作容器 | id、status、關聯的 messages/artifacts |
| Artifact | 產出物 | 審核報告、產生的檔案、結構化結果——任務「交卷」的東西 |
一條典型委派時序(也是第 5 節 Demo 要逐步走的路徑)大致如下:
- 發現:Client Agent 取得 Remote Agent 的 Agent Card,確認有目標 skill。
- 送出委派:對 Remote 端點送
message/send(或串流變體),帶上初始 Message(例如「請審核這份合約」+ DataPart)。 - 建立 Task:Remote 回傳 Task,狀態進入
submitted/working。 - 狀態回報:透過同步結果、SSE 事件或 push,更新
TaskStatusUpdateEvent。 - (可選)中斷補料:若進入
input-required,Client 再送一則同taskId的 Message 補資料。 - 交卷:終態
completed,並附上 Artifact(或失敗時的錯誤資訊)。
把 A2A 想成「遠端 function call」會低估它:function call 預設短、同步、參數固定;A2A Task 預設可以長跑、中斷、多輪、產出多個 artifact。面試時若被問「為什麼不直接 REST 打過去」,好答案是:REST 也能傳 JSON,但你沒有標準化的發現名片、任務狀態機、串流/推播回報、終態不可變——每一對 Agent 又得重發明一次。
委派方不該關心對方內部用了哪個 MCP server、哪個 tool schema。A2A 邊界上交換的是業務意圖與產物(「審這份合約」「這是 pass/fail 報告」);對方 Agent 內部怎麼用工具完成,是它自己的事。把 MCP payload 穿透塞進 A2A,等於把兩層協定黏死,失去「換掉內部工具實作也不影響對等契約」的好處。
message/send → 狀態事件 →(可選 input-required)→ completed + artifact。
互動 Demo:驅動一個 Task 走完生命週期
狀態機不是拿來看的,是拿來撞的:同一個事件在不同狀態下合不合法、合法時帳目怎麼變。
場景設定:Orchestrator Agent(Client)把「審核合約 CTR-2048」委派給 Compliance Agent(Remote)。下面這台模擬器沒有劇本——你先設定條件(回報通道、輪詢間隔、remote 預計工時、此 skill 是否需要額外授權),然後自己決定每一步要注入哪個事件。事件是否合法由轉移表判定;狀態、耗時、三種回報通道各需幾次請求,全部即時算出。
圖上畫出最常走的 11 條轉移;fail/cancel 從任何非終態都合法,走到未畫出的轉移時只會高亮節點。真正的判準是轉移表,不是這張圖的線。
與 MCP 共存、取捨與面試考點
什麼時候該用 A2A、什麼時候其實只需要 MCP 或內部函式呼叫?把選型邊界講死,面試才答得乾淨。
| 情境 | 偏向 | 理由 |
|---|---|---|
| 同一個進程內的子模組協作 | 內部 API/函式 | 沒有跨邊界互通需求,上協定只增加序列化與運維成本 |
| Agent 要呼叫外部工具/資料源 | MCP | 需要的是工具發現與呼叫契約,不是對等 Agent 的 Task lifecycle |
| 跨團隊/跨框架/跨供應商的 Agent 委派 | A2A | 需要標準名片、任務狀態、長跑回報與產物格式 |
| 專責 Agent 內部再打工具 | A2A 外 + MCP 內 | 對等邊界用 A2A;工具邊界用 MCP——兩層疊加,各管各的 |
選型口訣:工具邊 → MCP;對等 Agent 邊 → A2A;同進程邊 → 別硬上協定。
Q1:A2A 和 MCP 差在哪?邊界不同——A2A 是 Agent↔Agent(Task、Card、長跑狀態);MCP 是 Agent↔工具(primitives、同步 tool call)。
Q2:為什麼 Task 要有 input-required?對等協作常缺上下文;可恢復中斷讓多輪補料留在同一個 taskId,不必假裝一次 RPC 就能做完。
Q3:終態為什麼不可變?為了審計與重放: refinement 開新 Task(可共用 contextId),舊委派的最終狀態永遠可指認。
A2A 讓異質 Agent 說同一種話,但不自動處理授權範圍、資料外洩、惡意 Card、過度委派。生產上仍要:允許清單、最小權限、簽章/mTLS、審計日誌、對 Artifact 做內容檢查。協定解決的是互通;安全政策仍是宿主與平台的責任。
收束:你現在能畫出的那張圖
把本篇壓成一張心智圖,接上 ACP 互通篇那張三協定對照表時才站得穩。
讀完本篇,你應該能在白板上快速畫出:
- 兩層邊界:Agent↔Agent 用 A2A;Agent↔工具用 MCP。
- 發現:先拉 Agent Card(well-known/目錄),對齊 skills、auth、capabilities。
- 委派:
message/send建立 Task;用 Message/Parts 傳意圖與資料。 - 生命周期:
submitted → working,可經input-required恢復,終態不可變並以 Artifact 交卷。 - 回報通道:同步/SSE/push 共用同一套狀態語意。
下一篇《ACP 與 Agent 互通協定對照》會把 MCP/A2A/ACP 放在同一張選型表——本篇請把「A2A 這一格」記牢:它解決的是對等 Agent 如何發現彼此、委派任務、回報狀態,而不是工具插拔,也不是單一 runtime 怎麼跑。