# How to Build an AI Agent with Google ADK

- Tool: Google ADK
- Difficulty: Intermediate
- Time required: 35-50 min
- Compatibility: Python 3.10+, google-adk, Gemini API key (or Vertex AI credentials), any OS
- Last updated: November 2026

## TL;DR

Google's Agent Development Kit builds multi-agent systems where a coordinator automatically delegates to specialist sub-agents based on their descriptions, no routing code required. This guide builds an HR onboarding coordinator that hands new-hire requests to a Benefits agent or an IT Provisioning agent, each with its own tool. Stack: Python, google-adk, a Gemini API key. Budget 35-50 minutes.

## What you'll build

You'll build an HR onboarding coordinator for a mid-size company. A new hire's first-day questions land on one coordinator agent, which delegates benefits questions to a Benefits agent backed by a plan-lookup tool, and IT setup questions to an IT Provisioning agent backed by an account-provisioning tool. Neither specialist sees the other's questions; the coordinator's own job is just deciding who should.

ADK's delegation is automatic once you set it up: pass sub_agents=[benefits_agent, it_agent] to the coordinator's LlmAgent, and ADK's AutoFlow intercepts a transfer_to_agent function call the coordinator's LLM generates on its own, using each sub-agent's description to decide. You don't write an if/elif router; you write good descriptions and a coordinator instruction that tells it when to delegate at all.

Choose ADK when you're building on Gemini or Google Cloud and want multi-agent delegation as a built-in framework feature rather than something you assemble from a lower-level primitive. If you want the same coordinator-and-specialists shape on Claude or OpenAI models instead, the OpenAI Agents SDK guide's handoffs pattern is the closest equivalent.

## Before you start

- Python 3.10+ and a terminal
- A Gemini API key (GOOGLE_API_KEY) from Google AI Studio, or Vertex AI credentials
- pip install google-adk
- Comfort writing plain Python functions as tools

## Step-by-step guide

### 1. Install the ADK and scaffold an agent project

Install google-adk and set your API key. The adk CLI can scaffold a starting project, but this guide writes the agent directly in one file for clarity; either approach produces the same LlmAgent objects underneath.

```
pip install google-adk
export GOOGLE_API_KEY="..."
# Optional scaffold: adk create onboarding_agent
```

**Expected result:** google-adk installed and GOOGLE_API_KEY set; `adk --version` runs without error.

### 2. Define the Benefits agent and its tool

look_up_benefits_plan is a plain Python function with a docstring and type hints; ADK turns it into a callable tool automatically when you list it in an LlmAgent's tools. The agent's description is what the coordinator will read later to decide whether to delegate here, so make it specific, not generic.

```
from google.adk.agents import LlmAgent

def look_up_benefits_plan(employee_level: str) -> dict:
    """Look up the health and retirement benefits plan for a given employee level."""
    plans = {
        "junior": {"health": "Standard PPO", "retirement_match": "3%"},
        "senior": {"health": "Premium PPO", "retirement_match": "5%"},
    }
    return plans.get(employee_level, {"health": "Standard PPO", "retirement_match": "3%"})

benefits_agent = LlmAgent(
    name="BenefitsAgent",
    model="gemini-3.8-flash",
    description="Answers questions about health insurance, retirement plans, and benefits enrollment for new hires.",
    instruction="Help new hires understand their benefits. Always look up their specific plan before answering with numbers.",
    tools=[look_up_benefits_plan],
)
```

**Expected result:** A BenefitsAgent that, run on its own, answers a benefits question using real plan data from the tool.

### 3. Define the IT Provisioning agent and its tool

provision_it_account follows the same shape: a plain function the agent calls to actually create accounts, stubbed here to return a confirmation. Its description is deliberately distinct from BenefitsAgent's so the coordinator has a clear signal for which one fits a given question.

```
def provision_it_account(employee_name: str, department: str) -> dict:
    """Provision email, Slack, and VPN access for a new hire in the given department."""
    # In production this calls your identity provider's API (e.g. Okta, Google Workspace Admin SDK)
    return {"employee": employee_name, "email": f"{employee_name.lower().replace(' ', '.')}@company.com", "status": "provisioned"}

it_agent = LlmAgent(
    name="ITProvisioningAgent",
    model="gemini-3.8-flash",
    description="Sets up accounts, email, Slack, and VPN access for new hires on their first day.",
    instruction="Provision IT access for new hires once you have their name and department. Confirm what was set up.",
    tools=[provision_it_account],
)
```

**Expected result:** An ITProvisioningAgent that, run on its own, provisions an account and confirms the resulting email address.

### 4. Build the coordinator with automatic delegation

The coordinator lists both specialists in sub_agents=[...] and nothing else; no tools of its own. Its instruction tells it when to delegate at all, not how, since the how is handled by ADK's AutoFlow generating a transfer_to_agent call once the model decides which sub-agent's description fits.

```
coordinator = LlmAgent(
    name="OnboardingCoordinator",
    model="gemini-3.8-flash",
    description="Routes new-hire onboarding questions to the right specialist.",
    instruction=(
        "You help new hires on their first day. Delegate benefits and insurance questions "
        "to BenefitsAgent and account/access setup questions to ITProvisioningAgent. "
        "Don't try to answer either kind yourself."
    ),
    sub_agents=[benefits_agent, it_agent],
)

root_agent = coordinator  # ADK's CLI and dev UI look for this name
```

**Expected result:** A coordinator that, asked a benefits question, internally transfers to BenefitsAgent and returns its answer.

### 5. Run it locally and watch the delegation happen

adk run starts an interactive terminal chat against root_agent; adk web starts a local browser dev UI (not for production) that shows each transfer_to_agent call as it happens, which is the fastest way to confirm delegation is working as intended before writing any deployment code.

```
adk run onboarding_agent
# or, for a browser UI:
adk web --port 8000
```

**Expected result:** Typing 'What's my retirement match as a senior engineer?' shows a transfer to BenefitsAgent, then an answer citing the 5% match.

### 6. Harden the descriptions and prepare for deployment

If the coordinator ever delegates to the wrong specialist, the fix is almost always a vaguer description, not a bigger model. Tighten both agents' description fields with concrete nouns (benefits, insurance, retirement vs. accounts, email, VPN, access) until test questions route correctly, then deploy the whole tree to Cloud Run, GKE, or Agent Runtime; sub_agents deploy together as one unit, not as separate services.

```
# Tightened descriptions reduce ambiguous delegation:
benefits_agent.description = (
    "Answers questions about health insurance, retirement plans, 401k matching, "
    "and benefits enrollment. Does not handle IT, email, or account setup."
)
it_agent.description = (
    "Sets up email, Slack, VPN, and system accounts for new hires. "
    "Does not handle benefits, insurance, or retirement questions."
)
```

**Expected result:** A coordinator whose delegation choices stop being ambiguous on borderline questions after description edits, with no code changes.

## Complete code example

File: `onboarding_agent/agent.py`

```python
"""HR onboarding coordinator: delegates to BenefitsAgent or ITProvisioningAgent automatically.
Run: adk run onboarding_agent   (or: adk web --port 8000)
(pip install google-adk; set GOOGLE_API_KEY)
"""
from google.adk.agents import LlmAgent


def look_up_benefits_plan(employee_level: str) -> dict:
    """Look up the health and retirement benefits plan for a given employee level."""
    plans = {
        "junior": {"health": "Standard PPO", "retirement_match": "3%"},
        "senior": {"health": "Premium PPO", "retirement_match": "5%"},
    }
    return plans.get(employee_level, {"health": "Standard PPO", "retirement_match": "3%"})


def provision_it_account(employee_name: str, department: str) -> dict:
    """Provision email, Slack, and VPN access for a new hire in the given department."""
    # In production this calls your identity provider's API (e.g. Okta, Google Workspace Admin SDK)
    return {
        "employee": employee_name,
        "email": f"{employee_name.lower().replace(' ', '.')}@company.com",
        "status": "provisioned",
    }


benefits_agent = LlmAgent(
    name="BenefitsAgent",
    model="gemini-3.8-flash",
    description=(
        "Answers questions about health insurance, retirement plans, 401k matching, "
        "and benefits enrollment. Does not handle IT, email, or account setup."
    ),
    instruction="Help new hires understand their benefits. Always look up their specific plan before answering with numbers.",
    tools=[look_up_benefits_plan],
)

it_agent = LlmAgent(
    name="ITProvisioningAgent",
    model="gemini-3.8-flash",
    description=(
        "Sets up email, Slack, VPN, and system accounts for new hires. "
        "Does not handle benefits, insurance, or retirement questions."
    ),
    instruction="Provision IT access for new hires once you have their name and department. Confirm what was set up.",
    tools=[provision_it_account],
)

coordinator = LlmAgent(
    name="OnboardingCoordinator",
    model="gemini-3.8-flash",
    description="Routes new-hire onboarding questions to the right specialist.",
    instruction=(
        "You help new hires on their first day. Delegate benefits and insurance questions "
        "to BenefitsAgent and account/access setup questions to ITProvisioningAgent. "
        "Don't try to answer either kind yourself."
    ),
    sub_agents=[benefits_agent, it_agent],
)

root_agent = coordinator  # adk run / adk web look for this exact name
```

## Common mistakes

- **Writing vague sub-agent descriptions like 'handles HR stuff'** — undefined Fix: The coordinator's delegation quality is only as good as the descriptions it reads. Use concrete nouns for what each specialist does and explicitly does not handle.
- **Naming the final agent variable something other than root_agent** — undefined Fix: Both `adk run` and `adk web` look for that exact name at module level to find your entry point; anything else fails to load.
- **Giving the coordinator its own tools instead of keeping it as a pure router** — undefined Fix: A coordinator with tools starts answering things itself instead of delegating, defeating the point of having specialists with focused descriptions.
- **Assuming sub_agents run in parallel** — undefined Fix: LLM-based delegation via transfer_to_agent hands off control to one sub-agent at a time for that turn; it's sequential delegation, not fan-out. Use ADK's workflow agents for true parallel execution.
- **Testing only with adk web and shipping straight from there** — undefined Fix: The dev UI is explicitly not for production. Deploy the agent tree to Cloud Run, GKE, or Agent Runtime once testing confirms delegation works.

## Best practices

- Write each sub-agent's description with both what it does and what it explicitly doesn't, to reduce ambiguous delegation.
- Keep the coordinator free of its own tools so its only job is routing.
- Test borderline questions (ones that could plausibly go to either specialist) specifically, since those reveal weak descriptions fastest.
- Scope each sub-agent's tools to exactly what that specialist needs; BenefitsAgent has no reason to touch IT provisioning.
- Use adk web during development to see every transfer_to_agent call, then move to adk run or a real deployment for anything beyond local testing.
- Keep model choices consistent across sub-agents unless one genuinely needs more reasoning power than another.

## Use cases

### undefined



### undefined



### undefined



## Frequently asked questions

### How does the coordinator actually decide which sub-agent to use?

Its LLM reads its own instruction plus every sub-agent's description field and generates a transfer_to_agent function call naming the one it judges best. ADK's AutoFlow intercepts that call and switches execution to the named sub-agent; there's no separate classifier model involved.

### Can a sub-agent delegate further to its own sub-agents?

Yes, LlmAgent supports nesting sub_agents at any level, so a specialist can itself be a coordinator for narrower specialists. Keep nesting shallow in practice; each extra level adds a delegation decision that can go wrong.

### What's the difference between LlmAgent and the Agent class shown in some ADK examples?

Agent is commonly used as an alias/import path for LlmAgent in ADK examples and quickstarts; both refer to the same LLM-backed agent class. This guide imports LlmAgent directly for clarity when building multi-agent delegation.

### Does delegation work the same way with Vertex AI credentials instead of a Gemini API key?

Yes. Swap your authentication method (Vertex AI project/location credentials instead of GOOGLE_API_KEY) and the LlmAgent, sub_agents, and tool code are identical; only the auth and deployment target change.

### Can I force the coordinator to always delegate instead of ever answering directly?

State that explicitly in its instruction, as this guide's coordinator does ('Don't try to answer either kind yourself'). ADK doesn't hard-enforce it at the framework level; it's a prompting discipline backed by keeping the coordinator's own tools list empty.

### Can RapidDev build a multi-agent ADK system like this for our team?

Yes. RapidDev builds coordinator/specialist agent systems on Google ADK, the OpenAI Agents SDK, and Claude Agent SDK, including deployment to Cloud Run or Agent Runtime. A free 30-minute consultation is the fastest way to scope yours.

---

Source: https://www.rapidevelopers.com/build-ai-agent/how-to-build-an-ai-agent-with-google-adk
© RapidDev — https://www.rapidevelopers.com/build-ai-agent/how-to-build-an-ai-agent-with-google-adk
