Why ADK for Kotlin & Android Matters
The AI ecosystem is shifting toward the edge. With Gemini Nano available on over 140 million Android devices, developers can now run LLMs directly on mobile hardware — enhancing privacy, reducing latency, and lowering costs. But building agentic systems that span cloud and edge is complex.
ADK removes that friction. It handles orchestration, context management, and error handling so you can focus on your app logic. The 0.1.0 release for Kotlin and Android is the first step toward a unified agent framework for mobile.
What You'll Build
A trip assistant app that:
- Uses a cloud orchestrator (Gemini API) to understand user queries.
- Delegates sensitive tasks (e.g., booking verification) to an on-device subagent running Gemini Nano.
- Keeps private data offline while leveraging cloud reasoning.
Prerequisites
- Android Studio Hedgehog or later
- Kotlin 1.9+
- An API key for Gemini (cloud models)
- Device or emulator with Android 14+ (for Gemini Nano support)
Step 1: Add ADK Dependencies
Add the following to your build.gradle.kts:
// ADK for Android (includes on-device models)
implementation("com.google.adk:google-adk-kotlin-core-android:0.1.0")
// For cloud-only backend projects
// implementation("com.google.adk:google-adk-kotlin-core:0.1.0")
// ksp("com.google.adk:google-adk-kotlin-processor:0.1.0")
Sync your project. Now you're ready to build agents.
Step 2: Create the Cloud Orchestrator Agent
This agent will be the main entry point for user queries. It uses a cloud model (Gemini 2.5 Flash) and has access to tools and subagents.
val orchestrator = LlmAgent(
name = "genius_orchestrator",
model = Gemini(apiKey = apiKey, name = "gemini-2.5-flash"),
instruction = Instruction("""
You are a travel genius assistant.
First, use `get_trip_details` to get the full itinerary of the trip and
understand what events are scheduled.
Then, respond with a welcome message tailored to the trip state.
""".trimIndent()),
tools = listOf(GetTripDetailsTool(tripId)),
subAgents = listOf(carRentalPipeline, hotelPipeline),
disallowTransferToPeers = true,
disallowTransferToParent = true
)
Explanation:
model: Connects to a cloud Gemini model.tools: Custom functions the agent can call (e.g., fetching trip details).subAgents: Delegates specialized tasks (car rental, hotel) to other agents.disallowTransferToPeers/parent: Prevents the orchestrator from handing off control to other high-level agents.
Step 3: Build an On-Device Subagent with Gemini Nano
Now, create a subagent that runs entirely on-device using Gemini Nano. This agent will handle sensitive data (e.g., booking confirmations stored locally).
val bookingVerifierAgent = LlmAgent(
name = "BookingVerifier",
description = "Verifies booking confirmations using on-device Gemini Nano.",
model = GeminiNano(), // Runs locally — no network call
instruction = Instruction("""
You are an on-device booking verifier.
Given a booking ID, extract the confirmation details from the user's local documents.
Return only the confirmation number and status.
""".trimIndent()),
tools = listOf(ExtractBookingTool())
)
Key points:
GeminiNano()is the on-device model — zero data leaves the phone.- This agent is added as a subagent to the orchestrator (
subAgents = listOf(bookingVerifierAgent)). - The orchestrator can delegate tasks to it when privacy is critical.
Step 4: Define Tools with Annotations
ADK uses @Tool and @Param annotations to describe functions to the LLM. Here's an example inspired by the Hitchhiker's Guide to the Galaxy:
class ImprobabilityDriveService {
/** Calculates the improbability of a given event. */
@Tool
fun calculateImprobability(
@Param("The event to calculate the improbability for, e.g., 'A cup of tea materializing'")
event: String
): String {
return "The improbability of '$event' is approximately 42 to 1 against."
}
}
Then generate tools for an agent:
val heartOfGoldAgent = LlmAgent(
name = "HeartOfGold",
description = "Handles improbability drive queries.",
model = Gemini(apiKey = apiKey, name = "gemini-2.5-flash"),
instruction = Instruction("""
You are the ship computer of the Heart of Gold. You are cheerful, helpful, and slightly annoying.
Use real facts about yourself if asked, but keep it funny.
""".trimIndent()),
tools = ImprobabilityDriveService().generatedTools()
)
Step 5: Orchestrate Cloud + On-Device Agents
Combine everything into a root agent that routes queries to the right subagent:
val rootAgent = LlmAgent(
name = "MissionControl",
description = "The central router for space queries. Routes to HeartOfGold.",
subAgents = listOf(heartOfGoldAgent),
model = Gemini(apiKey = apiKey, name = "gemini-2.5-flash"),
instruction = Instruction("""
You are Mission Control. You are the central hub for all communications.
- If the query is about improbability, the Infinite Improbability Drive, or the Heart of Gold, transfer to `HeartOfGold`.
- Otherwise, respond directly with a professional but stressed persona.
""".trimIndent())
)
How it works:
- User asks: "What's the improbability of a cup of tea materializing?"
rootAgentrecognizes the topic → transfers toHeartOfGoldAgent.HeartOfGoldAgentcallsImprobabilityDriveService.calculateImprobability()→ returns result to user.
Limitations & Caveats
- Experimental: ADK 0.1.0 is an early release. APIs may change.
- On-device model limitations: Gemini Nano is optimized for specific tasks (e.g., summarization, extraction). Complex reasoning still requires cloud models.
- Device compatibility: Gemini Nano requires Android 14+ and specific hardware (Pixel 8, Samsung S24, etc.).
Next Steps
- Explore the ADK for Android demos on GitHub.
- Read about how Meta built a unified AI agent platform for large-scale automation.
- For GPU-optimized inference at scale, check out Maximizing GPU Utilization for LLM Inference.
Conclusion
ADK for Kotlin and Android opens the door to privacy-preserving, on-device AI agents that can seamlessly collaborate with cloud models. Start small, experiment with tool annotations, and gradually build complex agent hierarchies. The future of in-app AI is agentic — and it runs on Kotlin.

![]()
