书架构建器:使用 Gemini 为 Gemini 应用构建 Java Cloud Functions 函数

1. 简介

您是否喜欢钻研书籍,却困于繁杂的海量图书选择?假设有一款 AI 赋能的应用,它不仅能推荐理想的读物,还会根据您选择的图书类型提供简明摘要,让您快速掌握书本的精髓。在此 Codelab 中,我将引导您使用由 Gemini 提供支持的 BigQuery 和 Cloud Functions 构建此类应用。

项目概览

我们的应用场景围绕以下 4 个关键组件展开:

  • Book Database:这是一个庞大的互联网归档图书 BigQuery 公共数据集,将作为全面的图书目录。
  • AI 摘要引擎:借助 Gemini-Pro 语言模型,Google Cloud Functions 会根据用户请求生成富有洞见的摘要。
  • BigQuery 集成:BigQuery 中的远程函数,可调用 Cloud Functions 函数,以便按需提供图书摘要和主题。
  • 界面:托管在 Cloud Run 上的 Web 应用,可供用户查看结果。

我们将将实现分为 3 个 Codelab:

Codelab 1:使用 Gemini 为 Gemini 应用构建 Java Cloud Functions 函数。

Codelab 2:使用 Gemini 通过 BigQuery 构建仅限 SQL 的生成式 AI 应用。

Codelab 3:使用 Gemini 创建与 BigQuery 交互的 Java Spring Boot Web 应用。

2. 使用 Gemini 在 Java Cloud Functions 函数上以无服务器方式构建生成式 AI 应用

构建内容

您将创建一个

  • Java Cloud Functions 应用,用于实现 Gemini 1.0 Pro,以将特定提示作为 JSON 数组形式的输入并返回响应(Json 值标记为“回复”)。
  • 您将在 Gemini 的帮助下完成构建和部署步骤

3. 要求

  • 一个浏览器,例如 ChromeFirefox
  • 启用了结算功能的 Google Cloud 项目

以下是必备条件:

创建项目

  1. Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目
  2. 确保您的 Cloud 项目已启用结算功能。了解如何检查项目是否已启用结算功能

激活 Cloud Shell

  1. 您将使用 Cloud Shell,这是一个在 Google Cloud 中运行的命令行环境,它预加载了 bq

在 Cloud 控制台中,点击右上角的“激活 Cloud Shell”:6757b2fb50ddcc2d.png

  1. 在连接到 Cloud Shell 后,您应该会看到自己已通过身份验证,并且项目已设置为您的项目 ID。在 Cloud Shell 中运行以下命令,以确认您已通过身份验证:
gcloud auth list
  1. 在 Cloud Shell 中运行以下命令,以确认 gcloud 命令了解您的项目
gcloud config list project
  1. 如果项目未设置,请使用以下命令进行设置:
gcloud config set project <YOUR_PROJECT_ID>

如需了解 gcloud 命令和用法,请参阅文档

4. 启用 Gemini for Google Cloud 和必要的 API

启用 Gemini

  1. 前往 Marketplace 中的 Gemini for Google Cloud 启用该 API。您还可以使用以下命令:
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID
  1. 访问 Gemini 页面,然后点击“开始聊天”。

重要提示:请按照此 Codelab 中的第 1 步和第 2 步操作,分别开始使用 Gemini 和在 Cloud Shell IDE 中启用 Gemini。

启用其他必要的 API

我们该怎么做呢?让我们来问问 Gemini 吧。但在此之前,请记住:

LLM 具有不确定性。因此,在您尝试提出这些问题时,您收到的回答可能与我的屏幕截图中的回答有所不同。

点击右上角的“打开 Gemini”图标(位于 Google Cloud 控制台搜索栏旁边),前往 Gemini Chat 控制台。

26e1491322855614.png

在“在此处输入提示”部分输入以下问题:

How do I enable the cloud functions api using a gcloud command? 

您应该会收到类似如下的响应:

gcloud services enable cloudfunctions.googleapis.com

复制该命令(您可以使用命令代码段顶部的复制图标),然后在 Cloud Shell 终端中运行,以启用 Cloud Functions。对 Cloud Run 执行相同的操作,因为我们需要同时构建和部署 Cloud Functions 函数:

gcloud services enable \
  cloudfunctions.googleapis.com \
  aiplatform.googleapis.com \
  run.googleapis.com \
  cloudbuild.googleapis.com

5. 使用 Gemini 准备 Cloud Functions 模板

现在,我假设您已经在 Cloud Shell IDE 中启用了 Gemini。

点击 Cloud Shell 终端右上角的“打开编辑器”图标,打开 Cloud Shell 编辑器(我通常更喜欢在单独的标签页中并行打开终端和编辑器,以便在一个标签页中编写代码,在另一个标签页中构建)。

edd258384bc74f1f.png

打开编辑器后,确保编辑器控制台右下角的 Gemini 徽标处于有效状态(而非取消状态)。此外,确保左下角的 Google Cloud 项目指向您当前想要处理的有效项目。如果它们处于无效状态,请点击进行授权,选择您要指向的 Google Cloud 项目并将其激活。

两者都处于有效状态后,点击左下角的项目名称,在随即打开的名为“Cloud Code”的弹出式列表中向下滚动到“新应用”。

ca08602b576ebd57.png

在该列表中,选择“Cloud Functions 应用”。从弹出的列表中选择“Java”:

ac2b44245949da68.png

在结果列表中,输入项目名称“duetai-gemini-calling”而不是“helloworld”,然后点击“确定”。

bf9cfe86e35cdced.png

太棒了!您已经使用 Gemini 引导了简单的 Java Cloud Functions 应用,除了启用和激活配置之外,您没怎么做,对吧?

您应该会看到以下项目结构:

d56e410fb76f183f.png

现在,您就可以部署函数了。但这并非我们开始这项工作的原因。接下来,我们使用 Java SDK 在此 Cloud Functions 函数中构建 Gemini Pro API 实现。

现在,我们来为此用例构建功能,即在此 Cloud Functions 函数中调用 Gemini Pro 模型。为此,您可以添加更多提示,并使用 Gemini 逐步开发代码,也可以自行编写逻辑。我会同时采用这两种方法。

6. 添加依赖项

在 Gemini 聊天控制台中(左侧窗格中的 Cloud Code 编辑器内),输入以下提示:

what is the maven dependency for com.google.cloud.vertexai library

之所以专门询问 com.google.cloud.vertexai 软件包,是因为我在实现 Gemini 调用代码的源代码中使用了该软件包。

结果如下:

62c4295b9b4654e9.png

 <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-vertexai</artifactId>
      <version>0.1.0</version>
    </dependency>

复制下面的代码并将其粘贴到 pom.xml 文件中,放在 </dependencies> 标记前面,且紧邻该标记。将版本替换为 0.1.0(如果您使用 Spring Cloud GCP BOM 为您管理 spring-cloud-gcp 版本号,则可以移除 <version> 标记)。

依赖项部分应如下所示:

1800f10af9331210.png

如果需要,请务必更新版本号,使其与上述内容保持一致。如您所注意,我还添加了另一个依赖项:

    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.10</version>
    </dependency>

7. 修改函数入口点和类名称

  1. 前往“.vscode”文件夹下的“launch.json”文件。将函数名称从“function-hello-world”修改为“function-gemini-calling”。
  2. 将 entryPoint 值从“cloudcode.helloworld.HelloWorld”更新为“cloudcode.bookshelf.Bookshelf”。
  3. 现在,打开 Java 类文件“HelloWorld.java”。将软件包名称更改为 package cloudcode.bookshelf;在弹出的错误中,点击黄色灯泡,然后点击“将 HelloWorld.java 移至 package cloudcode.bookshelf”选项。

38d721978bddc8a8

  1. 将类名称更新为“书架”,在弹出的错误中,点击黄色的小灯泡,然后选择“将文件重命名为“Books.java”。选择该选项。

8. 创建用于调用 Gemini Pro 的方法

我们将在 Bookshelf.java 类中实现此功能。将 Bookshelf.java 替换为以下代码:

package cloudcode.bookshelf;
import java.io.BufferedWriter;
import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.cloud.vertexai.VertexAI;
import com.google.cloud.vertexai.api.GenerateContentResponse;
import com.google.cloud.vertexai.api.GenerationConfig;
import com.google.cloud.vertexai.generativeai.preview.GenerativeModel;
import com.google.cloud.vertexai.generativeai.preview.ResponseHandler;
import java.io.IOException;
import java.util.List;
import java.util.Arrays;
import java.util.Map;
import java.util.LinkedHashMap;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;

public class Bookshelf implements HttpFunction {
  private static final Gson gson = new Gson();

 @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    BufferedWriter writer = response.getWriter();

 // Get the request body as a JSON object.
 JsonObject requestJson = new Gson().fromJson(request.getReader(), JsonObject.class);
 JsonArray calls_array = requestJson.getAsJsonArray("calls");
 JsonArray calls = (JsonArray) calls_array.get(0);
 String context = calls.get(0).toString().replace("\"", "");

 //Invoke Gemini model
  String raw_result = callGemini(context);
  raw_result = raw_result.replace("\n","");
  String trimmed = raw_result.trim();
  List<String> result_list = Arrays.asList(trimmed);
  Map<String, List<String>> stringMap = new LinkedHashMap<>();
  stringMap.put("replies", result_list);
 
  // Serialization
  String return_value = gson.toJson(stringMap);
  writer.write(return_value);
    }
  public String callGemini(String context) throws IOException{
      String res = "";
        try (VertexAI vertexAi = new VertexAI("REPLACE_WITH_YOUR_PROJECT_ID", "us-central1"); ) {
          GenerationConfig generationConfig =
              GenerationConfig.newBuilder()
                  .setMaxOutputTokens(2048)
                  .setTemperature(0.4F)
                  .setTopK(32)
                  .setTopP(1)
                  .build();  
        GenerativeModel model = new GenerativeModel("gemini-pro", generationConfig, vertexAi);
        GenerateContentResponse response = model.generateContent(context);
        res = ResponseHandler.getText(response);
      }catch(Exception e){
        System.out.println(e);
        }
        return res;
    }
}

此类期望输入采用以下 JSON 结构:

{ &quot;calls&quot;: [[&quot;YOUR_PROMPT_HERE&quot;]] }

它会返回如下所示的响应:

(Json) Map<String, List<String>> {"replies": ["response"]}

在 Cloud Shell 编辑器的左侧窗格中,试用 Gemini Chat 选项来解释代码。或者,您也可以选择所有代码,然后点击所选代码左上角的黄色灯泡,然后选择“解释此代码”选项。

66fb67507793e368

9. 部署 Cloud Functions 函数

现在,Cloud Functions 函数已准备就绪,我们来问问 Gemini 如何部署它。在 Cloud Code 编辑器中,前往 Gemini 聊天对话,然后输入以下内容:

   How to deploy this Cloud Function with a gcloud command?

我收到的回复如下:

9f9db98933841864

现在,我想进一步探究一下。于是,我继续让 Gemini 告诉我完整的 gcloud functions deploy 命令。响应如下所示:

b77701c00dc3eaf1.png

我现在无法确定您是否会收到相同的回复,但我发现它还会提供一些额外的详细信息,这让我感到很惊讶,如下图所示:

请求正文格式:

82bf20304143a374.png

响应格式:

ade55b3de5d823a6.png

现在,我们继续运行 Gemini 提供的 gcloud 命令,部署该函数。为此,我们需要打开 Cloud Shell 终端。您可以在 https://console.cloud.google.com 的新标签页中将其打开,并确保选择了正确的项目。点击控制台右上角的“激活 Cloud Shell”图标,打开 Cloud Shell 终端,然后使用以下命令确保您位于正确的项目文件夹中:

cd duetai-gemini-calling

然后运行以下命令:

gcloud functions deploy bookshelf --runtime java17 --trigger-http --entry-point cloudcode.bookshelf.Bookshelf --allow-unauthenticated

系统会询问您“是否允许对新函数 [bookshelf] 进行未经身份验证的调用?”说“y”并按 Enter 键。然后,系统会询问您几个问题(如果适用),并部署您的无服务器 Cloud Functions 函数,部署后的网址为:https://us-central1-*******.cloudfunctions.net/bookshelf。

现在,我们来调用已部署的 Cloud Functions 函数并对其进行测试!

注意:如果您不小心跳过了“允许未经身份验证的调用”问题或选择了“否”,则将无法访问 Cloud Functions 函数的结果,并且在未授予其他 IAM 设置的情况下,会看到“权限错误”。注意这一点

10. 调用已部署的 Cloud Functions 函数

让我们来问问 Gemini 吧?我输入了提示

How to call the deployed cloud function?

我得到的结果如下:(你不一定看到完全相同的回答,请随意尝试不同的提示,看看回答的差异)。

1d2242715571fe6f.png

围绕调用已部署函数的其他方式、使用 gcloud 命令调用等方式,围绕特定问题来深入探究聊天。我提交了以下提示:

how to call the deployed cloud function using gcloud

我收到了以下回复:e7b29b2cfb57782c.png

您可以使用终端中的此响应(“gcloud functions call”命令),并进行调整以使其适用于我们的场景(或者,尝试在提示本身中传递参数,看看您是否能够在响应中获取详细的 gcloud functions call):

gcloud functions call bookshelf --region=us-central1 --gen2 --data '{"calls":[["Hello! This is my test prompt."]]}'

我的结果如下:

6f396d915251db78

11. 清理

您可以点击 Cloud Functions 的详情页面中的“删除”按钮,删除之前创建的 Cloud Functions。

12. 恭喜

您已成功构建、部署并测试了一个 Java Cloud Functions 函数,该函数可使用 Gemini 调用 Gemini 1.0 Pro!此应用可接受与图书推荐(包含图书摘要和主题)相关的输入提示。