Google Agent Development Kit (ADK) - TypeScript
ADK is Google's open-source, code-first TypeScript framework for building, evaluating, and deploying AI agents. Optimized for Gemini but model-agnostic. Requires Node.js 20.12.7+.
Quick Start
mkdir my-agent && cd my-agent npm init -y npm install @google/adk npm install @google/adk-devtools npm install -D typescript npm install zod npx tsc --init
Project structure:
my-agent/ ├── agent.ts ├── package.json ├── tsconfig.json └── .env
tsconfig.json:
{
"compilerOptions": {
"verbatimModuleSyntax": false
}
}
.env:
GOOGLE_GENAI_API_KEY=your_api_key # Or use GEMINI_API_KEY=your_api_key (also supported) # Or for Vertex AI: # GOOGLE_GENAI_USE_VERTEXAI=TRUE # GOOGLE_CLOUD_PROJECT=your_project # GOOGLE_CLOUD_LOCATION=us-central1
Minimal agent (agent.ts):
import { LlmAgent } from '@google/adk';
export const rootAgent = new LlmAgent({
name: 'assistant',
model: 'gemini-2.5-flash',
instruction: 'You are a helpful assistant.',
description: 'A general-purpose assistant.',
});
Run:
npx @google/adk-devtools run agent.ts # CLI npx @google/adk-devtools web # Dev UI at localhost:8000
Agent Types
| Type | Import | Use When |
|---|---|---|
LlmAgent | @google/adk | Flexible reasoning, tool selection |
SequentialAgent | @google/adk | Ordered multi-step pipelines |
ParallelAgent | @google/adk | Concurrent independent tasks |
LoopAgent | @google/adk | Iterative refinement |
BaseAgent | @google/adk | Custom orchestration logic |
See references/agents.md for detailed patterns and code examples.
Tools
Define tools with FunctionTool and Zod schemas:
import { FunctionTool, LlmAgent } from '@google/adk';
import { z } from 'zod';
const getWeather = new FunctionTool({
name: 'get_weather',
description: 'Get weather for a city.',
parameters: z.object({
city: z.string().describe('City name'),
}),
execute: async ({ city }) => {
return { city, temp: '72F', condition: 'sunny' };
},
});
export const rootAgent = new LlmAgent({
name: 'weather_agent',
model: 'gemini-2.5-flash',
instruction: 'Help users check weather.',
tools: [getWeather],
});
See references/tools.md for MCP, OpenAPI, LongRunningFunctionTool, and built-in tools.
Multi-Agent Orchestration
Six core patterns:
- •Coordinator/Dispatcher - Central LlmAgent routes to specialist sub-agents
- •Sequential Pipeline - SequentialAgent chains agents with
outputKeystate passing - •Parallel Fan-Out - ParallelAgent for concurrent work, then aggregate
- •Hierarchical Decomposition - Tree of delegating agents
- •Generator-Critic - Create then review with SequentialAgent
- •Iterative Refinement - LoopAgent until quality threshold or
maxIterations
See references/multi-agent.md for implementation details.
State Management
// 1. outputKey - auto-save agent response to state
const writer = new LlmAgent({
name: 'writer',
outputKey: 'draft', // state['draft'] = agent response
// ...
});
// 2. Instruction templating - read from state
const editor = new LlmAgent({
instruction: 'Edit this draft: {draft}',
// ...
});
// 3. CallbackContext - manual read/write
function myCallback(context: CallbackContext) {
const count = context.state.get('counter', 0);
context.state.set('counter', count + 1);
context.state.set('temp:scratch', 'temporary');
}
State prefixes: unprefixed (session), user: (cross-session per user), app: (global), temp: (discarded after invocation).
Callbacks & Guardrails
const agent = new LlmAgent({
name: 'safe_agent',
beforeAgentCallback: checkIfAgentShouldRun,
afterAgentCallback: modifyOutputAfterAgent,
beforeModelCallback: simpleBeforeModelModifier,
// Also: afterModelCallback, beforeToolCallback, afterToolCallback
});
Return undefined to proceed, return a Content/LlmResponse object to override. See references/callbacks.md.
Session & Runner
import { InMemoryRunner } from '@google/adk';
import { createUserContent } from '@google/genai';
const runner = new InMemoryRunner({ agent: rootAgent });
const session = await runner.sessionService.createSession({
appName: runner.appName,
userId: 'user-1',
state: { initial_key: 'value' },
});
for await (const event of runner.runAsync({
userId: session.userId,
sessionId: session.id,
newMessage: createUserContent('Hello'),
})) {
console.log(event);
}
Note: createUserContent and the Content type come from @google/genai (transitive dependency of @google/adk), not from @google/adk directly.
Testing & Evaluation
Create .test.json files alongside your agent:
{
"name": "weather_tests",
"data": [{
"query": "What's the weather in NYC?",
"expected_tool_calls": ["get_weather"],
"reference_answer": "temperature"
}]
}
Run: npx adk eval <agent_folder> <test_file.test.json>
See references/testing.md for evaluation metrics and patterns.
Backend Integrations
Express
import express from 'express';
import { InMemoryRunner, isFinalResponse, stringifyContent } from '@google/adk';
import { createUserContent } from '@google/genai';
const app = express();
app.use(express.json());
const runner = new InMemoryRunner({ agent: rootAgent });
app.post('/chat', async (req, res) => {
const { message, sessionId, userId } = req.body;
// Get or create session
let session = await runner.sessionService.getSession({
appName: runner.appName, userId, sessionId,
});
if (!session) {
session = await runner.sessionService.createSession({
appName: runner.appName, userId,
});
}
const events = [];
for await (const event of runner.runAsync({
userId, sessionId: session.id,
newMessage: createUserContent(message),
})) {
if (isFinalResponse(event)) {
events.push({ type: 'response', content: stringifyContent(event) });
}
}
res.json({ events });
});
app.listen(8080);
See references/deployment.md for Hono, Cloud Run, and container patterns.
Best Practices
- •Use Zod schemas - Type-safe tool parameters with
.describe()for LLM hints - •Use
outputKey- Auto-store agent output in state for downstream agents - •Unique state keys in ParallelAgent - Prevent race conditions
- •Descriptive
descriptionfields - Guides LLM routing to sub-agents - •
async*generators - UserunAsyncImplfor custom agent flow control - •Dev UI for debugging -
npx @google/adk-devtools webto inspect events/state
Common Pitfalls
- •Forgetting
verbatimModuleSyntax: falsein tsconfig - causes import errors - •Mutating session directly - Always use
CallbackContext.stateoroutputKey - •Missing Zod
.describe()- LLM gets no hint about parameter purpose - •Single sub-agent instance reuse - An agent can only be sub-agent once
- •Blocking in async generators - Use
for awaitwithrunAsync
Resources
- •references/agents.md - Agent types and custom agents
- •references/tools.md - FunctionTool, MCP, OpenAPI
- •references/multi-agent.md - Orchestration patterns
- •references/callbacks.md - Callbacks and state
- •references/testing.md - Evaluation framework
- •references/deployment.md - Express, Hono, Cloud Run