Generated banner for ML Kit Genai Prompt API
Generated logo for ML Kit Genai Prompt API

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

From the author

Analyzes Android codebases to implement ML Kit GenAI Prompt API. Use this skill to send natural language requests on-device to Gemini Nano, use structured output with Prompt API, implement prefix caching, optimize the current prompt, or apply best practices."
— the description by Google LLC

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

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/android/ml-kit-genai-prompt-api/download
  2. Unzip 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 minSdk is below 26, update it to 26.

  • Add the ML Kit GenAI Prompt API dependency (com.google.mlkit:genai-prompt) to the app-level build.gradle file, with version at least 1.0.0-beta4.

  • If com.google.mlkit:genai-schema-compiler dependency 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 FeatureStatus of a model is AVAILABLE before making an inference.

  • Release ML Kit instances by calling close() when an Activity, Fragment, or ViewModel is 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:

  1. 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.

  2. Return type: Return the @Generable typed object from the function signature instead of a String or JSON string.

    For example:

    fun parseEmail(email: String): String {
        ... 
    }

    should be refactored to:

    fun parseEmail(email: String): ParsedEmail? {
        ...
    }
    
  3. 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

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(): Boolean

The Structured Output API also has the following requirements:

  • Android API level 26 or higher (minSdk 26)

  • 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:

  1. Add the ML Kit Prompt API as a dependency in your app-level build.gradle.kts (or build.gradle) file, if you haven't already.

  2. Add the KSP plugin to your project-level build.gradle.kts file. 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"
    }
    
  3. Add the structured compiler dependencies to your app-level build.gradle.kts file:

    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 @Generable annotation to define the class as a target for structured output.

  • Use the @Guide annotations 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:

TypeDescriptionSupported @Guide constraints
StringFor text.description, enumValues
Double / FloatFor floating-point numbers.description, minimum, maximum
Int / LongFor whole numbers.description, minimum, maximum
BooleanFor 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 classFor nested structured objects.description

[!NOTE] Note: Circular dependencies between nested @Generable classes 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 @Generable annotation.

  • TypedFinishReason.STRUCTURE_VALUES_INVALID: The generated values violated the constraints defined in the @Guide annotations (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 @Generable data 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 @Guide annotations 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>): CountTokensResponse

Requirements 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