1. 總覽
生成式 AI 應用程式與其他應用程式一樣,都需要可觀測性。生成式 AI 是否需要特殊的觀測技術?
在本實驗室中,您將建立簡單的生成式 AI 應用程式。將其部署至 Cloud Run。並使用 Google Cloud Observability 服務和產品,為其導入必要的監控和記錄功能。
學習目標
- 使用 Cloud Shell 編輯器撰寫使用 Vertex AI 的應用程式
- 在 GitHub 中儲存應用程式程式碼
- 使用 gcloud CLI 將應用程式的原始碼部署至 Cloud Run
- 在生成式 AI 應用程式中新增監控和記錄功能
- 使用記錄指標
- 使用 Open Telemetry SDK 實作記錄和監控功能
- 深入瞭解負責任的 AI 資料處理方式
2. 先決條件
如果沒有 Google 帳戶,請建立新帳戶。
3. 專案設定
- 使用 Google 帳戶登入 Google Cloud 控制台。
- 建立新專案,或選擇重複使用現有專案。記下您剛建立或選取的專案 ID。
- 為專案啟用計費功能。
- 完成本實驗室的結算費用應低於 $5 美元。
- 您可以按照本實驗室結尾的步驟刪除資源,以免產生後續費用。
- 新使用者可獲得價值 $300 美元的免費試用期。
- 確認 Cloud Billing 的「我的專案」
-
已啟用計費功能
- 如果新專案的「
Billing account」欄顯示Billing is disabled,請按照下列步驟操作:- 按一下「
Actions」欄中的三點圖示 - 按一下「變更帳單」
- 選取要使用的帳單帳戶
- 按一下「
- 如果您參加的是現場活動,帳戶名稱可能為「Google Cloud Platform 試用帳單帳戶」
- 如果新專案的「
4. 準備 Cloud Shell 編輯器
- 前往 Cloud Shell 編輯器。如果系統顯示以下訊息,要求您授權 Cloud Shell 使用憑證呼叫 gcloud,請按一下「Authorize」(授權)繼續操作。

- 開啟終端機視窗
- 按一下漢堡選單

- 按一下「終端機」。
- 按一下「New Terminal」(新增終端機)

- 按一下漢堡選單
- 在終端機中設定專案 ID:
將gcloud config set project [PROJECT_ID][PROJECT_ID]替換為專案 ID。舉例來說,如果專案 ID 為lab-example-project,指令會是: 如果系統提示以下訊息,指出 gcloud 要求提供憑證給 GCPI API,請按一下「Authorize」(授權)繼續操作。gcloud config set project lab-project-id-example

執行成功後,您應該會看到以下訊息: 如果看到Updated property [core/project].
WARNING並收到Do you want to continue (Y/N)?提示,可能是輸入的專案 ID 有誤。按下N和Enter,找到正確的專案 ID 後,再次嘗試執行gcloud config set project指令。 - (選用) 如果您找不到專案 ID,請執行下列指令,查看所有專案的專案 ID,並依建立時間降序排序:
gcloud projects list \ --format='value(projectId,createTime)' \ --sort-by=~createTime
5. 啟用 Google API
在終端機中,啟用本實驗室所需的 Google API:
gcloud services enable \
run.googleapis.com \
cloudbuild.googleapis.com \
aiplatform.googleapis.com \
logging.googleapis.com \
monitoring.googleapis.com \
cloudtrace.googleapis.com
這個指令需要一段時間才能完成。最後,系統會產生類似以下的成功訊息:
Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.
如果收到開頭為 ERROR: (gcloud.services.enable) HttpError accessing 的錯誤訊息,且包含下列錯誤詳細資料,請延遲 1 到 2 分鐘後重試指令。
"error": {
"code": 429,
"message": "Quota exceeded for quota metric 'Mutate requests' and limit 'Mutate requests per minute' of service 'serviceusage.googleapis.com' ...",
"status": "RESOURCE_EXHAUSTED",
...
}
6. 建立生成式 AI 應用程式
在這個步驟中,您會編寫簡單的應用程式程式碼,根據要求使用 Gemini 模型顯示 10 個與所選動物相關的有趣事實。請按照下列步驟建立應用程式程式碼。
- 在終端機中建立
codelab-o11y目錄:mkdir "${HOME}/codelab-o11y" - 將目前目錄變更為
codelab-o11y:cd "${HOME}/codelab-o11y" - 使用 Spring Framework Starter 下載 Java 應用程式的 Bootstrap 程式碼:
curl https://start.spring.io/starter.zip \ -d dependencies=web \ -d javaVersion=17 \ -d type=maven-project \ -d bootVersion=3.4.1 -o java-starter.zip - 將啟動程序程式碼解壓縮到目前資料夾:
unzip java-starter.zip - 並從資料夾中移除封存檔案:
rm java-starter.zip - 建立
project.toml檔案,定義將程式碼部署至 Cloud Run 時使用的 Java 執行階段版本:cat > "${HOME}/codelab-o11y/project.toml" << EOF [[build.env]] name = "GOOGLE_RUNTIME_VERSION" value = "17" EOF - 在
pom.xml檔案中新增 Google Cloud SDK 依附元件:- 新增 Google Cloud Core 套件:
sed -i 's/<dependencies>/<dependencies>\ \ <dependency>\ <groupId>com.google.cloud<\/groupId>\ <artifactId>google-cloud-core<\/artifactId>\ <version>2.49.1<\/version>\ <\/dependency>\ /g' "${HOME}/codelab-o11y/pom.xml" - 新增 Google Cloud Vertex AI 套件:
sed -i 's/<dependencies>/<dependencies>\ \ <dependency>\ <groupId>com.google.cloud<\/groupId>\ <artifactId>google-cloud-vertexai<\/artifactId>\ <version>1.16.0<\/version>\ <\/dependency>\ /g' "${HOME}/codelab-o11y/pom.xml"
- 新增 Google Cloud Core 套件:
- 在 Cloud Shell 編輯器中開啟
DemoApplication.java檔案: 終端機上方的編輯器視窗中,現在應該會顯示cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/DemoApplication.java"DemoApplication.java檔案的架構式原始碼。檔案的原始碼會類似下列內容:package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } - 將編輯器中的程式碼換成下方的版本。如要替換程式碼,請刪除檔案內容,然後將下方程式碼複製到編輯器:
幾秒後,Cloud Shell 編輯器會自動儲存程式碼。package com.example.demo; import java.io.IOException; import java.util.Collections; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.google.cloud.ServiceOptions; import com.google.cloud.vertexai.VertexAI; import com.google.cloud.vertexai.api.GenerateContentResponse; import com.google.cloud.vertexai.generativeai.GenerativeModel; import com.google.cloud.vertexai.generativeai.ResponseHandler; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { String port = System.getenv().getOrDefault("PORT", "8080"); SpringApplication app = new SpringApplication(DemoApplication.class); app.setDefaultProperties(Collections.singletonMap("server.port", port)); app.run(args); } } @RestController class HelloController { private final String projectId = ServiceOptions.getDefaultProjectId(); private VertexAI vertexAI; private GenerativeModel model; @PostConstruct public void init() { vertexAI = new VertexAI(projectId, "us-central1"); model = new GenerativeModel("gemini-1.5-flash", vertexAI); } @PreDestroy public void destroy() { vertexAI.close(); } @GetMapping("/") public String getFacts(@RequestParam(defaultValue = "dog") String animal) throws IOException { String prompt = "Give me 10 fun facts about " + animal + ". Return this as html without backticks."; GenerateContentResponse response = model.generateContent(prompt); return ResponseHandler.getText(response); } }
將生成式 AI 應用程式的程式碼部署至 Cloud Run
- 在終端機視窗中執行指令,將應用程式的原始碼部署至 Cloud Run。
如果看到如下提示,表示指令會建立新的存放區。按一下gcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticatedEnter。 部署程序最多可能需要幾分鐘才能完成。部署程序完成後,您會看到類似以下的輸出內容:Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [us-central1] will be created. Do you want to continue (Y/n)?
Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic. Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
- 將顯示的 Cloud Run 服務網址複製到瀏覽器的另一個分頁或視窗。或者,您也可以在終端機中執行下列指令,列印服務網址,然後按住 Ctrl 鍵並點選顯示的網址,開啟該網址:
開啟網址時,您可能會收到 500 錯誤訊息,或看到以下訊息:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"' 這表示服務未完成部署作業。請稍候片刻,然後重新整理頁面。最後你會看到以「Fun Dog Facts」(狗狗趣味小知識) 開頭的文字,其中包含 10 個狗狗趣味小知識。Sorry, this is just a placeholder...
嘗試與應用程式互動,瞭解各種動物的有趣知識。如要這麼做,請將 animal 參數附加至網址,例如 ?animal=[ANIMAL],其中 [ANIMAL] 是動物名稱。舉例來說,附加 ?animal=cat 即可取得 10 個關於貓咪的趣味知識,附加 ?animal=sea turtle 則可取得 10 個關於海龜的趣味知識。
7. 稽核 Vertex API 呼叫
稽核 Google API 呼叫可回答「誰在何時何地呼叫特定 API?」等問題。在排解應用程式問題、調查資源耗用情形或執行軟體鑑識分析時,稽核作業非常重要。
稽核記錄可讓您追蹤管理員和系統活動,以及記錄對「資料讀取」和「資料寫入」API 作業的呼叫。如要稽核生成內容的 Vertex AI 要求,您必須在 Cloud 控制台中啟用「資料讀取」稽核記錄。
- 按一下下方按鈕,在 Cloud 控制台中開啟「稽核記錄」頁面
- 確認頁面已選取您為這個實驗室建立的專案。所選專案會顯示在頁面左上角,漢堡選單的右側:

如有需要,請從下拉式方塊選取正確的專案。 - 在「資料存取稽核記錄設定」表格的「服務」欄中,找出
Vertex AI API服務,然後選取服務名稱左側的核取方塊,選取該服務。
- 在右側的資訊面板中,選取「資料讀取」稽核類型。

- 按一下 [儲存]。
如要產生稽核記錄,請開啟服務網址。重新整理頁面,同時變更 ?animal= 參數的值,即可取得不同的結果。
瞭解稽核記錄
8. 記錄與生成式 AI 的互動
您不會在稽核記錄中找到 API 要求參數或回應資料。不過,這項資訊對於排解應用程式和工作流程分析問題可能非常重要。在本步驟中,我們將新增應用程式記錄,填補這項缺口。
實作作業會使用 Logback 和 Spring Boot,將應用程式記錄列印至標準輸出。這個方法會運用 Cloud Run 功能,擷取列印至標準輸出的資訊,並自動擷取至 Cloud Logging。如要以結構化資料的形式擷取資訊,請務必按照相應格式列印記錄。請按照下列操作說明,在應用程式中新增結構化記錄功能。
- 返回瀏覽器中的「Cloud Shell」視窗 (或分頁)。
- 在 Cloud Shell 編輯器中建立並開啟新檔案
LoggingEventGoogleCloudEncoder.java:cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/LoggingEventGoogleCloudEncoder.java" - 複製並貼上下列程式碼,實作 Logback 編碼器,將記錄編碼為字串化 JSON,並遵循 Google Cloud 結構化記錄格式:
package com.example.demo; import static ch.qos.logback.core.CoreConstants.UTF_8_CHARSET; import java.time.Instant; import ch.qos.logback.core.encoder.EncoderBase; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import java.util.HashMap; import com.google.gson.Gson; public class LoggingEventGoogleCloudEncoder extends EncoderBase<ILoggingEvent> { private static final byte[] EMPTY_BYTES = new byte[0]; private final Gson gson = new Gson(); @Override public byte[] headerBytes() { return EMPTY_BYTES; } @Override public byte[] encode(ILoggingEvent e) { var timestamp = Instant.ofEpochMilli(e.getTimeStamp()); var fields = new HashMap<String, Object>() { { put("timestamp", timestamp.toString()); put("severity", severityFor(e.getLevel())); put("message", e.getMessage()); } }; var params = e.getKeyValuePairs(); if (params != null && params.size() > 0) { params.forEach(kv -> fields.putIfAbsent(kv.key, kv.value)); } var data = gson.toJson(fields) + "\n"; return data.getBytes(UTF_8_CHARSET); } @Override public byte[] footerBytes() { return EMPTY_BYTES; } private static String severityFor(Level level) { switch (level.toInt()) { case Level.TRACE_INT: return "DEBUG"; case Level.DEBUG_INT: return "DEBUG"; case Level.INFO_INT: return "INFO"; case Level.WARN_INT: return "WARNING"; case Level.ERROR_INT: return "ERROR"; default: return "DEFAULT"; } } } - 在 Cloud Shell 編輯器中建立並開啟新檔案
logback.xml:cloudshell edit "${HOME}/codelab-o11y/src/main/resources/logback.xml" - 複製並貼上下列 XML,設定 Logback 使用編碼器和 Logback 附加程式,將記錄檔列印至標準輸出:
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true"> <appender name="Console" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="com.example.demo.LoggingEventGoogleCloudEncoder"/> </appender> <root level="info"> <appender-ref ref="Console" /> </root> </configuration> - 在 Cloud Shell 編輯器中重新開啟
DemoApplication.java檔案:cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/DemoApplication.java" - 將編輯器中的程式碼換成下方的版本,記錄生成式 AI 要求和回應。如要替換程式碼,請刪除檔案內容,然後將下方程式碼複製到編輯器:
package com.example.demo; import java.io.IOException; import java.util.Collections; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.google.cloud.ServiceOptions; import com.google.cloud.vertexai.VertexAI; import com.google.cloud.vertexai.api.GenerateContentResponse; import com.google.cloud.vertexai.generativeai.GenerativeModel; import com.google.cloud.vertexai.generativeai.ResponseHandler; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { String port = System.getenv().getOrDefault("PORT", "8080"); SpringApplication app = new SpringApplication(DemoApplication.class); app.setDefaultProperties(Collections.singletonMap("server.port", port)); app.run(args); } } @RestController class HelloController { private final String projectId = ServiceOptions.getDefaultProjectId(); private VertexAI vertexAI; private GenerativeModel model; private final Logger LOGGER = LoggerFactory.getLogger(HelloController.class); @PostConstruct public void init() { vertexAI = new VertexAI(projectId, "us-central1"); model = new GenerativeModel("gemini-1.5-flash", vertexAI); } @PreDestroy public void destroy() { vertexAI.close(); } @GetMapping("/") public String getFacts(@RequestParam(defaultValue = "dog") String animal) throws IOException { String prompt = "Give me 10 fun facts about " + animal + ". Return this as html without backticks."; GenerateContentResponse response = model.generateContent(prompt); LOGGER.atInfo() .addKeyValue("animal", animal) .addKeyValue("prompt", prompt) .addKeyValue("response", response) .log("Content is generated"); return ResponseHandler.getText(response); } }
幾秒後,Cloud Shell 編輯器會自動儲存變更。
將生成式 AI 應用程式的程式碼部署至 Cloud Run
- 在終端機視窗中執行指令,將應用程式的原始碼部署至 Cloud Run。
如果看到如下提示,表示指令會建立新的存放區。按一下gcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticatedEnter。 部署程序最多可能需要幾分鐘才能完成。部署程序完成後,您會看到類似以下的輸出內容:Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [us-central1] will be created. Do you want to continue (Y/n)?
Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic. Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
- 將顯示的 Cloud Run 服務網址複製到瀏覽器的另一個分頁或視窗。或者,您也可以在終端機中執行下列指令,列印服務網址,然後按住 Ctrl 鍵並點選顯示的網址,開啟該網址:
開啟網址時,您可能會收到 500 錯誤訊息,或看到以下訊息:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"' 這表示服務未完成部署作業。請稍候片刻,然後重新整理頁面。最後你會看到以「Fun Dog Facts」(狗狗趣味小知識) 開頭的文字,其中包含 10 個狗狗趣味小知識。Sorry, this is just a placeholder...
如要產生應用程式記錄,請開啟服務網址。重新整理頁面,同時變更 ?animal= 參數的值,即可取得不同的結果。
如要查看應用程式記錄,請執行下列操作:
- 按一下下方按鈕,在 Cloud 控制台中開啟記錄檔探索工具頁面:
- 將下列篩選條件貼到「查詢」窗格 (記錄檔探索工具介面中的 #2):
LOG_ID("run.googleapis.com%2Fstdout") AND severity=DEBUG - 點選「執行查詢」
查詢結果會顯示記錄,包括提示和 Vertex AI 回覆,以及安全評分。
9. 計算與生成式 AI 的互動次數
Cloud Run 會寫入代管指標,可用於監控已部署的服務。使用者管理的監控指標可進一步控管資料,以及指標更新的頻率。如要實作這類指標,必須編寫程式碼來收集資料,並將資料寫入 Cloud Monitoring。如要瞭解如何使用 OpenTelemetry SDK 實作,請參閱下一個 (選用) 步驟。
這個步驟說明實作使用者指標的替代做法,也就是記錄指標。記錄指標可讓您從應用程式寫入 Cloud Logging 的記錄項目產生監控指標。我們將使用上一個步驟中實作的應用程式記錄,定義計數器類型的記錄型指標。這項指標會計算 Vertex API 的成功呼叫次數。
- 查看上一步使用的「記錄檔探索器」視窗。在「查詢」窗格下方找到「動作」下拉式選單,然後點選開啟。請參閱下方螢幕截圖,找出選單:

- 在開啟的選單中選取「建立指標」,開啟「建立記錄指標」面板。
- 請按照下列步驟,在「建立記錄指標」面板中設定新的計數器指標:
- 設定「指標類型」:選取「計數器」。
- 在「詳細資料」部分中,設定下列欄位:
- 記錄指標名稱:將名稱設為
model_interaction_count。存在一些命名限制;詳情請參閱疑難排解一文。 - 說明:輸入指標說明。例如:
Number of log entries capturing successful call to model inference. - 單位:保留此欄位空白,或插入數字
1。
- 記錄指標名稱:將名稱設為
- 保留「篩選器選取」部分的值。請注意,「Build filter」(建立篩選器) 欄位與我們用來查看應用程式記錄的篩選器相同。
- (選用) 新增標籤,方便計算每種動物的叫聲次數。注意:這個標籤可能會大幅增加指標的基數,因此不建議用於正式環境:
- 按一下 [Add label] (新增標籤)。
- 在「標籤」部分中設定下列欄位:
- 標籤名稱:將名稱設為
animal。 - 說明:輸入標籤說明。例如:
Animal parameter。 - 標籤類型:選取
STRING。 - 欄位名稱:輸入
jsonPayload.animal。 - 規則運算式:留空。
- 標籤名稱:將名稱設為
- 然後按一下 [完成]。
- 按一下「建立指標」即可建立指標。
您也可以使用 gcloud logging metrics create CLI 指令或 google_logging_metric Terraform 資源,從「記錄指標」頁面建立記錄指標。
如要產生指標資料,請開啟服務網址。多次重新整理開啟的頁面,對模型發出多個呼叫。和先前一樣,請嘗試在參數中使用不同動物。
輸入 PromQL 查詢,搜尋記錄指標資料。如要輸入 PromQL 查詢,請按照下列步驟操作:
- 按一下下方按鈕,在 Cloud 控制台中開啟 Metrics Explorer 頁面:
- 在查詢建構工具窗格的工具列中,選取名稱為「< > MQL」或「< > PromQL」的按鈕。如要瞭解按鈕位置,請參閱下圖。

- 確認「語言」切換按鈕已選取「PromQL」。語言切換鍵位於可格式化查詢的工具列中。
- 在「查詢」編輯器中輸入查詢:
如要進一步瞭解如何使用 PromQL,請參閱「在 Cloud Monitoring 中使用 PromQL」。sum(rate(logging_googleapis_com:user_model_interaction_count{monitored_resource="cloud_run_revision"}[${__interval}])) - 按一下 [Run query] (執行查詢),您會看到類似以下螢幕截圖的折線圖:

請注意,啟用「自動執行」切換按鈕後,系統就不會顯示「執行查詢」按鈕。
10. (選用) 使用 Open Telemetry 監控及追蹤
如上一步所述,您可以使用 OpenTelemetry (Otel) SDK 導入指標。建議在多服務架構中使用 OTel。這個步驟會示範如何將 OTel 檢測點新增至 Spring Boot 應用程式。在這個步驟中,您將執行下列操作:
- 使用自動追蹤功能檢測 Spring Boot 應用程式
- 導入計數器指標,監控模型呼叫成功次數
- 將追蹤記錄與應用程式記錄檔建立關聯
建議您使用 OTel 收集器,從多項服務收集及擷取所有可觀測性資料,做為產品層級服務的架構。為簡化程序,這個步驟中的程式碼不會使用收集器。而是使用 OTel 匯出功能,將資料直接寫入 Google Cloud。
使用 OTel 元件和自動追蹤功能設定 Spring Boot 應用程式
- 返回瀏覽器中的「Cloud Shell」視窗 (或分頁)。
- 在終端機中,使用其他設定參數更新
application.permissions檔案: 這些參數會定義將可觀測性資料匯出至 Cloud Trace 和 Cloud Monitoring,並強制對「所有」追蹤記錄進行取樣。cat >> "${HOME}/codelab-o11y/src/main/resources/application.properties" << EOF otel.logs.exporter=none otel.traces.exporter=google_cloud_trace otel.metrics.exporter=google_cloud_monitoring otel.resource.attributes.service.name=codelab-o11y-service otel.traces.sampler=always_on EOF - 在
pom.xml檔案中新增必要的 OpenTelemetry 依附元件:sed -i 's/<dependencies>/<dependencies>\ \ <dependency>\ <groupId>io.opentelemetry.instrumentation<\/groupId>\ <artifactId>opentelemetry-spring-boot-starter<\/artifactId>\ <\/dependency>\ <dependency>\ <groupId>com.google.cloud.opentelemetry<\/groupId>\ <artifactId>exporter-auto<\/artifactId>\ <version>0.33.0-alpha<\/version>\ <\/dependency>\ <dependency>\ <groupId>com.google.cloud.opentelemetry<\/groupId>\ <artifactId>exporter-trace<\/artifactId>\ <version>0.33.0<\/version>\ <\/dependency>\ <dependency>\ <groupId>com.google.cloud.opentelemetry<\/groupId>\ <artifactId>exporter-metrics<\/artifactId>\ <version>0.33.0<\/version>\ <\/dependency>\ /g' "${HOME}/codelab-o11y/pom.xml" - 將 OpenTelemetry BOM 新增至
pom.xml檔案:sed -i 's/<\/properties>/<\/properties>\ <dependencyManagement>\ <dependencies>\ <dependency>\ <groupId>io.opentelemetry.instrumentation<\/groupId>\ <artifactId>opentelemetry-instrumentation-bom<\/artifactId>\ <version>2.12.0<\/version>\ <type>pom<\/type>\ <scope>import<\/scope>\ <\/dependency>\ <\/dependencies>\ <\/dependencyManagement>\ /g' "${HOME}/codelab-o11y/pom.xml" - 在 Cloud Shell 編輯器中重新開啟
DemoApplication.java檔案:cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/DemoApplication.java" - 將目前的程式碼換成會遞增成效指標的版本。如要替換程式碼,請刪除檔案內容,然後將下方程式碼複製到編輯器:
package com.example.demo; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.metrics.LongCounter; import java.io.IOException; import java.util.Collections; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.google.cloud.ServiceOptions; import com.google.cloud.vertexai.VertexAI; import com.google.cloud.vertexai.api.GenerateContentResponse; import com.google.cloud.vertexai.generativeai.GenerativeModel; import com.google.cloud.vertexai.generativeai.ResponseHandler; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { String port = System.getenv().getOrDefault("PORT", "8080"); SpringApplication app = new SpringApplication(DemoApplication.class); app.setDefaultProperties(Collections.singletonMap("server.port", port)); app.run(args); } } @RestController class HelloController { private final String projectId = ServiceOptions.getDefaultProjectId(); private VertexAI vertexAI; private GenerativeModel model; private final Logger LOGGER = LoggerFactory.getLogger(HelloController.class); private static final String INSTRUMENTATION_NAME = "genai-o11y/java/workshop/example"; private static final AttributeKey<String> ANIMAL = AttributeKey.stringKey("animal"); private final LongCounter counter; public HelloController(OpenTelemetry openTelemetry) { this.counter = openTelemetry.getMeter(INSTRUMENTATION_NAME) .counterBuilder("model_call_counter") .setDescription("Number of successful model calls") .build(); } @PostConstruct public void init() { vertexAI = new VertexAI(projectId, "us-central1"); model = new GenerativeModel("gemini-1.5-flash", vertexAI); } @PreDestroy public void destroy() { vertexAI.close(); } @GetMapping("/") public String getFacts(@RequestParam(defaultValue = "dog") String animal) throws IOException { String prompt = "Give me 10 fun facts about " + animal + ". Return this as html without backticks."; GenerateContentResponse response = model.generateContent(prompt); LOGGER.atInfo() .addKeyValue("animal", animal) .addKeyValue("prompt", prompt) .addKeyValue("response", response) .log("Content is generated"); counter.add(1, Attributes.of(ANIMAL, animal)); return ResponseHandler.getText(response); } } - 在 Cloud Shell 編輯器中重新開啟
LoggingEventGoogleCloudEncoder.java檔案:cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/LoggingEventGoogleCloudEncoder.java" - 將目前的程式碼換成會將追蹤屬性新增至所寫記錄的版本。新增屬性後,記錄檔就能與正確的追蹤範圍相互關聯。如要替換程式碼,請刪除檔案內容,然後將下方程式碼複製到編輯器:
package com.example.demo; import static ch.qos.logback.core.CoreConstants.UTF_8_CHARSET; import java.time.Instant; import java.util.HashMap; import ch.qos.logback.core.encoder.EncoderBase; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import com.google.cloud.ServiceOptions; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.context.Context; import com.google.gson.Gson; public class LoggingEventGoogleCloudEncoder extends EncoderBase<ILoggingEvent> { private static final byte[] EMPTY_BYTES = new byte[0]; private final Gson gson; private final String projectId; private final String tracePrefix; public LoggingEventGoogleCloudEncoder() { this.gson = new Gson(); this.projectId = lookUpProjectId(); this.tracePrefix = "projects/" + (projectId == null ? "" : projectId) + "/traces/"; } private static String lookUpProjectId() { return ServiceOptions.getDefaultProjectId(); } @Override public byte[] headerBytes() { return EMPTY_BYTES; } @Override public byte[] encode(ILoggingEvent e) { var timestamp = Instant.ofEpochMilli(e.getTimeStamp()); var fields = new HashMap<String, Object>() { { put("timestamp", timestamp.toString()); put("severity", severityFor(e.getLevel())); put("message", e.getMessage()); SpanContext context = Span.fromContext(Context.current()).getSpanContext(); if (context.isValid()) { put("logging.googleapis.com/trace", tracePrefix + context.getTraceId()); put("logging.googleapis.com/spanId", context.getSpanId()); put("logging.googleapis.com/trace_sampled", Boolean.toString(context.isSampled())); } } }; var params = e.getKeyValuePairs(); if (params != null && params.size() > 0) { params.forEach(kv -> fields.putIfAbsent(kv.key, kv.value)); } var data = gson.toJson(fields) + "\n"; return data.getBytes(UTF_8_CHARSET); } @Override public byte[] footerBytes() { return EMPTY_BYTES; } private static String severityFor(Level level) { switch (level.toInt()) { case Level.TRACE_INT: return "DEBUG"; case Level.DEBUG_INT: return "DEBUG"; case Level.INFO_INT: return "INFO"; case Level.WARN_INT: return "WARNING"; case Level.ERROR_INT: return "ERROR"; default: return "DEFAULT"; } } }
幾秒後,Cloud Shell 編輯器會自動儲存變更。
將生成式 AI 應用程式的程式碼部署至 Cloud Run
- 在終端機視窗中執行指令,將應用程式的原始碼部署至 Cloud Run。
如果看到如下提示,表示指令會建立新的存放區。按一下gcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticatedEnter。 部署程序最多可能需要幾分鐘才能完成。部署程序完成後,您會看到類似以下的輸出內容:Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [us-central1] will be created. Do you want to continue (Y/n)?
Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic. Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
- 將顯示的 Cloud Run 服務網址複製到瀏覽器的另一個分頁或視窗。或者,您也可以在終端機中執行下列指令,列印服務網址,然後按住 Ctrl 鍵並點選顯示的網址,開啟該網址:
開啟網址時,您可能會收到 500 錯誤訊息,或看到以下訊息:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"' 這表示服務未完成部署作業。請稍候片刻,然後重新整理頁面。最後你會看到以「Fun Dog Facts」(狗狗趣味小知識) 開頭的文字,其中包含 10 個狗狗趣味小知識。Sorry, this is just a placeholder...
如要產生遙測資料,請開啟服務網址。重新整理頁面,同時變更 ?animal= 參數的值,即可取得不同的結果。
探索應用程式追蹤記錄
- 按一下下方按鈕,在 Cloud 控制台中開啟 Trace 探索工具頁面:
- 選取其中一個最近的追蹤記錄。您應該會看到 5 或 6 個類似下方螢幕截圖的範圍。

- 找出追蹤事件處理常式 (
fun_facts方法) 呼叫的範圍。這是最後一個名為「/」的範圍。 - 在「追蹤詳細資料」窗格中,選取「記錄和事件」。您會看到與這個特定時距相關聯的應用程式記錄檔。系統會使用追蹤記錄和記錄檔中的追蹤記錄和時距 ID,偵測關聯性。您應該會看到寫入提示的應用程式記錄,以及 Vertex API 的回覆。
探索計數器指標
- 按一下下方按鈕,在 Cloud 控制台中開啟 Metrics Explorer 頁面:
- 在查詢建構工具窗格的工具列中,選取名稱為「< > MQL」或「< > PromQL」的按鈕。如要瞭解按鈕位置,請參閱下圖。

- 確認「語言」切換按鈕已選取「PromQL」。語言切換鍵位於可格式化查詢的工具列中。
- 在「查詢」編輯器中輸入查詢:
sum(rate(workload_googleapis_com:model_call_counter{monitored_resource="generic_task"}[${__interval}])) - 按一下「執行查詢」。啟用「自動執行」切換鈕後,系統就不會顯示「執行查詢」按鈕。
11. (選用) 記錄中經過模糊處理的機密資訊
在步驟 10 中,我們記錄了應用程式與 Gemini 模型互動的相關資訊。這項資訊包括動物名稱、實際提示和模型的回應。雖然將這項資訊儲存在記錄檔中應該很安全,但許多其他情況並非如此。提示可能包含使用者不想儲存的個人或其他私密資訊。為解決這個問題,您可以模糊處理寫入 Cloud Logging 的機密資料。為盡量減少程式碼修改,建議採用下列解決方案。
- 建立 PubSub 主題,用來儲存傳入的記錄項目
- 建立記錄接收器,將擷取的記錄重新導向至 Pub/Sub 主題。
- 按照下列步驟建立 Dataflow 管道,修改重新導向至 PubSub 主題的記錄:
- 從 Pub/Sub 主題讀取記錄檔項目
- 使用 DLP 檢查 API 檢查項目酬載是否含有機密資訊
- 使用其中一種 DLP 遮蓋方法,遮蓋酬載中的機密資訊
- 將經過模糊處理的記錄項目寫入 Cloud Logging
- 部署管道
12. (選用) 清除
為避免因使用程式碼研究室的資源和 API 而產生費用,建議您在完成實驗室後進行清理。如要避免付費,最簡單的方法就是刪除您為了本程式碼研究室所建立的專案。
- 如要刪除專案,請在終端機中執行刪除專案指令:
刪除 Cloud 專案後,系統就會停止對該專案使用的所有資源和 API 收取費用。您應該會看到以下訊息,其中PROJECT_ID=$(gcloud config get-value project) gcloud projects delete ${PROJECT_ID} --quietPROJECT_ID是您的專案 ID:Deleted [https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID]. You can undo this operation for a limited period by running the command below. $ gcloud projects undelete PROJECT_ID See https://cloud.google.com/resource-manager/docs/creating-managing-projects for information on shutting down projects. - (選用) 如果收到錯誤訊息,請參閱步驟 5,找出您在實驗室中使用的專案 ID。並代入第一個指令。舉例來說,如果專案 ID 為
lab-example-project,指令會是:gcloud projects delete lab-project-id-example --quiet
13. 恭喜
在本實驗室中,您已建立生成式 AI 應用程式,並使用 Gemini 模型進行預測。並透過基礎的監控和記錄功能檢測應用程式。您已將應用程式和原始碼的變更內容部署至 Cloud Run。接著,您可以使用 Google Cloud Observability 產品追蹤應用程式效能,確保應用程式的可靠性。
如要參與使用者體驗研究,協助我們改善您今天使用的產品,請按這裡註冊。
以下提供幾種繼續學習的方式:
- 程式碼實驗室:如何在 Cloud Run 上部署 Gemini 支援的聊天應用程式
- 程式碼研究室:如何搭配使用 Gemini 函式呼叫與 Cloud Run
- 如何使用 Cloud Run Jobs Video Intelligence API 逐場景處理影片
- 隨選研討會:Google Kubernetes Engine 新手上路
- 進一步瞭解如何使用應用程式記錄檔設定計數器和分佈指標
- 使用 OpenTelemetry Sidecar 寫入 OTLP 指標
- 參考資料:瞭解如何在 Google Cloud 中使用 Open Telemetry
