確定性生成式 AI,搭配 Java 專用 Gemini 函式呼叫

1. 簡介

生成式 AI 模型在理解及回應自然語言方面非常出色。但如果需要準確可預測的輸出內容,以利處理地址標準化等重要工作,該怎麼辦?傳統生成式模型有時可能會針對相同提示在不同時間點提供不同回覆,這樣可能會導致不一致的問題。這時 Gemini 函式呼叫功能就能派上用場,讓您以確定性方式控管 AI 回覆的元素。

本程式碼研究室以地址完成和標準化用途說明這個概念。為此,我們會建構 Java Cloud 函式,負責以下工作:

  1. 取得經緯度座標
  2. 呼叫 Google Maps Geocoding API 以取得對應地址
  3. 使用 Gemini 1.0 Pro 函式呼叫功能,確定這些地址的標準化和摘要格式,且符合我們所需的特定格式

那就繼續下一步吧!

2. Gemini 函式呼叫

Gemini 函式呼叫功能可在生成式 AI 時代脫穎而出,因為這能將生成式語言模型的靈活性,與傳統程式設計的精準度相互結合。

請務必完成以下工作,實作 Gemini 函式呼叫:

  1. 定義函式:清楚說明函式。說明必須包含下列資訊:
  • 函式的名稱,例如 getAddress
  • 函式預期的參數,例如字串形式的 latlng
  • 函式傳回的資料類型,例如地址字串清單。
  1. 建立 Gemini 工具:將函式說明以 API 規格的形式封裝成工具。這項工具就像是 Gemini 能用來理解 API 功能的專用工具箱。
  2. 使用 Gemini 自動化調度管理 API:傳送提示給 Gemini 後,Gemini 會分析要求,並找出可用工具的位置。然後執行下列工作,讓 Gemini 擔任智慧自動化調度管理工具:
  • 產生必要的 API 參數來呼叫已定義的函式。Gemini 不會代您呼叫 API。您必須根據 Gemini 函式呼叫作業產生的參數和簽名呼叫 API。
  • Gemini 處理結果時,會將 API 呼叫的結果傳回生成,並在最終回覆中納入結構化資訊。您可以按照您希望的方式處理這項資訊。

下圖顯示資料流、導入步驟,以及每個步驟 (例如應用程式、LLM 或 API) 的擁有者:

b9a39f55567072d3.png

建構項目

您將建立及部署 Java Cloud 函式,以便執行下列操作:

  • 取得經緯度座標。
  • 呼叫 Google Maps Geocoding API 以取得對應地址。
  • 使用 Gemini 1.0 Pro 函式呼叫功能,確定這些地址的標準化和摘要格式。

3. 需求條件

  • 瀏覽器,例如 ChromeFirefox
  • 已啟用計費功能的 Google Cloud 專案。

4. 事前準備

  1. Google Cloud 控制台的專案選取器頁面中,選取或建立 Google Cloud 專案
  2. 確認 Google Cloud 專案已啟用計費功能。瞭解如何檢查專案是否已啟用帳單功能
  3. 透過 Google Cloud 控制台啟用 Cloud Shell。詳情請參閱「使用 Cloud Shell」一文。
  4. 如未設定專案,請使用下列指令設定專案:
gcloud config set project <YOUR_PROJECT_ID>
  1. 在 Cloud Shell 中,設定下列環境變數:
export GCP_PROJECT=<YOUR_PROJECT_ID>
export GCP_REGION=us-central1
  1. 在 Cloud Shell 中執行下列指令,啟用必要的 Google Cloud API:
gcloud services enable cloudbuild.googleapis.com cloudfunctions.googleapis.com run.googleapis.com logging.googleapis.com storage-component.googleapis.com cloudaicompanion.googleapis.com aiplatform.googleapis.com
  1. 開啟 Cloud Shell 編輯器,按一下「擴充功能」,然後安裝 Gemini + Google Cloud Code 擴充功能

5. 實作 Cloud 函式

  1. 啟動 Cloud Shell 編輯器
  2. 按一下「Cloud Code」,然後展開「Cloud Functions」部分。
  3. 按一下「建立函式」圖示 (+) 圖示。
  4. 在「Create New Application」對話方塊中,選取「Java: Hello World」選項。
  5. 在專案路徑中提供專案名稱,例如 GeminiFunctionCalling
  6. 按一下「Explorer」Explorer查看專案結構,然後開啟 pom.xml 檔案。下圖顯示專案結構:

bdf07515f413dd9e.png

  1. pom.xml 檔案的 <dependencies>... </dependencies> 標記中加入必要的依附元件。您可以透過這項專案的 GitHub 存放區存取整個 pom.xml。將其中的 pom.xml 複製到您目前編輯的專案 pom.xml 檔案。
  2. GeminiFunctionCalling github 連結複製 HelloWorld.java 類別。您必須分別使用地理編碼 API 金鑰和 Google Cloud 專案 ID 更新 API_KEYproject_id

6. 使用 HelloWorld.java 類別瞭解呼叫函式

提示輸入內容

在這個範例中,輸入提示為「What's address for the latlong value 40.714224,-73.961452」

以下是與檔案輸入提示相對應的程式碼片段:

String promptText = "What's the address for the latlong value '" + latlngString + "'?"; //40.714224,-73.961452

API 規格

本範例使用 Reverse Geocoding API。API 規格如下:

/* Declare the function for the API to invoke (Geo coding API) */ 
FunctionDeclaration functionDeclaration =
    FunctionDeclaration.newBuilder()
        .setName("getAddress")
        .setDescription("Get the address for the given latitude and longitude value.")
        .setParameters(
            Schema.newBuilder()
                .setType(Type.OBJECT)
                .putProperties(
                    "latlng",
                    Schema.newBuilder()
                        .setType(Type.STRING)
                        .setDescription("This must be a string of latitude and longitude coordinates separated by comma")
                        .build())
                .addRequired("latlng")
                .build())
        .build();

運用 Gemini 自動化調度管理提示

提示輸入內容和 API 規格會傳送至 Gemini:

// Add the function to a "tool"
Tool tool = Tool.newBuilder()
.addFunctionDeclarations(functionDeclaration)
.build();

// Invoke the Gemini model with the use of the tool to generate the API parameters from the prompt input.
GenerativeModel model = GenerativeModel.newBuilder()
.setModelName(modelName)
.setVertexAi(vertexAI)
.setTools(Arrays.asList(tool))
.build();
GenerateContentResponse response = model.generateContent(promptText);
Content responseJSONCnt = response.getCandidates(0).getContent();

此回應就是對 API 的自動化調度管理參數 JSON。以下是輸出範例:

role: "model"
parts {
 function_call {
   name: "getAddress"
   args {
     fields {
       key: "latlng"
       value {
         string_value: "40.714224,-73.961452"
       }
     }
   }
 }
}

將下列參數傳遞至 Reverse Geocoding API:"latlng=40.714224,-73.961452"

將自動化調度管理結果與 "latlng=VALUE" 格式配對。

叫用 API

叫用 API 的程式碼區段如下:

// Create a request
     String url = API_STRING + "?key=" + API_KEY + params;
     java.net.http.HttpRequest request = java.net.http.HttpRequest.newBuilder()
         .uri(URI.create(url))
         .GET()
         .build();
     // Send the request and get the response
     java.net.http.HttpResponse<String> httpresponse = client.send(request, java.net.http.HttpResponse.BodyHandlers.ofString());
     // Save the response
     String jsonResult =  httpresponse.body().toString();

jsonResult 字串包含反向 Geocoding API 的回應。以下是格式化的輸出內容:

"...277 Bedford Ave, Brooklyn, NY 11211, USA; 279 Bedford Ave, Brooklyn, NY 11211, USA; 277 Bedford Ave, Brooklyn, NY 11211, USA;..."

處理 API 回應並準備提示

下列程式碼會處理來自 API 的回應,並準備提示內容,說明如何處理回應:

// Provide an answer to the model so that it knows what the result
     // of a "function call" is.
     String promptString =
     "You are an AI address standardizer for assisting with standardizing addresses accurately. Your job is to give the accurate address in the standard format as a JSON object containing the fields DOOR_NUMBER, STREET_ADDRESS, AREA, CITY, TOWN, COUNTY, STATE, COUNTRY, ZIPCODE, LANDMARK by leveraging the address string that follows in the end. Remember the response cannot be empty or null. ";

Content content =
         ContentMaker.fromMultiModalData(
             PartMaker.fromFunctionResponse(
                 "getAddress",
                 Collections.singletonMap("address", formattedAddress)));
     String contentString = content.toString();
     String address = contentString.substring(contentString.indexOf("string_value: \"") + "string_value: \"".length(), contentString.indexOf('"', contentString.indexOf("string_value: \"") + "string_value: \"".length()));

     List<SafetySetting> safetySettings = Arrays.asList(
       SafetySetting.newBuilder()
           .setCategory(HarmCategory.HARM_CATEGORY_HATE_SPEECH)
           .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_ONLY_HIGH)
           .build(),
       SafetySetting.newBuilder()
           .setCategory(HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT)
           .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_ONLY_HIGH)
           .build()
   );

叫用 Gemini 並傳回標準化地址

下列程式碼會將先前步驟中處理的輸出內容做為提示,傳遞給 Gemini:

GenerativeModel modelForFinalResponse = GenerativeModel.newBuilder()
     .setModelName(modelName)
     .setVertexAi(vertexAI)
     .build();
     GenerateContentResponse finalResponse = modelForFinalResponse.generateContent(promptString + ": " + address, safetySettings);
      System.out.println("promptString + content: " + promptString + ": " + address);
       // See what the model replies now
       System.out.println("Print response: ");
       System.out.println(finalResponse.toString());
       String finalAnswer = ResponseHandler.getText(finalResponse);
       System.out.println(finalAnswer);

finalAnswer 變數採用 JSON 格式的標準化地址。以下是輸出內容範例:

{"replies":["{ \"DOOR_NUMBER\": null, \"STREET_ADDRESS\": \"277 Bedford Ave\", \"AREA\": \"Brooklyn\", \"CITY\": \"New York\", \"TOWN\": null, \"COUNTY\": null, \"STATE\": \"NY\", \"COUNTRY\": \"USA\", \"ZIPCODE\": \"11211\", \"LANDMARK\": null} null}"]}

您已瞭解 Gemini 函式呼叫如何與地址標準化用途搭配運作,接下來您可以部署 Cloud 函式。

7. 部署及測試

  1. 如果已建立 GeminiFunctionCalling 專案並導入 Cloud 函式,請前往步驟 2。如果尚未建立專案,請前往 Cloud Shell 終端機,複製這個存放區:git clone https://github.com/AbiramiSukumaran/GeminiFunctionCalling
  2. 前往專案資料夾:cd GeminiFunctionCalling
  3. 執行下列陳述式,建構及部署 Cloud 函式:
gcloud functions deploy gemini-fn-calling --gen2 --region=us-central1 --runtime=java11 --source=. --entry-point=cloudcode.helloworld.HelloWorld --trigger-http

以下是部署後的網址格式:https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/gemini-fn-calling

  1. 在終端機執行下列指令,以測試 Cloud 函式:
gcloud functions call gemini-fn-calling --region=us-central1 --gen2 --data '{"calls":[["40.714224,-73.961452"]]}'

以下是隨機提示範例的回應:'{"replies":["{ "DOOR_NUMBER": "277", "STREET_ADDRESS": "Bedford Ave", "AREA": null, "CITY": "Brooklyn", "TOWN": null, "COUNTY": "Kings County", "STATE": "NY", "COUNTRY": "USA", "ZIPCODE": "11211", "LANDMARK": null}}```"]}'

8. 清除所用資源

如要避免系統向您的 Google Cloud 帳戶收取本文中所用資源的費用,請按照下列步驟操作:

  1. 在 Google Cloud 控制台中,前往「管理資源」頁面。
  2. 在專案清單中選取要刪除的專案,然後按一下「刪除」。
  3. 在對話方塊中輸入專案 ID,然後按一下「關閉」以刪除專案。
  4. 如要保留專案,請略過上述步驟並刪除 Cloud 函式,方法是前往 Cloud Functions 頁面,在函式清單中勾選要刪除的函式,然後按一下「刪除」。

9. 恭喜

恭喜!您已成功在 Java 應用程式中使用 Gemini 函式呼叫功能,並將生成式 AI 工作轉換成確定性、可靠的程序。如要進一步瞭解可用的模型,請參閱 Vertex AI LLM 產品說明文件