Go'da üretken yapay zeka uygulamaları için pratik gözlemlenebilirlik teknikleri

1. Genel Bakış

Üretken yapay zeka uygulamaları, diğer uygulamalar gibi gözlemlenebilirlik gerektirir. Üretken yapay zeka için özel gözlemlenebilirlik teknikleri gerekiyor mu?

Bu laboratuvarda basit bir üretken yapay zeka uygulaması oluşturacaksınız. Cloud Run'a dağıtın. Ayrıca Google Cloud gözlemlenebilirlik hizmetlerini ve ürünlerini kullanarak temel izleme ve günlük kaydı özellikleriyle donatın.

Öğrenecekleriniz

  • Cloud Shell Düzenleyici ile Vertex AI'ı kullanan bir uygulama yazma
  • Uygulama kodunuzu GitHub'da saklama
  • Uygulamanızın kaynak kodunu Cloud Run'a dağıtmak için gcloud CLI'yı kullanın.
  • Üretken yapay zeka uygulamanıza izleme ve günlük kaydı özellikleri ekleme
  • Günlük tabanlı metrikleri kullanma
  • Open Telemetry SDK ile günlük kaydını ve izlemeyi uygulama
  • Sorumlu yapay zeka veri işleme hakkında bilgi edinme

2. Ön koşullar

Google Hesabınız yoksa yeni bir hesap oluşturmanız gerekir.

3. Proje ayarlama

  1. Google Hesabınızla Google Cloud Console'da oturum açın.
  2. Yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanmayı seçin. Yeni oluşturduğunuz veya seçtiğiniz projenin proje kimliğini not edin.
  3. Proje için faturalandırmayı etkinleştirin.
    • Bu laboratuvarı tamamlamanın faturalandırma maliyeti 5 ABD dolarından az olmalıdır.
    • Daha fazla ücret ödememek için bu laboratuvarın sonundaki adımları uygulayarak kaynakları silebilirsiniz.
    • Yeni kullanıcılar 300 ABD doları değerinde ücretsiz deneme sürümünden yararlanabilir.
  4. Cloud Billing'deki Projelerim bölümünde faturalandırmanın etkinleştirildiğini onaylayın
      .
    • Yeni projenizin Billing account sütununda Billing is disabled yazıyorsa:
      1. Actions sütunundaki üç noktayı tıklayın.
      2. Faturalandırmayı değiştir'i tıklayın.
      3. Kullanmak istediğiniz faturalandırma hesabını seçin.
    • Canlı bir etkinliğe katılıyorsanız hesabın adı büyük olasılıkla Google Cloud Platform Deneme Sürümü Faturalandırma Hesabı olur.

4. Cloud Shell Düzenleyici'yi hazırlama

  1. Cloud Shell Düzenleyici'ye gidin. Kimlik bilgilerinizle gcloud'u çağırması için Cloud Shell'i yetkilendirmenizi isteyen aşağıdaki mesajı görürseniz devam etmek için Yetkilendir'i tıklayın.
    Cloud Shell'e yetki vermek için tıklayın.
  2. Terminal penceresini açın.
    1. Hamburger menüsünü Hamburger menü simgesi tıklayın.
    2. Terminal'i tıklayın.
    3. Yeni Terminal
      'i tıklayın.Cloud Shell Düzenleyici'de yeni terminal açma
  3. Terminalde proje kimliğinizi yapılandırın:
    gcloud config set project [PROJECT_ID]
    
    [PROJECT_ID] yerine projenizin kimliğini yazın. Örneğin, proje kimliğiniz lab-example-project ise komut şu şekilde olur:
    gcloud config set project lab-project-id-example
    
    gcloud'un GCPI API için kimlik bilgilerinizi istediğini belirten aşağıdaki mesajı görürseniz devam etmek için Yetkilendir'i tıklayın.
    Cloud Shell'e yetki vermek için tıklayın.
    Başarılı bir şekilde yürütüldüğünde aşağıdaki mesajı görmeniz gerekir:
    Updated property [core/project].
    
    WARNING simgesini görüyorsanız ve Do you want to continue (Y/N)? soruluyorsa proje kimliğini yanlış girmiş olabilirsiniz. N tuşuna, Enter tuşuna basın ve doğru proje kimliğini bulduktan sonra gcloud config set project komutunu tekrar çalıştırmayı deneyin.
  4. (İsteğe bağlı) Proje kimliğini bulmakta sorun yaşıyorsanız tüm projelerinizin oluşturulma zamanına göre azalan sırada sıralanmış proje kimliklerini görmek için aşağıdaki komutu çalıştırın:
    gcloud projects list \
         --format='value(projectId,createTime)' \
         --sort-by=~createTime
    

5. Google API'lerini etkinleştirme

Terminalde, bu laboratuvar için gerekli olan Google API'lerini etkinleştirin:

gcloud services enable \
     run.googleapis.com \
     cloudbuild.googleapis.com \
     aiplatform.googleapis.com \
     logging.googleapis.com \
     monitoring.googleapis.com \
     cloudtrace.googleapis.com

Bu komutun tamamlanması biraz zaman alabilir. Sonunda, şuna benzer bir başarı mesajı oluşturur:

Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.

ERROR: (gcloud.services.enable) HttpError accessing ile başlayan ve aşağıdakine benzer hata ayrıntıları içeren bir hata mesajı alırsanız 1-2 dakika bekledikten sonra komutu yeniden deneyin.

"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. Üretken yapay zeka Go uygulaması oluşturma

Bu adımda, seçtiğiniz bir hayvanla ilgili 10 eğlenceli bilgiyi göstermek için Gemini modelini kullanan basit bir isteğe dayalı uygulama kodu yazacaksınız. Uygulama kodu oluşturmak için aşağıdakileri yapın.

  1. Terminalde codelab-o11y dizinini oluşturun:
    mkdir ~/codelab-o11y
    
  2. Mevcut dizini codelab-o11y olarak değiştirin:
    cd ~/codelab-o11y
    
  3. Go modüllerini başlatın:
    go mod init codelab
    
  4. Go için Vertex AI SDK'yı yükleyin:
    go get cloud.google.com/go/vertexai/genai
    
  5. Mevcut proje kimliğini almak için Go'ya yönelik meta veri kitaplığını yükleyin:
    go get cloud.google.com/go/compute/metadata
    
  6. setup.go dosyası oluşturun ve dosyayı Cloud Shell Düzenleyici'de açın:
    cloudshell edit setup.go
    
    Başlatma kodunu barındırmak için kullanılır. Düzenleyici penceresinde setup.go adlı yeni bir boş dosya görünür.
  7. Aşağıdaki kodu kopyalayın ve açılan setup.go dosyasına yapıştırın:
    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
    }
    
  8. Terminal penceresine dönün ve Cloud Shell Düzenleyici'de bir main.go dosyası oluşturup açmak için aşağıdaki komutu çalıştırın:
    cloudshell edit main.go
    
    Artık terminalin üzerindeki düzenleyici penceresinde boş bir dosya görünmelidir. Ekranınız aşağıdaki gibi görünür:
    main.go dosyasını düzenlemeye başladıktan sonra Cloud Shell Düzenleyici'yi göster
  9. Aşağıdaki kodu kopyalayın ve açılan main.go dosyasına yapıştırın:
    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)
        }
    }
    
    Cloud Shell Editor, birkaç saniye sonra kodunuzu otomatik olarak kaydeder.

Üretken yapay zeka uygulamasının kodunu Cloud Run'a dağıtma

  1. Terminal penceresinde, uygulamanın kaynak kodunu Cloud Run'a dağıtma komutunu çalıştırın.
    gcloud run deploy codelab-o11y-service \
         --source="${HOME}/codelab-o11y/" \
         --region=us-central1 \
         --allow-unauthenticated
    
    Aşağıdaki gibi bir istem görürseniz komutun yeni bir depo oluşturacağını bildirir. Enter simgesini tıklayın.
    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)?
    
    Dağıtım işlemi birkaç dakika sürebilir. Dağıtım işlemi tamamlandıktan sonra aşağıdaki gibi bir çıkış görürsünüz:
    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
    
  2. Görüntülenen Cloud Run hizmeti URL'sini tarayıcınızdaki ayrı bir sekmeye veya pencereye kopyalayın. Alternatif olarak, hizmet URL'sini yazdırmak için terminalde aşağıdaki komutu çalıştırın ve URL'yi açmak için Ctrl tuşunu basılı tutarken gösterilen URL'yi tıklayın:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    URL açıldığında 500 hatası alabilir veya şu mesajı görebilirsiniz:
    Sorry, this is just a placeholder...
    
    Bu, hizmetlerin dağıtımının tamamlanmadığı anlamına gelir. Birkaç dakika bekleyip sayfayı yenileyin. Sonunda, Köpeklerle İlgili Eğlenceli Bilgiler ile başlayan ve köpeklerle ilgili 10 eğlenceli bilgi içeren bir metin görürsünüz.

Farklı hayvanlar hakkında eğlenceli bilgiler edinmek için uygulamayla etkileşime geçmeyi deneyin. Bunu yapmak için URL'ye animal parametresini ekleyin. Örneğin, [ANIMAL] bir hayvan adı olmak üzere ?animal=[ANIMAL]. Örneğin, kedilerle ilgili 10 ilginç bilgi almak için ?animal=cat, deniz kaplumbağalarıyla ilgili 10 ilginç bilgi almak için ?animal=sea turtle ekleyin.

7. Vertex API çağrılarınızı denetleme

Google API çağrılarını denetlemek, "Belirli bir API'yi kim, nerede ve ne zaman çağırdı?" gibi soruların yanıtlarını sağlar. Uygulamanızda sorun giderirken, kaynak tüketimini incelerken veya yazılım adli analizi yaparken denetim önemlidir.

Denetleme günlükleri, yönetim ve sistem etkinliklerini izlemenin yanı sıra "veri okuma" ve "veri yazma" API işlemlerine yapılan çağrıları kaydetmenize olanak tanır. İçerik oluşturmak için yapılan Vertex AI isteklerini denetlemek üzere Cloud Console'da "Veri Okuma" denetleme günlüklerini etkinleştirmeniz gerekir.

  1. Cloud Console'da Denetleme Günlükleri sayfasını açmak için aşağıdaki düğmeyi tıklayın

  2. Sayfada bu laboratuvar için oluşturduğunuz projenin seçili olduğundan emin olun. Seçilen proje, hamburger menüsünün hemen sağındaki sayfanın sol üst köşesinde gösterilir:
    Google Cloud Console proje açılır listesi
    Gerekirse açılır listeden doğru projeyi seçin.
  3. Veri erişimi denetim günlükleri yapılandırması tablosundaki Hizmet sütununda Vertex AI API hizmetini bulun ve hizmet adının solundaki onay kutusunu işaretleyerek hizmeti seçin.
    Vertex AI API'yi seçin
  4. Sağdaki bilgi panelinde "Veri Okundu" denetim türünü seçin.
    Veri okuma günlüklerini kontrol etme
  5. Kaydet'i tıklayın.

Denetleme günlükleri oluşturmak için hizmet URL'sini açın. Farklı sonuçlar almak için ?animal= parametresinin değerini değiştirirken sayfayı yenileyin.

Denetleme günlüklerini inceleme

  1. Cloud Console'da Günlük Gezgini sayfasını açmak için aşağıdaki düğmeyi tıklayın:

  2. Aşağıdaki filtreyi Sorgu bölmesine yapıştırın.
    LOG_ID("cloudaudit.googleapis.com%2Fdata_access") AND
    protoPayload.serviceName="aiplatform.googleapis.com"
    
    Sorgu bölmesi, Günlük Gezgini sayfasının üst kısmında bulunan bir düzenleyicidir:
    Denetleme günlüklerini sorgulama
  3. Sorguyu çalıştır'ı tıklayın.
  4. Denetleme günlüğü girişlerinden birini seçin ve günlükte yakalanan bilgileri incelemek için alanları genişletin.
    Kullanılan yöntem ve model de dahil olmak üzere Vertex API çağrısı hakkında ayrıntıları görebilirsiniz. Ayrıca, çağıranın kimliğini ve hangi izinlerin çağrıyı yetkilendirdiğini de görebilirsiniz.

8. Üretken yapay zeka ile etkileşimleri kaydetme

Denetleme günlüklerinde API isteği parametrelerini veya yanıt verilerini bulamazsınız. Ancak bu bilgiler, uygulama ve iş akışı analizinde sorun giderme için önemli olabilir. Bu adımda, uygulama günlüğü ekleyerek bu boşluğu dolduruyoruz. Günlük kaydı, yapılandırılmış günlükler yazmak için standart Go log/slog paketini kullanır. log/slog paketi, Google Cloud'a günlük yazmayı bilmiyor. Standart çıkışa yazmayı destekler. Ancak Cloud Run, standart çıkışa yazdırılan bilgileri yakalama ve bunları otomatik olarak Cloud Logging'e aktarma özelliklerine sahiptir. Yapılandırılmış günlüklerin doğru şekilde yakalanması için yazdırılan günlük uygun şekilde biçimlendirilmelidir. Go uygulamamıza yapılandırılmış günlük kaydı özellikleri eklemek için aşağıdaki talimatları uygulayın.

  1. Tarayıcınızda "Cloud Shell" penceresine (veya sekmesine) dönün.
  2. Terminalde setup.go dosyasını yeniden açın:
    cloudshell edit ~/codelab-o11y/setup.go
    
  3. Kodu, günlük kaydını ayarlayan sürümle değiştirin. Kodu değiştirmek için dosyanın içeriğini silin, ardından aşağıdaki kodu kopyalayıp düzenleyiciye yapıştırın:
    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))
    }
    
  4. Terminal'e dönün ve main.go dosyasını yeniden açın:
    cloudshell edit ~/codelab-o11y/main.go
    
  5. Uygulama kodunu, modelle etkileşimi kaydeden sürümle değiştirin. Kodu değiştirmek için dosyanın içeriğini silin, ardından aşağıdaki kodu kopyalayıp düzenleyiciye yapıştırın:
    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)
        }
    }
    

Günlük kaydı, günlükleri stdout konumuna yazdıracak şekilde yapılandırılır. Bu konumda günlükler Cloud Run günlük kaydı aracısı tarafından toplanır ve Cloud Logging'e eşzamansız olarak alınır. main() işlevi, yapılandırılmış biçimlendirme yönergelerine uyan JSON şemasını kullanmak için Go standart yapılandırılmış günlüğünü ayarlayacak şekilde değiştirildi. Tüm return ifadeleri, çıkmadan önce hata günlüklerini yazan kodla değiştirilir. Handler() işlevi, Vertex AI API çağrısından yanıt alırken yapılandırılmış günlük yazacak şekilde düzenlenir. Günlük, isteğin animal parametresini, modelin istemini ve yanıtını yakalar.

Cloud Shell Düzenleyici, birkaç saniye sonra değişikliklerinizi otomatik olarak kaydeder.

Üretken yapay zeka uygulamasının kodunu Cloud Run'a dağıtma

  1. Terminal penceresinde, uygulamanın kaynak kodunu Cloud Run'a dağıtma komutunu çalıştırın.
    gcloud run deploy codelab-o11y-service \
         --source="${HOME}/codelab-o11y/" \
         --region=us-central1 \
         --allow-unauthenticated
    
    Aşağıdaki gibi bir istem görürseniz komutun yeni bir depo oluşturacağını bildirir. Enter simgesini tıklayın.
    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)?
    
    Dağıtım işlemi birkaç dakika sürebilir. Dağıtım işlemi tamamlandıktan sonra aşağıdaki gibi bir çıkış görürsünüz:
    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
    
  2. Görüntülenen Cloud Run hizmeti URL'sini tarayıcınızdaki ayrı bir sekmeye veya pencereye kopyalayın. Alternatif olarak, hizmet URL'sini yazdırmak için terminalde aşağıdaki komutu çalıştırın ve URL'yi açmak için Ctrl tuşunu basılı tutarken gösterilen URL'yi tıklayın:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    URL açıldığında 500 hatası alabilir veya şu mesajı görebilirsiniz:
    Sorry, this is just a placeholder...
    
    Bu, hizmetlerin dağıtımının tamamlanmadığı anlamına gelir. Birkaç dakika bekleyip sayfayı yenileyin. Sonunda, Köpeklerle İlgili Eğlenceli Bilgiler ile başlayan ve köpeklerle ilgili 10 eğlenceli bilgi içeren bir metin görürsünüz.

Uygulama günlüklerini oluşturmak için hizmet URL'sini açın. Farklı sonuçlar almak için ?animal= parametresinin değerini değiştirirken sayfayı yenileyin.
Uygulama günlüklerini görmek için şunları yapın:

  1. Cloud Console'da Günlük Gezgini sayfasını açmak için aşağıdaki düğmeyi tıklayın:

  2. Aşağıdaki filtreyi Sorgu bölmesine yapıştırın (Günlük Gezgini arayüzünde 2. adım):
    LOG_ID("run.googleapis.com%2Fstdout") AND
    severity=DEBUG
    
  3. Sorguyu çalıştır'ı tıklayın.

Sorgunun sonucu, güvenlik derecelendirmeleri de dahil olmak üzere istem ve Vertex AI yanıtını içeren günlükleri gösterir.

9. Üretken yapay zeka ile etkileşimleri sayma

Cloud Run, dağıtılan hizmetleri izlemek için kullanılabilecek yönetilen metrikler yazar. Kullanıcı tarafından yönetilen izleme metrikleri, veriler ve metrik güncelleme sıklığı üzerinde daha fazla kontrol sağlar. Bu tür bir metriği uygulamak için veri toplayıp Cloud Monitoring'e yazan bir kod yazılması gerekir. OpenTelemetry SDK'yı kullanarak nasıl uygulayacağınızı öğrenmek için sonraki (isteğe bağlı) adıma bakın.

Bu adımda, kullanıcı metriğini kodda uygulamanın alternatifi olan günlüğe dayalı metrikler gösterilmektedir. Günlük tabanlı metrikler, uygulamanızın Cloud Logging'e yazdığı günlük girişlerinden izleme metrikleri oluşturmanıza olanak tanır. Sayaç türünde günlük tabanlı bir metrik tanımlamak için önceki adımda uyguladığımız uygulama günlüklerini kullanacağız. Bu metrik, Vertex API'ye yapılan başarılı çağrıların sayısını gösterir.

  1. Önceki adımda kullandığımız Günlük Gezgini penceresine bakın. Sorgu bölmesinde İşlemler açılır menüsünü bulun ve açmak için tıklayın. Menüyü bulmak için aşağıdaki ekran görüntüsüne bakın:
    İşlemler açılır menüsünü içeren sorgu sonuçları araç çubuğu
  2. Açılan menüde Günlüğe dayalı metrik oluştur panelini açmak için Metrik oluştur'u seçin.
  3. Günlük tabanlı metrik oluştur panelinde yeni bir sayaç metriği yapılandırmak için aşağıdaki adımları uygulayın:
    1. Metrik türünü ayarlayın: Sayaç'ı seçin.
    2. Ayrıntılar bölümünde aşağıdaki alanları ayarlayın:
      • Günlük metriği adı: Adı model_interaction_count olarak ayarlayın. Adlandırmayla ilgili bazı kısıtlamalar vardır. Ayrıntılar için adlandırmayla ilgili kısıtlamalar Sorun Giderme bölümüne bakın.
      • Açıklama: Metrik için bir açıklama girin. Örneğin, Number of log entries capturing successful call to model inference.
      • Birimler: Bu alanı boş bırakın veya 1 rakamını girin.
    3. Filtre seçimi bölümündeki değerleri olduğu gibi bırakın. Filtre oluştur alanının, uygulama günlüklerini görmek için kullandığımız filtreyle aynı olduğunu unutmayın.
    4. (İsteğe bağlı) Her hayvan için yapılan çağrı sayısını hesaplamaya yardımcı olan bir etiket ekleyin. NOT: Bu etiket, metriğin kardinalitesini büyük ölçüde artırabilir ve üretimde kullanılması önerilmez:
      1. Etiket ekle'yi tıklayın.
      2. Etiketler bölümünde aşağıdaki alanları ayarlayın:
        • Etiket adı: Adı animal olarak ayarlayın.
        • Açıklama: Etiketin açıklamasını girin. Örneğin, Animal parameter.
        • Etiket türü: STRING seçeneğini belirleyin.
        • Alan adı: Tür jsonPayload.animal.
        • Regular expression (Normal ifade): Boş bırakın.
      3. Bitti'yi tıklayın
    5. Metriği oluşturmak için Metrik oluştur'u tıklayın.

Ayrıca, gcloud logging metrics create CLI komutunu kullanarak veya google_logging_metric Terraform kaynağıyla Günlük tabanlı metrikler sayfasından günlük tabanlı metrik oluşturabilirsiniz.

Metrik verileri oluşturmak için hizmet URL'sini açın. Modele birden fazla istek göndermek için açılan sayfayı birkaç kez yenileyin. Daha önce olduğu gibi, parametrede farklı hayvanlar kullanmayı deneyin.

Günlük tabanlı metrik verilerini aramak için PromQL sorgusunu girin. PromQL sorgusu girmek için aşağıdakileri yapın:

  1. Cloud Console'da Metrik Gezgini sayfasını açmak için aşağıdaki düğmeyi tıklayın:

  2. Sorgu oluşturucu bölmesinin araç çubuğunda, adı < > MQL veya < > PromQL olan düğmeyi seçin. Düğmenin konumunu aşağıdaki resimde görebilirsiniz.
    Metrik Gezgini&#39;ndeki MQL düğmesinin konumu
  3. Dil açma/kapatma düğmesinde PromQL'nin seçili olduğunu doğrulayın. Dil değiştirme düğmesi, sorgunuzu biçimlendirmenize olanak tanıyan araç çubuğunda yer alır.
  4. Sorgunuzu Sorgular düzenleyicisine girin:
    sum(rate(logging_googleapis_com:user_model_interaction_count{monitored_resource="cloud_run_revision"}[${__interval}]))
    
    PromQL'i kullanma hakkında daha fazla bilgi için Cloud Monitoring'de PromQL bölümüne bakın.
  5. Run Query'yi (Sorguyu Çalıştır) tıklayın. Şu ekran görüntüsüne benzer bir çizgi grafik görürsünüz:
    Sorgulanan metrikleri göster

    Otomatik çalıştır açma/kapatma düğmesi etkinleştirildiğinde Sorguyu Çalıştır düğmesinin gösterilmediğini unutmayın.

10. (İsteğe bağlı) İzleme ve izleme için Open Telemetry'yi kullanma

Önceki adımda belirtildiği gibi, OpenTelemetry (Otel) SDK'sını kullanarak metrikleri uygulayabilirsiniz. Mikro hizmet mimarilerinde OTel kullanılması önerilen bir uygulamadır. Bu adımda aşağıdakiler açıklanmaktadır:

  • Uygulamanın izlenmesini ve izlenmesini desteklemek için OTel bileşenlerini başlatma
  • OTel yapılandırmasını Cloud Run ortamının kaynak meta verileriyle doldurma
  • Otomatik izleme özellikleriyle Flask uygulamasını izleme
  • Başarılı model çağrılarının sayısını izlemek için sayaç metriği uygulama
  • İzlemeyi uygulama günlükleriyle ilişkilendirme

Ürün düzeyindeki hizmetler için önerilen mimari, bir veya daha fazla hizmetin tüm gözlemlenebilirlik verilerini toplamak ve almak için OTel toplayıcı kullanmaktır. Bu adımdaki kod, basitlik açısından toplayıcıyı kullanmaz. Bunun yerine, verileri doğrudan Google Cloud'a yazan OTel dışa aktarma işlemlerini kullanır.

İzleme ve metrik izleme için OTel bileşenlerini ayarlama

  1. Tarayıcınızda "Cloud Shell" penceresine (veya sekmesine) dönün.
  2. Terminalde setup.go dosyasını yeniden açın:
    cloudshell edit ~/codelab-o11y/setup.go
    
  3. Kodu, OpenTelemetry izleme ve metrik toplama işlemlerini başlatan sürümle değiştirin. Kodu değiştirmek için dosyanın içeriğini silin, ardından aşağıdaki kodu kopyalayıp düzenleyiciye yapıştırın:
    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)
    }
    
  4. Terminale dönün ve go.mod dosyasındaki Go modülü tanımlarını güncellemek için aşağıdaki komutu çalıştırın:
    go mod tidy
    
  5. Terminal'e dönün ve main.go dosyasını yeniden açın:
    cloudshell edit ~/codelab-o11y/main.go
    
  6. Mevcut kodu, HTTP izlemeyi etkinleştiren ve performans metriği yazan sürümle değiştirin. Kodu değiştirmek için dosyanın içeriğini silin, ardından aşağıdaki kodu kopyalayıp düzenleyiciye yapıştırın:
    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)
        }
    }
    

Uygulama artık kod yürütmeyi izleme ile izlemek ve başarılı yürütme sayısını metrik olarak uygulamak için OpenTelemetry SDK'sını kullanıyor. main() yöntemi, izler ve metrikler için OpenTelemetry dışa aktarıcılarını doğrudan Google Cloud Tracing ve Monitoring'e yazacak şekilde ayarlamak üzere değiştirildi. Ayrıca, toplanan izleri ve metrikleri Cloud Run ortamıyla ilgili meta verilerle doldurmak için ek yapılandırmalar da gerçekleştirir. Handler() işlevi, Vertex AI API çağrısı her geçerli sonuç döndürdüğünde metrik sayacını artıracak şekilde güncellenir.

Cloud Shell Düzenleyici, birkaç saniye sonra değişikliklerinizi otomatik olarak kaydeder.

Üretken yapay zeka uygulamasının kodunu Cloud Run'a dağıtma

  1. Terminal penceresinde, uygulamanın kaynak kodunu Cloud Run'a dağıtma komutunu çalıştırın.
    gcloud run deploy codelab-o11y-service \
         --source="${HOME}/codelab-o11y/" \
         --region=us-central1 \
         --allow-unauthenticated
    
    Aşağıdaki gibi bir istem görürseniz komutun yeni bir depo oluşturacağını bildirir. Enter simgesini tıklayın.
    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)?
    
    Dağıtım işlemi birkaç dakika sürebilir. Dağıtım işlemi tamamlandıktan sonra aşağıdaki gibi bir çıkış görürsünüz:
    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
    
  2. Görüntülenen Cloud Run hizmeti URL'sini tarayıcınızdaki ayrı bir sekmeye veya pencereye kopyalayın. Alternatif olarak, hizmet URL'sini yazdırmak için terminalde aşağıdaki komutu çalıştırın ve URL'yi açmak için Ctrl tuşunu basılı tutarken gösterilen URL'yi tıklayın:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    URL açıldığında 500 hatası alabilir veya şu mesajı görebilirsiniz:
    Sorry, this is just a placeholder...
    
    Bu, hizmetlerin dağıtımının tamamlanmadığı anlamına gelir. Birkaç dakika bekleyip sayfayı yenileyin. Sonunda, Köpeklerle İlgili Eğlenceli Bilgiler ile başlayan ve köpeklerle ilgili 10 eğlenceli bilgi içeren bir metin görürsünüz.

Telemetri verileri oluşturmak için hizmet URL'sini açın. Farklı sonuçlar almak için ?animal= parametresinin değerini değiştirirken sayfayı yenileyin.

Uygulama izlerini keşfetme

  1. Cloud Console'da Trace Explorer sayfasını açmak için aşağıdaki düğmeyi tıklayın:

  2. En son izlerden birini seçin. Aşağıdaki ekran görüntüsünde gösterildiği gibi 5 veya 6 aralık görmeniz gerekir.
    Trace Gezgini&#39;nde uygulama aralığının görünümü
  3. Etkinlik işleyiciye (fun_facts yöntemi) yapılan çağrıyı izleyen aralığı bulun. Bu, / adlı son aralık olacaktır.
  4. İzleme ayrıntıları bölmesinde Günlükler ve etkinlikler'i seçin. Bu belirli aralıkla ilişkili uygulama günlüklerini görürsünüz. Korelasyon, izdeki ve günlükteki iz ve aralık kimlikleri kullanılarak algılanır. İstem ve Vertex API'nin yanıtını yazan uygulama günlüğünü görmeniz gerekir.

Karşı metriği inceleme

  1. Cloud Console'da Metrik Gezgini sayfasını açmak için aşağıdaki düğmeyi tıklayın:

  2. Sorgu oluşturucu bölmesinin araç çubuğunda, adı < > MQL veya < > PromQL olan düğmeyi seçin. Düğmenin konumunu aşağıdaki resimde görebilirsiniz.
    Metrik Gezgini&#39;ndeki MQL düğmesinin konumu
  3. Dil açma/kapatma düğmesinde PromQL'nin seçili olduğunu doğrulayın. Dil değiştirme düğmesi, sorgunuzu biçimlendirmenize olanak tanıyan araç çubuğunda yer alır.
  4. Sorgunuzu Sorgular düzenleyicisine girin:
    sum(rate(workload_googleapis_com:model_call_counter{monitored_resource="generic_task"}[${__interval}]))
    
  5. Run Query'yi (Sorgu Çalıştır) tıklayın.Auto-run (Otomatik çalıştırma) açma/kapatma düğmesi etkinleştirildiğinde Run Query düğmesi gösterilmez.

11. (İsteğe bağlı) Günlüklerdeki hassas bilgileri karartma

10. adımda, uygulamanın Gemini modeliyle etkileşimi hakkında bilgi kaydettik. Bu bilgiler arasında hayvanın adı, asıl istem ve modelin yanıtı yer alıyordu. Bu bilgilerin günlükte saklanması güvenli olsa da diğer birçok senaryo için bu durum geçerli değildir. İstem, kullanıcının depolanmasını istemediği kişisel veya hassas bilgiler içerebilir. Bu sorunu çözmek için Cloud Logging'e yazılan hassas verileri karartabilirsiniz. Kod değişikliklerini en aza indirmek için aşağıdaki çözüm önerilir.

  1. Gelen günlük girişlerini depolamak için bir PubSub konusu oluşturun.
  2. Alınan günlükleri Pub/Sub konusuna yönlendiren bir günlük havuzu oluşturun.
  3. Aşağıdaki adımları uygulayarak Pub/Sub konusuna yönlendirilen günlükleri değiştiren bir Dataflow ardışık düzeni oluşturun:
    1. Pub/Alt konusundaki bir günlük girişini okuma
    2. DLP inceleme API'sini kullanarak girişin yükünde hassas bilgiler olup olmadığını inceleme
    3. VKÖ redaksiyon yöntemlerinden birini kullanarak yükteki hassas bilgileri redakte edin.
    4. Karartılmış günlük girişini Cloud Logging'e yazma
  4. Ardışık düzeni dağıtma

12. (İsteğe bağlı) Temizleme

Bu codelab'de kullanılan kaynaklar ve API'ler için ücretlendirilme riskini önlemek amacıyla laboratuvarı tamamladıktan sonra temizlik yapmanız önerilir. Faturalandırılmanın önüne geçmenin en kolay yolu, codelab için oluşturduğunuz projeyi silmektir.

  1. Projeyi silmek için terminalde proje silme komutunu çalıştırın:
    PROJECT_ID=$(gcloud config get-value project)
    gcloud projects delete ${PROJECT_ID} --quiet
    
    Cloud projenizi sildiğinizde, bu projede kullanılan tüm kaynaklar ve API'ler için faturalandırma durdurulur. PROJECT_ID yerine proje kimliğinizin yazıldığı şu mesajı görürsünüz:
    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.
    
  2. (İsteğe bağlı) Hata alırsanız laboratuvar sırasında kullandığınız proje kimliğini bulmak için 5. adıma bakın. Bunu ilk talimattaki komutla değiştirin. Örneğin, proje kimliğiniz lab-example-project ise komut şu şekilde olur:
    gcloud projects delete lab-project-id-example --quiet
    

13. Tebrikler

Bu laboratuvarda, tahminlerde bulunmak için Gemini modelini kullanan bir üretken yapay zeka uygulaması oluşturdunuz. Ayrıca uygulamayı temel izleme ve günlük kaydı özellikleriyle donattık. Uygulamayı ve kaynak kodundaki değişiklikleri Cloud Run'a dağıttınız. Ardından, uygulamanın performansını izlemek için Google Cloud Observability ürünlerini kullanırsınız. Böylece uygulamanın güvenilirliğinden emin olabilirsiniz.

Bugün kullandığınız ürünleri iyileştirmek için kullanıcı deneyimi (UX) araştırmasına katılmak isterseniz buradan kaydolun.

Öğrenmeye devam etmek için kullanabileceğiniz bazı seçenekler: