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://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/get-started.md

This page describes how to do the following:

  • Configure your project to use Prompt API

  • Provide text-only input and receive a response

  • Provide an image input with related text input and receive a response

For more details about the Prompt API, see the reference documentation for Kotlin (com.google.mlkit.genai.prompt) and Java (com.google.mlkit.genai.prompt.java, com.google.mlkit.genai.prompt).

Configure project

[!NOTE] Note: This API requires Android API level 26 or higher.

Add the ML Kit Prompt API as a dependency in your build.gradle configuration:

implementation("com.google.mlkit:genai-prompt:1.0.0-beta2")

If you need your responses in a certain format using the Structured Output API, you need to configure KSP and add additional dependencies. For details, see Generate structured output.

Implement generative model

To implement the code in your project, follow these steps:

  • Create a generativeModel object:

    Kotlin
    // Get a GenerativeModel instance
    val generativeModel = Generation.getClient()
    Java
    // Get a GenerativeModel instance
    GenerativeModelFutures generativeModelFutures = GenerativeModelFutures
        .from(Generation.INSTANCE.getClient());
    
  • Check if Gemini Nano is AVAILABLE, DOWNLOADABLE, or UNAVAILABLE. Then, download the feature if it is downloadable:

    Kotlin
    val status = generativeModel.checkStatus()
    when (status) {
        FeatureStatus.UNAVAILABLE -> {
            // Gemini Nano not supported on this device or device hasn't fetched the latest configuration to support it
        }
    
        FeatureStatus.DOWNLOADABLE -> {
            // Gemini Nano can be downloaded on this device, but is not currently downloaded
            generativeModel.download().collect { status ->
                when (status) {
                    is DownloadStatus.DownloadStarted ->
                        Log.d(TAG, "starting download for Gemini Nano")
    
                    is DownloadStatus.DownloadProgress ->
                        Log.d(TAG, "Nano ${status.totalBytesDownloaded} bytes downloaded")
    
                    DownloadStatus.DownloadCompleted -> {
                        Log.d(TAG, "Gemini Nano download complete")
                        modelDownloaded = true
                    }
    
                    is DownloadStatus.DownloadFailed -> {
                        Log.e(TAG, "Nano download failed ${status.e.message}")
                    }
                }
            }
        }
    
        FeatureStatus.DOWNLOADING -> {
            // Gemini Nano currently being downloaded
        }
    
        FeatureStatus.AVAILABLE -> {
            // Gemini Nano currently downloaded and available to use on this device
        }
    }
    Java
    ListenableFuture<Integer> status = generativeModelFutures.checkStatus();
    Futures.addCallback(generativeModelFutures.checkStatus(), new FutureCallback<>() {
        @Override
        public void onSuccess(Integer featureStatus) {
            switch (featureStatus) {
                case FeatureStatus.AVAILABLE -> {
                    // Gemini Nano currently downloaded and available to use on this device
                }
                case FeatureStatus.UNAVAILABLE -> {
                    // Gemini Nano not supported on this device or device hasn't fetched the latest configuration to support it
                }
                case FeatureStatus.DOWNLOADING -> {
                    // Gemini Nano currently being downloaded
                }
                case FeatureStatus.DOWNLOADABLE -> {
                    generativeModelFutures.download(new DownloadCallback() {
                        @Override
                        public void onDownloadStarted(long l) {
                            Log.d(TAG, "starting download for Gemini Nano");
                        }
                        @Override
                        public void onDownloadProgress(long l) {
                            Log.d(TAG, "Nano " + l + " bytes downloaded");
                        }
                        @Override
                        public void onDownloadCompleted() {
                            Log.d(TAG, "Gemini Nano download complete");
                        }
                        @Override
                        public void onDownloadFailed(@NonNull GenAiException e) {
                            Log.e(TAG, "Nano download failed: " + e.getMessage());
                        }
                    });
                }
            }
        }
        @Override
        public void onFailure(@NonNull Throwable t) {
            // Failed to check status
        }
    }, ContextCompat.getMainExecutor(context));

Provide text-only input

Kotlin
val response = generativeModel.generateContent("Write a 3 sentence story about a magical dog.")
Java
GenerateContentResponse response = generativeModelFutures.generateContent(
  new GenerateContentRequest.Builder(
    new TextPart("Write a 3 sentence story about a magical dog."))
  .build())
  .get();

Alternatively, add optional parameters:

Kotlin
val response = generativeModel.generateContent(
    generateContentRequest(
        TextPart("Write a 3 sentence story about a magical dog."),
    ) {
        // Optional parameters
        temperature = 0.2f
        topK = 10
        candidateCount = 3
    },
)
Java
GenerateContentRequest.Builder requestBuilder =
        new GenerateContentRequest.Builder(
                new TextPart("Write a 3 sentence story about a magical dog."));
requestBuilder.setTemperature(.2f);
requestBuilder.setTopK(10);
requestBuilder.setCandidateCount(3);

GenerateContentResponse response =
        generativeModelFutures.generateContent(requestBuilder.build()).get();

For more information about the optional parameters, see Optional configurations.

Provide multimodal (image and text) input

Bundle an image and a text input together in the generateContentRequest() function, with the text prompt being a question or command related to the image. You can bundle multiple images and text together in the same request.

Kotlin
val response = generativeModel.generateContent(
    generateContentRequest(ImagePart(bitmap), TextPart(textPrompt)) {
        // optional parameters
        ...
    },
)
Java
GenerateContentResponse response = generativeModelFutures.generateContent(
    new GenerateContentRequest.Builder(
        new ImagePart(bitmap),
        new TextPart("textPrompt"))
    // optional parameters
    .build())
.get();

Process inference result

  • Run the inference and retrieve the result. You can choose to either wait for the full result or stream the response as it's generated for both text-only and multimodal prompts.

    • This uses non-streaming inference, which retrieves the entire result from the AI model before returning the result:

    Kotlin
    // Call the AI model to generate content and store the complete
    // in a new variable named 'response' once it's finished
    val response = generativeModel.generateContent("Write a 3 sentence story about a magical dog")
    Java
    GenerateContentResponse response = generativeModelFutures.generateContent(
            new GenerateContentRequest.Builder(
                    new TextPart("Write a 3 sentence story about a magical dog."))
                    .build())
            .get();
    • The following snippets are examples of using streaming inference, which retrieves the result in chunks as it's being generated:

    Kotlin
    // Streaming inference
    var fullResponse = ""
    generativeModel.generateContentStream("Write a 3 sentence story about a magical dog").collect { chunk ->
        val newChunkReceived = chunk.candidates[0].text
        print(newChunkReceived)
        fullResponse += newChunkReceived
    }
    Java
    // Streaming inference
    StringBuilder fullResponse = new StringBuilder();
    generativeModelFutures.generateContent(new GenerateContentRequest.Builder(
        (new TextPart("Write a 3 sentence story about a magical dog"))).build(),
            chunk -> {
                Log.d(TAG, chunk);
                fullResponse.append(chunk);
            });

For more information about streaming and non-streaming inference, see Streaming versus non-streaming.

Latency optimization

To optimize for the first inference call, your application may optionally call warmup(). This loads Gemini Nano into memory and initializes runtime components.

Optional configurations

As part of each GenerateContentRequest, you can set the following optional parameters:

  • temperature : Controls the degree of randomness in token selection.

  • seed : Enables generating stable and deterministic results.

  • topK : Controls randomness and diversity in results.

  • candidateCount : Requests the number of unique responses returned. Note that the exact number of responses may not be the same as candidateCount because duplicate responses are automatically removed.

  • maxOutputTokens : Defines the maximum number of tokens that can be generated in the response.

For more guidance on setting optional configurations, see GenerateContentRequest.

Supported features and limitations

  • Input must be under 4000 tokens (or approximately 3000 English words). For more information, see the countTokens reference.

  • Use cases that require long output (more than 4K tokens) should be avoided.

  • AICore enforces an inference quota per app. For more information, see Quota per application.

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