1. 簡介
你喜歡閱讀書籍,但在眾多選擇中感到不知所措嗎?想像一下,如果有個 AI 輔助應用程式,不但能推薦適合你的閱讀內容,還能根據你偏好的類型提供精簡摘要,讓你一窺書籍精髓,那該有多好。在本程式碼研究室中,我將逐步說明如何使用 Gemini 提供的 BigQuery 和 Cloud Functions 建構這類應用程式。
專案總覽
我們的用途主要圍繞以下 4 個主要元件:
- 圖書資料庫:我們擁有龐大的 BigQuery 公開資料集,內含眾多 網際網路封存書籍的公開資料集,做為我們完整的書籍目錄。
- AI 摘要引擎:Google Cloud Functions 配備 Gemini-Pro 語言模型,可根據使用者要求產生有洞察力的摘要。
- BigQuery 整合:BigQuery 中的遠端函式,可呼叫 Cloud Functions,以便隨選提供書籍摘要和主題。
- 使用者介面:在 Cloud Run 上託管的網頁應用程式,可提供網頁應用程式供使用者查看結果。
我們會將實作項目分成 3 個程式碼研究室:
程式碼研究室 1:使用 Gemini 為 Gemini 應用程式建構 Java Cloud Function。
程式碼研究室 2:透過 BigQuery 使用 Gemini 建構 SQL 專用的生成式 AI 應用程式。
程式碼研究室 3:使用 Gemini 建立可與 BigQuery 互動的 Java Spring Boot 網頁應用程式。
2. 使用 Gemini,在 Java Cloud 函式以無伺服器的方式建構生成式 AI 應用程式
建構項目
您將建立
- 實作 Gemini 1.0 Pro 的 Java Cloud Functions 應用程式,可將特定提示做為 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. 啟用 Google Cloud 專用 Gemini 和必要的 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 並非確定性,所以嘗試這些提示時,你收到的回應可能會與螢幕截圖中的回應不同。
前往 Gemini 對話主控台,在 Google Cloud 控制台的搜尋列旁邊,按一下右上角的「開啟 Gemini」圖示。
在「請輸入提示」部分輸入以下問題:
How do I enable the cloud functions api using a gcloud command?
您應該會得到類似以下的回覆:
gcloud services enable cloudfunctions.googleapis.com
複製該指令 (您可以使用指令片段頂端的複製圖示),然後在 Cloud Shell 終端機中執行,即可啟用 Cloud 函式。請為 Cloud Run 執行相同的操作,因為我們需要這兩者才能建構及部署 Cloud 函式:
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 終端機右上角的「Open Editor」(開啟編輯器) 圖示,即可開啟 Cloud Shell 編輯器 (我通常會在不同的分頁中同時開啟終端機和編輯器,這樣就能在一個分頁中編寫程式碼,並在另一個分頁中進行建構)。
開啟編輯器後,請確認編輯器控制台右下角的 Gemini 標誌處於啟用狀態 (且未取消)。此外,請確認左下角的 Google Cloud 專案指向您要使用的現有專案。如果這些專案處於「未啟用」狀態,請按一下並授權,選取要指向的 Google Cloud 專案,並啟用專案。
兩者都啟用後,請按一下左下角的專案名稱,然後在名為「Cloud Code」的彈出式清單中,向下捲動至「New Application」(新增應用程式)。
在清單中選取 Cloud Functions 應用程式。在彈出的清單中,選取「Java」:
在結果清單中,輸入專案名稱「duetai-gemini-calling」(不要輸入 helloworld),然後按一下「OK」。
太棒了!您已使用 Gemini 啟動簡單的 Java Cloud Functions 應用程式,除了啟用和啟動設定之外,您並未執行其他操作,對嗎?
您應該會看到以下專案結構:
您現在可以部署函式了。但這並不是我們推出這項功能的原因。繼續使用 Java SDK,在這個 Cloud 函式中建構 Gemini Pro API 實作項目。
現在,讓我們根據用途建構功能,以在這個 Cloud 函式中叫用 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」。
- 將 itemPoint 值從「cloudcode.helloworld.HelloWorld」更新為 cloudcode.Book.Bookshelf。
- 接著前往 Java 類別檔案「HelloWorld.java」。將套件名稱變更為 cloudcode.bookshelf;在彈出的錯誤訊息中,按一下黃色燈泡,然後點選「Move HelloWorld.java」至套件 cloudcode.bookshelf。
- 將類別名稱更新為 Bookshelf,然後在彈出的錯誤訊息中,按一下黃色小燈泡,然後選取「Rename file to 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 Chat 選項來說明程式碼。您也可以選取所有程式碼,然後按一下所選範圍左上角的黃色燈泡,然後選擇「說明」選項。
9. 部署 Cloud 函式
Cloud 函式已準備就緒,接下來讓我們詢問 Gemini 的部署方式。前往 Cloud Code 編輯器中的 Gemini 對話,然後輸入以下內容:
How to deploy this Cloud Function with a gcloud command?
我收到以下回覆:
我現在想進一步探討這個問題。因此我請 Gemini 提供完整的 gcloud 函式部署指令。回應如下所示:
我無法確定你會收到相同的回覆,但我發現它會提供更多詳細資料,這點相當有趣,如下圖所示:
要求主體格式:
和
回應格式:
現在繼續執行 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 並進行測試!
注意:如果您不小心略過「允許未經認證的叫用」問題,或選取「否」,就無法存取 Cloud Functions 的結果,而且如果未授予其他 IAM 設定,就會看到「權限錯誤」訊息。請留意這一點
10. 呼叫已部署的 Cloud 函式
我們來問問 Gemini 吧?我已輸入提示
How to call the deployed cloud function?
我找到的結果如下:(你不一定會看到完全相同的回覆,可以隨意嘗試各種提示,看看回應之間的差異)。
請在即時通訊中提出具體問題,例如如何以其他方式叫用已部署的函式、使用 gcloud 指令進行呼叫等。我已提交以下提示:
how to call the deployed cloud function using gcloud
我收到以下回應:
您可以使用終端機中的這項回應 (「gcloud functions call」指令) 進行調整,讓其適用於我們的情境 (或者,嘗試在提示中傳遞參數,看看是否能從回應中取得詳細的 gcloud 函式呼叫):
gcloud functions call bookshelf --region=us-central1 --gen2 --data '{"calls":[["Hello! This is my test prompt."]]}'
以下是我的結果:
11. 清除所用資源
在 Cloud Functions 的詳細資料頁面中,按一下 [DELETE] (刪除) 按鈕,即可刪除您先前建立的 Cloud Functions。
12. 恭喜
您已成功建構、部署及測試 Java Cloud 函式,以便使用 Gemini 呼叫 Gemini 1.0 Pro!這個應用程式會使用書籍的摘要和主題,接收與書籍推薦相關的輸入提示。