ML Kit Genai Prompt API
Android (Google)OfficialCreated by Google LLCDistributed by Android (Google)
- Skill
- Tool integration
- Software development
- Apache-2.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a comprehensive guide for developers to implement the ML Kit GenAI Prompt API within Android projects. It covers the end-to-end lifecycle of on-device generative AI, including model availability checks, dependency configuration, and resource management. The skill also details advanced optimization techniques such as prefix caching for reduced latency and structured output generation for type-safe data handling.
What it does
- Configures Android projects with the necessary ML Kit GenAI dependencies.
- Provides patterns for checking model availability and managing the download lifecycle.
- Demonstrates how to implement implicit and explicit prefix caching to improve inference speed.
- Guides the refactoring of string-based prompts into type-safe structured output using annotations.
- Offers best practices for resource management, including proper model instance disposal.
- Provides optimization strategies for prompt design to enhance model performance.
When to use it
- When integrating on-device generative AI features using Gemini Nano in Android apps.
- When you need to optimize inference latency for recurring prompt prefixes.
- When you need to ensure your AI responses are returned in a structured, type-safe format.
- When managing the lifecycle of generative model instances to prevent memory leaks.
Advantages
- Reduces inference latency through efficient prefix caching mechanisms.
- Enables type-safe AI interactions by mapping responses directly to data classes.
- Provides clear lifecycle management patterns for stable app performance.
- Offers granular control over model state and cache management.
Usage examples
- “How do I check if Gemini Nano is ready to use on the device?”
- The skill provides the logic to check the FeatureStatus of the generative model and handle the download process if the model is not yet available.
- “How can I refactor my string-based prompt to return a structured data object?”
- The skill demonstrates using the @Generable annotation and the generateTypedContentRequest method to map AI responses to a specific Kotlin data class.
- “How do I speed up my app's AI response time for long prompts?”
- The skill explains how to implement prefix caching by separating static prompt prefixes from dynamic suffixes.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/android/ml-kit-genai-prompt-api/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip ml-kit-genai-prompt-api.zip -d .agents/skills
Documentation by Google LLC
This skill provides step-by-step guidance for integrating and optimizing the ML Kit GenAI Prompt API in Android apps.
Prerequisites
Android API level must be 26 or higher. If
minSdkis below 26, update it to 26.Add the ML Kit GenAI Prompt API dependency (
com.google.mlkit:genai-prompt) to the app-levelbuild.gradlefile, with version at least1.0.0-beta4.If
com.google.mlkit:genai-schema-compilerdependency is used and KSP plugin version is below 2.3.6, update it to 2.3.6.
Detailed steps
1. Prompt optimization
To optimize prompts for use with the ML Kit Prompt API, follow the prompt optimization guide.
2. Prefix caching optimization
If the prompt is more than 200 words, implement the prefix caching API.
3. Lifecycle and best practices
The model must be fully downloaded and available before calling the first inference. Follow the guide on implementing a generative model to check that the
FeatureStatusof a model isAVAILABLEbefore making an inference.Release ML Kit instances by calling
close()when anActivity,Fragment, orViewModelis destroyed. Example:// Instantiating model in activity, fragment, or ViewModel val generativeModel = Generation.getClient() // When activity, fragment, or ViewModel is destroyed generativeModel.close()<br />
4. Structured output
When implementing or refactoring a prompt to use structured output, follow these rules:
Check for API availability: Verify Structured Output feature is available on the device with
isStructuredOutputFeatureAvailable()before using it. Refer to the Structured Output API guide for full instructions.Return type: Return the
@Generabletyped object from the function signature instead of aStringor JSON string.For example:
fun parseEmail(email: String): String { ... }should be refactored to:
fun parseEmail(email: String): ParsedEmail? { ... }Example:
This is the example code before refactoring:
suspend fun parseEmail(email: String): String { val parseEmailPrompt = "Parse this email and return the sender, title, and short summary of the email less than 10 words: " val parsedEmail = generativeModel.generateContent(parseEmailPrompt + email) return parsedEmail.candidates[0].text }<br />
This is the example code after using Structured Output API:
@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 less than 10 words") var summary: String = "" ) suspend fun parseEmail(email: String): ParsedEmail? { val parseEmailPrompt = "Parse this email: $email" val baseRequest = GenerateContentRequest.Builder(TextPart(parseEmailPrompt)).build() val typedRequest = generateTypedContentRequest(baseRequest, ParsedEmail::class) val typedResponse = generativeModel.generateContent(typedRequest) return typedResponse.candidates[0].response }<br />
Files
- ATTRIBUTION.mdAdded by AutoGineer986 B
- LICENSELicence file added by AutoGineer11.1 KiB
- SKILL.md4.1 KiB
- references/get-started.md10.6 KiB
- references/prefix-caching.md5.7 KiB
- references/prompt-design.md3.5 KiB
- references/prompt-optimization.md4.5 KiB
- references/structured-output.md10.2 KiB
- references/system-instructions.md3.3 KiB
references/structured-output.md
If you need to parse the responses from the Prompt API into certain formats, such as JSON, for further processing, use the Structured Output API.
With the Structured Output API, you define the target output structure using Kotlin classes and annotations. The Prompt API then returns a response in the form of your Kotlin object.
Generating structured output is particularly useful for tasks like the following:
Entity extraction: Extracting structured fields (for example, event name, date, location) from unstructured text.
Classification: Categorizing input text into predefined categories.
Data serialization: Converting unstructured user input into a format suitable for database storage or API calls.
Prerequisites
To verify that the Structured Output API is available on the device, use the
isStructuredOutputFeatureAvailable() API. The API returns true if the
Structured Output API is available on the device, and false otherwise.
suspend fun isStructuredOutputFeatureAvailable(): BooleanThe Structured Output API also has the following requirements:
Android API level 26 or higher (
minSdk26)KSP plugin version 2.3.6 or higher
Limitations
The Structured Output API has the following limitations:
Works in Kotlin only.
ProGuard might interfere with the parsing of your annotated class. Add your annotated class to your keep rules to exclude them from ProGuard if you get errors parsing, for example:
Keep classes used by structured output for deserialization for release builds.
-keep class com.google.mlkit.genai.demo.kotlin.Plant { *; }
Configure project
To get started with the Structured Output API, follow these steps:
Add the ML Kit Prompt API as a dependency in your app-level
build.gradle.kts(orbuild.gradle) file, if you haven't already.Add the KSP plugin to your project-level
build.gradle.ktsfile. Use a KSP plugin version that is compatible with your Kotlin version; we recommend KSP version 2.3.6 or higher.dependencies { ... classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:2.3.6" }Add the structured compiler dependencies to your app-level
build.gradle.ktsfile:dependencies { ... ksp("com.google.mlkit:genai-schema-compiler:1.0.0-alpha1") }
Define the output structure
Define the structure of the data you want the model to return using Kotlin data classes. There are two main annotations for defining the output structure:
Use the
@Generableannotation to define the class as a target for structured output.Use the
@Guideannotations on the class properties to provide descriptions and constraints that guide the model's output.
The following example defines a structure for extracting plant information:
import com.google.mlkit.genai.schema.annotations.Generable
import com.google.mlkit.genai.schema.annotations.Guide
@Generable
data class PlantList(
@Guide(description = "The list of plants found", minItems = 1, maxItems = 5)
val plants: List<Plant>
)
@Generable("Information about a plant species")
data class Plant(
@Guide(description = "The common name of the plant")
val commonName: String,
@Guide(description = "The full latin scientific name of the plant")
val scientificName: String,
@Guide(
description = "The maximum height of the plant in centimeters.",
minimum = 1.0,
maximum = 10000.0
)
val maxHeightCm: Int,
@Guide(description = "Whether the plant is poisonous or not")
val isPoisonous: Boolean?,
@Guide(
description = "The primary continent where this plant is native to",
enumValues = ["Africa", "Antarctica", "Asia", "Australia", "Europe", "North America", "South America"]
)
val nativeContinent: String
)Supported types and constraints
The following types are supported within a @Generable annotated class,
along with their respective @Guide constraints:
| Type | Description | Supported @Guide constraints |
|---|---|---|
String | For text. | description, enumValues |
Double / Float | For floating-point numbers. | description, minimum, maximum |
Int / Long | For whole numbers. | description, minimum, maximum |
Boolean | For true/false values. | description |
List<T> | For lists of supported types or nested @Generable classes. | description, minItems, maxItems |
List<String> | For lists of String values. | description, enumValues, minItems, maxItems > [!NOTE] > Note: Setting the enumValues parameter defines the values allowed for the individual list items. |
@Generable class | For nested structured objects. | description |
[!NOTE] Note: Circular dependencies between nested
@Generableclasses are not supported (for example, a class referencing itself, or Class A referencing Class B which in turn references Class A).
Generate structured content
To request structured output, use the generateTypedContentRequest helper
function to wrap your standard prompt and specify the target output class.
// 1. Initialize your GenerativeModel as usual
val generativeModel = Generation.getClient()
// 2. Prepare the prompt text
val promptText = "List some common plants found in California."
val baseRequest = GenerateContentRequest.Builder(TextPart(promptText)).build()
// 3. Create the typed request, specifying the target class (e.g., PlantList)
val typedRequest = generateTypedContentRequest(
generateContentRequest = baseRequest,
outputClass = PlantList::class
)
// 4. Run the inference
try {
val typedResponse = generativeModel.generateContent(typedRequest)
// 5. Access the parsed object
// The response candidates contain the parsed object of type T (PlantList in this case)
val plantList: PlantList? = typedResponse.candidates.firstOrNull()?.response
if (plantList != null) {
// Process the structured data
for (plant in plantList.plants) {
Log.d("StructuredOutput", "Found plant: ${plant.commonName} (${plant.scientificName})")
}
} else {
Log.e("StructuredOutput", "Failed to parse response into the desired structure.")
// Inspect finish reason for details
val finishReason = typedResponse.candidates.firstOrNull()?.finishReason
Log.d("StructuredOutput", "Finish reason: $finishReason")
}
} catch (e: GenAiException) {
// Handle API errors
when (e.errorCode) {
GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS -> {
Log.e("StructuredOutput", "The class structure is not supported.")
}
GenAiException.STRUCTURED_OUTPUT_INVALID_VALUE -> {
Log.e("StructuredOutput", "The model generated values that violate the schema constraints.")
}
else -> {
Log.e("StructuredOutput", "API error: ${e.message}")
}
}
}Handle finish reasons and errors
When using the Structured Output API, you should handle potential exceptions
thrown by the API and inspect the finishReason property in the response
candidates if the parsed response is null.
finishReason values
The finishReason property can take one of the following values:
TypedFinishReason.STOP: The model finished generating successfully and the output matches the schema.TypedFinishReason.MAX_TOKENS: The model stopped because it reached the token limit. The output might be incomplete.TypedFinishReason.PARSE_CLASS_ERROR: The model completed generation, but the resulting JSON couldn't be parsed into the target Kotlin class.TypedFinishReason.STRUCTURE_NOT_ANNOTATED: The target class or its nested classes are missing the required@Generableannotation.TypedFinishReason.STRUCTURE_VALUES_INVALID: The generated values violated the constraints defined in the@Guideannotations (for example value out of range, list size out of bounds).TypedFinishReason.OTHER: Generation stopped due to other reasons.
Exceptions
The Structured Output API might throw GenAiException with the following
error codes:
GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS(-104): The structure of the annotated class is invalid or contains unsupported types. This is typically a development-time configuration error. Review your@Generabledata class definition to check that all property types are supported and that there aren't any circular dependencies.GenAiException.STRUCTURED_OUTPUT_INVALID_VALUE(-105): The values generated by the model are invalid or fail constraints verification. This is a runtime error. If you encounter this error frequently, consider the following solutions:Refining your prompt instructions to guide the model more strictly.
Relaxing the constraints (like minimum, maximum, or list size limits) in your
@Guideannotations if they are too restrictive for the model's capabilities.Implementing a fallback strategy in your app, such as retrying the request or displaying a default state.
Count tokens
To check if your structured prompt is within the input token limit, calculate
the token count using the countTokens() method.
Because structured output requests need to instruct the model on the schema
structure, counting tokens on just the raw prompt text (using a
GenerateContentRequest instance) isn't accurate. To get an accurate token
count, you must pass the complete GenerateTypedContentRequest instance, which
includes your target class and schema configurations, to the countTokens()
method:
suspend fun <T : Any> countTokens(request: GenerateTypedContentRequest<T>): CountTokensResponseRequirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Google LLC
- Publisher
- Android (Google) (Official)
- Distributed by
- Android (Google)
- Source
- android/skills · device-ai/ml-kit-genai-prompt-api · commit bf68e2d
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.txt)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Google LLC or Android (Google).
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download ml-kit-genai-prompt-api.zip