README 建議用 agents-cli playground 開本機環境。那個適合聊天測試,但我想看的是原始 HTTP 介面,所以直接跑 uvicorn:
.venv/Scripts/python.exe -m uvicorn app.fast_api_app:app --host 127.0.0.1 --port 8123
log 裡有四個實驗性警告:InMemoryCredentialService、AgentCardBuilder、A2aAgentExecutor、A2aAgentExecutorConfig。
警告文字自己把界線畫得很清楚:
ADK Implementation for A2A support (A2aAgentExecutor, RemoteA2aAgent and corresponding supporting components etc.) is in experimental mode and is subject to breaking changes. A2A protocol and SDK are themselves not experimental.
協定穩定,ADK 的接法會變。這句話決定了架構文件該怎麼寫:協定那層可以當成穩定介面往上蓋,ADK 的 A2A 接法要當成可替換的實作。後面講 Executor 邊界的時候會回到這個判斷。
curl http://127.0.0.1:8123/a2a/app/.well-known/agent-card.json
回 200。路徑裡的 app 是 Day 6 講的 App(name="app")。
{
"name": "root_agent",
"description": "An ADK Agent",
...
}
An ADK Agent。這是硬寫的字串,跟我的 instruction 沒關係。
而 orchestrator 做路由的時候讀的就是這段。scaffold 出來的 agent 直接掛上去,別的 agent 拿到的路由依據等於沒有依據。
我的 instruction 有出現,但在別的位置:
"skills": [
{
"id": "root_agent",
"name": "model",
"description": "I am a helpful AI assistant designed to provide accurate and useful information.",
"tags": ["llm"]
},
...
]
skills[0],名字叫 model,而且 ADK 把第二人稱的 You are a helpful AI assistant 改寫成第一人稱的 I am...。所以它確實被當成對外描述在用,只是不在 card 的 description 欄位。
要能被正確路由,description 必須自己覆寫。這是 scaffold 之後第一件該改的事,而它不會報錯,你只會發現路由怪怪的。
supportedInterfaces 有三筆,0.3 出現兩次"supportedInterfaces": [
{ "url": "...", "protocolBinding": "JSONRPC", "protocolVersion": "1.0" },
{ "url": "...", "protocolBinding": "JSONRPC", "protocolVersion": "0.3" },
{ "url": "...", "protocolBinding": "JSONRPC", "protocolVersion": "0.3" }
]
去翻 app/app_utils/a2a.py,原因在 _add_v0_3_compat_interface:它無條件 append 一筆 0.3,而 builder 本來就放了一筆,所以重複。
它存在的理由寫在那個函式的 docstring 裡:
Advertise a v0.3 JSON-RPC interface so the served card stays consumable by v0.3 A2A clients — notably Gemini Enterprise registration, whose validator still requires the 0.3 card shape (top-level
url/protocolVersion).
Gemini Enterprise 的驗證器還在要求 0.3 的卡片形狀。所以 card 最下面同時有 top-level 的 "protocolVersion": "0.3" 與 "url"。
這條線索一路連到我後面寫 Gemini Enterprise 註冊的那兩篇。Google 自己在 scaffold 裡放了相容層,說明那個版本落差是已知的。
順便一個相關的細節:同一個檔案裡的 _A2AServerCallContextBuilder 會在 A2A-Version header 被 proxy 剝掉時,從 method 名稱的形狀反推版本。有斜線的像 message/send 判為 0.3,PascalCase 像 SendMessage 判為 1.0。也就是 A2A 1.0 把 method 命名換掉了,我前面幾篇用的四個 method 名稱是 0.3 的寫法。
"url": "http://0.0.0.0:8000/a2a/app"
我跑在 127.0.0.1:8123,card 上寫 0.0.0.0:8000。
看 _resolve_app_url 的退回順序:明確傳入的 app_url,然後 APP_URL 環境變數,然後從 Agent Runtime 的環境變數自組,最後退回硬寫的 http://0.0.0.0:8000。我三個都沒有,所以拿到最後那個。
本機自己玩不痛,因為你是直接 curl 端點,沒有照 card 上的 url 去打。上雲之後就會痛。別的 agent 抓到你的卡,照 url 那個值送 message/send,打到 0.0.0.0:8000,找不到人。抓卡那一步是成功的,所以症狀會是「明明抓得到卡卻叫不動」。
修法是部署時把 APP_URL 設成公開端點。這件事我留一篇單獨寫,因為它是本機到雲端之間最容易漏的一步。
playground 的聊天介面測的是「模型答得對不對」。上面三個問題在聊天介面裡完全看不出來,因為它們都不影響本機單機對話,只影響別的 agent 怎麼看你。
把 card 撈出來看一遍是十秒的事,能提早看到三個之後很難追的問題。