开始在 Android 应用中使用 Gemini API(客户端 SDK)

本教程演示了如何使用适用于 Android 的 Google AI 客户端 SDK 直接从 Android 应用访问 Gemini API。如果您不想直接使用 REST API 或服务器端代码(如 Python)来访问 Android 应用中的 Gemini 模型,则可以使用此客户端 SDK。

在本教程中,您将了解如何执行以下操作:

此外,本教程还包含一些高级用例(例如令牌计数)以及控制内容生成的选项。

建议在设备上访问 Gemini

通过本教程中介绍的 Android 客户端 SDK,您可以访问在 Google 的服务器上运行的 Genmini Pro 型号。对于涉及处理敏感数据、实现离线可用性或为常用用户流节省费用的用例,您可以考虑访问在设备上运行的 Gemini Nano。如需了解详情,请参阅 Android(设备端)教程

前提条件

本教程假定您熟悉如何使用 Android Studio 开发 Android 应用。

如需完成本教程,请确保您的开发环境和 Android 应用满足以下要求:

  • Android Studio(最新版本)
  • 您的 Android 应用必须以 API 级别 21 或更高级别为目标平台。

设置项目

在调用 Gemini API 之前,您需要设置 Android 项目,其中包括设置 API 密钥、将 SDK 依赖项添加到 Android 项目,以及初始化模型。

设置您的 API 密钥

您需要 API 密钥才能使用 Gemini API。如果您还没有密钥,请在 Google AI Studio 中创建密钥。

获取 API 密钥

保护您的 API 密钥

强烈建议您不要将 API 密钥签入版本控制系统。请改为将 API 密钥存储在 local.properties 文件中(位于项目的根目录中,但不在版本控制系统中),然后使用 Android 版 Secrets Gradle 插件将 API 密钥作为 build 配置变量读取。

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;

本教程中的所有代码段均使用此最佳做法。此外,如果您想查看 Secrets Gradle 插件的实现,可以查看此 SDK 的示例应用,或使用 Android Studio Iguana 的最新预览,其中包含 Gemini API Starter 模板(其中包含 local.properties 文件,以帮助您上手)。

将 SDK 依赖项添加到您的项目

  1. 在您的模块(应用级)Gradle 配置文件(例如 <project>/<app-module>/build.gradle.kts)中,添加 Google AI SDK for 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.3.0")
    }
    

    Java

    对于 Java,您需要添加两个额外的库。

    dependencies {
        // ... other androidx dependencies
    
        // add the dependency for the Google AI client SDK for Android
        implementation("com.google.ai.client.generativeai:generativeai:0.3.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. 将您的 Android 项目与 Gradle 文件同步。

初始化生成模型

您需要先初始化 GenerativeModel 对象,然后才能进行任何 API 调用:

Kotlin

val generativeModel = GenerativeModel(
    // Use a model that's applicable for your use case (see "Implement basic use cases" below)
    modelName = "MODEL_NAME",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

Java

对于 Java,您还需要初始化 GenerativeModelFutures 对象。

// Use a model that's applicable for your use case (see "Implement basic use cases" below)
GenerativeModel gm = new GenerativeModel(/* modelName */ "MODEL_NAME",
// 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);

指定模型时,请注意以下事项:

  • 使用特定于您的用例的模型(例如,gemini-pro-vision 适用于多模态输入)。在本指南中,每种实现的说明都列出了针对每个应用场景推荐的模型。

实现常见使用场景

现在,您的项目已设置完毕,接下来,您可以探索如何使用 Gemini API 实现不同的用例:

根据纯文本输入生成文本

当提示输入仅包含文本时,请将 gemini-pro 模型与 generateContent 结合使用以生成文本输出:

Kotlin

请注意,generateContent() 是一个挂起函数,需要从协程作用域中调用。如果您不熟悉协程,请参阅 Android 上的 Kotlin 协程

val generativeModel = GenerativeModel(
    // For text-only input, use the gemini-pro model
    modelName = "gemini-pro",
    // 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

请注意,generateContent() 会返回一个 ListenableFuture。如果您不熟悉此 API,请参阅有关使用 ListenableFuture 的 Android 文档。

// For text-only input, use the gemini-pro model
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-pro",
// 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);

根据文本和图片输入生成文本(多模态)

Gemini 提供了一个多模态模型 (gemini-pro-vision),因此您可以同时输入文字和图片。请务必查看提示的图片要求

当提示输入同时包含文本和图片时,请将 gemini-pro-vision 模型与 generateContent 结合使用以生成文本输出:

Kotlin

请注意,generateContent() 是一个挂起函数,需要从协程作用域中调用。如果您不熟悉协程,请参阅 Android 上的 Kotlin 协程

val generativeModel = GenerativeModel(
    // For text-and-images input (multimodal), use the gemini-pro-vision model
    modelName = "gemini-pro-vision",
    // 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

请注意,generateContent() 会返回一个 ListenableFuture。如果您不熟悉此 API,请参阅有关使用 ListenableFuture 的 Android 文档。

// For text-and-images input (multimodal), use the gemini-pro-vision model
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-pro-vision",
// 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);

发起多轮对话(聊天)

使用 Gemini,您可以构建多轮自由对话。该 SDK 通过管理对话状态来简化流程,因此与 generateContent 不同,您不必自行存储对话记录。

如需构建多轮对话(如聊天),请使用 gemini-pro 模型,并通过调用 startChat() 来初始化聊天。然后,使用 sendMessage() 发送一条新用户消息,此操作还会将消息和响应附加到聊天记录中。

对于与对话内容关联的 role,有两个可能的选项:

  • user:提供提示的角色。这是 sendMessage 调用的默认值。

  • model:提供响应的角色。使用现有 history 调用 startChat() 时,可以使用此角色。

Kotlin

请注意,generateContent() 是一个挂起函数,需要从协程作用域中调用。如果您不熟悉协程,请参阅 Android 上的 Kotlin 协程

val generativeModel = GenerativeModel(
    // For text-only input, use the gemini-pro model
    modelName = "gemini-pro",
    // 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

请注意,generateContent() 会返回一个 ListenableFuture。如果您不熟悉此 API,请参阅有关使用 ListenableFuture 的 Android 文档。

// For text-only input, use the gemini-pro model
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-pro",
// 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 userMessage = new Content.Builder()
    .setRole("user")
    .addText("How many paws are in my house?")
    .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);

使用流式传输加快互动速度

默认情况下,模型会在完成整个生成过程后返回响应。您可以不等待整个结果,而是使用流式传输来处理部分结果,从而实现更快的互动。

以下示例展示了如何使用 generateContentStream 实现流式传输,以根据文本和图像输入提示生成文本。

Kotlin

请注意,generateContentStream() 是一个挂起函数,需要从协程作用域中调用。如果您不熟悉协程,请参阅 Android 上的 Kotlin 协程

val generativeModel = GenerativeModel(
    // For text-and-image input (multimodal), use the gemini-pro-vision model
    modelName = "gemini-pro-vision",
    // 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

此 SDK 中的 Java 流式传输方法会从 Reactive Streams 库返回 Publisher 类型。

// For text-and-images input (multimodal), use the gemini-pro-vision model
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-pro-vision",
// 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);

final String[] fullResponse = {""};

streamingResponse.subscribe(new Subscriber<GenerateContentResponse>() {
    @Override
    public void onNext(GenerateContentResponse generateContentResponse) {
        String chunk = generateContentResponse.getText();
        fullResponse[0] += chunk;
    }

    @Override
    public void onComplete() {
        System.out.println(fullResponse[0]);
    }

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

    @Override
    public void onSubscribe(Subscription s) { }
});

您可以在纯文本输入和聊天用例中使用类似的方法:

Kotlin

请注意,generateContentStream() 是一个挂起函数,需要从协程作用域中调用。如果您不熟悉协程,请参阅 Android 上的 Kotlin 协程

// 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

此 SDK 中的 Java 流式传输方法会从 Reactive Streams 库返回一个 Publisher 类型。

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

final String[] fullResponse = {""};

streamingResponse.subscribe(new Subscriber<GenerateContentResponse>() {
    @Override
    public void onNext(GenerateContentResponse generateContentResponse) {
        String chunk = generateContentResponse.getText();
        fullResponse[0] += chunk;
    }

    @Override
    public void onComplete() {
        System.out.println(fullResponse[0]);
    }

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

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

final String[] fullResponse = {""};

streamingResponse.subscribe(new Subscriber<GenerateContentResponse>() {
    @Override
    public void onNext(GenerateContentResponse generateContentResponse) {
        String chunk = generateContentResponse.getText();
        fullResponse[0] += chunk;
    }

    @Override
    public void onComplete() {
        System.out.println(fullResponse[0]);
    }

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

实现高级用例

本教程上一部分中介绍的常见用例可帮助您熟练使用 Gemini API。本部分介绍了一些可能被视为更高级的用例。

计算词元数

使用长提示时,在将任何内容发送到模型之前统计令牌数可能很有用。以下示例展示了如何针对各种用例使用 countTokens()

Kotlin

请注意,countTokens() 是一个挂起函数,需要从协程作用域中调用。如果您不熟悉协程,请参阅 Android 上的 Kotlin 协程

// 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

请注意,countTokens() 会返回一个 ListenableFuture。如果您不熟悉此 API,请参阅有关使用 ListenableFuture 的 Android 文档。

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]));

用于控制内容生成的选项

您可以通过配置模型参数和使用安全设置来控制内容生成。

配置模型参数

您向模型发送的每个提示都包含控制模型如何生成回答的参数值。对于不同的参数值,模型会生成不同的结果。详细了解模型参数

Kotlin

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

val generativeModel = GenerativeModel(
    modelName = "MODEL_NAME",
    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();

GenerativeModel gm = new GenerativeModel(
    "MODEL_NAME",
    BuildConfig.apiKey,
    generationConfig
);

GenerativeModelFutures model = GenerativeModelFutures.from(gm);

使用安全设置

您可以使用安全设置来调整收到可能被视为有害的响应的可能性。默认情况下,安全设置会屏蔽在所有维度上可能是中等和/或高可能性为不安全内容的内容。详细了解安全设置

设置一项安全设置的方法如下:

Kotlin

val generativeModel = GenerativeModel(
    modelName = "MODEL_NAME",
    apiKey = BuildConfig.apiKey,
    safetySettings = listOf(
        SafetySetting(HarmCategory.HARASSMENT, BlockThreshold.ONLY_HIGH)
    )
)

Java

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

GenerativeModel gm = new GenerativeModel(
    "MODEL_NAME",
    BuildConfig.apiKey,
    null, // generation config is optional
    Collections.singletonList(harassmentSafety)
);

GenerativeModelFutures model = GenerativeModelFutures.from(gm);

您还可以设定多项安全设置:

Kotlin

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

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

val generativeModel = GenerativeModel(
    modelName = "MODEL_NAME",
    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);

GenerativeModel gm = new GenerativeModel(
    "MODEL_NAME",
    BuildConfig.apiKey,
    null, // generation config is optional
    Arrays.asList(harassmentSafety, hateSpeechSafety)
);

GenerativeModelFutures model = GenerativeModelFutures.from(gm);

后续步骤

  • 提示设计是创建提示以从语言模型引出所需回复的过程。编写结构良好的提示是确保语言模型提供准确、高质量的响应的重要部分。了解撰写提示的最佳做法

  • Gemini 提供了多个模型变体来满足不同用例的需求,例如输入类型和复杂度、聊天或其他对话框语言任务的实现,以及大小限制。了解可用的 Gemini 模型

  • Gemini 提供了用于请求提高速率限制的选项。Genmini Pro 型号的速率限制为每分钟 60 个请求。

  • 通过本教程中介绍的 Android 客户端 SDK,您可以访问在 Google 的服务器上运行的 Genmini Pro 型号。对于涉及处理敏感数据、实现离线可用性或为常用用户流节省费用的用例,您可以考虑访问在设备上运行的 Gemini Nano。如需了解详情,请参阅 Android(设备端)教程