A2A 協定:打破 AI 溝通的高牆
03 Aug 2026
開了一間規模龐大的跨國企業,重金聘請全世界最頂尖的十位專家:精通量化分析的資料科學家、能寫出得獎文案的創意總監、執行力無可挑剔的專案經理。這個夢幻團隊理論上無堅不摧——但架構有個致命陷阱:這十位專家被分別關在十個完全隔音的獨立房間裡,而且每個人說著完全不同的語言。
當需要完成複雜的大型專案時,我們沒有辦法讓他們開會。只能自己跑去第一個房間要資料,再跑到第二個房間請人翻譯,翻完拿去分析,最後跑到第三個房間求人把結果寫成報告。夢幻團隊的潛力,全部被那堵無法溝通的無形高牆消耗殆盡。這正是目前企業級 AI 應用的殘酷現況。
單一 AI 的瓶頸
到了這個階段,為什麼我們會覺得單一超大型 AI 助理好像已經不夠用了?我們不是已經有參數動輒幾千億的大型語言模型了嗎?因為真實世界問題的複雜度正在指數級上升 – 一個單一的 AI 模型,無論參數多龐大,它的上下文空間、推理邏輯,甚至專業微調都有極限——它存在某種方向性。有的擅長寫文案,有的擅長分析數據。
當要求 AI 規劃一個完整的跨國供應鏈最佳化方案時,這已經不只是「幫我寫一段優美的文案」或「解析一段長程式碼」那麼簡單。它需要:
| 子任務 | 需要的專業 |
|---|---|
| 抓取即時全球天氣資料 | 氣象資料 API |
| 分析航運競爭對手定價 | 市場情報 |
| 預估匯率波動的財務成本 | 財務分析 |
| 產出策略報告 | 策略規劃 |
單一模型處理這種跨領域多步驟任務,不只容易產生幻覺(開始胡說八道),運算效率也極度不合理——不可能讓一個超大型模型去處理所有雞毛蒜皮的小事。所以開發者開始走向多代理(Multi-Agent)架構。市場上出現各種 AI 框架,像是 LangGraph、CrewAI,或是 Google 提出的 ADK(Agent Development Kit),用不同框架打造出各種極度專業的 AI 專家。
問題又回到開場的比喻:它們聽不懂彼此的語言。用 LangGraph 寫出來的資料分析 AI,在底層邏輯和資料格式上,聽不懂用 CrewAI 寫出來的規劃 AI 在說什麼。這不只是兩段程式碼接不起來的問題,而是整個企業想擴充自動化流程時會撞上的高牆。
A2A 協定:AI 之間的共通語
Google 提出的 A2A(Agent-to-Agent)協定,是一個基於 HTTP 的開放標準(HTTP 就是我們上網用的網頁通訊協定)。它的目的就是打破孤島,成為所有 AI 代理之間的共通語。用開場的比喻來說:A2A 協定就像是在那些隔音房間之間牽起實體的網路線,並且發給每個 AI 一台完美的通用翻譯機與任務指派系統。
這絕對不是只在實驗室自嗨的小眾技術,它解決的是實實在在的企業痛點,而且已經獲得業界巨頭的廣泛支援:
| 公司 | 動態 |
|---|---|
| Microsoft | 計劃將 A2A 整合進 Azure AI Foundry 與 Copilot Studio |
| SAP | 支援 A2A,並整合進自家平台與代理 |
| Salesforce | 支援 A2A |
| ServiceNow | 支援 A2A |
| Atlassian | 支援 A2A |
| Box | 支援 A2A |
| LangChain | 支援 A2A |
| MongoDB | 支援 A2A |
| Auth0 | 正在將 A2A 支援整合進平台與代理 |
連 SAP、Salesforce、ServiceNow 這種商用軟體巨頭都進來了,代表未來的企業後台,可能真的就是一堆 AI 在背景互相開會、協商。整個科技產業都意識到:我們談論的不再是單一使用者的單一 AI,而是如何管理幾千幾萬個微型代理,讓它們同時運作,形成模組化、可擴充的 AI 生態系統。
代理卡(Agent Card):AI 的數位身份證
在一個擁有數千個服務的 AI 網路裡,甚至是在茫茫網際網路大海中,AI 要怎麼知道誰具備什麼技能?如果彼此之間沒有一本共同的「黃頁目錄」,那條籤起來的網路線就毫無意義——總得知道要打給誰。這就帶出 A2A 協定的第二個關鍵概念:代理卡(Agent Card),AI 的數位身份證。
A2A 架構下有三個核心參與者:
發出需求的使用者
│
▼
客戶端代理 ──(A2A)──> 遠端代理(A2A 伺服器)
遠端代理對客戶端來說,是一個刻意設計成不透明(Black Box)的系統。客戶端代理在委派任務時,完全不需要知道遠端 AI 是用 Python 還是 Java 寫的,也不用管它背後跑的是 GPT-4 還是 Gemini。這就是系統解耦(Decoupling)的精髓——客戶端唯一需要解析的,就只有那張代理卡。
代理卡是一個標準化、結構化的 JSON 檔案,記錄了:
| 欄位 | 說明 |
|---|---|
| 端點 URL | 遠端 AI 的位址 |
| 版本 | 代理卡的版本,方便相容性管理 |
| 通訊能力 | 例如能否進行即時事件串流傳輸、推送通知、狀態轉移歷史 |
| 技能 | 它會做什麼,含輸入/輸出格式 |
| 認證要求 | 存取這個代理需要哪種身份驗證(例如 API Key) |
像資料提到的 weather 天氣代理,它的代理卡就會清楚標明:具備查詢天氣的技能,輸入地點(例如「巴黎的天氣如何?」),然後輸出對應的氣溫與降雨機率。
// 天氣代理的代理卡(agent-card.json)
type AgentCard = {
name: string
url: string
version: string
description: string
skills: Array<{
id: string
name: string
description: string
inputModes: string[]
outputModes: string[]
}>
capabilities: {
streaming: boolean
pushNotifications: boolean
stateTransitionHistory: boolean
}
authentication: {
schemes: string[]
}
defaultInputModes: string[]
defaultOutputModes: string[]
}
const weatherAgentCard: AgentCard = {
name: 'weather-agent',
url: 'https://weather.example.com/a2a',
version: '1.0.0',
description: '查詢全球即時天氣與降雨機率',
skills: [
{
id: 'check_weather',
name: 'check_weather',
description: '輸入地點,回傳氣溫與降雨機率',
inputModes: ['text'],
outputModes: ['text'],
},
],
capabilities: { streaming: true, pushNotifications: false, stateTransitionHistory: true },
authentication: { schemes: ['apiKey'] },
defaultInputModes: ['text'],
defaultOutputModes: ['text'],
}
代理發現:三種找名片的方式
遠端代理是一張靜態的 JSON 名片,那客戶端代理要怎麼在浩瀚的網路上動態發現這張名片?A2A 定義了三種明確的代理發現策略:
- 眾所周知的 URL(Well-Known URL):遠端代理把代理卡放在一個標準化的路徑下,例如網站根目錄的
/.well-known/agent.json,讓其他系統可以自動化爬取和識別。就像直接走到大廳的公佈欄去看名單。這適合完全公開的基礎服務。但如果牽涉到企業機密的財務分析,總不能把名片直接貼在大廳,讓網路上所有的爬蟲程式都看得到。 - 精選登錄檔(Selective Registry):集中式的目錄服務,就像企業內部的 App Store 或受嚴格控管的目錄服務。所有代理卡都必須經過稽核,發布到集中的登錄檔裡。客戶端代理可以根據特定標準查詢,例如「幫我找一個擁有存取 Q3 財報權限、而且回應延遲保證在一秒內的財務 AI」。這種模式非常適合企業環境,因為可以透過登錄檔進行嚴格的存取控制、版本管理和流量監控——就像企業內部有門禁的 AI 人才庫。
- 直接設定(Direct Configuration):如果兩個系統根本是同一個開發團隊寫的,只是拆成兩個微服務,有更直接的做法:開發者把遠端代理卡的資訊直接寫進程式碼或環境變數裡,完全不透過任何外部目錄。它們早就認識彼此,不需要在外面拋頭露面被別人發現,只需要專注於彼此溝通就好。
| 發現策略 | 方式 | 適合場景 |
|---|---|---|
| 眾所周知的 URL | /.well-known/agent.json |
公開的基礎服務 |
| 精選登錄檔 | 集中式稽核目錄 | 企業受控環境 |
| 直接設定 | 環境變數 | 緊密耦合的私有系統 |
非同步任務通訊:不是粗暴的 HTTP POST
透過三種策略,客戶端代理找到了對的 AI 專家、拿到了數位名片、知道輸入輸出格式。接下來它們具體怎麼對話?A2A 的通訊嚴格圍繞非同步任務(Asynchronous Task)建構。所有通訊透過 HTTP/HTTPS,資料層使用 JSON-RPC 2.0 協定。但 HTTP 本身是無狀態的,不會記住過去的對話。為了解決這個問題,伺服器每次接受任務時都會產生一個 Context ID,就像任務的追蹤號碼,用來保留長任務的上下文連貫性——寄包裹的追蹤碼。
這也帶出一個實用的能力:多輪對話(Multi-turn)。當遠端代理發現資訊不足、需要客戶端補資料時,它可以把任務狀態設為 input-required,明確回覆「還缺什麼」;客戶端補上資訊後,再以同一個 Context ID 續問。這讓 A2A 的互動不是一次性的問與答,而是可以來回補齊資料的完整協作流程。
四種互動機制:依任務輕重緩急選擇通訊方式
A2A 定義了四種互動機制,代理可以根據任務性質選擇最有效率的溝通方式。用點餐的經驗來比喻最容易理解:
| 機制 | 點餐比喻 | 技術 | 適合任務 |
|---|---|---|---|
| 同步請求/回應 | 得來速點餐 | 阻塞式 HTTP | 極快、立刻要結果的簡單任務 |
| 非同步輪詢 | 美食街叫號機 | Polling + Context ID | 中等耗時任務 |
| 串流更新 | 回轉壽司 | SSE(Server-Sent Events) | 生成式 AI、長文件輸出 |
| 推送通知 | 外燴送餐 | Callback URL | 跨天、資源密集型任務 |
同步請求與回應(得來速點餐)
在得來速點一份漢堡,把車停在窗口、引擎不熄火,什麼事都不做,死死盯著店員直到他把漢堡遞過來。技術上這就是阻塞型操作:客戶端發出 HTTP 請求後連線保持開啟,一直等到收到遠端代理完整的結果回應。
const response = await fetch('https://calculator-agent.example.com/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'req-001',
method: 'tasks/send',
params: {
id: 'task-001',
message: { role: 'user', parts: [{ text: '計算 2 + 2' }] },
},
}),
})
const result = await response.json() // 阻塞等待完整結果
很卡,但適合那些運算極快、立刻就要有結果的簡單任務。
非同步輪詢(美食街叫號機)
去百貨公司的美食街點餐,店員給一個會震動的叫號機。點完餐可以先去旁邊逛街,只是得偶爾低頭看叫號機亮了沒。客戶端可以先去執行其他工作,然後定期拿 Context ID 問伺服器「任務標記為完成了嗎?」。
但輪詢有致命傷:擴充性很差。在一個有一萬個微型代理的企業系統裡,每個客戶端代理每秒都去問伺服器「好了沒」,會產生巨大的無效網路流量,甚至造成伺服器崩潰。這就是 A2A 提供第三、四種更優雅機制的原因。
串流更新(回轉壽司)
坐在日式回轉壽司店的吧檯,師傅在裡面做壽司,做完一盤就直接推到軌道上送到面前,完全不需要一直開口問「好了沒」。只要軌道連線著,好料就會源源不絕主動送過來。
SSE 建立了一個持久的單向連線,這對生成式 AI 特別有用。遠端代理正在生成一份長達五十頁的報告時,不需要等全部寫完才回傳,而是寫完一段就透過 SSE 推送一段,客戶端代理就能即時處理這些增量結果。
const response = await fetch('https://report-agent.example.com/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'req-002',
method: 'tasks/sendSubscribe',
params: {
id: 'task-002',
message: {
role: 'user',
parts: [{ text: '生成一份 50 頁的市場分析報告' }],
},
},
}),
})
// 透過 SSE 串流接收增量結果,寫完一段處理一段
const reader = response.body?.getReader()
const decoder = new TextDecoder()
while (true) {
const { value, done } = await reader!.read()
if (done) break
processChunk(decoder.decode(value))
}
實務上,tasks/sendSubscribe 回傳的是標準 SSE 格式(event:/data: 欄位),不建議手刻解析器。用現成的 eventsource-parser(或 Node 端的 EventSource client)來拆解串流,既能正確處理多行 data,也少踩邊界案例的坑——上面的 getReader() 迴圈是示意「逐段處理」的思維,實作時換成解析器更穩。
推送通知(外燴送餐)
舉辦一場派對,請外燴公司。給他們地址和電話,告訴他們「菜全部做好再主動聯絡送到這個地址」,中間完全不用管他們怎麼煮,也不用開著連線等。
對於極耗時、甚至需要跨越多個日曆執行好幾天的資源密集型任務,保持連線或一直輪詢都太浪費網路資源。客戶端可以提供一個回覆網址(Callback URL),當遠端伺服器任務狀態發生重大改變或完成時,它會主動發送一個 HTTP POST 到那個網址來通知客戶端。
await fetch('https://research-agent.example.com/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'req-003',
method: 'tasks/send',
params: {
id: 'task-003',
message: { role: 'user', parts: [{ text: '模擬供應鏈風險分析' }] },
pushNotificationConfig: {
url: 'https://client.example.com/callback',
token: 'secret-token',
},
},
}),
})
跨模態的工件傳遞
A2A 協定有一個關鍵技術亮點:與模態無關(Modality Agnostic)。這代表 A2A 不只是用來傳遞程式碼指令或純文字結果。代理執行任務時產生的輸出,在 A2A 規範裡被統稱為 Artifact(工件)。這些工件不只是結構化的 JSON 資料——如果遠端代理是影像生成模型,它可以直接把高畫質圖片檔或音訊檔作為工件回傳。這大大省去人類在不同軟體間轉換格式的時間。
資料分析 AI 可以直接產出一支包含動態圖表的影片,直接作為工件交給簡報 AI 排版。這就是 A2A 跨模態的威力。
MCP vs A2A:向外看 vs 向內看
前陣子才大力推廣的 MCP(Model Context Protocol),跟 A2A 是不是在做同一件事?A2A 會不會是多餘的?
很多人會把兩者搞混,因為它們看起來都在解決 AI 溝通的問題。但實際上它們不僅不衝突,反而是完美的互補。簡單來說:MCP 的焦點是向外看,A2A 的焦點是向內看。可參考這裡-MCP:讓 AI 從只會聊天到真正做事。
| MCP | A2A | |
|---|---|---|
| 核心問題 | 單一 AI 如何存取外部系統 | AI 與 AI 如何協調委派 |
| 方向 | 向外看(代理 → 工具) | 向內看(代理 → 代理) |
| 比喻 | AI 拿工具的手 | AI 之間的橋樑 |
| 互動對象 | 非 AI 的外部系統、資料、工具 | 其他 AI 代理 |
MCP 專注於讓單一 AI 代理能與非 AI 的外部系統互動,為代理建立上下文——讀取本地端電腦的檔案、查詢第三方 SQL 資料庫。沒有 MCP,AI 就缺乏現實世界的資料。但當這個代理拿到 SQL 資料庫的資料後,如果需要把它交給另一個專門生成互動式圖表的 AI,MCP 就無能為力了。這時需要 A2A 登場——它專注代理與代理之間的協調與任務委派。沒有 A2A,AI 就永遠只能孤軍奮戰。
MCP:授權代理查詢企業內部 SQL 資料庫
↓ 撈出第一季銷售資料
A2A:使用 JSON-RPC 把原始資料打包
↓ 跨網路移交給託管在 Google Cloud 的視覺化代理
↓ 產出圖表 Artifact
兩者結合,才是企業級多代理生態系統的完整藍圖。
實作:日曆代理
Google 的 a2a-samples 儲存庫展示了具體的實踐範例——用 Python 和 Google ADK 建立的日曆代理(calendar agent),專門處理行程的微服務。我們改寫為 TypeScript:
import { LlmAgent } from '@google/adk'
// 官方 a2a-samples 是 Python 範例:
// from google.adk.tools.google_api_tool import CalendarToolset
// toolset = CalendarToolset(client_id=..., client_secret=...)
// tools = await toolset.get_tools()
// 此處以 TypeScript 示意對應的代理結構,
// getCalendarTools() 代表取得行事曆工具集的步驟
const calendarTools = await getCalendarTools()
// 建立配備 Gemini 模型的 LLM 代理
const calendarAgent = new LlmAgent({
name: 'calendar_agent',
model: 'gemini-2.0-flash-001',
instruction: '行事曆助理,負責查詢與安排行程。',
tools: calendarTools,
})
// 3. 代理卡中明確定義「檢查可用性」技能
const calendarAgentCard = {
name: 'Calendar Agent',
url: 'http://localhost:8000/',
version: '1.0.0',
description: '管理行事曆行程',
skills: [
{
id: 'check_availability',
name: 'check_availability',
description: '檢查指定時間是否可預約',
inputModes: ['text'],
outputModes: ['text'],
},
],
capabilities: { streaming: true, pushNotifications: false },
}
其他客戶端 AI 就可以透過 A2A 發現這個日曆代理,送出 JSON-RPC 請求呼叫 check_availability,問「下週二下午三點有空嗎?」:
const response = await fetch('http://localhost:8000/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'req-010',
method: 'tasks/send',
params: {
id: 'task-010',
message: {
role: 'user',
parts: [{ text: '下週二下午三點有空嗎?' }],
},
},
}),
})
開發者還推薦使用 Trickle AI 工具。當多個代理透過非同步 JSON-RPC 互相丟訊息時,出錯會變成一場惡夢,根本不知道誰丟給誰。Trickle AI 可以將底層的 A2A 通訊視覺化,清楚看到哪個代理呼叫了誰、帶了什麼參數。
企業級安全防線
任何代理都可以透過 HTTP 呼叫另一個代理的 API,如果未經授權的外部 AI 代理突然呼叫了日曆代理,甚至利用漏洞修改行程怎麼辦?機器與機器之間的信任機制是核心問題。A2A 沒有把安全當做事後補充的選項,而是把它放在架構的核心位置——它不是一個門戶洞開的 API 系統。有四道防線:
防線一:mTLS 雙向驗證
┌──────────┐ 憑證 ┌──────────┐
│ 客戶端AI │ ◄──────────────────► │ 日曆代理 │
│ 出示憑證 │ │ 出示憑證 │
└──────────┘ └──────────┘
通訊雙方都必須證明真實身份
防線二:全面的稽核日誌
所有代理間通訊:哪個 Context ID、幾毫秒、傳了什麼任務、
帶了什麼工件,通通鉅細靡遺記錄
防線三:代理卡聲明認證要求
代理卡上明確列出存取需要的身份驗證方式,集中管理
防線四:憑證只放 HTTP Header
OAuth token 只能透過 Header 傳遞,禁止放 URL 或 Body
第一道防線:mTLS(相互傳輸層安全性)。一般瀏覽網頁看到的鎖頭是 TLS,只有伺服器向客戶端證明身份。但在 mTLS 中,通訊的雙方都必須出示由受信任的憑證機構頒發的加密憑證——不只伺服器要自證清白,客戶端也要。這就像一種只有授權 AI 才擁有的秘密握手,徹底防堵偽造身份的流氓代理。雙向驗證是微服務架構的黃金標準。
第二道防線:全面的稽核日誌。A2A 規範了所有代理間通訊——哪一個 Context ID、在什麼毫秒傳送了什麼任務、帶了什麼工件,全部都要記錄下來。反走過必留下痕跡。發生越權存取時,資安團隊就可以沿著 JSON-RPC 的呼叫鏈,一路追蹤回最原始的發起者。
第三道防線:代理卡聲明認證要求。前面介紹代理卡時提到它記錄了身份驗證方式(authentication 欄位)——這不是擺好看的。把認證要求集中寫在代理卡上,等於每一張代理卡都內建了「要進這扇門得先出示哪種鑰匙」的門禁清單,客戶端不用猜、也不用私相授受,身份驗證的管理因此集中且可稽核。
第四道防線:憑證只放 HTTP Header。A2A 嚴格禁止把密碼或 token 放在 URL 或訊息 Body 裡。為什麼差很多?因為企業 IT 架構中,應用程式防火牆和負載平衡器通常會記錄 HTTP 的 URL 和訊息正文來除錯。如果把金鑰放在 Body,很容易在系統日誌中以明文暴露——任何 IT 人員看 log 就把密碼看光了。把憑證隔離在 HTTP Header,底層網路裝置記錄日誌時就能輕易遮蔽過濾,確保機密授權資料不會外流。
何時該用 A2A:經驗法則
看完這些能力,什麼情況才需要把 A2A 請出來?基本判斷很簡單:當需要協調兩個或兩個以上、而且很可能用不同框架打造的 AI 代理一起協作時,就用 A2A。具體來說,它特別適合:
- 多框架協作:團隊同時用了 ADK、LangGraph、CrewAI,各自的代理需要互相溝通
- 複雜工作流程編排:一個代理做資料收集、委派給另一個做分析、再委派給第三個產出報告
- 動態資訊檢索:主代理需要即時向專門的「資料獲取代理」要最新資料
但要注意的是,只有單一代理、或代理之間關係固定不會變動時,A2A 就是殺雞用牛刀。A2A 的價值在於「跨框架、動態發現、可擴充」——如果這些都不是我們的痛點,用程式直接呼叫彼此的方法還更快更簡單。就像開場的比喻,只有當夢幻團隊真的需要互相開會時,才值得牽起那些網路線。
對 UI/UX 的影響:讓多代理協作看得見
多代理在背景互相開會、委派任務,但人類使用者最怕的就是「不知道它到底在幹嘛」。A2A 系統的 UI/UX 核心是透明度與信任。
代理網路視覺化
Trickle AI 這種工具讓開發者看到 A2A 通訊,企業使用者也需要看到任務被怎麼探討與委派。以供應鏈分析儀表板為例:
┌─────────────────────────────────────────────────────────┐
│ 🔗 多代理協作視圖 │
├─────────────────────────────────────────────────────────┤
│ │
│ 使用者請求:分析跨國供應鏈最佳化方案 │
│ │
│ 主控代理 ──┬── 委派 → 天氣代理(即時天氣) ✓ 完成 │
│ │ │
│ ├── 委派 → 航運分析代理(對手定價)✓ 完成 │
│ │ │
│ ├── 委派 → 財務代理(匯率波動) ✓ 完成 │
│ │ │
│ └── 彙整 → 策略報告 ⏳ 生成中 │
│ │
│ ┌─ 委派鏈追蹤 ────────────────────────────────────┐ │
│ │ 主控 → 財務代理 [Context: ctx-001, 0.8s] │ │
│ │ 財務 → 匯率API [Context: ctx-002, 1.2s] │ │
│ │ 憑證:mTLS ✓ | 稽核日誌已啟用 ✓ │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
委派決策的可解釋性
當主控代理自主動態發現並委派任務時,UI 應該呈現「為什麼選這個代理」。以企業登錄檔搜尋為例:
┌─────────────────────────────────────────────────────────┐
│ 🔍 代理委派決策 │
├─────────────────────────────────────────────────────────┤
│ │
│ 需求:需要一個能存取 Q3 財報的財務分析 AI │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ [1] finance-analyst-v2 ★ 已稽核 │ │
│ │ 存取權限:Q3 財報 ✓ | 延遲保證:0.8s │ │
│ │ 信任分數:98 | 上次稽核:2026-07-28 │ │
│ │ │ │
│ │ [2] quick-math-agent 未稽核 │ │
│ │ 存取權限:Q3 財報 ✓ | 延遲保證:0.3s │ │
│ │ 信任分數:32 | 無稽核紀錄 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 🤖 已自動選擇 [1] finance-analyst-v2 │
│ (較慢但已稽核,符合企業安全政策) │
│ │
│ ┌──────────────┐ ┌────────────────────┐ │
│ │ 改用 [2] │ │ 查看稽核日誌 │ │
│ └──────────────┘ └────────────────────┘ │
└─────────────────────────────────────────────────────────┘
安全事件的可見性
mTLS、稽核日誌這些安全機制,也應該轉化為使用者能理解的介面,而不是只存在於後台 log 裡:
┌─────────────────────────────────────────────────────────┐
│ 🛡 代理間信任狀態 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ mTLS 雙向驗證 ┌──────────┐ │
│ │ 主控代理 │ ◄───────────────► │ 財務代理 │ │
│ │ 憑證✓ │ 加密通道已建立 │ 憑證✓ │ │
│ └──────────┘ └──────────┘ │
│ │
│ 本日代理間通訊:1,284 筆 │
│ ✓ 已稽核通訊:1,284 筆(100%) │
│ ⚠ 異常嘗試:0 筆 │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ 查看完整稽核日誌(1,284 筆) │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
前後端技術怎麼落地:讓代理網路看得見
前面幾個 UI 設計決策把「透明度與信任」講得很美,但實際要怎麼做出來?多代理通訊不像一般 API 呼叫——它橫跨多個伺服器、有非同步委派、有憑證與稽核,這些資料天生就分散在各個代理身上。要讓前端畫得出來,後端必須先把「分散的通訊軌跡」彙整成一條可以串流的事件流。
後端:把分散的通訊軌跡彙整成事件流
A2A 的 UI/UX 影響有一個核心難題:代理通訊資料不在一台機器上。主控代理在 A 伺服器,財務代理在 B 伺服器,匯率 API 在 C 伺服器——每個節點只知道自己的那一段。如果每個代理各回各的 log,前端根本拼不出「主控 → 財務 → 匯率API」這條完整委派鏈。
解法是讓後端把每個代理的執行階段當作事件,統一彙整後透過 SSE(Server-Sent Events) 推送:
// 後端:委派鏈追蹤服務,彙整各代理的階段事件
import { createServer } from 'node:http'
const agents = new Map<string, { name: string; status: string }>()
createServer(async (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
})
const send = (event: string, data: unknown) => {
res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`)
}
// 每個代理執行時回報自己的狀態,由後端統一彙整
send('agent-status', {
chain: [
{ id: 'ctx-001', from: '主控代理', to: '財務代理', durationMs: 800, status: 'done' },
{ id: 'ctx-002', from: '財務代理', to: '匯率API', durationMs: 1200, status: 'done' },
{ id: 'ctx-003', from: '主控代理', to: '策略報告', status: 'running' },
],
security: { mTLS: true, audited: 1284 },
})
// 代理完成時即時更新
agents.set('strategy-report', { name: '策略報告', status: 'done' })
send('agent-status', {
chain: [{ id: 'ctx-003', from: '主控代理', to: '策略報告', status: 'done' }],
security: { mTLS: true, audited: 1285 },
})
send('done', {})
})
關鍵不是用了什麼協定,而是後端把分散在 A、B、C 三台伺服器的執行階段,彙整成一條有先後順序的委派鏈——前端才畫得出「主控 → 財務 → 匯率API」這張網。如果沒有這層彙整,每個代理各自為政,介面就只能顯示「任務處理中」這個空泛的狀態。
前端:把事件流畫成代理網路
後端把事件送出來了,前端的工作是把事件流渲染成看得懂的代理網路:
// 前端(React):把委派鏈事件渲染成節點圖
import { useEffect, useState } from 'react'
type AgentStep = { id: string; from: string; to: string; status: string }
function AgentNetwork() {
const [chain, setChain] = useState<AgentStep[]>([])
const [mTLS, setMTLS] = useState(false)
useEffect(() => {
const es = new EventSource('/api/delegation-chain')
es.addEventListener('agent-status', (e) => {
const data = JSON.parse(e.data)
setChain((prev) => [...prev, ...data.chain])
setMTLS(data.security.mTLS)
})
return () => es.close()
}, [])
return (
<div className="agent-network">
{chain.map((step) => (
<div key={step.id} className={`step ${step.status}`}>
{step.from} → {step.to}
{step.status === 'done' ? ' ✓' : ' ⏳'}
</div>
))}
<div className="security">
{mTLS ? '🔒 mTLS 雙向驗證已建立' : '⚠ 加密通道未建立'}
</div>
</div>
)
}
注意幾個設計決策:
| 前端手法 | 對應的 UI/UX 效果 |
|---|---|
EventSource 訂閱委派鏈事件 |
委派過程即時出現,而不是等全部完成才顯示 |
每步 ✓ / ⏳ 狀態標記 |
使用者一眼看到「進行到哪一步」,等待變可預期 |
| 安全狀態獨立渲染 | mTLS、稽核這些機制不只存在後台 log,而是變成介面上的視覺訊號 |
| 委派鏈依序堆疊 | 把分散的代理呼叫,拼回「主控 → 財務 → 匯率API」的因果順序 |
判斷在後端,呈現在前端
最後一個重點跟 RAG 那篇一樣:前端絕對不能自己決定「該選哪個代理」。前面 委派決策的可解釋性 說的「採用已稽核的 finance-analyst-v2」這種判斷,必須在後端用確定性規則(稽核狀態、信任分數、安全政策)算好,前端只負責把結果和理由畫出來。選代理的邏輯放在後端,才能跟 UI 分開測試、被其他系統(排程、報表)重複使用。
正確的分工是:
後端(資料與判斷) 前端(呈現與互動)
┌───────────────────────┐ ┌───────────────────────┐
│ 彙整代理通訊軌跡 │ │ 渲染委派鏈節點圖 │
│ 依安全政策挑選代理 │───▶│ 呈現信任分數與稽核狀態 │
│ 產生稽核日誌事件 │ │ 可展開的委派決策面板 │
│ 記錄憑證與 mTLS 狀態 │ │ 渲染安全事件警示 │
└───────────────────────┘ └───────────────────────┘
只管「誰能做、做了沒」 只管「怎麼呈現」
多代理協作最容易失控的地方,就是「每個代理各講各的話,使用者聽不懂」。後端把分散的委派與安全事件彙整成結構化資料,前端再把這些資料畫成節點圖與狀態標記——兩邊各司其職,透明與信任才真的做出來,而不是停留在設計稿上。
總結
A2A 協定為下一個世代的超級自動化鋪平標準化道路:
- 打破孤島:以 HTTP + JSON-RPC 2.0 成為不同 AI 框架之間的通用語言
- 代理卡:AI 的數位身份證,記錄技能與輸入輸出格式
- 三種發現策略:眾所周知 URL、精選登錄檔、直接設定
- 四種互動機制:依任務輕重緩急選擇同步、輪詢、串流或推送通知
- 與 MCP 互補:MCP 是拿工具的手,A2A 是代理之間的橋樑
- 企業級安全:mTLS 雙向驗證、稽核日誌、代理卡認證聲明、Header 憑證管理
在不遠的將來,數位助理不再是一個單打獨鬥的個體。當丟出一個極度複雜的商業需求,AI 助理會自動在背景解析任務、搜尋目錄、跨越不同的伺服器與平台,組建一個由各種專屬 AI 構成的臨時「超級專家大腦」,行雲流水地完成從資料分析到圖文產出的所有工作流程。
但這也留下一個值得深思的治理問題:當主控 AI 為了追求最高效率,自主動態發現並委派任務給一個登錄檔中完全未經人類事先審查、但透過 A2A 溝通無礙的陌生遠端 AI,會發生什麼事?回顧開場的比喻——如果這些專家為了完成專案,自己決定透過網路線引進外部未知的專家系統來處理機密資料呢?
技術標準給了 AI 建立無限橋樑的能力,但這張由機器自主編織出來的網路,最終拓撲結構可能遠超人類最初的設計。當 AI 開始繞過人類的管理層,建立起屬於它們自己的專家社交圈與信任網路時,我們還能完全掌握這個自動化工作流程的內部邏輯與邊界嗎?這值得我們在擁抱自動化的同時,持續保持警惕與思考。