1. Omówienie
Aplikacje korzystające z generatywnej AI wymagają możliwości obserwacji jak każda inna aplikacja. Czy w przypadku generatywnej AI wymagane są specjalne techniki obserwowalności?
W tym laboratorium utworzysz prostą aplikację wykorzystującą generatywną AI. Wdróż go w Cloud Run. Dodaj do niego niezbędne funkcje monitorowania i logowania, korzystając z usług i produktów dostrzegalności Google Cloud.
Czego się nauczysz
- napisać aplikację korzystającą z Vertex AI za pomocą edytora Cloud Shell.
- Przechowywanie kodu aplikacji w GitHubie
- Wdrażanie kodu źródłowego aplikacji w Cloud Run za pomocą interfejsu wiersza poleceń gcloud
- Dodawanie funkcji monitorowania i logowania do aplikacji z generatywną AI
- Korzystanie ze wskaźników opartych na logach
- Implementacja logowania i monitorowania za pomocą pakietu Open Telemetry SDK
- Informacje o odpowiedzialnym przetwarzaniu danych przez AI
2. Wymagania wstępne
Jeśli nie masz jeszcze konta Google, utwórz nowe konto.
3. Konfigurowanie projektu
- Zaloguj się w konsoli Google Cloud za pomocą konta Google.
- Utwórz nowy projekt lub użyj istniejącego. Zapisz identyfikator projektu, który został właśnie utworzony lub wybrany.
- Włącz płatności w projekcie.
- Przeprowadzenie tego ćwiczenia powinno kosztować mniej niż 5 USD.
- Aby uniknąć dalszych opłat, możesz usunąć zasoby, wykonując czynności opisane na końcu tego modułu.
- Nowi użytkownicy mogą skorzystać z bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.
- Sprawdź, czy płatności są włączone w sekcji Moje projekty w Rozliczeniach usługi Google Cloud.
- Jeśli w kolumnie
Billing account
nowego projektu widać wartośćBilling is disabled
:- Kliknij 3 kropki w kolumnie
Actions
. - Kliknij Zmień rozliczenia.
- Wybierz konto rozliczeniowe, którego chcesz użyć.
- Kliknij 3 kropki w kolumnie
- Jeśli uczestniczysz w wydarzeniu na żywo, konto będzie prawdopodobnie nazywać się Próbne konto rozliczeniowe Google Cloud Platform.
- Jeśli w kolumnie
4. Przygotowanie edytora Cloud Shell
- Otwórz edytor Cloud Shell. Jeśli pojawi się to pytanie o autoryzację Cloud Shell do wywoływania gcloud za pomocą Twoich danych logowania, kliknij Autoryzuj, aby kontynuować.
- Otwórz okno terminala
- Kliknij menu z 3 kreskami
- Kliknij Terminal.
- Kliknij Nowy terminal
.
- Kliknij menu z 3 kreskami
- W terminalu skonfiguruj identyfikator projektu:
Zastąpgcloud config set project [PROJECT_ID]
[PROJECT_ID]
identyfikatorem projektu. Jeśli np. identyfikator projektu tolab-example-project
, polecenie będzie wyglądać tak: Jeśli pojawi się komunikat, że gcloud prosi o Twoje dane logowania do interfejsu GCPI API, kliknij Autoryzuj, aby kontynuować.gcloud config set project lab-project-id-example
Po pomyślnym wykonaniu tej czynności powinien wyświetlić się komunikat: Jeśli widziszUpdated property [core/project].
WARNING
i pojawia się pytanieDo you want to continue (Y/N)?
, prawdopodobnie nieprawidłowo wpisano identyfikator projektu. Gdy znajdziesz prawidłowy identyfikator projektu, naciśnijN
, a potemEnter
i spróbuj ponownie uruchomić poleceniegcloud config set project
. - (Opcjonalnie) Jeśli masz problem ze znalezieniem identyfikatora projektu, uruchom to polecenie, aby wyświetlić identyfikatory wszystkich swoich projektów posortowane według czasu utworzenia w kolejności malejącej:
gcloud projects list \ --format='value(projectId,createTime)' \ --sort-by=~createTime
5. Włączanie interfejsów API Google
W terminalu włącz interfejsy Google API wymagane w tym laboratorium:
gcloud services enable \
run.googleapis.com \
cloudbuild.googleapis.com \
aiplatform.googleapis.com \
logging.googleapis.com \
monitoring.googleapis.com \
cloudtrace.googleapis.com
Wykonanie tego polecenia może trochę potrwać. W efekcie wyświetli się komunikat o udanym przeprowadzeniu operacji podobny do tego:
Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.
Jeśli pojawi się komunikat o błędzie rozpoczynający się od ERROR: (gcloud.services.enable) HttpError accessing
i zawierający informacje o błędzie podobne do tych poniżej, powtórz polecenie po 1–2 minutach.
"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. Tworzenie aplikacji generatywnej AI w Go
W tym kroku napiszesz kod prostej aplikacji działającej na podstawie żądań, która korzysta z modelu Gemini, aby wyświetlać 10 ciekawych faktów o wybranym przez Ciebie zwierzęciu. Aby utworzyć kod aplikacji, wykonaj te czynności.
- Utwórz w terminalu katalog
codelab-o11y
:mkdir ~/codelab-o11y
- Zmień bieżący katalog na
codelab-o11y
:cd ~/codelab-o11y
- Inicjowanie modułów Go:
go mod init codelab
- Zainstaluj pakiet Vertex AI SDK for Go:
go get cloud.google.com/go/vertexai/genai
- Zainstaluj bibliotekę metadanych dla Go, aby uzyskać bieżący identyfikator projektu:
go get cloud.google.com/go/compute/metadata
- Utwórz plik
setup.go
i otwórz go w edytorze Cloud Shell: Będzie on używany do hostowania kodu inicjowania. W oknie edytora pojawi się nowy pusty plik o nazwiecloudshell edit setup.go
setup.go
. - Skopiuj ten kod i wklej go do otwartego pliku
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 }
- Wróć do okna terminala i uruchom to polecenie, aby utworzyć i otworzyć plik
main.go
w edytorze Cloud Shell: W oknie edytora nad terminalem powinien pojawić się pusty plik. Ekran powinien wyglądać tak:cloudshell edit main.go
- Skopiuj ten kod i wklej go do otwartego pliku
main.go
: Po kilku sekundach edytor Cloud Shell automatycznie zapisze kod.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) } }
Wdrażanie kodu aplikacji generatywnej AI w Cloud Run
- W oknie terminala uruchom polecenie, aby wdrożyć kod źródłowy aplikacji do Cloud Run.
Jeśli zobaczysz taki komunikat, oznacza to, że polecenie utworzy nowe repozytorium. Kliknijgcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticated
Enter
. Proces wdrażania może potrwać kilka minut. Po zakończeniu procesu wdrażania zobaczysz dane wyjściowe podobne do tych: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
- Skopiuj wyświetlony adres URL usługi Cloud Run na osobną kartę lub do osobnego okna w przeglądarce. Możesz też uruchomić to polecenie w terminalu, aby wydrukować adres URL usługi, a potem kliknąć wyświetlony adres URL, przytrzymując klawisz Ctrl, aby go otworzyć:
Po otwarciu adresu URL może pojawić się błąd 500 lub komunikat:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"'
Oznacza to, że usługi nie zostały wdrożone. Zaczekaj chwilę i odśwież stronę. Na końcu zobaczysz tekst zaczynający się od słów Ciekawostki o psach i zawierający 10 ciekawostek o tych zwierzętach.Sorry, this is just a placeholder...
Spróbuj wejść w interakcję z aplikacją, aby dowiedzieć się ciekawych faktów o różnych zwierzętach. Aby to zrobić, dodaj parametr animal
do adresu URL, np. ?animal=[ANIMAL]
, gdzie [ANIMAL]
to nazwa zwierzęcia. Na przykład dodaj ?animal=cat
, aby uzyskać 10 ciekawostek o kotach, lub ?animal=sea turtle
, aby uzyskać 10 ciekawostek o żółwiach morskich.
7. Sprawdzanie wywołań interfejsu Vertex API
Audyt wywołań interfejsu Google API pozwala uzyskać odpowiedzi na pytania w rodzaju „kto, gdzie i kiedy wywołał dany interfejs API?”. Weryfikacja jest ważna podczas rozwiązywania problemów z aplikacją, badania wykorzystania zasobów lub przeprowadzania analizy kryminalistycznej oprogramowania.
Logi kontrolne umożliwiają śledzenie działań administracyjnych i systemowych, a także rejestrowanie wywołań operacji interfejsu API „odczytywanie danych” i „zapisywanie danych”. Aby sprawdzić żądania Vertex AI dotyczące generowania treści, musisz włączyć logi kontrolne „Dane odczytywane” w konsoli Cloud.
- Kliknij przycisk poniżej, aby otworzyć stronę Dzienniki kontrolne w konsoli Google Cloud.
- Sprawdź, czy na stronie wybrany jest projekt utworzony na potrzeby tego laboratorium. Wybrany projekt jest widoczny w lewym górnym rogu strony obok menu hamburgera:
W razie potrzeby wybierz odpowiedni projekt z menu. - W tabeli Konfiguracja logów kontrolnych dostępu do danych w kolumnie Usługa znajdź usługę
Vertex AI API
i kliknij pole wyboru po lewej stronie jej nazwy. - W panelu informacyjnym po prawej stronie wybierz typ audytu „Odczyt danych”.
- Kliknij Zapisz.
Aby wygenerować dzienniki kontrolne, otwórz adres URL usługi. Aby uzyskać inne wyniki, odśwież stronę, zmieniając wartość parametru ?animal=
.
Poznawanie dzienników kontrolnych
- Kliknij przycisk poniżej, aby otworzyć stronę Eksplorator logów w konsoli Google Cloud:
- Wklej ten filtr w panelu Zapytanie.
Panel Zapytanie to edytor znajdujący się u góry strony Eksplorator logów:LOG_ID("cloudaudit.googleapis.com%2Fdata_access") AND protoPayload.serviceName="aiplatform.googleapis.com"
- Kliknij Uruchom zapytanie.
- Wybierz jeden z wpisów w dzienniku kontrolnym i rozwiń pola, aby sprawdzić informacje zarejestrowane w dzienniku.
Możesz zobaczyć szczegóły wywołania interfejsu Vertex API, w tym użytą metodę i model. Możesz też zobaczyć tożsamość wywołującego i uprawnienia autoryzujące wywołanie.
8. Rejestrowanie interakcji z generatywną AI
W dziennikach kontrolnych nie ma parametrów żądania ani danych odpowiedzi interfejsu API. Te informacje mogą jednak być ważne w przypadku problemów z analizą aplikacji i przepływu pracy. W tym kroku wypełniamy tę lukę, dodając rejestrowanie aplikacji. Do zapisywania ustrukturyzowanych logów używany jest standardowy pakiet Go log/slog
. Pakiet log/slog
nie wie, jak zapisać logi w Google Cloud. Obsługuje zapisywanie na standardowe wyjście. Cloud Run zawiera jednak funkcje, które umożliwiają automatyczne przechwytywanie informacji drukowanych na standardowym wyjściu i przetwarzanie ich w Cloud Logging. Aby poprawnie rejestrować dzienniki uporządkowane, należy odpowiednio sformatować wydrukowany dziennik. Aby dodać do aplikacji Go obsługę uporządkowanego logowania, wykonaj podane niżej instrukcje.
- Wróć do okna (lub karty) Cloud Shell w przeglądarce.
- W terminalu ponownie otwórz
setup.go
:cloudshell edit ~/codelab-o11y/setup.go
- Zastąp kod wersją, która konfiguruje rejestrowanie. Aby zastąpić kod, usuń zawartość pliku, a potem skopiuj i wklej podany niżej kod do edytora:
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)) }
- Wróć do terminala i ponownie otwórz
main.go
:cloudshell edit ~/codelab-o11y/main.go
- Zastąp kod aplikacji wersją, która rejestruje interakcje z modelem. Aby zastąpić kod, usuń zawartość pliku, a potem skopiuj i wklej podany niżej kod do edytora:
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) } }
Logowanie jest skonfigurowane tak, aby drukować logi do pliku stdout
, gdzie są one zbierane przez agenta logowania Cloud Run i asynchronicznie przesyłane do Cloud Logging. Funkcja main()
została zmodyfikowana, aby skonfigurować standardowy log strukturyzowany Go do korzystania ze schematu JSON zgodnego z wytycznymi dotyczącymi formatowania strukturyzowanego. Wszystkie instrukcje return
są zastępowane przez kod, który przed zakończeniem działania programu zapisuje dzienniki błędów. Funkcja Handler()
jest instrumentowana w celu zapisywania ustrukturyzowanego dziennika po otrzymaniu odpowiedzi z wywołania interfejsu Vertex AI API. Log zawiera parametr zwierzęcia z żądania oraz prompt i odpowiedź modelu.
Po kilku sekundach edytor Cloud Shell automatycznie zapisuje zmiany.
Wdrażanie kodu aplikacji generatywnej AI w Cloud Run
- W oknie terminala uruchom polecenie, aby wdrożyć kod źródłowy aplikacji do Cloud Run.
Jeśli zobaczysz taki komunikat, oznacza to, że polecenie utworzy nowe repozytorium. Kliknijgcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticated
Enter
. Proces wdrażania może potrwać kilka minut. Po zakończeniu procesu wdrażania zobaczysz dane wyjściowe podobne do tych: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
- Skopiuj wyświetlony adres URL usługi Cloud Run na osobną kartę lub do osobnego okna w przeglądarce. Możesz też uruchomić to polecenie w terminalu, aby wydrukować adres URL usługi, a potem kliknąć wyświetlony adres URL, przytrzymując klawisz Ctrl, aby go otworzyć:
Po otwarciu adresu URL może pojawić się błąd 500 lub komunikat:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"'
Oznacza to, że usługi nie zostały wdrożone. Zaczekaj chwilę i odśwież stronę. Na końcu zobaczysz tekst zaczynający się od słów Ciekawostki o psach i zawierający 10 ciekawostek o tych zwierzętach.Sorry, this is just a placeholder...
Aby wygenerować dzienniki aplikacji, otwórz adres URL usługi. Aby uzyskać inne wyniki, odśwież stronę, zmieniając wartość parametru ?animal=
.
Aby wyświetlić logi aplikacji:
- Kliknij przycisk poniżej, aby otworzyć stronę Eksplorator logów w konsoli Cloud:
- Wklej ten filtr w panelu Zapytanie (pozycja 2 w interfejsie Eksploratora logów):
LOG_ID("run.googleapis.com%2Fstdout") AND severity=DEBUG
- Kliknij Uruchom zapytanie.
Wynik zapytania zawiera logi z promptem i odpowiedzią Vertex AI, w tym oceny bezpieczeństwa.
9. Liczenie interakcji z generatywną AI
Cloud Run zapisuje dane zarządzane, których można używać do monitorowania wdrożonych usług. Dane monitorowania zarządzane przez użytkowników zapewniają większą kontrolę nad danymi i częstotliwością ich aktualizacji. Wdrożenie takiej metryki wymaga napisania kodu, który będzie zbierać dane i zapisywać je w Cloud Monitoring. Aby dowiedzieć się, jak zaimplementować tę funkcję za pomocą pakietu SDK OpenTelemetry, przejdź do następnego (opcjonalnego) kroku.
Ten krok pokazuje alternatywę dla implementowania danych o użytkownikach w kodzie – dane oparte na logach. Wskaźniki oparte na logach umożliwiają generowanie danych monitorowania na podstawie wpisów logów zapisywanych przez aplikację w Cloud Logging. Do zdefiniowania danych typu licznik na podstawie dzienników aplikacji użyjemy dzienników aplikacji zaimplementowanych w poprzednim kroku. Dane zliczają liczbę udanych wywołań interfejsu Vertex API.
- Spójrz na okno Eksploratora logów, którego użyliśmy w poprzednim kroku. W panelu Zapytanie odszukaj menu Działania i kliknij je, aby je otworzyć. Menu znajdziesz na zrzucie ekranu poniżej:
- W otwartym menu kliknij Utwórz wskaźnik, aby otworzyć panel Utwórz wskaźnik oparty na logach.
- Aby skonfigurować nowy licznik w panelu Tworzenie danych opartych na logach:
- Ustaw Typ wskaźnika: wybierz Licznik.
- W sekcji Szczegóły ustaw te pola:
- Nazwa wskaźnika logu: ustaw nazwę na
model_interaction_count
. Obowiązują pewne ograniczenia dotyczące nazw. Szczegółowe informacje znajdziesz w rozdziale dotyczącym rozwiązywania problemów z ograniczeniami dotyczącymi nazw. - Opis: wpisz opis danych. na przykład
Number of log entries capturing successful call to model inference.
. - Jednostki: pozostaw to pole puste lub wstaw cyfrę
1
.
- Nazwa wskaźnika logu: ustaw nazwę na
- Pozostaw wartości w sekcji Wybór filtra. Pamiętaj, że pole Filtrowanie kompilacji zawiera ten sam filtr, którego użyliśmy do wyświetlenia dzienników aplikacji.
- (Opcjonalnie) Dodaj etykietę, która pomoże zliczać liczbę połączeń dla każdego zwierzęcia. UWAGA: ta etykieta może znacznie zwiększyć liczebność danych i nie jest zalecana do użytku w produkcji:
- Kliknij Dodaj etykietę.
- W sekcji Etykiety ustaw te pola:
- Nazwa etykiety: ustaw nazwę na
animal
. - Opis: wpisz opis etykiety. Na przykład:
Animal parameter
. - Typ etykiety: kliknij
STRING
. - Nazwa pola: wpisz
jsonPayload.animal
. - Wyrażenie regularne: pozostaw puste.
- Nazwa etykiety: ustaw nazwę na
- Kliknij przycisk Gotowe.
- Aby utworzyć dane, kliknij Utwórz dane.
Możesz też utworzyć wskaźnik oparty na logach na stronie Wskaźniki oparte na logach, używając gcloud logging metrics create
polecenia wiersza poleceń lub google_logging_metric
zasobu Terraform.
Aby wygenerować dane statystyczne, otwórz adres URL usługi. Odśwież otwartą stronę kilka razy, aby wykonać kilka wywołań modelu. Podobnie jak wcześniej, spróbuj użyć w tym parametrze różnych zwierząt.
Wpisz zapytanie PromQL, aby wyszukać dane wskaźnika opartego na logach. Aby wpisać zapytanie PromQL:
- Kliknij przycisk poniżej, aby otworzyć stronę Eksplorator danych w konsoli Google Cloud:
- Na pasku narzędzi w panelu kreatora zapytań kliknij przycisk o nazwie < > MQL lub < > PromQL. Lokalizacja przycisku – patrz zdjęcie poniżej.
- Sprawdź, czy w opcji Język wybrana jest opcja PromQL. Przełącznik języka znajduje się na tej samej belce narzędzi, która umożliwia formatowanie zapytania.
- Wpisz zapytanie w edytorze Zapytania:
Więcej informacji o używaniu PromQL znajdziesz w artykule PromQL w Cloud Monitoring.sum(rate(logging_googleapis_com:user_model_interaction_count{monitored_resource="cloud_run_revision"}[${__interval}]))
- Kliknij Uruchom zapytanie. Zobaczysz wykres liniowy podobny do tego:
Pamiętaj, że gdy włączony jest przełącznik Automatyczne uruchamianie, przycisk Uruchom zapytanie nie jest widoczny.
10. (Opcjonalnie) Używanie OpenTelemetry do monitorowania i śledzenia
Jak wspomnieliśmy w poprzednim kroku, dane można wdrażać za pomocą pakietu OpenTelemetry (Otel) SDK. Zalecane jest używanie usługi OTel w architekturach mikroserwisów. Ten krok obejmuje:
- Inicjowanie komponentów OTel w celu obsługi śledzenia i monitorowania aplikacji
- Wypełnianie konfiguracji OTel za pomocą metadanych zasobów środowiska Cloud Run
- Instrumentowanie aplikacji Flask z automatycznymi funkcjami śledzenia
- Wdrożenie licznika do monitorowania liczby udanych wywołań modelu
- Korelacja śledzenia z logami aplikacji
Zalecana architektura usług na poziomie usługi polega na użyciu kolektora Otel do zbierania i przetwarzania wszystkich danych dotyczących możliwości obserwacji w przypadku co najmniej jednej usługi. Ze względu na prostotę kod na tym etapie nie korzysta z kolekcjonera. Zamiast tego używa eksportów OTel, które zapisują dane bezpośrednio w Google Cloud.
Konfigurowanie komponentów usługi OTel na potrzeby monitorowania śledzenia i danych
- Wróć do okna (lub karty) Cloud Shell w przeglądarce.
- W terminalu ponownie otwórz
setup.go
:cloudshell edit ~/codelab-o11y/setup.go
- Zastąp kod wersją, która inicjuje śledzenie i zbieranie danych OpenTelemetry. Aby zastąpić kod, usuń zawartość pliku, a potem skopiuj i wklej podany niżej kod do edytora:
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) }
- Wróć do terminala i uruchom to polecenie, aby zaktualizować definicje modułów Go w pliku
go.mod
:go mod tidy
- Wróć do terminala i ponownie otwórz
main.go
:cloudshell edit ~/codelab-o11y/main.go
- Zastąp obecny kod wersją, która umożliwia rejestrowanie śledzenia HTTP i zapisywanie danych o skuteczności. Aby zastąpić kod, usuń zawartość pliku, a potem skopiuj i wklej podany niżej kod do edytora:
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) } }
Aplikacja korzysta teraz z pakietu SDK OpenTelemetry, aby śledzić wykonywanie kodu za pomocą śledzenia i implementować zliczanie liczby udanych jego wykonań jako dane. Metoda main()
została zmodyfikowana, aby skonfigurować eksportery OpenTelemetry w celu zapisywania śladów i danych bezpośrednio w Google Cloud Tracing i Monitoring. Wykonuje też dodatkowe konfiguracje, aby wypełnić zebrane ślady i dane metadanymi związanymi ze środowiskiem Cloud Run. Funkcja Handler()
jest aktualizowana, aby zwiększać licznik danych za każdym razem, gdy wywołanie interfejsu Vertex AI API zwraca prawidłowe wyniki.
Po kilku sekundach edytor Cloud Shell automatycznie zapisuje zmiany.
Wdrażanie kodu aplikacji generatywnej AI w Cloud Run
- W oknie terminala uruchom polecenie, aby wdrożyć kod źródłowy aplikacji do Cloud Run.
Jeśli zobaczysz taki komunikat, oznacza to, że polecenie utworzy nowe repozytorium. Kliknijgcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticated
Enter
. Proces wdrażania może potrwać kilka minut. Po zakończeniu procesu wdrażania zobaczysz dane wyjściowe podobne do tych: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
- Skopiuj wyświetlony adres URL usługi Cloud Run na osobną kartę lub do osobnego okna w przeglądarce. Możesz też uruchomić to polecenie w terminalu, aby wydrukować adres URL usługi, a potem kliknąć wyświetlony adres URL, przytrzymując klawisz Ctrl, aby go otworzyć:
Po otwarciu adresu URL może pojawić się błąd 500 lub komunikat:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"'
Oznacza to, że usługi nie zostały wdrożone. Zaczekaj chwilę i odśwież stronę. Na końcu zobaczysz tekst zaczynający się od słów Ciekawostki o psach i zawierający 10 ciekawostek o tych zwierzętach.Sorry, this is just a placeholder...
Aby wygenerować dane telemetryczne, otwórz adres URL usługi. Aby uzyskać inne wyniki, odśwież stronę, zmieniając wartość parametru ?animal=
.
Analiza śladów aplikacji
- Kliknij przycisk poniżej, aby otworzyć stronę Eksplorator logów czasu w konsoli Cloud:
- Wybierz jeden z najnowszych śladów. Powinieneś/powinnaś zobaczyć 5 lub 6 elementów, które wyglądają jak na zrzucie ekranu poniżej.
- Znajdź blok kodu, który śledzi wywołanie do metody obsługi zdarzenia (metody
fun_facts
). Będzie to ostatni element o nazwie/
. - W panelu Szczegóły śledzenia kliknij Logi i zdarzenia. Zobaczysz logi aplikacji powiązane z tym konkretnym spanem. Korelacja jest wykrywana na podstawie identyfikatorów śledzenia i spanu w logu czasu. Powinieneś zobaczyć log aplikacji, który zawiera prompt i odpowiedź interfejsu Vertex API.
Wskaźnik licznika
- Kliknij przycisk poniżej, aby otworzyć stronę Eksplorator danych w konsoli Google Cloud:
- Na pasku narzędzi w panelu kreatora zapytań kliknij przycisk o nazwie < > MQL lub < > PromQL. Lokalizacja przycisku – patrz obraz poniżej.
- Sprawdź, czy w opcji Język wybrana jest opcja PromQL. Przełącznik języka znajduje się na tej samej belce narzędzi, która umożliwia formatowanie zapytania.
- Wpisz zapytanie w edytorze Zapytania:
sum(rate(workload_googleapis_com:model_call_counter{monitored_resource="generic_task"}[${__interval}]))
- Kliknij Uruchom zapytanie.Gdy włączony jest przełącznik Automatyczne uruchamianie, przycisk Uruchom zapytanie nie jest widoczny.
11. (Opcjonalnie) Zaciemnione informacje poufne z logów
W kroku 10 odnotowaliśmy informacje o interakcji aplikacji z modelem Gemini. Te informacje obejmowały nazwę zwierzęcia, prompt i odpowiedź modelu. Przechowywanie tych informacji w dzienniku powinno być bezpieczne, ale niekoniecznie w wielu innych przypadkach. Prośba może zawierać dane osobowe lub inne informacje poufne, których użytkownik nie chce przechowywać. Aby temu zapobiec, możesz zafałszować dane wrażliwe zapisywane w Cloud Logging. Aby zminimalizować modyfikacje kodu, zalecamy zastosowanie tego rozwiązania.
- Tworzenie tematu Pub/Sub do przechowywania przychodzących wpisów w logach
- Utwórz ujście logów, które przekierowuje pozyskane logi do tematu Pub/Sub.
- Utwórz potok Dataflow, który modyfikuje dzienniki przekierowywane do tematu Pub/Sub w ten sposób:
- Czytanie wpisu w logu z tematu PubSub
- Sprawdzanie danych wejściowych rekordu pod kątem informacji poufnych za pomocą interfejsu DLP inspection API
- Usuń informacje poufne z ładunku za pomocą jednej z metod zapobiegania utracie danych.
- Zapisywanie zafałszowanego wpisu w pliku logów w Cloud Logging
- Wdrażanie potoku
12. (Opcjonalnie) Czyszczenie
Aby uniknąć opłat za zasoby i interfejsy API używane w tym laboratorium, zalecamy ich usunięcie po zakończeniu pracy. Najprostszym sposobem na uniknięcie płatności jest usunięcie projektu utworzonego na potrzeby tego samouczka.
- Aby usunąć projekt, uruchom w terminalu polecenie usuwania projektu:
Usunięcie projektu Cloud powoduje zaprzestanie naliczania opłat za wszystkie zasoby i interfejsy API używane w tym projekcie. Powinien pojawić się komunikat, w którymPROJECT_ID=$(gcloud config get-value project) gcloud projects delete ${PROJECT_ID} --quiet
PROJECT_ID
będzie identyfikatorem projektu: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.
- (Opcjonalnie) Jeśli pojawi się błąd, w kroku 5 sprawdź, jak znaleźć identyfikator projektu użyty w tym module. Zastąp nim polecenie w pierwszej instrukcji. Jeśli np. identyfikator projektu to
lab-example-project
, polecenie będzie wyglądać tak:gcloud projects delete lab-project-id-example --quiet
13. Gratulacje
W tym module udało Ci się utworzyć aplikację generatywnej AI, która do prognozowania korzysta z modela Gemini. W aplikacji zostały też zaimplementowane podstawowe funkcje monitorowania i logowania. Wdrożysz aplikację i zmiany z kodu źródłowego w Cloud Run. Następnie możesz używać usług Google Cloud Observability do śledzenia wydajności aplikacji, aby mieć pewność, że jest ona niezawodna.
Jeśli chcesz wziąć udział w badaniu wrażeń użytkowników (UX), aby ulepszyć usługi, z których korzystasz obecnie, zarejestruj się tutaj.
Oto kilka opcji dalszej nauki:
- Codelab Wdrażanie aplikacji do czatu opartej na Gemini w Cloud Run
- Codelab Jak używać wywoływania funkcji Gemini z Cloud Run
- Jak za pomocą interfejsu Cloud Run Jobs Video Intelligence API przetwarzać filmy według scen
- Warsztat na żądanie Google Kubernetes Engine – wprowadzenie
- Dowiedz się więcej o konfigurowaniu wskaźników licznika i rozkładu za pomocą dzienników aplikacji
- Zapisywanie danych OTLP za pomocą podrzędnego OpenTelemetry
- Informacje o korzystaniu z Open Telemetry w Google Cloud