1. 簡介
你喜歡深入瞭解書籍,但選擇太多讓你不知從何下手嗎?想像一下,如果有一款 AI 輔助應用程式,不僅能推薦最適合你的讀物,還能根據你選擇的類型提供簡要摘要,讓你一窺書中精髓。在本程式碼研究室中,我將逐步說明如何使用 BigQuery 和 Cloud Functions (由 Gemini 提供技術支援) 建構這類應用程式。
專案總覽
我們的用途圍繞以下 4 個主要元件:
- 書籍資料庫:網際網路封存書籍的龐大 BigQuery 公開資料集,將做為我們完整的書籍目錄。
- AI 摘要引擎:Google Cloud Functions 會搭載 Gemini Pro 語言模型,根據使用者要求生成深入的摘要。
- BigQuery 整合:BigQuery 中的遠端函式,可呼叫我們的 Cloud Function,依需求提供書籍摘要和主題。
- 使用者介面:託管在 Cloud Run 的網頁應用程式,可供使用者查看結果。
我們會將實作項目分成 3 個程式碼研究室:
程式碼研究室 1:使用 Gemini 建構 Gemini 應用程式的 Java Cloud Function。
程式碼實驗室 2:使用 Gemini 搭配 BigQuery,建構僅限 SQL 的生成式 AI 應用程式。
程式碼實驗室 3:使用 Gemini 建立可與 BigQuery 互動的 Java Spring Boot 網頁應用程式。
2. 使用 Gemini 在 Java Cloud Function 上以無伺服器方式建構生成式 AI 應用程式
建構項目
您將建立
- Java Cloud Functions 應用程式會實作 Gemini 1.0 Pro,以 JSON 陣列的形式接收特定提示做為輸入內容,並傳回回應 (標示為「replies」的 JSON 值)。
- 您將在 Gemini 的協助下完成建構及部署步驟
3. 需求條件
事前須知如下:
建立專案
- 在 Google Cloud 控制台的專案選取器頁面中,選取或建立 Google Cloud 專案。
- 確認 Cloud 專案已啟用計費功能。瞭解如何檢查專案是否已啟用計費功能。
啟用 Cloud Shell
- 您將使用 Cloud Shell,這是 Google Cloud 中執行的指令列環境,已預先載入 bq:
在 Cloud 控制台,按一下右上角的「啟用 Cloud Shell」:
- 連至 Cloud Shell 後,您應該會看到驗證已完成,專案也已設為獲派的專案 ID。在 Cloud Shell 中執行下列指令,確認您已通過驗證:
gcloud auth list
- 在 Cloud Shell 中執行下列指令,確認 gcloud 指令已瞭解您的專案
gcloud config list project
- 如果未設定專案,請使用下列指令來設定:
gcloud config set project <YOUR_PROJECT_ID>
如要瞭解 gcloud 指令和用法,請參閱說明文件。
4. 啟用 Gemini for Google Cloud 和必要的 API
啟用 Gemini
- 前往 Marketplace 中的 Gemini for Google Cloud 啟用 API。您也可以使用下列指令:
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID
- 前往 Gemini 頁面,然後按一下「開始對話」。
重要事項:請按照這個程式碼實驗室的步驟 1 和 2 操作,分別開始使用 Gemini 和在 Cloud Shell IDE 中啟用 Gemini。
啟用其他必要的 API
我們該怎麼做?我們來問問 Gemini 吧!但請先注意以下事項:
LLM 屬於非確定性模型,因此,您嘗試這些提示時,收到的回覆可能與我螢幕截圖中的回覆不同。
在 Google Cloud 控制台的搜尋列旁,按一下右上角的「開啟 Gemini」圖示,前往 Gemini 對話控制台。

在「在這裡輸入提示」部分輸入以下問題:
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 編輯器 (我通常偏好在不同的分頁中並行開啟終端機和編輯器,這樣就能在一個分頁中編寫程式碼,在另一個分頁中建構程式碼)。

開啟編輯器後,請確認編輯器控制台右下角的 Gemini 標誌已啟用 (而非取消)。此外,請確認左下角的 Google Cloud 專案指向您目前要使用的有效專案。如果這些服務處於非啟用狀態,請點選服務、授權,然後選取要指向的 Google Cloud 專案,並啟用服務。
兩者都啟用後,按一下左下角的專案名稱,然後在開啟的彈出式清單中,向下捲動至「New Application」(新應用程式)。

在該清單中,選取「Cloud Functions application」(Cloud Functions 應用程式)。在彈出式清單中選取 Java:

在產生的清單中,輸入專案名稱「duetai-gemini-calling」而非 helloworld,然後按一下「確定」。

太棒了!您已使用 Gemini 啟動簡單的 Java Cloud Functions 應用程式,除了啟用和啟動設定外,您幾乎沒有做任何事,對吧?
您應該會看到以下專案結構:

現在可以部署函式了。但這並非我們啟動這項計畫的原因。接下來,我們將使用 Java SDK,在這個 Cloud Function 中建構 Gemini Pro API 實作項目。
現在,讓我們為這個用途建構功能,也就是在這個 Cloud Function 中叫用 Gemini Pro 模型。為此,您可以自由新增更多提示,讓 Gemini 逐步開發程式碼,或自行編寫邏輯。我會混合使用這兩種方法。
6. 新增依附元件
在 Gemini 對話控制台 (位於左窗格的 Cloud Code 編輯器內) 中,輸入下列提示:
what is the maven dependency for com.google.cloud.vertexai library
我要求提供 com.google.cloud.vertexai 套件的具體範例,是因為我在實作 Gemini 呼叫程式碼時,就是使用這個套件。
我得到以下結果:

<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> 標記)。
依附元件部分應如下所示:

請務必視需要更新版本號碼,使其與上述內容相符。如您所見,我還一併加入了另一個依附元件:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
</dependency>
7. 修改函式進入點和類別名稱
- 前往「.vscode」資料夾下的「launch.json」檔案。將函式名稱從「function-hello-world」編輯為「function-gemini-calling」。
- 將 entryPoint 值從「cloudcode.helloworld.HelloWorld」更新為「cloudcode.bookshelf.Bookshelf」。
- 現在請前往「HelloWorld.java」Java 類別檔案。將套件名稱變更為套件 cloudcode.bookshelf;在彈出的錯誤中,按一下黃色燈泡,然後按一下「Move HelloWorld.java」選項,將套件移至 cloudcode.bookshelf。

- 將類別名稱更新為 Bookshelf,然後在彈出的錯誤訊息中,按一下黃色小燈泡,並選取「Rename file to Bookshelf.java」(將檔案重新命名為 Bookshelf.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 結構如下:
{ "calls": [["YOUR_PROMPT_HERE"]] }
系統會傳回如下所示的回應:
(Json) Map<String, List<String>> {"replies": ["response"]}
在左側窗格的 Cloud Shell 編輯器中,試用 Gemini 對話選項來解說程式碼。或者,您也可以選取所有程式碼,然後按一下選取範圍左上角的黃色燈泡,並選擇「說明這項內容」選項。

9. 部署 Cloud 函式
Cloud 函式已準備就緒,現在來問問 Gemini 如何部署。前往 Cloud Code 編輯器中的 Gemini 對話,然後輸入下列內容:
How to deploy this Cloud Function with a gcloud command?
我收到以下回覆:

我現在想進一步探究。因此我請 Gemini 提供完整的 gcloud functions deploy 指令。回應如下所示:

我無法保證你會收到相同回覆,但令我驚訝的是,Gemini 竟然還補充了更多細節,如下圖所示:
要求主體格式:

和
回覆格式:

現在請執行 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 Function,以及部署的網址:https://us-central1-*******.cloudfunctions.net/bookshelf。
現在,讓我們叫用已部署的 Cloud Functions 並進行測試!
注意:如果您不小心略過「允許未經驗證的叫用」問題或選取「N」,則未授予額外 IAM 設定時,您將無法存取 Cloud Functions 的結果,並會看到「權限錯誤」。請注意這一點。
10. 呼叫已部署的 Cloud Function
我們來問問 Gemini 吧。我輸入了提示
How to call the deployed cloud function?
我得到以下結果:(您可能會看到完全相同的結果,也可能不會。歡迎隨意調整提示,看看回覆內容有何不同)。

針對部署的函式,詢問其他叫用方式、使用 gcloud 指令呼叫等問題。我提交了以下提示:
how to call the deployed cloud function using gcloud
我收到以下回覆:
您可以從終端機使用這項回應 (「gcloud functions call」指令),並進行調整,使其適用於我們的情境 (或者,嘗試在提示中傳遞參數,看看是否能在回應中取得詳細的 gcloud functions call):
gcloud functions call bookshelf --region=us-central1 --gen2 --data '{"calls":[["Hello! This is my test prompt."]]}'
我的結果如下:

11. 清理
如要刪除先前建立的 Cloud Functions,請按一下 Cloud Functions 詳細資料頁面中的「DELETE」按鈕。
12. 恭喜
您已成功建構、部署及測試 Java Cloud Functions,並使用 Gemini 呼叫 Gemini 1.0 Pro!這項應用程式會根據書籍摘要和主題,取得與書籍推薦相關的輸入提示。