# Google ADK
Google Agent Development Kit
* 一個模組化框架
* 支援多智能體
* 支援MCP
* 可跨平台
![quickstart-flow-tool[1]](https://google.github.io/adk-docs/assets/quickstart-flow-tool.png)
## 基礎操作
**以下為 WSL 環境下操作步驟**
[Agent Development Kit -- Quickstart](https://google.github.io/adk-docs/get-started/quickstart/#venv-install)
* 使用 `uv` ([uv 安裝](https://docs.astral.sh/uv/getting-started/installation/))
```bash=
mkdir google_adk
uv init
uv run main.py
uv pip install google-adk
mkdir multi_tool_agent/
echo "from . import agent" > multi_tool_agent/__init__.py
touch multi_tool_agent/agent.py
touch multi_tool_agent/.env
```

:::spoiler agent.py
```python=
import datetime
from zoneinfo import ZoneInfo
from google.adk.agents import Agent
def get_weather(city: str) -> dict:
"""Retrieves the current weather report for a specified city.
Args:
city (str): The name of the city for which to retrieve the weather report.
Returns:
dict: status and result or error msg.
"""
if city.lower() == "new york":
return {
"status": "success",
"report": (
"The weather in New York is sunny with a temperature of 25 degrees"
" Celsius (41 degrees Fahrenheit)."
),
}
else:
return {
"status": "error",
"error_message": f"Weather information for '{city}' is not available.",
}
def get_current_time(city: str) -> dict:
"""Returns the current time in a specified city.
Args:
city (str): The name of the city for which to retrieve the current time.
Returns:
dict: status and result or error msg.
"""
if city.lower() == "new york":
tz_identifier = "America/New_York"
else:
return {
"status": "error",
"error_message": (
f"Sorry, I don't have timezone information for {city}."
),
}
tz = ZoneInfo(tz_identifier)
now = datetime.datetime.now(tz)
report = (
f'The current time in {city} is {now.strftime("%Y-%m-%d %H:%M:%S %Z%z")}'
)
return {"status": "success", "report": report}
root_agent = Agent(
name="weather_time_agent",
model="gemini-2.0-flash",
description=(
"Agent to answer questions about the time and weather in a city."
),
instruction=(
"You are a helpful agent who can answer user questions about the time and weather in a city."
),
tools=[get_weather, get_current_time],
)
```
:::
[google_api_key](https://aistudio.google.com/apikey)
:::spoiler .env
```bash
GOOGLE_GENAI_USE_VERTEXAI=FALSE
GOOGLE_API_KEY=PASTE_YOUR_ACTUAL_API_KEY_HERE
```
:::
* run
`uv run adk web` ,接著瀏覽器開啟 http://127.0.0.1:8000

**function calling**

**response**

## Workflow Agents
* Sequential agents
* Loop agents
* Parallel agents
### 1. Sequential agents
**線性流程示意圖**
![sequential-agent[1]](https://hackmd.io/_uploads/SJUDhZa0Jx.png)
**以線性方式進行,agent1 的輸出為 agent2 的輸入**
* **程式碼 & 結果**
**範例中讓 code_writer_agent 產生第一版兩數字相加程式碼,code_reviewer_agent 判斷是否夠好(有無優化空間),最後 code_refactorer_agent 決定終版**
[Sequential agents code](https://google.github.io/adk-docs/agents/workflow-agents/sequential-agents/#full-example-code-development-pipeline)

### 2. Loop agents
**循環流程示意圖**
![loop-agent[1]](https://hackmd.io/_uploads/SJhZJGTAyx.png)
**不斷循環 Agent ,直到滿足條件(夠好)或是達到上限(循環次數)**
* **程式碼 & 結果**
[Loop agents code](https://google.github.io/adk-docs/agents/workflow-agents/loop-agents/#how-it-works)
**在原始程式碼的這段控制循環上限**
```python=46
# Create the LoopAgent
loop_agent = LoopAgent(
name="LoopAgent", sub_agents=[writer_agent, critic_agent], max_iterations=2
)
```
**下圖為 `max_iterations=5` 的結果,writer_agent 和 critic_agent 各進行五次**

### 3. Parallel agents
**平行流程示意圖**
![parallel-agent[1]](https://hackmd.io/_uploads/SkANyfT01e.png)
**適合用於每個 Agent 負責不同事物**
* **程式碼 & 結果**
**官方範例為「再生能源、電動車技術、碳捕獲法」三種 Agent**
[Parallel agents code](https://google.github.io/adk-docs/agents/workflow-agents/parallel-agents/#full-example-parallel-web-research)

## Multi-agent systems (MAS)
* 多個不同的 Agent 組合
* 模組化、專業化、可重用性、可維護性、工作流程結構化控制(Workflow Agent)
* 父子結構 Agent
* 協調器
* 互動溝通機制
### Agent Hirearchy 代理層級結構
**在 Agent 之中定義其父子關係,每個 sub_agent 只會對應到一個 parent_agent**
```python=
from google.adk.agents import LlmAgent, BaseAgent
greeter = LlmAgent(name="Greeter", model="gemini-2.0-flash")
task_doer = BaseAgent(name="TaskExecutor")
# 建立父子關係
coordinator = LlmAgent(
name="Coordinator",
model="gemini-2.0-flash",
description="I coordinate greetings and tasks.",
sub_agents=[
greeter,
task_doer
]
)
# 顯示階層關係
print(f"Greeter 的父 Agent:{greeter.parent_agent.name}")
print(f"TaskExecutor 的父 Agent:{task_doer.parent_agent.name}")
```

### Workflow Agents as Orchestrators
* Sequential Agent
**僅實作結合 Agent Hirearchy 的 Sequential agent**
```python=
from google.adk.agents import SequentialAgent, LlmAgent
step1 = LlmAgent(name="Step1_Fetch", output_key="data") # Saves output to state['data']
step2 = LlmAgent(name="Step2_Process", instruction="Process data from state key 'data'.")
pipeline = SequentialAgent(name="MyPipeline", sub_agents=[step1, step2])
print(f"開始執行 {pipeline.name}\n")
state = {}
for agent in pipeline.sub_agents:
print(agent.name)
```

* Paralle Agent
**與 Sqquential agent 寫法大致相同,可以透過 `session.state` 避免 agent 間的衝突**
```python=
from google.adk.agents import ParallelAgent, LlmAgent
fetch_weather = LlmAgent(name="WeatherFetcher", output_key="weather")
fetch_news = LlmAgent(name="NewsFetcher", output_key="news")
gatherer = ParallelAgent(name="InfoGatherer", sub_agents=[fetch_weather, fetch_news])
```
* Loop Agent
[Loop Agent 作法範例](https://google.github.io/adk-docs/agents/multi-agents/#22-workflow-agents-as-orchestrators:~:text=LoopAgent%3A%20Executes%20its%20sub_agents%20sequentially%20in%20a%20loop.)
### Interaction & Communication Mechanisms
1. session.state
**在以下片段中AgentB 會將AgentA的輸出作為輸入使用**
```pytohn
agent_A = LlmAgent(name="AgentA", instruction="Find the capital of France.", output_key="capital_city")
agent_B = LlmAgent(name="AgentB", instruction="Tell me about the city stored in state key 'capital_city'.")
```
2. Agent Transfer
**parent_agent 的指令(instruction) 要明確什麼時候用哪個**
**sub_agent 的描述(description) 要清楚到能讓 parent_agent 選擇**
```python
booking_agent = LlmAgent(name="Booker", description="Handles flight and hotel bookings.")
info_agent = LlmAgent(name="Info", description="Provides general information and answers questions.")
coordinator = LlmAgent(
name="Coordinator",
instruction="You are an assistant. Delegate booking tasks to Booker and info requests to Info.",
description="Main coordinator.",
# AutoFlow is typically used implicitly here
sub_agents=[booking_agent, info_agent]
)
```
3. Agent Tool
**將其它 Agent 也視為一個 tool 來呼叫**
**`agent_tool.AgentTool()` 將 Agent 包裝成 tool**
```python
from pydantic import BaseModel
# Define a target agent (could be LlmAgent or custom BaseAgent)
class ImageGeneratorAgent(BaseAgent): # Example custom agent
name: str = "ImageGen"
description: str = "Generates an image based on a prompt."
# ... internal logic ...
# ... internal logic ...
# ... internal logic ...
image_agent = ImageGeneratorAgent()
image_tool = agent_tool.AgentTool(agent=image_agent) # Wrap the agent
# Parent agent uses the AgentTool
artist_agent = LlmAgent(
name="Artist",
model="gemini-2.0-flash",
instruction="Create a prompt and use the ImageGen tool to generate the image.",
tools=[image_tool] # Include the AgentTool
)
```