A2A 從 v0.3 升到 v1.0:會噴錯的那幾條,反而最好修
A2A 從 v0.3 升上 v1.0,十一個 JSON-RPC 方法全部改名。這是整份 breaking change 清單裡最不需要擔心的一段。
先把分工講清楚,這篇不重複別人的地盤。A2A 是什麼、它跟 MCP 各自負責 agent 生態的哪一段、TaskState 那組狀態怎麼運作,站上 8 月 22 日那篇〈一個 agent 中途反問你問題,這件事在 MCP 的抽象裡沒有位置〉已經拆過一輪。這篇只做一件事:手上有照 v0.3 寫的 client,直接往 v1.0 升,會在哪裡壞、哪裡先壞、哪裡壞了你還不知道。
時間差先擺出來。gh api 查 releases,v0.3.0 是 2025 年 7 月 30 日,v1.0.0 到 2026 年 3 月 12 日才發,最新的 v1.0.1 是 2026 年 5 月 28 日。中間隔了七個多月,那七個多月裡寫成的程式碼、教學、範例,全部是舊名字。
為什麼改名反而是最安全的一段
規格 docs/specification.md 的 §5.3 Method Mapping Reference 給了一張對照表。這張表是全集,不是舉例:message/send 變 SendMessage、message/stream 變 SendStreamingMessage、tasks/get 變 GetTask、tasks/cancel 變 CancelTask、tasks/resubscribe 變 SubscribeToTask,推播設定那四個 tasks/pushNotificationConfig/* 變成 CreateTaskPushNotificationConfig 到 DeleteTaskPushNotificationConfig,還有 agent/getAuthenticatedExtendedCard 變 GetExtendedAgentCard。
十一條。你照這張表改完就結束了。
它安全的原因不在於數量少,在於它壞掉的時候會講話。規格 §9.5 明列 -32601 MethodNotFoundError:「Method not found / The requested method does not exist or is not available」。舊名字送出去,對面回一個有編號的錯誤,你的 log 裡會有一行紅字,紅字裡有方法名。從錯誤訊息走回程式碼,中間沒有推理成本。
換插座的道理。規格不合,插頭根本插不進去,你站在那邊當場就知道要換轉接頭。真正麻煩的從來不是插不進去的那種,是插得進去、電壓不對的那種。
三個不會講話的改動
清單往下走,接下來這幾條就沒有錯誤碼了。
第一個是 enum。v1.0 把 enum 值從 kebab-case 改成 SCREAMING_SNAKE_CASE,理由是要對齊 ProtoJSON 的規範。這個改動在你的程式碼裡的落點,是一個字串比對。
字串比對失敗不是錯誤,是「不相等」。switch 落進 default、if 判斷走另一條路、狀態機停在原地等一個永遠不會送到的值——沒有 exception,沒有錯誤碼,沒有紅字。你只會發現任務好像卡住了,然後開始懷疑是不是網路問題。
kind 這個 discriminator 欄位是第二個。它被移除了,改成看 JSON 裡有哪個 member 來判斷型別。讀 kind 的那一行不會炸,它拿到 undefined 然後乖乖往下傳。判型失敗這種事有個討厭的性質:它很少在讀錯的那一行出事,通常是在後面某個已經假設了型別的地方才出事,而那個地方離現場可能隔了好幾層呼叫。
第三個最陰。TaskStatusUpdateEvent 拿掉了 final 這個布林欄位。串流的迴圈本來就是靠讀 final 決定什麼時候收工的;欄位不在了,讀到 undefined,undefined 是 falsy,迴圈的終止條件永遠不成立。
它壞掉的樣子不像壞掉,像慢。
這三段我要標清楚:規格文件只寫了「改了什麼」,至於「你的程式碼會怎麼靜默地錯」,是我照著改動內容推的,不是規格的原話。
中間還混了一個不會壞的東西
那張對照表裡有一列很容易被跳過:ListTasks。它的「v0.3.0 舊名」那格是空的,因為 v0.3.0 根本沒有這個操作,是 v1.0 新增的。
升級清單通常是拿來找「哪裡會壞」的,所以讀的人會自動過濾掉不會壞的那幾行。新增的操作永遠不會壞,它只是不存在於你的程式碼裡而已。於是升級做完、測試全綠、上線,你手上仍然是一份 v0.3 形狀的 client,只是換了新名字在跑。
拿到新版規格的第一件事,除了對照 breaking change,還得對照一次「多出來什麼」。這兩份清單在文件裡混在同一頁,但在你的腦子裡應該是兩件事。
Agent Card 那組欄位是在握手階段錯的
剩下的改動集中在 AgentCard,也就是雙方認識彼此的那一步。
supportsAuthenticatedExtendedCard 搬進了 capabilities.extendedAgentCard。protocolVersion 從 AgentCard 本身搬到了各個 AgentInterface 底下。最大的一筆是 preferredTransport 加上 additionalInterfaces 兩個欄位,合併成一個 supportedInterfaces[] 陣列。
最後那筆不是改名,是形狀變了。舊的 reader 去讀 preferredTransport,讀到 undefined,於是判定「這個 agent 沒有指定偏好的 transport」,然後照預設值往下走。整段握手不會失敗,只是雙方對「等一下要用哪條路講話」這件事的認知已經分岔了。
握手階段的錯有個特性:它離真正出事的地方最遠。等到某個 streaming 呼叫行為怪怪的,你會去查那個呼叫,不會回頭查三十分鐘前那次 agent card 的解析。
怎麼排這份清單
那句開場的斷言,到這裡可以升級成一個判準。
排 breaking change 的處理順序,用「它壞掉的時候,誰會告訴你」來排,不要用「這個改動看起來有多大」來排。有錯誤碼的排最後,因為它會自己來找你,你不去處理它也會逼你處理。沒有錯誤碼、只會讓某個布林值變成 undefined 的排最前面,因為除了你自己,沒有人會提這件事。
十一個方法改名很顯眼,照表改一小時。一個 enum 的大小寫不顯眼,出事的時候你可能要查三天,而且查的方向大概是網路、逾時、對方服務不穩,繞一圈才回到那個字串。顯眼程度跟危險程度在這份清單上幾乎是反過來的。
還有一層:規格文件的 breaking change 清單是照模組排的,方法名一段、型別一段、AgentCard 一段。這個排法對寫規格的人很合理,對要升級的人不合理。讀的時候自己重排一次,標準只有一個,就是它會不會噴東西給你看。
誠實邊界
這篇的每一條改動都出自官方 repo 的 docs/whats-new-v1.md 與 docs/specification.md(v1.0.1 tag)。版本與日期是 gh api repos/a2aproject/A2A/releases 查來的。專案現況也是實查:沒有 archived、Apache-2.0、2026 年 9 月 1 日還有 push、25,586 顆星,還在積極維護。
我沒有做的事也列一下:沒有升級過任何一個 client,沒有送出過任何一次 v1.0 的呼叫,上面每一段「壞掉會長什麼樣」都是照規格的改動內容推的。要真的動手升級之前,docs/whats-new-v1.md 值得自己從頭讀一次——它比這篇完整,也比這篇無趣。










