將 A2A 與既有代理框架整合:Hermes Agent 示範
為什麼 A2A 對代理編排很重要
Agent2Agent 協定(A2A)是 Google 於 2025 年 4 月提出的開放標準,用於代理間通訊。它定義了一個 AI 代理如何發現另一個代理的能力、向它發送任務、接收串流輸出,並在任務的生命週期中追蹤狀態——全部透過 JSON-RPC 2.0 進行,且不假設雙方代理共用同一個框架、同一個模型提供者,或同一個部署拓撲。
A2A 填補了 MCP 未涵蓋的缺口。MCP 將代理連接到工具和資料來源——它是一個工具呼叫協定。A2A 則將代理連接到代理。一個需要特定能力(定價邏輯、目錄搜尋、RFQ 處理)的代理,可以將工作委派給透過 A2A 端點暴露該能力的遠端代理,以 A2A 任務的形式接收結果,然後繼續自己的工作流程。兩個協定是互補的:MCP 給代理雙手;A2A 給代理同事。
A2A 規範定義了三個核心原語:
- Agent Card — 一個位於
/.well-known/agent-card.json的 JSON 文件,描述代理的身分、能力、技能和服務端點。這是代理之間互相發現的方式。 - Task — 工作單元。用戶端透過
message/send(非串流)或message/stream(串流)發送任務。任務在狀態之間轉換:submitted、working、input-required、completed、failed、canceled。 - Artifact — 任務執行過程中產生的結構化輸出,在可用時即串流傳送給用戶端。
對於 B2B 部署而言,價值主張很明確:與其建構一個做所有事的單體代理,不如組合各自擁有一個領域的專用代理——它們透過協定協調,而非透過共享記憶體或硬編碼的函式呼叫。
整合問題
大多數既有的代理框架不支援 A2A。它們有自己的原生 API 介面、自己的任務模型、自己的串流機制。Hermes Agent(由 Nous Research 開發)在 /v1/chat/completions 暴露了一個 OpenAI 相容的 API Server,以及一個基於 run 的 SSE 串流介面,位於 /v1/runs 和 /v1/runs/{id}/events。OpenClaw 在 POST /v1/responses 提供了一個 OpenResponses 相容 API。LangGraph 有自己的圖表執行模型。CrewAI 有自己的 crew 調度。
這些框架都不會為了支援 A2A 而重寫內部。它們也不應該這樣做——它們的原生 API 很好地服務了自己的生態系。問題是:它們能否在不改變自身程式碼的情況下參與 A2A 代理網路?
答案是一個橋接層——一個位於 A2A 協定和框架原生 API 之間的元件。橋接層一端實作 A2A 的 JSON-RPC 介面(Agent Card、任務生命週期、串流),另一端轉譯為框架的原生呼叫。框架不知道自己正透過 A2A 被呼叫。A2A 用戶端也不知道是哪個框架在執行任務。
本文以 Hermes Agent 為示範,走過橋接模式。同樣的模式也適用於 OpenClaw 和其他框架——唯一需要改變的只是橋接 handler。
橋接架構
此模式的一個可用參考實作是 a2a_daemon_engine——一個 A2A 協定常駐程式,以閘道模組方式運行,並將執行路由到可插拔的 handler。架構如下:
A2A Client (any agent or application)
│
POST /{endpoint_id}/a2a (message/send | message/stream)
│
▼
Gateway (auth, routing, SSE client management)
│
▼
A2A Daemon Executor
│
resolve_agent(uuid) → Database lookup
load_agent_handler() ← data-driven, metadata-based routing
│
├── HermesAgentHandler
│ → POST /v1/runs → GET /v1/runs/{id}/events → SSE streaming
│ → POST /v1/chat/completions (non-streaming)
│
└── [AnyFrameworkHandler] ← same interface, different translation
→ framework's native API
橋接層有三層:
A2A 協定層 — 處理 JSON-RPC 分派、Agent Card 服務、任務狀態機和 A2A SDK EventQueue。這與框架無關,對每個整合都相同。
閘道傳輸層 — 處理 HTTP、認證、SSE 用戶端生命週期和路由。同樣與框架無關。閘道擁有線路;橋接層擁有轉譯。
框架 handler — 唯一的框架特定程式碼。它實作一個
ask_model()介面:接受 A2A 訊息部分和情境、呼叫框架的原生 API、將回應轉換回 A2A 訊息部分,並(在串流模式下)將 token 增量轉發到 SSE 通道。
新增一個框架只需寫一個 handler 類別。其餘的一切——協定介面、閘道分派、SSE 管理、任務持久化——都是共享基礎設施。
示範:Hermes Agent 橋接
HermesAgentHandler 是完整的範例。它將 A2A 任務語意橋接到 Hermes Agent API Server。該 handler 支援兩種執行模式:
非串流:message/send 搭配 message_response
handler 呼叫 Hermes API Server 的 POST /v1/chat/completions——OpenAI 相容端點。請求將轉換後的 A2A 訊息部分作為 chat completion 承載攜帶。Hermes 處理請求(模型推論、工具呼叫、代理推理)並回傳單一回應。handler 將回應轉換為帶有 ROLE_AGENT 的 A2A Message,並將其發送到 SDK EventQueue。
用戶端收到一個包含完整代理文字的單一 JSON-RPC 回應。沒有中間狀態事件,沒有串流區塊——請求會阻塞直到 Hermes 完成。
串流:message/send 搭配 task_execution 和 stream: true
handler 呼叫 POST /v1/runs 建立一個 run,然後開啟一個到 GET /v1/runs/{id}/events 的 SSE 連線。Hermes 隨事件發生即串流:token 增量、推理元資料、工具呼叫/結果通知、批准請求和生命週期事件(run.created、run.completed、run.failed)。
handler 在背景執行緒中執行一個排空迴圈。每個 message.delta 事件被推送到閘道的 SSE 管理器,以即時交付給已連線的用戶端。handler 將 token 累積到單一緩衝區中。當 run.completed 到達時,累積的文字作為單一 A2A Message 發送到 SDK EventQueue,而 COMPLETED 狀態事件僅推送到 SSE。
這種雙路徑設計——SSE 用於即時區塊,SDK EventQueue 用於最終累積訊息——是對 A2A SDK v2 的一個約束的回應,如下所述。
跨代理邊界的人類介入批准
Hermes 支援人類介入批准閘——當代理需要許可才能執行敏感操作時,它會暫停並發出批准請求。橋接層將此轉譯為 A2A 的 INPUT_REQUIRED 狀態,向呼叫代理(或人類操作員)發出需要輸入的信號。回應透過 POST /v1/runs/{id}/approval 傳回,run 隨即繼續。
這正是橋接模式展現其價值之處。A2A 將 INPUT_REQUIRED 定義為一等任務狀態。Hermes 有自己的批准機制。橋接層將兩者互相映射,而呼叫代理——它本身可能是一個在不同框架上運行的 A2A 用戶端——看到的是一個標準的協定狀態轉換,而非 Hermes 特定的細節。一個代理委派鏈可以包含一個需要人類批准的步驟(採購授權、資料存取決策、報價批准),而 A2A 協定將該閘透明地跨框架邊界傳遞。
A2A 狀態映射
A2A 定義了一個任務狀態機:submitted → working → input-required | completed | failed | canceled。每個框架有自己的事件詞彙。橋接層在兩者之間映射。
Hermes 事件到狀態的映射:
| Hermes SSE Event | A2A Task State | Bridge Action |
|---|---|---|
run.created |
WORKING |
註冊 run_id 以支援取消 |
message.delta |
WORKING |
累積 token;逐區塊發送到 SSE |
reasoning.available |
WORKING |
推理元資料——不發出 token |
tool.call / tool.result |
WORKING |
僅工具執行元資料 |
approval.required |
INPUT_REQUIRED |
發出批准區塊;儲存 pending_approval |
run.completed |
COMPLETED |
設定串流事件;累積最終文字 |
run.failed |
FAILED |
發出錯誤區塊;設定 FAILED 狀態 |
POST /v1/runs/{id}/stop |
CANCELED |
透過 tasks/cancel 外部取消 |
POST /v1/runs/{id}/approval |
(繼續 run) | 透過 operation="approval_response" 解決 |
這張表是橋接層的核心。每個框架整合都會產生一張等價的表——左側是框架的原生事件,右側是 A2A 狀態,中間是橋接動作。參考實作中的 HERMES_INTEGRATION.md 文件記錄了確切的 Hermes 事件格式、配置鍵和端到端流程細節。
A2A SDK v2 約束與雙路徑修正
A2A SDK v2(a2a-sdk==1.0.2)對 on_message_send 路徑施加了兩個約束,形塑了每個橋接實作:
- 僅允許單一 Message。 向 SDK EventQueue 發出多個
Message物件會引發InvalidAgentResponseError: Multiple Message objects received.。 - 不允許 TaskStatusUpdateEvent。 狀態事件會引發
InvalidAgentResponseError: Received TaskStatusUpdateEvent in message mode.。
一個天真的橋接層會為每個 token 增量發出一個 Message——自然的串流模式。SDK 會拒絕這種做法。它也會拒絕在 message/send 路徑上的狀態事件(WORKING、COMPLETED)。
修正方式是一個雙路徑輸出通道:
- SSE(閘道管理): Token 區塊即時推送到 SSE。已連線的用戶端看到串流輸出隨事件發生。狀態事件(WORKING、COMPLETED、FAILED)也僅發送到 SSE。
- SDK EventQueue: 串流完成後,一個包含完整回應文字的單一累積
Message被發送到 SDK EventQueue。這就是 JSON-RPCmessage/send回應所回傳的內容。
用戶端透過 SSE 獲得即時串流,並透過 SDK 獲得乾淨的單一訊息 JSON-RPC 回應。兩個通道都正常運作;都不違反 SDK 約束。此模式與框架無關——無論後端是 Hermes、OpenClaw 或任何未來的 handler,它都適用。
將同模式套用於 OpenClaw
OpenClaw 的 Gateway API 暴露了與 Hermes 不同的原生介面,但橋接模式完全相同。一個 OpenClawHandler 會實作相同的 ask_model() 介面,並將 A2A 任務語意轉譯為 OpenClaw Gateway 呼叫:
- 非串流映射到
POST /v1/responses,A2A 訊息部分轉換為 OpenResponses 輸入項。回應被轉換回 A2AMessage。 - 串流映射到
POST /v1/responses搭配stream: true,消耗 SSE 事件串流並將 token 增量轉發到 A2A SSE 通道。OpenResponses 串流格式使用response.output_text.delta作為 token 區塊,response.completed作為完成——事件名稱不同,橋接結構相同。 - 代理選擇使用
model欄位(openclaw/<agentId>)或x-openclaw-agent-id標頭,從 A2A 代理元資料映射。 - 對話連續性利用 OpenClaw 的
previous_response_id或user欄位進行穩定的 session 路由,這自然地映射到 A2A 任務持久化。
OpenClaw 的狀態映射表如下:
| OpenClaw Event | A2A Task State | Bridge Action |
|---|---|---|
response.created |
WORKING |
註冊 response ID |
response.output_text.delta |
WORKING |
累積 token;發送到 SSE |
response.completed |
COMPLETED |
累積最終文字;發出 Message |
response.failed |
FAILED |
發出錯誤;設定 FAILED |
相同的欄位、相同的結構、不同的事件名稱。橋接 handler 是框架之間唯一需要改變的部分。
配置:元資料驅動路由
代理路由是元資料驅動的,而非環境變數驅動的。資料庫中的每個代理記錄在 metadata JSON 欄位中攜帶其 handler 配置。對於 Hermes 支援的代理:
{
"module_name": "a2a_daemon_engine.handlers.a2a_hermes_handler",
"class_name": "HermesAgentHandler",
"hermes_api_url": "http://127.0.0.1:8642",
"hermes_api_key": "hermes-local-key",
"hermes_model": "hermes-agent",
"hermes_timeout": 300.0
}
對於 OpenClaw 支援的代理,元資料會指向 OpenClaw handler:
{
"module_name": "a2a_daemon_engine.handlers.a2a_openclaw_handler",
"class_name": "OpenClawHandler",
"openclaw_api_url": "http://127.0.0.1:3000",
"openclaw_api_key": "openclaw-key",
"openclaw_agent_id": "pricing-agent",
"openclaw_timeout": 300.0
}
配置解析遵循一個優先順序鏈:代理元資料(DB)→ 設定字典 → Config 預設值(環境變數)。每個代理的覆寫優先於全域預設值。兩個代理可以指向不同的框架——一個指向 Hermes 處理推理密集型任務,另一個指向 OpenClaw 處理工作流程編排任務——而 A2A 協定介面對呼叫代理來說看起來完全相同。
這帶來了什麼能力
橋接模式提供了三種從零建構難以組裝的能力:
1. 帶串流的代理間委派。 A2A 用戶端代理可以向 Hermes 支援的代理發送任務,並透過 SSE 接收即時 token 串流。呼叫代理不需要知道遠端代理執行的是 Hermes——它看到的是一個帶有 Agent Card 和 JSON-RPC 介面的 A2A 端點。
2. 跨代理邊界的人類介入批准。 框架原生的批准閘(Hermes 批准請求、OpenClaw 操作員批准)映射到 A2A INPUT_REQUIRED 狀態。一個代理委派鏈可以包含一個需要人類批准的步驟,而 A2A 協定將該狀態轉換傳回原始代理或操作員——無論鏈中的每個代理執行在哪個框架上。
3. 從單一閘道進行多框架路由。 相同的閘道、相同的執行器、相同的 A2A 協定介面服務於不同框架的 handler。新增一個框架只需寫一個 handler 類別並插入一個代理記錄——不需要新的部署,不需要新的協定實作。
參考實作還支援 AWS Lambda 分派以實現無伺服器 A2A、實驗性 gRPC 傳輸與雙向串流,以及雙後端持久化(DynamoDB 或 PostgreSQL),透過複合分區鍵實現多租戶隔離。a2a_daemon_engine 儲存庫及其 Hermes 整合指南包含完整的實作、配置參考和狀態映射細節。
一家中型經銷商需要報價代理與目錄代理溝通,目錄代理再與庫存代理溝通——每個代理由不同框架支撐,每個代理由不同團隊擁有。A2A 給這些代理一個共享的協定。一個橋接層讓 Hermes Agent、OpenClaw 和任何其他框架都能參與,而無需重寫內部。a2a_daemon_engine 是該橋接模式的一個可用參考實作,以 Hermes Agent 示範。
申請一個範圍明確的建構
為期一週的發掘。您會拿到系統清單、工作流程地圖和固定範圍——無論您最終是否與我們合作開發。
想為您的系統建構這個嗎?
這裡的每份文件都來自真實的生產工作。如果您有目標系統和工作流程想法,我們可以在一週內確定範圍。
申請客製開發為期一週的發掘階段。您會拿到系統清單、工作流程地圖和固定範圍——無論您最終是否與我們合作開發。