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 Go.
На этом этапе вы напишете код простого приложения на основе запросов, которое использует модель Gemini, чтобы показать 10 забавных фактов о животном по вашему выбору. Выполните следующие действия, чтобы создать код приложения.
- В терминале создайте каталог
codelab-o11y
:mkdir ~/codelab-o11y
- Измените текущий каталог на
codelab-o11y
:cd ~/codelab-o11y
- Инициализируем модули Go:
go mod init codelab
- Установите Vertex AI SDK для Go:
go get cloud.google.com/go/vertexai/genai
- Установите библиотеку метаданных для Go, чтобы получить текущий идентификатор проекта:
go get cloud.google.com/go/compute/metadata
- Создайте файл
setup.go
и откройте его в редакторе Cloud Shell: Он будет использоваться для размещения кода инициализации. В окне редактора появится новый пустой файл с именемcloudshell edit setup.go
setup.go
. - Скопируйте следующий код и вставьте его в открывшийся файл
setup.go
:package main import ( "context" "os" "cloud.google.com/go/compute/metadata" ) func projectID(ctx context.Context) (string, error) { var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT") if projectID == "" { return metadata.ProjectIDWithContext(ctx) } return projectID, nil }
- Вернитесь в окно терминала и выполните следующую команду, чтобы создать и открыть файл
main.go
в редакторе Cloud Shell: Пустой файл должен появиться в окне редактора над терминалом. Ваш экран будет выглядеть примерно так:cloudshell edit main.go
- Скопируйте следующий код и вставьте его в открывшийся файл
main.go
: Через несколько секунд редактор Cloud Shell автоматически сохранит ваш код.package main import ( "context" "fmt" "net/http" "os" "cloud.google.com/go/vertexai/genai" ) var model *genai.GenerativeModel func main() { ctx := context.Background() projectID, err := projectID(ctx) if err != nil { return } var client *genai.Client client, err = genai.NewClient(ctx, projectID, "us-central1") if err != nil { return } defer client.Close() model = client.GenerativeModel("gemini-1.5-flash-001") http.HandleFunc("/", Handler) port := os.Getenv("PORT") if port == "" { port = "8080" } if err := http.ListenAndServe(":"+port, nil); err != nil { return } } func Handler(w http.ResponseWriter, r *http.Request) { animal := r.URL.Query().Get("animal") if animal == "" { animal = "dog" } prompt := fmt.Sprintf("Give me 10 fun facts about %s. Return the results as HTML without markdown backticks.", animal) resp, err := model.GenerateContent(r.Context(), genai.Text(prompt)) if err != nil { w.WriteHeader(http.StatusTooManyRequests) return } if len(resp.Candidates) > 0 && len(resp.Candidates[0].Content.Parts) > 0 { htmlContent := resp.Candidates[0].Content.Parts[0] w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, htmlContent) } }
Разверните код приложения 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...
Попробуйте взаимодействовать с приложением, чтобы узнать забавные факты о разных животных. Для этого добавьте параметр animal
к URL-адресу, например ?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 или данные ответа. Однако эта информация может быть важна для устранения неполадок приложения и анализа рабочего процесса. На этом этапе мы восполним этот пробел, добавив ведение журнала приложений. Для ведения журнала используется стандартный пакет Go log/slog
для записи структурированных журналов. Пакет log/slog
не умеет записывать журналы в Google Cloud. Он поддерживает запись в стандартный вывод. Однако функция Cloud Run позволяет собирать информацию, выводящуюся в стандартный вывод, и автоматически передавать ее в Cloud Logging. Для правильного ведения структурированных журналов распечатанный журнал должен быть соответствующим образом отформатирован. Следуйте инструкциям ниже, чтобы добавить возможности структурированного ведения журнала в наше приложение Go.
- Вернитесь в окно (или вкладку) Cloud Shell в браузере.
- В терминале снова откройте
setup.go
:cloudshell edit ~/codelab-o11y/setup.go
- Замените код версией, которая настраивает ведение журнала. Чтобы заменить код, удалите содержимое файла, а затем скопируйте приведенный ниже код и вставьте его в редактор:
package main import ( "context" "os" "log/slog" "cloud.google.com/go/compute/metadata" ) func projectID(ctx context.Context) (string, error) { var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT") if projectID == "" { return metadata.ProjectIDWithContext(ctx) } return projectID, nil } func setupLogging() { opts := &slog.HandlerOptions{ Level: slog.LevelDebug, ReplaceAttr: func(group []string, a slog.Attr) slog.Attr { switch a.Key { case slog.LevelKey: a.Key = "severity" if level := a.Value.Any().(slog.Level); level == slog.LevelWarn { a.Value = slog.StringValue("WARNING") } case slog.MessageKey: a.Key = "message" case slog.TimeKey: a.Key = "timestamp" } return a }, } jsonHandler := slog.NewJSONHandler(os.Stdout, opts) slog.SetDefault(slog.New(jsonHandler)) }
- Вернитесь в терминал и снова откройте
main.go
:cloudshell edit ~/codelab-o11y/main.go
- Замените код приложения версией, в которой протоколируется взаимодействие с моделью. Чтобы заменить код, удалите содержимое файла, а затем скопируйте приведенный ниже код и вставьте его в редактор:
package main import ( "context" "fmt" "net/http" "os" "encoding/json" "log/slog" "cloud.google.com/go/vertexai/genai" ) var model *genai.GenerativeModel func main() { ctx := context.Background() projectID, err := projectID(ctx) if err != nil { return } setupLogging() var client *genai.Client client, err = genai.NewClient(ctx, projectID, "us-central1") if err != nil { slog.ErrorContext(ctx, "Failed to marshal response to JSON", slog.Any("error", err)) os.Exit(1) } defer client.Close() model = client.GenerativeModel("gemini-1.5-flash-001") http.HandleFunc("/", Handler) port := os.Getenv("PORT") if port == "" { port = "8080" } if err := http.ListenAndServe(":"+port, nil); err != nil { slog.ErrorContext(ctx, "Failed to start the server", slog.Any("error", err)) os.Exit(1) } } func Handler(w http.ResponseWriter, r *http.Request) { animal := r.URL.Query().Get("animal") if animal == "" { animal = "dog" } prompt := fmt.Sprintf("Give me 10 fun facts about %s. Return the results as HTML without markdown backticks.", animal) resp, err := model.GenerateContent(r.Context(), genai.Text(prompt)) if err != nil { w.WriteHeader(http.StatusTooManyRequests) return } jsonBytes, err := json.Marshal(resp) if err != nil { slog.Error("Failed to marshal response to JSON", slog.Any("error", err)) } else { slog.DebugContext(r.Context(), "content is generated", slog.String("animal", animal), slog.String("prompt", prompt), slog.String("response", string(jsonBytes))) } if len(resp.Candidates) > 0 && len(resp.Candidates[0].Content.Parts) > 0 { htmlContent := resp.Candidates[0].Content.Parts[0] w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, htmlContent) } }
Ведение журнала настроено на печать журналов на stdout
, где они собираются агентом журналирования Cloud Run и асинхронно принимаются в Cloud Logging. Функция main()
изменена для настройки стандартного структурированного журнала Go для использования схемы JSON, соответствующей рекомендациям по структурированному форматированию . Все его операторы return
заменяются кодом, который записывает журналы ошибок перед выходом. Функция Handler()
предназначена для записи структурированного журнала при получении ответа от вызова API Vertex AI. В журнале фиксируются параметры животного в запросе, а также подсказка и ответ модели.
Через несколько секунд редактор 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 для поддержки отслеживания и мониторинга приложения.
- Заполнение конфигурации OTel метаданными ресурсов среды Cloud Run
- Инструментирование приложения колбы с возможностью автоматического отслеживания
- Внедрение счетчика-метрики для отслеживания количества успешных вызовов модели.
- Сопоставление трассировки с журналами приложений
Рекомендуемая архитектура для служб уровня продукта — использовать сборщик OTel для сбора и приема всех данных наблюдения для одной или нескольких служб. Для простоты код на этом этапе не использует сборщик. Вместо этого он использует экспорт OTel, который записывает данные непосредственно в Google Cloud.
Настройка компонентов OTel для отслеживания и мониторинга показателей
- Вернитесь в окно (или вкладку) Cloud Shell в браузере.
- В терминале снова откройте
setup.go
:cloudshell edit ~/codelab-o11y/setup.go
- Замените код версией, которая инициализирует трассировку OpenTelemetry и сбор метрик. Чтобы заменить код, удалите содержимое файла, а затем скопируйте приведенный ниже код и вставьте его в редактор:
package main import ( "context" "errors" "fmt" "net/http" "os" "log/slog" "go.opentelemetry.io/contrib/detectors/gcp" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/contrib/propagators/autoprop" "go.opentelemetry.io/otel" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.27.0" "go.opentelemetry.io/otel/trace" cloudmetric "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric" cloudtrace "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace" "cloud.google.com/go/compute/metadata" ) var ( projID string ) func projectID(ctx context.Context) (string, error) { var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT") if projectID == "" { return metadata.ProjectIDWithContext(ctx) } return projectID, nil } func setupLogging() { opts := &slog.HandlerOptions{ Level: slog.LevelDebug, ReplaceAttr: func(group []string, a slog.Attr) slog.Attr { switch a.Key { case slog.LevelKey: a.Key = "severity" if level := a.Value.Any().(slog.Level); level == slog.LevelWarn { a.Value = slog.StringValue("WARNING") } case slog.MessageKey: a.Key = "message" case slog.TimeKey: a.Key = "timestamp" } return a }, } jsonHandler := slog.NewJSONHandler(os.Stdout, opts) instrumentedHandler := handlerWithSpanContext(jsonHandler) slog.SetDefault(slog.New(instrumentedHandler)) } type spanContextLogHandler struct { slog.Handler } func handlerWithSpanContext(handler slog.Handler) *spanContextLogHandler { return &spanContextLogHandler{Handler: handler} } func (t *spanContextLogHandler) Handle(ctx context.Context, record slog.Record) error { if s := trace.SpanContextFromContext(ctx); s.IsValid() { trace := fmt.Sprintf("projects/%s/traces/%s", projID, s.TraceID()) record.AddAttrs( slog.Any("logging.googleapis.com/trace", trace), ) record.AddAttrs( slog.Any("logging.googleapis.com/spanId", s.SpanID()), ) record.AddAttrs( slog.Bool("logging.googleapis.com/trace_sampled", s.TraceFlags().IsSampled()), ) } return t.Handler.Handle(ctx, record) } func setupTelemetry(ctx context.Context) (shutdown func(context.Context) error, err error) { var shutdownFuncs []func(context.Context) error shutdown = func(ctx context.Context) error { var err error for _, fn := range shutdownFuncs { err = errors.Join(err, fn(ctx)) } shutdownFuncs = nil return err } projID, err = projectID(ctx) if err != nil { err = errors.Join(err, shutdown(ctx)) return } res, err2 := resource.New( ctx, resource.WithDetectors(gcp.NewDetector()), resource.WithTelemetrySDK(), resource.WithAttributes(semconv.ServiceNameKey.String(os.Getenv("K_SERVICE"))), ) if err2 != nil { err = errors.Join(err2, shutdown(ctx)) return } otel.SetTextMapPropagator(autoprop.NewTextMapPropagator()) texporter, err2 := cloudtrace.New(cloudtrace.WithProjectID(projID)) if err2 != nil { err = errors.Join(err2, shutdown(ctx)) return } tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithResource(res), sdktrace.WithBatcher(texporter)) shutdownFuncs = append(shutdownFuncs, tp.Shutdown) otel.SetTracerProvider(tp) mexporter, err2 := cloudmetric.New(cloudmetric.WithProjectID(projID)) if err2 != nil { err = errors.Join(err2, shutdown(ctx)) return } mp := sdkmetric.NewMeterProvider( sdkmetric.WithReader(sdkmetric.NewPeriodicReader(mexporter)), sdkmetric.WithResource(res), ) shutdownFuncs = append(shutdownFuncs, mp.Shutdown) otel.SetMeterProvider(mp) return shutdown, nil } func registerHttpHandler(route string, handleFn http.HandlerFunc) { instrumentedHandler := otelhttp.NewHandler(otelhttp.WithRouteTag(route, handleFn), route) http.Handle(route, instrumentedHandler) }
- Вернитесь в терминал и выполните следующую команду, чтобы обновить определения модуля Go в файле
go.mod
:go mod tidy
- Вернитесь в терминал и снова откройте
main.go
:cloudshell edit ~/codelab-o11y/main.go
- Замените текущий код версией, которая обеспечивает трассировку HTTP и записывает показатели производительности. Чтобы заменить код, удалите содержимое файла, а затем скопируйте приведенный ниже код и вставьте его в редактор:
package main import ( "context" "errors" "fmt" "net/http" "os" "encoding/json" "log/slog" "cloud.google.com/go/vertexai/genai" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" ) var model *genai.GenerativeModel var counter metric.Int64Counter const scopeName = "genai-o11y/go/workshop/example" func main() { ctx := context.Background() projectID, err := projectID(ctx) if err != nil { return } setupLogging() shutdown, err := setupTelemetry(ctx) if err != nil { slog.ErrorContext(ctx, "error setting up OpenTelemetry", slog.Any("error", err)) os.Exit(1) } meter := otel.Meter(scopeName) counter, err = meter.Int64Counter("model_call_counter") if err != nil { slog.ErrorContext(ctx, "error setting up OpenTelemetry", slog.Any("error", err)) os.Exit(1) } var client *genai.Client client, err = genai.NewClient(ctx, projectID, "us-central1") if err != nil { slog.ErrorContext(ctx, "Failed to marshal response to JSON", slog.Any("error", err)) os.Exit(1) } defer client.Close() model = client.GenerativeModel("gemini-1.5-flash-001") registerHttpHandler("/", Handler) port := os.Getenv("PORT") if port == "" { port = "8080" } if err = errors.Join(http.ListenAndServe(":"+port, nil), shutdown(ctx)); err != nil { slog.ErrorContext(ctx, "Failed to start the server", slog.Any("error", err)) os.Exit(1) } } func Handler(w http.ResponseWriter, r *http.Request) { animal := r.URL.Query().Get("animal") if animal == "" { animal = "dog" } prompt := fmt.Sprintf("Give me 10 fun facts about %s. Return the results as HTML without markdown backticks.", animal) resp, err := model.GenerateContent(r.Context(), genai.Text(prompt)) if err != nil { w.WriteHeader(http.StatusTooManyRequests) return } jsonBytes, err := json.Marshal(resp) if err != nil { slog.ErrorContext(r.Context(), "Failed to marshal response to JSON", slog.Any("error", err)) } else { slog.DebugContext(r.Context(), "content is generated", slog.String("animal", animal), slog.String("prompt", prompt), slog.String("response", string(jsonBytes))) } if len(resp.Candidates) > 0 && len(resp.Candidates[0].Content.Parts) > 0 { clabels := []attribute.KeyValue{attribute.Key("animal").String(animal)} counter.Add(r.Context(), 1, metric.WithAttributes(clabels...)) htmlContent := resp.Candidates[0].Content.Parts[0] w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, htmlContent) } }
Приложение теперь использует OpenTelemetry SDK для инструментирования выполнения кода с помощью трассировки и реализации подсчета количества успешных выполнений в качестве метрики. Метод main()
изменен для настройки экспортеров OpenTelemetry для трассировок и метрик для прямой записи в Google Cloud Tracing and Monitoring. Он также выполняет дополнительные настройки для заполнения собранных трассировок и метрик метаданными, связанными со средой Cloud Run. Функция Handler()
обновляется и увеличивает счетчик метрики каждый раз, когда вызов Vertex AI API возвращает действительные результаты.
Через несколько секунд редактор 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