Instructivo: Comienza a usar la API de Gemini


En este instructivo, se muestra cómo acceder a la API de Gemini directamente desde tu app para Android con el SDK cliente de la IA de Google para Android. Puedes usar este SDK cliente si no quieres trabajar directamente con las APIs de REST o con el código del servidor (como Python) para acceder a los modelos de Gemini en tu app para Android.

En este instructivo, aprenderás a hacer lo siguiente:

Además, este instructivo contiene secciones sobre casos de uso avanzados (como recuento de tokens) y opciones para controlar la generación de contenido.

Considera acceder a Gemini integrado en el dispositivo

El SDK cliente para Android que se describe en este instructivo te permite acceder a los modelos de Gemini Pro que se ejecutan en los servidores de Google. Para los casos de uso que implican el procesamiento de datos sensibles, la disponibilidad sin conexión o el ahorro de costos para los flujos de usuarios que se usan con frecuencia, te recomendamos que consideres acceder a Gemini Nano, que se ejecuta en el dispositivo. Para obtener más detalles, consulta el instructivo para Android (en el dispositivo).

Requisitos previos

En este instructivo, se asume que estás familiarizado con el uso de Android Studio para desarrollar apps para Android.

Para completar este instructivo, asegúrate de que tu entorno de desarrollo y tu app para Android cumplan con los siguientes requisitos:

  • Android Studio (versión más reciente)
  • Tu app para Android debe orientarse al nivel de API 21 o versiones posteriores.

Configura tu proyecto

Antes de llamar a la API de Gemini, debes configurar tu proyecto de Android, lo que incluye configurar la clave de API, agregar las dependencias del SDK a tu proyecto de Android y, luego, inicializar el modelo.

Cómo configurar tu clave de API

Para usar la API de Gemini, necesitarás una clave de API. Si aún no tienes una, créala en Google AI Studio.

Obtén una clave de API.

Protege tu clave de API

Te recomendamos que no incluyas una clave de API en tu sistema de control de versión. En su lugar, debes almacenarla en un archivo local.properties (que se encuentra en el directorio raíz de tu proyecto, pero se excluye del control de versión) y, luego, usar el complemento Secrets Gradle para Android para leer tu clave de API como una variable de configuración de compilación.

Kotlin

// Access your API key as a Build Configuration variable
val apiKey = BuildConfig.apiKey

Java

// Access your API key as a Build Configuration variable
String apiKey = BuildConfig.apiKey;

Todos los fragmentos de este instructivo utilizan esta práctica recomendada. Además, si quieres ver la implementación del complemento Secrets Gradle, puedes revisar la app de ejemplo de este SDK o usar la versión preliminar más reciente de Android Studio Iguana, que incluye una plantilla de inicio de la API de Gemini (que incluye el archivo local.properties para comenzar).

Agrega la dependencia del SDK a tu proyecto

  1. En el archivo de configuración de Gradle (como <project>/<app-module>/build.gradle.kts) del módulo (nivel de app), agrega la dependencia del SDK de IA de Google para Android:

    Kotlin

    dependencies {
      // ... other androidx dependencies
    
      // add the dependency for the Google AI client SDK for Android
      implementation("com.google.ai.client.generativeai:generativeai:0.7.0")
    }
    

    Java

    Para Java, debes agregar dos bibliotecas adicionales.

    dependencies {
        // ... other androidx dependencies
    
        // add the dependency for the Google AI client SDK for Android
        implementation("com.google.ai.client.generativeai:generativeai:0.7.0")
    
        // Required for one-shot operations (to use `ListenableFuture` from Guava Android)
        implementation("com.google.guava:guava:31.0.1-android")
    
        // Required for streaming operations (to use `Publisher` from Reactive Streams)
        implementation("org.reactivestreams:reactive-streams:1.0.4")
    }
    
  2. Sincroniza tu proyecto de Android con archivos Gradle.

Inicializa el modelo generativo

Antes de realizar llamadas a las APIs, debes inicializar el modelo generativo:

Kotlin

val generativeModel = GenerativeModel(
    // The Gemini 1.5 models are versatile and work with most use cases
    modelName = "gemini-1.5-flash",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

Java

En el caso de Java, también debes inicializar el objeto GenerativeModelFutures.

// Use a model that's applicable for your use case
// The Gemini 1.5 models are versatile and work with most use cases
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-1.5-flash",
// Access your API key as a Build Configuration variable (see "Set up your API key" above)
    /* apiKey */ BuildConfig.apiKey);

// Use the GenerativeModelFutures Java compatibility layer which offers
// support for ListenableFuture and Publisher APIs
GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Cuando especifiques un modelo, ten en cuenta lo siguiente:

  • Usa un modelo que sea específico para tu caso de uso (por ejemplo, gemini-1.5-flash es para entrada multimodal). En esta guía, las instrucciones para cada implementación enumeran el modelo recomendado para cada caso de uso.

Implementa casos de uso comunes

Ahora que tu proyecto está configurado, puedes explorar el uso de la API de Gemini para implementar diferentes casos de uso:

Genera texto a partir de entradas de solo texto

Cuando la entrada de instrucción incluya solo texto, usa un modelo de Gemini 1.5 o el modelo de Gemini 1.0 Pro con generateContent para generar una salida de texto:

Kotlin

Ten en cuenta que generateContent() es una función de suspensión y se debe llamar desde un alcance de corrutinas. Si no estás familiarizado con las corrutinas, consulta Corrutinas de Kotlin en Android.

val generativeModel = GenerativeModel(
    // The Gemini 1.5 models are versatile and work with both text-only and multimodal prompts
    modelName = "gemini-1.5-flash",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

val prompt = "Write a story about a magic backpack."
val response = generativeModel.generateContent(prompt)
print(response.text)

Java

Ten en cuenta que generateContent() muestra un ListenableFuture. Si no conoces esta API, consulta la documentación de Android sobre Cómo usar un ListenableFuture.

// The Gemini 1.5 models are versatile and work with both text-only and multimodal prompts
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-1.5-flash",
// Access your API key as a Build Configuration variable (see "Set up your API key" above)
    /* apiKey */ BuildConfig.apiKey);
GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Content content = new Content.Builder()
    .addText("Write a story about a magic backpack.")
    .build();

Executor executor = // ...

ListenableFuture<GenerateContentResponse> response = model.generateContent(content);
Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
    @Override
    public void onSuccess(GenerateContentResponse result) {
        String resultText = result.getText();
        System.out.println(resultText);
    }

    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

Generar texto a partir de entradas de texto e imágenes (multimodal)

Gemini proporciona varios modelos que pueden controlar entradas multimodales (modelos de Gemini 1.5) para que puedas ingresar imágenes y texto. Asegúrate de revisar los requisitos de imágenes para las instrucciones.

Cuando la entrada de la instrucción incluya imágenes y texto, usa un modelo de Gemini 1.5 con generateContent para generar una salida de texto:

Kotlin

Ten en cuenta que generateContent() es una función de suspensión y se debe llamar desde un alcance de corrutinas. Si no estás familiarizado con las corrutinas, consulta Corrutinas de Kotlin en Android.

val generativeModel = GenerativeModel(
    // The Gemini 1.5 models are versatile and work with both text-only and multimodal prompts
    modelName = "gemini-1.5-flash",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

val image1: Bitmap = // ...
val image2: Bitmap = // ...

val inputContent = content {
    image(image1)
    image(image2)
    text("What's different between these pictures?")
}

val response = generativeModel.generateContent(inputContent)
print(response.text)

Java

Ten en cuenta que generateContent() muestra un ListenableFuture. Si no conoces esta API, consulta la documentación de Android sobre Cómo usar un ListenableFuture.

// The Gemini 1.5 models are versatile and work with both text-only and multimodal prompts
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-1.5-flash",
// Access your API key as a Build Configuration variable (see "Set up your API key" above)
    /* apiKey */ BuildConfig.apiKey);
GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Bitmap image1 = // ...
Bitmap image2 = // ...

Content content = new Content.Builder()
    .addText("What's different between these pictures?")
    .addImage(image1)
    .addImage(image2)
    .build();

Executor executor = // ...

ListenableFuture<GenerateContentResponse> response = model.generateContent(content);
Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
    @Override
    public void onSuccess(GenerateContentResponse result) {
        String resultText = result.getText();
        System.out.println(resultText);
    }

    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

Crea conversaciones de varios turnos (chat)

Con Gemini, puedes entablar conversaciones de formato libre en múltiples turnos. El SDK simplifica el proceso, ya que administra el estado de la conversación, por lo que, a diferencia de generateContent, no tienes que almacenar el historial de la conversación.

Para crear una conversación de varios turnos (como el chat), usa un modelo de Gemini 1.5 o el modelo de Gemini 1.0 Pro, e inicializa el chat llamando a startChat(). Luego, usa sendMessage() para enviar un mensaje al usuario nuevo, que también adjuntará el mensaje y la respuesta al historial de chat.

Existen dos opciones posibles para role asociado al contenido de una conversación:

  • user: Es la función que proporciona los mensajes. Este valor es el predeterminado para las llamadas sendMessage.

  • model: Es la función que proporciona las respuestas. Esta función se puede usar cuando se llama a startChat() con history existentes.

Kotlin

Ten en cuenta que generateContent() es una función de suspensión y se debe llamar desde un alcance de corrutinas. Si no estás familiarizado con las corrutinas, consulta Corrutinas de Kotlin en Android.

val generativeModel = GenerativeModel(
    // The Gemini 1.5 models are versatile and work with multi-turn conversations (like chat)
    modelName = "gemini-1.5-flash",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

val chat = generativeModel.startChat(
    history = listOf(
        content(role = "user") { text("Hello, I have 2 dogs in my house.") },
        content(role = "model") { text("Great to meet you. What would you like to know?") }
    )
)

chat.sendMessage("How many paws are in my house?")

Java

Ten en cuenta que generateContent() muestra un ListenableFuture. Si no conoces esta API, consulta la documentación de Android sobre Cómo usar un ListenableFuture.

// The Gemini 1.5 models are versatile and work with multi-turn conversations (like chat)
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-1.5-flash",
// Access your API key as a Build Configuration variable (see "Set up your API key" above)
    /* apiKey */ BuildConfig.apiKey);
GenerativeModelFutures model = GenerativeModelFutures.from(gm);

// (optional) Create previous chat history for context
Content.Builder userContentBuilder = new Content.Builder();
userContentBuilder.setRole("user");
userContentBuilder.addText("Hello, I have 2 dogs in my house.");
Content userContent = userContentBuilder.build();

Content.Builder modelContentBuilder = new Content.Builder();
modelContentBuilder.setRole("model");
modelContentBuilder.addText("Great to meet you. What would you like to know?");
Content modelContent = userContentBuilder.build();

List<Content> history = Arrays.asList(userContent, modelContent);

// Initialize the chat
ChatFutures chat = model.startChat(history);

// Create a new user message
Content.Builder userMessageBuilder = new Content.Builder();
userMessageBuilder.setRole("user");
userMessageBuilder.addText("How many paws are in my house?");
Content userMessage = userMessageBuilder.build();

Executor executor = // ...

// Send the message
ListenableFuture<GenerateContentResponse> response = chat.sendMessage(userMessage);

Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
    @Override
    public void onSuccess(GenerateContentResponse result) {
        String resultText = result.getText();
        System.out.println(resultText);
    }

    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

Usa la transmisión para tener interacciones más rápidas

De forma predeterminada, el modelo muestra una respuesta después de completar todo el proceso de generación. Puedes lograr interacciones más rápidas si no esperas todo el resultado y, en su lugar, usa la transmisión para controlar resultados parciales.

En el siguiente ejemplo, se muestra cómo implementar la transmisión con generateContentStream para generar texto a partir de un mensaje de entrada de imagen y texto.

Kotlin

Ten en cuenta que generateContentStream() es una función de suspensión y se debe llamar desde un alcance de corrutinas. Si no estás familiarizado con las corrutinas, consulta Corrutinas de Kotlin en Android.

val generativeModel = GenerativeModel(
    // The Gemini 1.5 models are versatile and work with both text-only and multimodal prompts
    modelName = "gemini-1.5-flash",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

val image1: Bitmap = // ...
val image2: Bitmap = // ...

val inputContent = content {
    image(image1)
    image(image2)
    text("What's the difference between these pictures?")
}

var fullResponse = ""
generativeModel.generateContentStream(inputContent).collect { chunk ->
    print(chunk.text)
    fullResponse += chunk.text
}

Java

Los métodos de transmisión de Java en este SDK muestran un tipo Publisher de la biblioteca Reactive Streams.

// The Gemini 1.5 models are versatile and work with both text-only and multimodal prompts
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-1.5-flash",
// Access your API key as a Build Configuration variable (see "Set up your API key" above)
    /* apiKey */ BuildConfig.apiKey);
GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Bitmap image1 = // ...
Bitmap image2 = // ...

Content content = new Content.Builder()
    .addText("What's different between these pictures?")
    .addImage(image1)
    .addImage(image2)
    .build();

Publisher<GenerateContentResponse> streamingResponse =
    model.generateContentStream(content);

StringBuilder outputContent = new StringBuilder();

streamingResponse.subscribe(new Subscriber<GenerateContentResponse>() {
    @Override
    public void onNext(GenerateContentResponse generateContentResponse) {
        String chunk = generateContentResponse.getText();
        outputContent.append(chunk);
    }

    @Override
    public void onComplete() {
        System.out.println(outputContent);
    }

    @Override
    public void onError(Throwable t) {
        t.printStackTrace();
    }

    @Override
    public void onSubscribe(Subscription s) {
      s.request(Long.MAX_VALUE);
    }
});

Puedes usar un enfoque similar para los casos de uso de entrada de solo texto y chat:

Kotlin

Ten en cuenta que generateContentStream() es una función de suspensión y se debe llamar desde un alcance de corrutinas. Si no estás familiarizado con las corrutinas, consulta Corrutinas de Kotlin en Android.

// Use streaming with text-only input
generativeModel.generateContentStream(inputContent).collect { chunk ->
    print(chunk.text)
}
// Use streaming with multi-turn conversations (like chat)
val chat = generativeModel.startChat()
chat.sendMessageStream(inputContent).collect { chunk ->
    print(chunk.text)
}

Java

Los métodos de transmisión de Java en este SDK muestran un tipo Publisher de la biblioteca Reactive Streams.

// Use streaming with text-only input
Publisher<GenerateContentResponse> streamingResponse =
    model.generateContentStream(inputContent);

StringBuilder outputContent = new StringBuilder();

streamingResponse.subscribe(new Subscriber<GenerateContentResponse>() {
    @Override
    public void onNext(GenerateContentResponse generateContentResponse) {
        String chunk = generateContentResponse.getText();
        outputContent.append(chunk);
    }

    @Override
    public void onComplete() {
        System.out.println(outputContent);
    }

    @Override
    public void onSubscribe(Subscription s) {
      s.request(Long.MAX_VALUE);
    }

    // ... other methods omitted for brevity
});
// Use streaming with multi-turn conversations (like chat)
ChatFutures chat = model.startChat(history);

Publisher<GenerateContentResponse> streamingResponse =
    chat.sendMessageStream(inputContent);

StringBuilder outputContent = new StringBuilder();

streamingResponse.subscribe(new Subscriber<GenerateContentResponse>() {
    @Override
    public void onNext(GenerateContentResponse generateContentResponse) {
        String chunk = generateContentResponse.getText();
        outputContent.append(chunk);
    }

    @Override
    public void onComplete() {
        System.out.println(outputContent);
    }

    @Override
    public void onSubscribe(Subscription s) {
      s.request(Long.MAX_VALUE);
    }

    // ... other methods omitted for brevity
});

Implementa casos de uso avanzados

Los casos de uso comunes descritos en la sección anterior de este instructivo te ayudarán a familiarizarte con el uso de la API de Gemini. En esta sección, se describen algunos casos de uso que podrían considerarse más avanzados.

Llamada a función

Las llamadas a función facilitan la obtención de resultados de datos estructurados de modelos generativos. Luego, puedes usar estos resultados para llamar a otras APIs y mostrar los datos de respuesta relevantes al modelo. En otras palabras, las llamadas a función te ayudan a conectar modelos generativos a sistemas externos para que el contenido generado incluya la información más actualizada y precisa. Obtén más información en el instructivo de llamada a funciones.

Contar tokens

Cuando se usan instrucciones largas, puede ser útil contar los tokens antes de enviar contenido al modelo. En los siguientes ejemplos, se muestra cómo usar countTokens() para varios casos de uso:

Kotlin

Ten en cuenta que countTokens() es una función de suspensión y se debe llamar desde un alcance de corrutinas. Si no estás familiarizado con las corrutinas, consulta Corrutinas de Kotlin en Android.

// For text-only input
val (totalTokens) = generativeModel.countTokens("Write a story about a magic backpack.")

// For text-and-image input (multi-modal)
val multiModalContent = content {
    image(image1)
    image(image2)
    text("What's the difference between these pictures?")
}

val (totalTokens) = generativeModel.countTokens(multiModalContent)

// For multi-turn conversations (like chat)
val history = chat.history
val messageContent = content { text("This is the message I intend to send")}
val (totalTokens) = generativeModel.countTokens(*history.toTypedArray(), messageContent)

Java

Ten en cuenta que countTokens() muestra un ListenableFuture. Si no conoces esta API, consulta la documentación de Android sobre Cómo usar un ListenableFuture.

Content text = new Content.Builder()
    .addText("Write a story about a magic backpack.")
    .build();

Executor executor = // ...

// For text-only input
ListenableFuture<CountTokensResponse> countTokensResponse = model.countTokens(text);

Futures.addCallback(countTokensResponse, new FutureCallback<CountTokensResponse>() {
    @Override
    public void onSuccess(CountTokensResponse result) {
        int totalTokens = result.getTotalTokens();
        System.out.println("TotalTokens = " + totalTokens);
    }

    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

// For text-and-image input
Bitmap image1 = // ...
Bitmap image2 = // ...

Content multiModalContent = new Content.Builder()
    .addImage(image1)
    .addImage(image2)
    .addText("What's different between these pictures?")
    .build();

ListenableFuture<CountTokensResponse> countTokensResponse = model.countTokens(multiModalContent);

// For multi-turn conversations (like chat)
List<Content> history = chat.getChat().getHistory();

Content messageContent = new Content.Builder()
    .addText("This is the message I intend to send")
    .build();

Collections.addAll(history, messageContent);

ListenableFuture<CountTokensResponse> countTokensResponse = model.countTokens(history.toArray(new Content[0]));

Opciones para controlar la generación de contenido

Puedes controlar la generación de contenido mediante la configuración de los parámetros del modelo y el uso de la configuración de seguridad.

Configura los parámetros del modelo

Cada instrucción que envías al modelo incluye valores de parámetros que controlan cómo el modelo genera una respuesta. El modelo puede generar resultados diferentes para los valores de parámetros diferentes. Obtén más información sobre los parámetros del modelo.

Kotlin

val config = generationConfig {
    temperature = 0.9f
    topK = 16
    topP = 0.1f
    maxOutputTokens = 200
    stopSequences = listOf("red")
}

val generativeModel = GenerativeModel(
    // The Gemini 1.5 models are versatile and work with most use cases
    modelName = "gemini-1.5-flash",
    apiKey = BuildConfig.apiKey,
    generationConfig = config
)

Java

GenerationConfig.Builder configBuilder = new GenerationConfig.Builder();
configBuilder.temperature = 0.9f;
configBuilder.topK = 16;
configBuilder.topP = 0.1f;
configBuilder.maxOutputTokens = 200;
configBuilder.stopSequences = Arrays.asList("red");

GenerationConfig generationConfig = configBuilder.build();

// The Gemini 1.5 models are versatile and work with most use cases
GenerativeModel gm = new GenerativeModel(
    "gemini-1.5-flash",
    BuildConfig.apiKey,
    generationConfig
);

GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Usar la configuración de seguridad

Puedes usar la configuración de seguridad para ajustar la probabilidad de recibir respuestas que puedan considerarse dañinas. De forma predeterminada, la configuración de seguridad bloquea el contenido con probabilidad media o alta de ser contenido no seguro en todas las dimensiones. Obtén más información sobre la configuración de seguridad.

Sigue estos pasos para establecer una configuración de seguridad:

Kotlin

val generativeModel = GenerativeModel(
    // The Gemini 1.5 models are versatile and work with most use cases
    modelName = "gemini-1.5-flash",
    apiKey = BuildConfig.apiKey,
    safetySettings = listOf(
        SafetySetting(HarmCategory.HARASSMENT, BlockThreshold.ONLY_HIGH)
    )
)

Java

SafetySetting harassmentSafety = new SafetySetting(HarmCategory.HARASSMENT,
    BlockThreshold.ONLY_HIGH);

// The Gemini 1.5 models are versatile and work with most use cases
GenerativeModel gm = new GenerativeModel(
    "gemini-1.5-flash",
    BuildConfig.apiKey,
    null, // generation config is optional
    Collections.singletonList(harassmentSafety)
);

GenerativeModelFutures model = GenerativeModelFutures.from(gm);

También puedes establecer más de una configuración de seguridad:

Kotlin

val harassmentSafety = SafetySetting(HarmCategory.HARASSMENT, BlockThreshold.ONLY_HIGH)

val hateSpeechSafety = SafetySetting(HarmCategory.HATE_SPEECH, BlockThreshold.MEDIUM_AND_ABOVE)

val generativeModel = GenerativeModel(
    // The Gemini 1.5 models are versatile and work with most use cases
    modelName = "gemini-1.5-flash",
    apiKey = BuildConfig.apiKey,
    safetySettings = listOf(harassmentSafety, hateSpeechSafety)
)

Java

SafetySetting harassmentSafety = new SafetySetting(HarmCategory.HARASSMENT,
    BlockThreshold.ONLY_HIGH);

SafetySetting hateSpeechSafety = new SafetySetting(HarmCategory.HATE_SPEECH,
    BlockThreshold.MEDIUM_AND_ABOVE);

// The Gemini 1.5 models are versatile and work with most use cases
GenerativeModel gm = new GenerativeModel(
    "gemini-1.5-flash",
    BuildConfig.apiKey,
    null, // generation config is optional
    Arrays.asList(harassmentSafety, hateSpeechSafety)
);

GenerativeModelFutures model = GenerativeModelFutures.from(gm);

¿Qué sigue?

  • El diseño de instrucciones es el proceso de crear instrucciones que producen la respuesta deseada de los modelos de lenguaje. Escribir instrucciones bien estructuradas es una parte esencial de garantizar respuestas precisas y de alta calidad desde un modelo de lenguaje. Obtén más información sobre las prácticas recomendadas para la redacción de instrucciones.

  • Gemini ofrece varias variaciones del modelo para satisfacer las necesidades de distintos casos de uso, como los tipos de entrada y la complejidad, las implementaciones para chat y otras tareas de lenguaje de diálogo, y las restricciones de tamaño. Obtén más información sobre los modelos de Gemini disponibles.

  • El SDK cliente para Android que se describe en este instructivo te permite acceder a los modelos de Gemini Pro que se ejecutan en los servidores de Google. Para los casos de uso que implican el procesamiento de datos sensibles, la disponibilidad sin conexión o el ahorro de costos para los flujos de usuarios que se usan con frecuencia, te recomendamos que consideres acceder a Gemini Nano, que se ejecuta en el dispositivo. Para obtener más detalles, consulta el instructivo para Android (en el dispositivo).