1. Обзор
Приложения генеративного ИИ, как и любые другие, требуют наблюдаемости. Требуются ли для генеративного ИИ специальные методы наблюдения?
В этой лабораторной работе вы создадите простое приложение для генерации искусственного интеллекта. Развернете его в Cloud Run . И оснастите его необходимыми функциями мониторинга и логирования, используя сервисы и продукты Google Cloud для обеспечения наблюдаемости.
Что вы узнаете
- Напишите приложение, использующее Vertex AI с редактором Cloud Shell.
- Сохраняйте код своего приложения на GitHub.
- Используйте gcloud CLI для развертывания исходного кода вашего приложения в Cloud Run.
- Добавьте возможности мониторинга и ведения журналов в ваше приложение Gen AI.
- Использование метрик на основе логов
- Реализация логирования и мониторинга с помощью Open Telemetry SDK
- Получите представление об ответственном обращении с данными в рамках искусственного интеллекта.
2. Предварительные требования
Если у вас еще нет учетной записи Google, вам необходимо создать новую .
3. Настройка проекта
- Войдите в консоль Google Cloud, используя свою учетную запись Google.
- Создайте новый проект или выберите вариант повторного использования существующего. Запишите идентификатор созданного или выбранного вами проекта.
- Включите выставление счетов по проекту.
- Выполнение этой лабораторной работы должно обойтись менее чем в 5 долларов США в виде расходов на оплату.
- В конце этой лабораторной работы вы можете выполнить действия по удалению ресурсов, чтобы избежать дальнейших списаний средств.
- Новые пользователи могут воспользоваться бесплатной пробной версией стоимостью 300 долларов США .
- Подтвердите, что выставление счетов включено в разделе «Мои проекты» в Cloud Billing.
- Если в столбце
Billing accountBilling is disabled:- Нажмите на три точки в столбце
Actions. - Нажмите «Изменить оплату».
- Выберите платежный аккаунт, который вы хотите использовать.
- Нажмите на три точки в столбце
- Если вы участвуете в мероприятии в режиме реального времени, учетная запись, скорее всего, будет называться Google Cloud Platform Trial Billing Account.
- Если в столбце
4. Подготовка редактора Cloud Shell.
- Перейдите в редактор Cloud Shell . Если появится сообщение с запросом на авторизацию Cloud Shell для вызова gcloud с использованием ваших учетных данных, нажмите «Авторизовать» , чтобы продолжить.

- Открыть окно терминала
- Нажмите на значок гамбургера.

- Нажмите «Терминал»
- Нажмите «Новый терминал»

- Нажмите на значок гамбургера.
- В терминале настройте идентификатор вашего проекта:
Заменитеgcloud config set project [PROJECT_ID][PROJECT_ID]на идентификатор вашего проекта. Например, если идентификатор вашего проекта —lab-example-project, команда будет выглядеть так: Если появится сообщение о том, что gcloud запрашивает ваши учетные данные для API GCPI, нажмите «Авторизовать» , чтобы продолжить.gcloud config set project lab-project-id-example

После успешного выполнения вы должны увидеть следующее сообщение: Если вы видитеUpdated property [core/project].
WARNINGи вас спрашиваютDo you want to continue (Y/N)?, то, скорее всего, вы неправильно ввели идентификатор проекта. НажмитеN, затемEnterи попробуйте снова запустить командуgcloud config set projectпосле того, как найдете правильный идентификатор проекта. - (Необязательно) Если у вас возникли проблемы с поиском идентификатора проекта, выполните следующую команду, чтобы увидеть идентификаторы всех ваших проектов, отсортированных по времени создания в порядке убывания:
gcloud projects list \ --format='value(projectId,createTime)' \ --sort-by=~createTime
5. Включите API Google.
В терминале включите API Google, необходимые для выполнения этой лабораторной работы:
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. Создайте приложение для генерации искусственного интеллекта.
На этом этапе вам нужно будет написать код простого приложения, работающего по принципу запросов и использующего модель Gemini для отображения 10 интересных фактов о выбранном вами животном. Выполните следующие действия, чтобы создать код приложения.
- В терминале создайте каталог
codelab-o11y:mkdir "${HOME}/codelab-o11y" - Перейдите в текущий каталог
codelab-o11y:cd "${HOME}/codelab-o11y" - Загрузите загрузочный код Java-приложения, используя стартовый пакет фреймворка Spring:
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, чтобы определить версию среды выполнения Java, которая будет использоваться при развертывании кода в Cloud Run:cat > "${HOME}/codelab-o11y/project.toml" << EOF [[build.env]] name = "GOOGLE_RUNTIME_VERSION" value = "17" EOF - Добавьте зависимости Google Cloud SDK в файл
pom.xml:- Добавьте пакет 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:
- Откройте файл
DemoApplication.javaв редакторе Cloud Shell: В окне редактора над терминалом теперь должен отобразиться сгенерированный исходный код файла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 Editor автоматически сохранит ваш код.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); } }
Разверните код приложения Gen 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
- Скопируйте отображаемый URL-адрес службы Cloud Run в отдельную вкладку или окно браузера. В качестве альтернативы, выполните следующую команду в терминале, чтобы вывести URL-адрес службы, и щелкните по отображаемому URL-адресу, удерживая клавишу Ctrl , чтобы открыть его:
При открытии URL-адреса может появиться ошибка 500 или сообщение:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"' Это означает, что развертывание сервиса не завершилось. Подождите несколько минут и обновите страницу. В конце вы увидите текст, начинающийся с «Забавные факты о собаках» и содержащий 10 интересных фактов о собаках.Sorry, this is just a placeholder...
Попробуйте взаимодействовать с приложением, чтобы узнать интересные факты о разных животных. Для этого добавьте параметр animal к URL-адресу, например ?animal=[ANIMAL] где [ANIMAL] — название животного. Например, добавьте ?animal=cat чтобы получить 10 интересных фактов о кошках, или ?animal=sea turtle чтобы получить 10 интересных фактов о морских черепахах.
7. Проведите аудит вызовов API Vertex.
Аудит вызовов API Google позволяет получить ответы на такие вопросы, как «Кто вызывает тот или иной API, где и когда?». Аудит важен при устранении неполадок в приложении, исследовании потребления ресурсов или проведении анализа программного обеспечения.
Журналы аудита позволяют отслеживать административные и системные действия, а также регистрировать вызовы операций API «чтение данных» и «запись данных». Для аудита запросов Vertex AI к генерации контента необходимо включить журналы аудита «Чтение данных» в консоли Cloud.
- Нажмите на кнопку ниже, чтобы открыть страницу «Журналы аудита» в консоли Cloud.
- Убедитесь, что на странице выбран проект, который вы создали для этой лабораторной работы. Выбранный проект отображается в верхнем левом углу страницы, справа от меню-гамбургера:

При необходимости выберите нужный проект из выпадающего списка. - В таблице конфигурации журналов аудита доступа к данным в столбце «Сервис» найдите сервис
Vertex AI APIи выберите его, установив флажок слева от имени сервиса.
- В информационной панели справа выберите тип аудита «Чтение данных».

- Нажмите « Сохранить ».
Для создания журналов аудита откройте URL-адрес сервиса. Обновите страницу, изменяя значение параметра ?animal= чтобы получить другие результаты.
Изучите журналы аудита
- Нажмите на кнопку ниже, чтобы открыть страницу «Проводник журналов» в консоли Cloud:
- Вставьте следующий фильтр в панель запросов.
Панель запросов — это редактор, расположенный в верхней части страницы «Проводник журналов»:LOG_ID("cloudaudit.googleapis.com%2Fdata_access") AND protoPayload.serviceName="aiplatform.googleapis.com"
- Нажмите « Выполнить запрос» .
- Выберите одну из записей журнала аудита и разверните поля для просмотра информации, содержащейся в журнале.
Здесь вы можете увидеть подробную информацию о вызове API Vertex, включая использованный метод и модель. Вы также можете увидеть идентификатор вызывающего пользователя и права доступа, которые разрешили этот вызов.
8. Запись взаимодействий с Gen AI.
В журналах аудита не отображаются параметры запросов API и данные ответов. Однако эта информация может быть важна для устранения неполадок в приложениях и анализа рабочих процессов. На этом этапе мы восполняем этот пробел, добавляя ведение журналов приложения.
В данной реализации используется Logback с Spring Boot для вывода логов приложения на стандартный вывод. Этот метод использует возможности Cloud Run для захвата информации, выводимой на стандартный вывод, и её автоматической передачи в Cloud Logging. Для захвата информации в виде структурированных данных, выводимые логи должны быть соответствующим образом отформатированы. Следуйте приведенным ниже инструкциям, чтобы добавить в приложение возможности структурированного логирования.
- Вернитесь в окно (или вкладку) «Cloud Shell» в вашем браузере.
- Создайте и откройте новый файл
LoggingEventGoogleCloudEncoder.javaв редакторе Cloud Shell: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"; } } } - Создайте и откройте новый файл
logback.xmlв редакторе Cloud Shell: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> - Откройте файл
DemoApplication.javaв редакторе Cloud Shell:cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/DemoApplication.java" - Замените код в редакторе на версию, показанную ниже, для регистрации запросов и ответов от Gen 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 Editor автоматически сохранит ваши изменения.
Разверните код приложения Gen 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
- Скопируйте отображаемый URL-адрес службы Cloud Run в отдельную вкладку или окно браузера. В качестве альтернативы, выполните следующую команду в терминале, чтобы вывести URL-адрес службы, и щелкните по отображаемому URL-адресу, удерживая клавишу Ctrl , чтобы открыть его:
При открытии URL-адреса может появиться ошибка 500 или сообщение:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"' Это означает, что развертывание сервиса не завершилось. Подождите несколько минут и обновите страницу. В конце вы увидите текст, начинающийся с «Забавные факты о собаках» и содержащий 10 интересных фактов о собаках.Sorry, this is just a placeholder...
Для создания логов приложения откройте URL-адрес сервиса. Обновите страницу, изменяя значение параметра ?animal= чтобы получить другие результаты.
Чтобы просмотреть журналы приложения, выполните следующие действия:
- Нажмите на кнопку ниже, чтобы открыть страницу просмотра журналов в консоли Cloud:
- Вставьте следующий фильтр в панель запросов (№2 в интерфейсе обозревателя журналов ):
LOG_ID("run.googleapis.com%2Fstdout") AND severity=DEBUG - Нажмите « Выполнить запрос» .
В результате запроса отображаются журналы с запросом и ответом от Vertex AI, включая оценки безопасности .
9. Подсчет взаимодействий с Gen AI.
Cloud Run записывает управляемые метрики , которые можно использовать для мониторинга развернутых сервисов. Управляемые пользователем метрики мониторинга обеспечивают больший контроль над данными и частотой обновления метрик. Для реализации таких метрик требуется написать код, который собирает данные и записывает их в Cloud Monitoring . См. следующий (необязательный) шаг, чтобы узнать, как реализовать это с помощью OpenTelemetry SDK.
На этом шаге показана альтернатива реализации пользовательских метрик в коде — метрики на основе логов . Метрики на основе логов позволяют генерировать метрики мониторинга из записей логов, которые ваше приложение записывает в Cloud Logging. Мы будем использовать логи приложения, которые мы реализовали на предыдущем шаге, чтобы определить метрику на основе логов типа счетчик . Метрика будет подсчитывать количество успешных вызовов API Vertex.
- Посмотрите на окно обозревателя журналов , которое мы использовали на предыдущем шаге. В панели запросов найдите выпадающее меню « Действия» и щелкните по нему, чтобы открыть. См. снимок экрана ниже, чтобы найти это меню:

- В открывшемся меню выберите пункт «Создать метрику» , чтобы открыть панель «Создать метрику на основе логов» .
- Выполните следующие действия, чтобы настроить новую метрику счетчика на панели «Создание метрик на основе журналов» :
- Выберите тип метрики : выберите «Счетчик» .
- В разделе «Подробности» укажите следующие поля:
- Имя метрики журнала : задайте имя
model_interaction_count. Действуют некоторые ограничения на именование; подробности см. в разделе «Устранение неполадок, связанных с ограничениями на именование». - Описание : Введите описание метрики. Например,
Number of log entries capturing successful call to model inference. - Единицы измерения : Оставьте это поле пустым или вставьте цифру
1.
- Имя метрики журнала : задайте имя
- Оставьте значения в разделе «Выбор фильтра» . Обратите внимание, что поле фильтра «Сборка» имеет тот же фильтр, который мы использовали для просмотра журналов приложения.
- (Необязательно) Добавьте метку, которая поможет подсчитать количество звонков для каждого животного. ПРИМЕЧАНИЕ: эта метка может значительно увеличить кардинальность метрики и не рекомендуется для использования в производстве:
- Нажмите «Добавить метку» .
- В разделе «Метки» задайте следующие поля:
- Название метки : Задайте название
animal. - Описание : Введите описание метки. Например,
Animal parameter. - Тип метки : Выберите
STRING. - Название поля : Тип
jsonPayload.animal. - Регулярное выражение : Оставьте поле пустым.
- Название метки : Задайте название
- Нажмите «Готово».
- Нажмите «Создать метрику» , чтобы создать метрику.
Вы также можете создать метрику на основе логов на странице «Метрики на основе логов» , используя команду CLI gcloud logging metrics create или ресурс Terraform google_logging_metric .
Для генерации метрических данных откройте URL-адрес сервиса. Обновите открытую страницу несколько раз, чтобы выполнить несколько вызовов к модели. Как и раньше, попробуйте использовать разных животных в качестве параметров.
Введите PromQL-запрос для поиска данных метрик, основанных на логах. Для ввода PromQL-запроса выполните следующие действия:
- Нажмите на кнопку ниже, чтобы открыть страницу обозревателя метрик в консоли Cloud:
- На панели инструментов конструктора запросов выберите кнопку с именем < > MQL или < > PromQL . Расположение кнопки показано на рисунке ниже.

- Убедитесь, что в переключателе «Язык» выбран параметр PromQL . Переключатель языка находится на той же панели инструментов, что и для форматирования запроса.
- Введите свой запрос в редактор запросов :
Для получения дополнительной информации об использовании PromQL см. раздел «PromQL в мониторинге облачных сервисов» .sum(rate(logging_googleapis_com:user_model_interaction_count{monitored_resource="cloud_run_revision"}[${__interval}])) - Нажмите «Выполнить запрос» . Вы увидите линейный график, похожий на этот снимок экрана:

Обратите внимание, что при включении параметра «Автозапуск» кнопка «Выполнить запрос» не отображается.
10. (Необязательно) Используйте Open Telemetry для мониторинга и трассировки.
Как упоминалось на предыдущем шаге, метрики можно реализовать с помощью SDK OpenTelemetry (Otel). Использование OTel в многосервисных архитектурах является рекомендуемой практикой. На этом шаге демонстрируется добавление инструментов OTel в приложение Spring Boot. На этом шаге вы выполните следующие действия:
- Инструментирование Spring Boot-приложений с возможностью автоматической трассировки.
- Внедрение счетчика метрик для мониторинга количества успешных вызовов модели.
- Сопоставьте данные трассировки с журналами приложений.
Рекомендуемая архитектура для сервисов уровня продукта предполагает использование сборщика OTel для сбора и обработки всех данных мониторинга из множества сервисов. В этом шаге код не использует сборщик для простоты. Вместо этого он использует экспорт OTel, который записывает данные непосредственно в Google Cloud.
Настройка приложения Spring Boot с использованием компонентов OTel и автоматической трассировки.
- Вернитесь в окно (или вкладку) «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 - Добавьте необходимые зависимости OpenTelemetry в файл
pom.xml: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" - Добавьте BOM-объект OpenTelemetry в файл
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" - Откройте файл
DemoApplication.javaв редакторе Cloud Shell: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); } } - Откройте файл
LoggingEventGoogleCloudEncoder.javaзаново в редакторе Cloud Shell: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 Editor автоматически сохранит ваши изменения.
Разверните код приложения Gen 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
- Скопируйте отображаемый URL-адрес службы Cloud Run в отдельную вкладку или окно браузера. В качестве альтернативы, выполните следующую команду в терминале, чтобы вывести URL-адрес службы, и щелкните по отображаемому URL-адресу, удерживая клавишу Ctrl , чтобы открыть его:
При открытии URL-адреса может появиться ошибка 500 или сообщение:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"' Это означает, что развертывание сервиса не завершилось. Подождите несколько минут и обновите страницу. В конце вы увидите текст, начинающийся с «Забавные факты о собаках» и содержащий 10 интересных фактов о собаках.Sorry, this is just a placeholder...
Для генерации телеметрических данных откройте URL-адрес сервиса. Обновите страницу, изменяя значение параметра ?animal= чтобы получить другие результаты.
Изучите трассировки приложения.
- Нажмите на кнопку ниже, чтобы открыть страницу обозревателя трассировки в консоли Cloud:
- Выберите один из последних треков. Вы должны увидеть 5 или 6 фрагментов, похожих на те, что показаны на скриншоте ниже.

- Найдите фрагмент кода, отслеживающий вызов обработчика событий (метода
fun_facts). Это будет последний фрагмент кода с именем/. - В панели сведений о трассировке выберите «Журналы и события» . Вы увидите журналы приложений, которые соответствуют этому конкретному сегменту. Корреляция определяется с помощью идентификаторов трассировки и сегмента в трассировке и в журнале. Вы должны увидеть журнал приложения, в котором были записаны запрос и ответ от API Vertex.
Изучите контрметрику
- Нажмите на кнопку ниже, чтобы открыть страницу обозревателя метрик в консоли Cloud:
- На панели инструментов конструктора запросов выберите кнопку с именем < > MQL или < > PromQL . Расположение кнопки показано на рисунке ниже.

- Убедитесь, что в переключателе «Язык» выбран параметр PromQL . Переключатель языка находится на той же панели инструментов, что и для форматирования запроса.
- Введите свой запрос в редактор запросов :
sum(rate(workload_googleapis_com:model_call_counter{monitored_resource="generic_task"}[${__interval}])) - Нажмите кнопку «Выполнить запрос» . Когда переключатель «Автозапуск» включен, кнопка «Выполнить запрос» не отображается.
11. (Необязательно) Замаскированная конфиденциальная информация из журналов.
На шаге 10 мы записали в лог информацию о взаимодействии приложения с моделью Gemini. Эта информация включала имя животного, сам запрос и ответ модели. Хотя хранение этой информации в логе должно быть безопасным, это не обязательно верно для многих других сценариев. Запрос может содержать некоторую личную или иную конфиденциальную информацию, которую пользователь не хочет сохранять. Для решения этой проблемы можно замаскировать конфиденциальные данные, записываемые в Cloud Logging. Для минимизации изменений в коде рекомендуется следующее решение.
- Создайте тему PubSub для хранения входящих записей журнала.
- Создайте приемник логов , который перенаправляет поступающие логи в топик PubSub.
- Создайте конвейер Dataflow , который изменяет журналы, перенаправляемые в тему PubSub, выполнив следующие шаги:
- Прочитайте запись в журнале из темы PubSub.
- Проверьте содержимое записи на наличие конфиденциальной информации с помощью API проверки DLP.
- Удалите конфиденциальную информацию из полезной нагрузки, используя один из методов удаления данных с помощью DLP.
- Запишите зашифрованную запись в журнал Cloud Logging.
- Разверните конвейер
12. (Необязательно) Уборка
Чтобы избежать риска взимания платы за ресурсы и API, используемые в практическом задании, рекомендуется выполнить очистку после его завершения. Самый простой способ избежать выставления счетов — удалить проект, созданный для этого задания.
- Чтобы удалить проект, выполните команду delete project в терминале:
Удаление вашего облачного проекта прекращает выставление счетов за все ресурсы и API, используемые в этом проекте. Вы должны увидеть следующее сообщение, гдеPROJECT_ID=$(gcloud config get-value project) gcloud projects delete ${PROJECT_ID} --quietPROJECT_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, чтобы найти идентификатор проекта, который вы использовали во время лабораторной работы. Подставьте его в команду в первой инструкции. Например, если ваш идентификатор проекта —
lab-example-project, команда будет следующей:gcloud projects delete lab-project-id-example --quiet
13. Поздравляем!
В этой лабораторной работе вы создали приложение Gen AI, использующее модель Gemini для прогнозирования. Вы также оснастили приложение необходимыми функциями мониторинга и логирования. Затем вы развернули приложение и внесли изменения из исходного кода в Cloud Run . После этого вы использовали продукты Google Cloud Observability для отслеживания производительности приложения, чтобы убедиться в его надежности.
Если вас интересует участие в исследовании пользовательского опыта (UX) для улучшения продуктов, с которыми вы работаете сегодня, зарегистрируйтесь здесь .
Вот несколько вариантов для продолжения обучения:
- Codelab: Как развернуть чат-приложение на базе Gemini в Cloud Run
- Codelab: Как использовать вызов функций Gemini с помощью Cloud Run
- Как использовать API Cloud Run Jobs Video Intelligence для покадровой обработки видео.
- По запросу: мастер-класс по Google Kubernetes Engine Onboard
- Узнайте больше о настройке счетчиков и метрик распространения с помощью журналов приложений.
- Записывайте метрики OTLP, используя вспомогательный модуль OpenTelemetry.
- Ссылка на использование Open Telemetry в Google Cloud