1. Обзор
Приложения Gen AI требуют наблюдения, как и любые другие. Требуются ли специальные методы наблюдения для генеративного ИИ ?
В ходе этой лабораторной работы вы создадите простое приложение Gen AI. Разверните его в Cloud Run . Оснастите его необходимыми возможностями мониторинга и ведения журналов с помощью сервисов и продуктов наблюдения Google Cloud.
Что вы узнаете
- Напишите приложение, использующее Vertex AI, с помощью редактора Cloud Shell.
- Сохраните код приложения на GitHub.
- Используйте gcloud CLI для развертывания исходного кода вашего приложения в Cloud Run.
- Добавьте возможности мониторинга и регистрации в свое приложение Gen AI.
- Использование метрик на основе журналов
- Реализация ведения журналов и мониторинга с помощью Open Telemetry SDK
- Получите представление об ответственной обработке данных ИИ
2. Предварительные условия
Если у вас еще нет учетной записи Google, вам необходимо создать новую учетную запись .
3. Настройка проекта
- Войдите в Google Cloud Console под своей учетной записью Google.
- Создайте новый проект или повторно используйте существующий проект. Запишите идентификатор проекта, который вы только что создали или выбрали.
- Включите биллинг для проекта.
- Завершение этой лабораторной работы должно стоить менее 5 долларов США.
- Вы можете выполнить действия, описанные в конце этого практического занятия, чтобы удалить ресурсы и избежать дальнейших расходов.
- Новые пользователи имеют право на бесплатную пробную версию стоимостью 300 долларов США .
- Убедитесь, что оплата включена в разделе «Мои проекты» в Cloud Billing.
- Если в вашем новом проекте в столбце
Billing account
указано,Billing is disabled
:- Нажмите на три точки в столбце «
Actions
. - Нажмите Изменить платеж.
- Выберите платежный аккаунт, который вы хотите использовать.
- Нажмите на три точки в столбце «
- Если вы посещаете живое мероприятие, учетная запись, скорее всего, будет называться Пробная платежная учетная запись Google Cloud Platform.
- Если в вашем новом проекте в столбце
4. Подготовьте редактор Cloud Shell.
- Перейдите в редактор Cloud Shell . Если вам будет предложено следующее сообщение с запросом на авторизацию Cloud Shell для вызова gcloud с вашими учетными данными, нажмите «Авторизовать», чтобы продолжить.
- Открыть окно терминала
- Нажмите на гамбургер-меню
- Нажмите Терминал
- Нажмите «Новый терминал».
- Нажмите на гамбургер-меню
- В терминале настройте идентификатор вашего проекта:
Заменитеgcloud config set project [PROJECT_ID]
[PROJECT_ID]
на идентификатор вашего проекта. Например, если идентификатор вашего проекта —lab-example-project
, команда будет такой: Если вам будет предложено следующее сообщение о том, что gcloud запрашивает ваши учетные данные для GCPI API, нажмите «Авторизовать» , чтобы продолжить.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. Создайте приложение Gen AI.
На этом этапе вы напишете код простого приложения на основе запросов, которое использует модель Gemini, чтобы показать 10 забавных фактов о животном по вашему выбору. Выполните следующие действия, чтобы создать код приложения.
- В терминале создайте каталог
codelab-o11y
:mkdir "${HOME}/codelab-o11y"
- Измените текущий каталог на
codelab-o11y
:cd "${HOME}/codelab-o11y"
- Загрузите загрузочный код приложения Java с помощью Spring Framework Starter:
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 автоматически сохранит ваш код.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-unauthenticated
Enter
. Процесс развертывания может занять до нескольких минут. После завершения процесса развертывания вы увидите следующий результат: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-адрес:
При открытии URL-адреса вы можете получить ошибку 500 или увидеть сообщение:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"'
Это означает, что сервисы не завершили свое развертывание. Подождите несколько минут и обновите страницу. В конце вы увидите текст, начинающийся со слов «Забавные факты о собаках» и содержащий 10 забавных фактов о собаках.Sorry, this is just a placeholder...
Попробуйте взаимодействовать с приложением, чтобы узнать забавные факты о разных животных. Для этого добавьте к URL-адресу параметр animal
, например ?animal=[ANIMAL]
, где [ANIMAL]
— имя животного. Например, добавьте ?animal=cat
чтобы получить 10 забавных фактов о кошках, или ?animal=sea turtle
чтобы получить 10 забавных фактов о морских черепахах.
7. Аудит вызовов Vertex API
Аудит вызовов API Google дает ответы на такие вопросы, как «Кто вызывает тот или иной API, где и когда?». Аудит важен при устранении неполадок в приложении, исследовании потребления ресурсов или проведении криминалистического анализа программного обеспечения.
Журналы аудита позволяют отслеживать административную и системную деятельность, а также регистрировать вызовы операций API «чтение данных» и «запись данных». Для аудита запросов Vertex AI на создание контента необходимо включить журналы аудита «Чтение данных» в облачной консоли.
- Нажмите кнопку ниже, чтобы открыть страницу журналов аудита в облачной консоли.
- Убедитесь, что на странице выбран проект, созданный вами для этой лабораторной работы. Выбранный проект отображается в верхнем левом углу страницы справа от гамбургер-меню:
При необходимости выберите правильный проект из поля со списком. - В таблице конфигурации журналов аудита доступа к данным в столбце Сервис найдите сервис
Vertex AI API
и выберите сервис, установив флажок, расположенный слева от названия сервиса. - В информационной панели справа выберите тип аудита «Чтение данных».
- Нажмите Сохранить .
Чтобы создать журналы аудита, откройте URL-адрес службы. Обновите страницу, изменив значение параметра ?animal=
чтобы получить другие результаты.
Изучите журналы аудита
- Нажмите кнопку ниже, чтобы открыть страницу обозревателя журналов в облачной консоли:
- Вставьте следующий фильтр в панель запросов.
Панель запросов — это редактор, расположенный в верхней части страницы обозревателя журналов:LOG_ID("cloudaudit.googleapis.com%2Fdata_access") AND protoPayload.serviceName="aiplatform.googleapis.com"
- Нажмите Выполнить запрос .
- Выберите одну из записей журнала аудита и разверните поля для проверки информации, записанной в журнале.
Вы можете просмотреть подробную информацию о вызове Vertex API, включая использованный метод и модель. Вы также можете увидеть личность инициатора и разрешения, авторизовавшие вызов.
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 автоматически сохранит изменения.
Разверните код приложения Gen AI в Cloud Run.
- В окне терминала выполните команду для развертывания исходного кода приложения в Cloud Run.
Если вы увидите приглашение, подобное приведенному ниже, информирующее вас о том, что команда создаст новый репозиторий. Нажмитеgcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticated
Enter
. Процесс развертывания может занять до нескольких минут. После завершения процесса развертывания вы увидите следующий результат: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-адрес:
При открытии URL-адреса вы можете получить ошибку 500 или увидеть сообщение:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"'
Это означает, что службы не завершили свое развертывание. Подождите несколько минут и обновите страницу. В конце вы увидите текст, начинающийся со слов «Забавные факты о собаках» и содержащий 10 забавных фактов о собаках.Sorry, this is just a placeholder...
Чтобы создать журналы приложений, откройте URL-адрес службы. Обновите страницу, изменив значение параметра ?animal=
чтобы получить другие результаты.
Чтобы просмотреть журналы приложений, выполните следующие действия:
- Нажмите кнопку ниже, чтобы открыть страницу обозревателя журналов в облачной консоли:
- Вставьте следующий фильтр в панель запросов (№ 2 в интерфейсе обозревателя журналов ):
LOG_ID("run.googleapis.com%2Fstdout") AND severity=DEBUG
- Нажмите Выполнить запрос .
В результате запроса отображаются журналы с подсказками и ответами Vertex AI, включая рейтинги безопасности .
9. Подсчитайте взаимодействия с Gen AI
Cloud Run записывает управляемые метрики , которые можно использовать для мониторинга развернутых сервисов. Метрики мониторинга, управляемые пользователем, обеспечивают больший контроль над данными и частотой обновления метрик. Для реализации такой метрики требуется написать код, который собирает данные и записывает их в Cloud Monitoring . См. следующий (необязательный) шаг, чтобы узнать, как реализовать его с помощью OpenTelemetry SDK.
На этом этапе показана альтернатива реализации пользовательской метрики в метриках на основе журнала кода. Метрики на основе журналов позволяют генерировать метрики мониторинга на основе записей журнала, которые ваше приложение записывает в Cloud Logging. Мы будем использовать журналы приложений, которые мы реализовали на предыдущем шаге, для определения основанной на журналах метрики типа counter . Метрика будет подсчитывать количество успешных вызовов Vertex API.
- Посмотрите на окно проводника журналов , которое мы использовали на предыдущем шаге. На панели «Запросы» найдите раскрывающееся меню «Действия» и щелкните его, чтобы открыть. См. скриншот ниже, чтобы найти меню:
- В открывшемся меню выберите Создать метрику , чтобы открыть панель Создать метрику на основе журнала .
- Выполните следующие действия, чтобы настроить новую метрику счетчика на панели «Создать метрику на основе журнала» .
- Установите тип метрики : выберите «Счетчик» .
- В разделе «Подробности» установите следующие поля:
- Имя метрики журнала : задайте имя
model_interaction_count
. Применяются некоторые ограничения на именование; Подробности см. в разделе «Ограничения на именование». Устранение неполадок. - Описание : введите описание метрики. Например,
Number of log entries capturing successful call to model inference.
- Единицы измерения : оставьте это поле пустым или вставьте цифру
1
.
- Имя метрики журнала : задайте имя
- Оставьте значения в разделе Выбор фильтра . Обратите внимание, что в поле «Фильтр сборки» используется тот же фильтр, который мы использовали для просмотра журналов приложений.
- (Необязательно) Добавьте метку, которая поможет подсчитать количество звонков для каждого животного. ПРИМЕЧАНИЕ. Эта метка может значительно увеличить мощность метрики, поэтому ее не рекомендуется использовать в рабочей среде:
- Нажмите Добавить метку .
- В разделе «Метки» задайте следующие поля:
- Имя метки : установите имя
animal
. - Описание : введите описание метки. Например,
Animal parameter
. - Тип метки : выберите
STRING
. - Имя поля : Введите
jsonPayload.animal
. - Регулярное выражение : оставьте его пустым.
- Имя метки : установите имя
- Нажмите Готово
- Нажмите Создать метрику , чтобы создать метрику.
Вы также можете создать метрику на основе журнала на странице показателей на основе журнала , используя команду gcloud logging metrics create
CLI или ресурс google_logging_metric
Terraform .
Чтобы сгенерировать данные метрик, откройте URL-адрес службы. Обновите открытую страницу несколько раз, чтобы выполнить несколько вызовов модели. Как и раньше, попробуйте использовать в качестве параметра разных животных.
Введите запрос PromQL для поиска данных метрик на основе журналов. Чтобы ввести запрос PromQL, выполните следующие действия:
- Нажмите кнопку ниже, чтобы открыть страницу обозревателя метрик в облачной консоли:
- На панели инструментов панели построителя запросов выберите кнопку с именем < > MQL или < > PromQL . Расположение кнопки показано на рисунке ниже.
- Убедитесь, что PromQL выбран в переключателе языка . Переключатель языка находится на той же панели инструментов, которая позволяет форматировать запрос.
- Введите запрос в редактор запросов :
Дополнительные сведения об использовании PromQL см. в разделе PromQL в Cloud Monitoring .sum(rate(logging_googleapis_com:user_model_interaction_count{monitored_resource="cloud_run_revision"}[${__interval}]))
- Нажмите «Выполнить запрос» . Вы увидите линейный график, похожий на этот скриншот:
Обратите внимание: когда включен переключатель «Автозапуск» , кнопка «Выполнить запрос» не отображается.
10. (Необязательно) Используйте открытую телеметрию для мониторинга и отслеживания.
Как упоминалось на предыдущем шаге, метрики можно реализовать с помощью OpenTelemetry (Otel) SDK. Рекомендуется использовать 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"
- Добавьте спецификацию 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 автоматически сохранит изменения.
Разверните код приложения Gen AI в Cloud Run.
- В окне терминала выполните команду для развертывания исходного кода приложения в Cloud Run.
Если вы увидите приглашение, подобное приведенному ниже, информирующее вас о том, что команда создаст новый репозиторий. Нажмитеgcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticated
Enter
. Процесс развертывания может занять до нескольких минут. После завершения процесса развертывания вы увидите следующий результат: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-адрес:
При открытии URL-адреса вы можете получить ошибку 500 или увидеть сообщение:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"'
Это означает, что сервисы не завершили свое развертывание. Подождите несколько минут и обновите страницу. В конце вы увидите текст, начинающийся со слов «Забавные факты о собаках» и содержащий 10 забавных фактов о собаках.Sorry, this is just a placeholder...
Чтобы создать данные телеметрии, откройте URL-адрес службы. Обновите страницу, изменив значение параметра ?animal=
чтобы получить другие результаты.
Изучите следы приложений
- Нажмите кнопку ниже, чтобы открыть страницу обозревателя трассировки в облачной консоли:
- Выберите одну из самых последних трассировок. Вы должны увидеть 5 или 6 пролетов, как показано на скриншоте ниже.
- Найдите диапазон, который отслеживает вызов обработчика событий (метод
fun_facts
). Это будет последний диапазон с именем/
. - В области сведений о трассировке выберите Журналы и события . Вы увидите журналы приложений, соответствующие этому конкретному диапазону. Корреляция обнаруживается с помощью идентификаторов трассировки и диапазона в трассировке и журнале. Вы должны увидеть журнал приложения, в котором записано приглашение и ответ Vertex API.
Изучите метрику счетчика
- Нажмите кнопку ниже, чтобы открыть страницу обозревателя метрик в облачной консоли:
- На панели инструментов панели построителя запросов выберите кнопку с именем < > MQL или < > PromQL . Расположение кнопки показано на рисунке ниже.
- Убедитесь, что PromQL выбран в переключателе языка . Переключатель языка находится на той же панели инструментов, которая позволяет форматировать запрос.
- Введите запрос в редактор запросов :
sum(rate(workload_googleapis_com:model_call_counter{monitored_resource="generic_task"}[${__interval}]))
- Нажмите «Выполнить запрос» . Если включен переключатель «Автозапуск» , кнопка «Выполнить запрос» не отображается.
11. (Необязательно) Скрытая конфиденциальная информация из журналов.
На шаге 10 мы записали информацию о взаимодействии приложения с моделью Gemini. Эта информация включала имя животного, фактическую подсказку и ответ модели. Хотя хранение этой информации в журнале должно быть безопасным, во многих других сценариях это не обязательно. Приглашение может содержать некоторую личную или иную конфиденциальную информацию, которую пользователь не хочет хранить. Чтобы решить эту проблему, вы можете скрыть конфиденциальные данные, записываемые в Cloud Logging. Чтобы свести к минимуму изменения кода, рекомендуется следующее решение.
- Создайте тему PubSub для хранения входящих записей журнала.
- Создайте приемник журналов , который перенаправляет загруженные журналы в тему PubSub.
- Создайте конвейер потока данных , который изменяет журналы, перенаправленные в тему PubSub, выполнив следующие действия:
- Прочитайте запись журнала из темы PubSub.
- Проверьте полезную нагрузку записи на наличие конфиденциальной информации с помощью API проверки DLP.
- Отредактируйте конфиденциальную информацию в полезных данных, используя один из методов редактирования DLP.
- Запишите запутанную запись журнала в Cloud Logging.
- Развертывание конвейера
12. (Необязательно) Очистка
Чтобы избежать риска взимания платы за ресурсы и API, используемые в лаборатории кода, рекомендуется выполнить очистку после завершения лабораторной работы. Самый простой способ избавиться от выставления счетов — удалить проект, созданный для лаборатории кода.
- Чтобы удалить проект, выполните команду удаления проекта в терминале:
При удалении проекта Cloud прекращается выставление счетов за все ресурсы и API, используемые в этом проекте. Вы должны увидеть это сообщение, гдеPROJECT_ID=$(gcloud config get-value project) gcloud projects delete ${PROJECT_ID} --quiet
PROJECT_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
- Как использовать Cloud Run Jobs Video Intelligence API для поэтапной обработки видео
- Семинар по запросу Google Kubernetes Engine Onboard
- Узнайте больше о настройке счетчиков и показателей распределения с помощью журналов приложений.
- Напишите OTLP-метрики с помощью дополнительного модуля OpenTelemetry.
- Ссылка на использование открытой телеметрии в Google Cloud