ML Kit GenAI Prompt API — On-Device Prompting for Android with Gemini Nano
Google's Android skill covers on-device prompting through ML Kit: API 26, Gemini Nano availability, structured output with @Generable, prefix caching, system instructions, lifecycle, and device constraints.

ML Kit GenAI Prompt API
ML Kit GenAI Prompt API is Google's Android skill for sending natural-language requests to Gemini Nano on a device. It covers prompt design, structured output, prefix caching, system instructions, model availability, and lifecycle cleanup.
The install is small, but the runtime requirements are not. This is on-device AI with a device-gated model, a beta SDK, and APIs that are still changing. The skill is most useful when you treat it as a checklist for those constraints, not as a guarantee that a prompt will run on every Android phone.
Source and revision
| Field | Value |
|---|---|
| Maintainer | Google LLC (android/skills) |
| Canonical source | device-ai/ml-kit-genai-prompt-api/SKILL.md at ac42384 |
| Revision inspected | ac4238481a4837fd6c8387f32116706293ee81a7, updated 2026-09-07 |
| Access date | 2026-10-23 |
| License | Apache-2.0 (LICENSE.txt); the skill frontmatter says "Complete terms in LICENSE.txt" |
| Install unit | device-ai/ml-kit-genai-prompt-api/, including six local reference files |
What the skill actually does
The core file gives a short implementation path:
- Prompt optimization. Use concise prompts, examples for in-context learning, XML/HTML delimiters for dynamic input, output constraints, and the Structured Output API when the response must be parsed.
- Prefix caching. If the prompt is more than 200 words, separate a static prefix from the dynamic suffix and use the prefix caching API.
- Lifecycle. Check
FeatureStatusbefore the first inference. Download the model if it isDOWNLOADABLE. Callclose()on theGenerativeModelwhen the activity, fragment, or view model is destroyed. - Structured output. Verify
isStructuredOutputFeatureAvailable()before use, return a@Generabletyped object instead of a string, and handle parse errors.
The six local references expand on prompt optimization, prompt design, prefix caching, getting started, structured output, and system instructions. The skill routes to them rather than duplicating everything.
Runtime constraints you must plan for
| Constraint | Detail |
|---|---|
| Android API level | 26 or higher (minSdk 26) |
| Prompt API dependency | com.google.mlkit:genai-prompt, at least 1.0.0-beta4 according to SKILL.md |
| Structured output | Kotlin only; KSP plugin 2.3.6 or higher; genai-schema-compiler |
| Model | Gemini Nano must be AVAILABLE on the device |
| Download | If DOWNLOADABLE, the app must download it before inference |
| System instructions | Require Gemini Nano V3 or higher |
| Prefix caching | Experimental; only a subset of Prompt API devices; text-only input |
| Device support | Changes over time; check the current Prompt API device-support list |
The version detail is a real drift signal: the SKILL.md says 1.0.0-beta4, while the get-started reference at the same commit shows 1.0.0-beta2. Treat the skill's prerequisite as the newer requirement and verify the current release in the Android documentation before pinning a version.
Illustrative implementation
This is a constructed example based on the skill's documented API, not a compiled or run app.
Task: parse a customer email into sender, title, and a short summary.
Before: the function returns a String, and the caller parses JSON by hand.
After:
@Generable
data class ParsedEmail(
@Guide(description = "Sender of the email")
var sender: String = "",
@Guide(description = "Title of the email")
var title: String = "",
@Guide(description = "Summary of the email in 10 words or fewer")
var summary: String = ""
)
suspend fun parseEmail(email: String): ParsedEmail? {
val prompt = "Parse this email: $email"
val baseRequest = GenerateContentRequest.Builder(TextPart(prompt)).build()
val typedRequest = generateTypedContentRequest(baseRequest, ParsedEmail::class)
val response = generativeModel.generateContent(typedRequest)
return response.candidates.firstOrNull()?.response
}
The surrounding code still needs:
- A
checkStatus()branch that handlesUNAVAILABLE,DOWNLOADABLE,DOWNLOADING, andAVAILABLE. - A fallback UI when the model is unavailable or the download fails.
isStructuredOutputFeatureAvailable()before the typed request.- ProGuard keep rules for the annotated class in release builds.
close()in the owner'sonDestroyoronCleared.
The skill's prompt-optimization reference also recommends delimiters such as <email>[content]</email> so the model can distinguish instructions from user data. That is a prompt-injection mitigation, not a guarantee.
When to use it
- You are adding on-device summarization, classification, entity extraction, or rewriting to an Android app.
- You need structured output instead of parsing free-form JSON.
- You have a long, repeated prompt prefix and want to test prefix caching.
- You need to check Gemini Nano availability and handle model download.
- You are reviewing an Android codebase that already uses ML Kit GenAI.
When not to use it
- You need a model that runs on every Android device. Gemini Nano availability is device-gated.
- You need a cloud model with larger context or stronger reasoning. This is on-device and constrained.
- You are building for iOS, web, or desktop.
- You need a stable, long-term API. The SDK and several features are beta or experimental.
- You need to process images with prefix caching. Prefix caching is text-only.
- You need a server-side key or a hosted endpoint. There is no API key in this workflow; the model is on the device.
Install
android skills add ml-kit-genai-prompt-api --project=.
The Android CLI installs the skill into the current project for detected agents. Use --agent to target a specific host and --all only if you want the whole Android collection.
Prerequisites and footprint
| Item | Detail |
|---|---|
| Build | Android project with minSdk 26 or higher |
| Dependency | com.google.mlkit:genai-prompt (beta) |
| Tooling | KSP 2.3.6+ for structured output; ProGuard keep rules |
| Device | Gemini Nano available, or downloadable and permitted by the user |
| Network | Model download and any app content the prompt includes |
| Storage | Model download plus prefix-cache files in app-private storage |
| Credentials | None; this is on-device inference |
| Writes | App code and Gradle files you approve |
Prefix caching stores encrypted cache files and metadata, including the original prefix text, in the app's private storage. The reference says the cache count is managed by LRU and can be cleared with clearImplicitCaches().
Limitations
- Device availability is the hard gate. A device that does not support Gemini Nano cannot run the feature, regardless of
minSdk. - Beta and experimental APIs. Prefix caching is experimental,
clearImplicitCaches()is experimental, and the Prompt API dependency is beta. - Structured output is Kotlin-only. Java projects cannot use the typed output path described here.
- Version drift. The core file and the get-started reference disagree on the dependency version. Verify the current release.
- No credential story, but a download story. The absence of API keys does not mean zero network or storage cost.
- Prompt injection still applies. On-device content can contain instructions. Delimiters help; they are not a security boundary.
- No runtime test by us. We did not build the app or run it on a device.
Verify it yourself
- Read the skill and all six references. Confirm the API level, dependency version, KSP version, and model requirements for your target devices.
- Check the current Prompt API device-support list. Do not assume a flagship device from last year is supported.
- Write a small screen that calls
checkStatus()and renders every state, includingUNAVAILABLEandDOWNLOADABLE. Test it on a device that lacks the model. - Test structured output with a deliberately invalid value to see how
finishReasonandGenAiExceptionsurface. - Add the ProGuard keep rule and test a release build, not only debug.
- Verify
close()is called and that a second screen does not reuse a closed model.
Review transparency
| Field | Value |
|---|---|
| Last reviewed | 2026-10-23 |
| What was inspected | Full SKILL.md, references/get-started.md, prompt-optimization.md, prefix-caching.md, structured-output.md, system-instructions.md, repository README, license, pinned commit metadata |
| What was not done | No install, no Android build, no device run, no model download, no structured-output test |
| Reviewers | Editorial source inspection only. Not a two-model security review. |
| Re-vet trigger | Any change to the dependency version, device-support list, or beta status; more than 30 days |
This is an original guide with short attributed code examples. It does not reproduce the full skill or its reference files.
Related
- Gemini Skills — Gemini CLI skills, not on-device Android
- Kotlin Rules — editor conventions
- Jetpack Compose Rules — UI conventions
- Prompt Optimization — model-agnostic prompt work
- How to Vet an Agent Skill — review before installing
Related Articles & Guides
#skillsPlaywright Skill — Code-First Browser Automation for Agents
lackeyjb's Playwright Skill writes and runs reusable Playwright scripts through run.js — code-first, unlike Playwright MCP control or DevTools inspection.
#skillsUI UX Pro Max — Searchable Design Intelligence for Agents
UI UX Pro Max packages seven design skills, a local search corpus and a CLI. The core is MIT; logo/CIP and extended asset generation sit behind a paid Premium tier.
#skillsBrowser Testing with DevTools — Real Chrome Evidence Through MCP
Addy Osmani's browser-testing skill connects an agent to Chrome DevTools MCP for DOM inspection, console logs, network traces, screenshots, and accessibility checks, with explicit profile-isolation and untrusted-content rules.