ADK 的 tool 就是普通 Python 函式,丟進 tools=[...] 就好。沒有裝飾器,沒有 JSON schema 檔,沒有註冊步驟。
def get_weather(query: str) -> str:
"""Simulates a web search. Use it get information on weather.
Args:
query: A string containing the location to get weather information for.
Returns:
A string with the simulated weather information for the queried location.
"""
if "sf" in query.lower() or "san francisco" in query.lower():
return "It's 60 degrees and foggy."
return "It's 90 degrees and sunny."
型別標註加 docstring,ADK 拿這兩樣去組工具描述。
我把本機的 A2A card curl 下來(完整過程在 Day 9),get_weather 在裡面長這樣:
{
"id": "root_agent-get_weather",
"name": "get_weather",
"description": "Simulates a web search. Use it get information on weather.\n\nArgs:\n query: A string containing the location to get weather information for.\n\nReturns:\n A string with the simulated weather information for the queried location.",
"tags": ["llm", "tools"]
}
整段 docstring,連 Args: 和 Returns: 的縮排都保留,變成 A2A skill 的 description。
所以那句話在這裡是字面成立的:你寫的 Python docstring 就是別的 agent 用來決定要不要呼叫你的依據。 它同時是給人看的註解、給模型看的 prompt、以及跨系統的公開介面文件。三個角色同一份字串。
看第二個工具:
def get_current_time(query: str) -> str:
"""Simulates getting the current time for a city.
Args:
city: The name of the city to get the current time for.
Returns:
A string with the current time information.
"""
簽名是 query,docstring 的 Args: 寫 city。
這個不一致原封不動被發佈到 agent card 上,我 curl 到的 description 裡就是 city: The name of the city to get the current time for.。模型讀到的參數名跟實際要填的名字不同。
會發生是因為沒有任何工具會攔它。ruff 不管 docstring 內容跟簽名對不對,型別檢查器也不管,測試更不會測一個字串。這是 Google 自己的範本,而它就這樣過了。
一旦接受「描述欄位是執行期行為」,同樣的模式到處都是:
description 與 skills[].description
寫這些的時候問題要換一個:不是「這個東西是什麼」,是「什麼情況該選它」。因為模型做的是條件匹配。
Use it get information on weather 這句連文法都缺一個 to,而它是模型判斷要不要叫這支工具的主要依據。
寫完一個 tool,離開前確認四件事:
第一項聽起來很蠢,但這是 Google 範本踩到的那個。
把 server 起起來,curl 出完整的 agent card。有三個問題只有在那份 JSON 裡看得到,其中一個會讓上雲之後別的 agent 完全找不到你。