أساليب المراقبة العملية لتطبيق الذكاء الاصطناعي التوليدي في Go

1. نظرة عامة

تتطلّب تطبيقات الذكاء الاصطناعي التوليدي إمكانية المراقبة مثل أي تطبيقات أخرى. هل هناك تقنيات مراقبة خاصة مطلوبة للذكاء الاصطناعي التوليدي؟

في هذا التمرين المعملي، ستُنشئ تطبيقًا بسيطًا مستندًا إلى الذكاء الاصطناعي التوليدي. انشر التطبيق على Cloud Run. ويمكنك تجهيزها بإمكانات المراقبة والتسجيل الأساسية باستخدام خدمات ومنتجات مراقبة Google Cloud.

ما ستتعرّف عليه

  • كتابة تطبيق يستخدم Vertex AI باستخدام محرِّر Cloud Shell
  • تخزين رمز تطبيقك في GitHub
  • استخدام gcloud CLI لنشر رمز تطبيقك المصدر إلى Cloud Run
  • إضافة إمكانات المراقبة والتسجيل إلى تطبيق الذكاء الاصطناعي التوليدي
  • استخدام المقاييس المستندة إلى السجلّات
  • تنفيذ التسجيل والمراقبة باستخدام حزمة تطوير البرامج (SDK) Open Telemetry
  • الحصول على إحصاءات حول التعامل المسؤول مع بيانات الذكاء الاصطناعي

2. المتطلبات الأساسية

إذا لم يكن لديك حساب على Google، عليك إنشاء حساب جديد.

3- إعداد المشروع

  1. سجِّل الدخول إلى Google Cloud Console باستخدام حسابك على Google.
  2. أنشئ مشروعًا جديدًا أو اختَر إعادة استخدام مشروع حالي. اكتب رقم تعريف المشروع الذي أنشأته أو اخترته للتو.
  3. فعِّل الفوترة للمشروع.
    • من المفترض أن تبلغ تكلفة إكمال هذا الدرس التطبيقي أقل من 5 دولار أمريكي (أو ما يعادله بالعملة المحلية) في تكاليف الفوترة.
    • يمكنك اتّباع الخطوات الواردة في نهاية هذا البرنامج التدريبي لحذف الموارد لتجنُّب تحصيل المزيد من الرسوم.
    • يكون المستخدمون الجدد مؤهّلين للاستفادة من فترة تجريبية مجانية بقيمة 300 دولار أمريكي.
  4. تأكَّد من تفعيل الفوترة في مشاريعي في "الفوترة في Google Cloud".
    • إذا كان مشروعك الجديد يعرض الرمز Billing is disabled في عمود Billing account:
      1. انقر على النقاط الثلاث في عمود Actions.
      2. انقر على تغيير الفوترة.
      3. اختَر حساب الفوترة الذي تريد استخدامه.
    • إذا كنت تشارك في حدث مباشر، من المرجّح أن يكون اسم الحساب حساب فوترة الفترة التجريبية في Google Cloud Platform.

4. إعداد محرِّر Cloud Shell

  1. انتقِل إلى محرِّر Cloud Shell. إذا ظهرت لك الرسالة التالية تطلب منك تفويض Cloud Shell للاتصال بـ gcloud باستخدام بيانات اعتمادك، انقر على تفويض للمتابعة.
    انقر على تفويض Cloud Shell.
  2. افتح نافذة المحطة الطرفية
      .
    1. انقر على قائمة الخطوط الثلاثة رمز قائمة الهمبرغر.
    2. انقر على Terminal (الوحدة الطرفية).
    3. انقر على وحدة تحكّم جديدة
      فتح وحدة طرفية جديدة في محرِّر Cloud Shell.
  3. في المحطة الطرفية، اضبط رقم تعريف المشروع:
    gcloud config set project [PROJECT_ID]
    
    استبدِل [PROJECT_ID] بمعرّف مشروعك. على سبيل المثال، إذا كان رقم تعريف مشروعك هو lab-example-project، سيكون الأمر على النحو التالي:
    gcloud config set project lab-project-id-example
    
    إذا ظهرت لك الرسالة التالية التي تفيد بأنّ gcloud تطلب بيانات اعتمادك لـ GCPI API، انقر على تفويض للمتابعة.
    انقر على تفويض Cloud Shell.
    عند التنفيذ الناجح، من المفترض أن تظهر لك الرسالة التالية:
    Updated property [core/project].
    
    إذا ظهر لك رمز WARNING وتلقّيت رسالة Do you want to continue (Y/N)?، هذا يعني على الأرجح أنّك أدخلت رقم تعريف المشروع بشكل غير صحيح. اضغط على N، ثم اضغط على Enter، وحاول تنفيذ الأمر gcloud config set project مرة أخرى بعد العثور على رقم تعريف المشروع الصحيح.
  4. (اختياري) إذا كنت تواجه مشكلة في العثور على رقم تعريف المشروع، يمكنك تنفيذ الأمر التالي للاطّلاع على رقم تعريف جميع مشاريعك مرتبة حسب وقت الإنشاء بترتيب تنازلي:
    gcloud projects list \
         --format='value(projectId,createTime)' \
         --sort-by=~createTime
    

5- تفعيل Google APIs

في الوحدة الطرفية، فعِّل واجهات برمجة تطبيقات 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 وتتضمّن تفاصيل الخطأ كما هو موضّح أدناه، أعِد محاولة تنفيذ الأمر بعد تأخير يتراوح بين دقيقة ودقيقتين.

"error": {
  "code": 429,
  "message": "Quota exceeded for quota metric 'Mutate requests' and limit 'Mutate requests per minute' of service 'serviceusage.googleapis.com' ...",
  "status": "RESOURCE_EXHAUSTED",
  ...
}

6- إنشاء تطبيق "الذكاء الاصطناعي التوليدي"

في هذه الخطوة، ستكتب رمزًا للتطبيق البسيط المستنِد إلى الطلبات والذي يستخدم نموذج Gemini لعرض 10 حقائق ممتعة عن حيوان من اختيارك. اتّبِع الخطوات التالية لإنشاء رمز التطبيق.

  1. في الوحدة الطرفية، أنشئ الدليل codelab-o11y:
    mkdir ~/codelab-o11y
    
  2. تغيير الدليل الحالي إلى codelab-o11y:
    cd ~/codelab-o11y
    
  3. بدء وحدات Go:
    go mod init codelab
    
  4. ثبِّت حزمة تطوير برامج Vertex AI لبرنامج Go:
    go get cloud.google.com/go/vertexai/genai
    
  5. ثبِّت مكتبة البيانات الوصفية لنظام التشغيل Go للحصول على رقم تعريف المشروع الحالي:
    go get cloud.google.com/go/compute/metadata
    
  6. أنشئ ملفًا بتنسيق setup.go وافتح الملف في محرِّر Cloud Shell:
    cloudshell edit setup.go
    
    سيتم استخدامه لاستضافة رمز الإعداد. سيظهر ملف فارغ جديد باسم setup.go في نافذة المحرِّر.
  7. انسخ الرمز التالي والصقه في ملف 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
    }
    
  8. ارجع إلى نافذة الوحدة الطرفية ونفِّذ الأمر التالي لإنشاء ملف main.go وفتحه في محرِّر Cloud Shell:
    cloudshell edit main.go
    
    من المفترض أن يظهر الآن ملف فارغ في نافذة المحرِّر أعلى وحدة التحكّم الطرفية. ستظهر شاشتك على النحو التالي:
    عرض "محرِّر Cloud Shell" بعد بدء تعديل main.go
  9. انسخ الرمز التالي والصقه في ملف main.go الذي تم فتحه:
    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 الرمز تلقائيًا.

نشر رمز تطبيق الذكاء الاصطناعي التوليدي على Cloud Run

  1. في نافذة الوحدة الطرفية، شغِّل الأمر لنشر رمز المصدر للتطبيق على 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
    
  2. انسخ عنوان URL المعروض لخدمة Cloud Run إلى علامة تبويب أو نافذة منفصلة في المتصفّح. بدلاً من ذلك، يمكنك تنفيذ الأمر التالي في وحدة التحكّم الطرفية لطباعة عنوان URL للخدمة والنقر على عنوان URL المعروض مع الضغط مع الاستمرار على مفتاح Ctrl لفتح عنوان URL:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    عند فتح عنوان URL، قد يظهر لك الخطأ 500 أو تظهر لك الرسالة التالية:
    Sorry, this is just a placeholder...
    
    يعني ذلك أنّه لم يتم الانتهاء من نشر الخدمات. يُرجى الانتظار بضع دقائق وإعادة تحميل الصفحة. في النهاية، سيظهر لك نص يبدأ بـ معلومات طريفة عن الكلاب ويحتوي على 10 معلومات طريفة عن الكلاب.

يمكنك التفاعل مع التطبيق للحصول على حقائق ممتعة عن الحيوانات المختلفة. لإجراء ذلك، أضِف المَعلمة animal إلى عنوان URL، مثل ?animal=[ANIMAL] حيث يكون [ANIMAL] اسم حيوان. على سبيل المثال، يمكنك إضافة ?animal=cat للحصول على 10 حقائق طريفة عن القطط أو ?animal=sea turtle للحصول على 10 حقائق طريفة عن السلاحف البحرية.

7- تدقيق طلبات البيانات من واجهة برمجة التطبيقات في Vertex

توفّر تدقيق طلبات البيانات من Google API إجابات عن أسئلة مثل "من يطلب بيانات من واجهة برمجة تطبيقات معيّنة، وأين، ومتى؟". من المهم إجراء التدقيق عند تحديد المشاكل في تطبيقك وحلّها أو التحقيق في استهلاك الموارد أو إجراء تحليل للبرامج الجنائية.

تتيح لك سجلّات التدقيق تتبُّع الأنشطة الإدارية وأنشطة النظام، بالإضافة إلى تسجيل طلبات البيانات إلى عمليات واجهة برمجة التطبيقات "قراءة البيانات" و "كتابة البيانات". لتدقيق طلبات Vertex AI لإنشاء المحتوى، عليك تفعيل سجلّات تدقيق "قراءة البيانات" في وحدة تحكّم Cloud.

  1. انقر على الزر أدناه لفتح صفحة "سجلّات التدقيق" في وحدة تحكّم Cloud.

  2. تأكَّد من أنّ الصفحة تتضمّن المشروع الذي أنشأته لهذا البرنامج التدريبي. يظهر المشروع المحدّد في أعلى يمين الصفحة مباشرةً من قائمة الهامبرغر:
    القائمة المنسدلة لمشاريع Google Cloud Console
    إذا لزم الأمر، اختَر المشروع الصحيح من مربّع الاختيار.
  3. في جدول إعداد سجلّات التدقيق في الوصول إلى البيانات، ابحث عن خدمة Vertex AI API في عمود "الخدمة" واختَرها من خلال وضع علامة في مربّع الاختيار على يمين اسم الخدمة.
    اختَر Vertex AI API.
  4. في لوحة المعلومات على يسار الصفحة، اختَر نوع التدقيق "قراءة البيانات".
    التحقّق من سجلّات "قراءة البيانات"
  5. انقر على حفظ.

لإنشاء سجلّات التدقيق، افتح عنوان URL للخدمة. أعِد تحميل الصفحة مع تغيير قيمة المَعلمة ?animal= للحصول على نتائج مختلفة.

استكشاف سجلّات التدقيق

  1. انقر على الزر أدناه لفتح صفحة "مستكشف السجلّات" في وحدة تحكّم Cloud:

  2. الصِق الفلتر التالي في لوحة "الطلب".
    LOG_ID("cloudaudit.googleapis.com%2Fdata_access") AND
    protoPayload.serviceName="aiplatform.googleapis.com"
    
    لوحة "طلبات البحث" هي محرِّر يقع بالقرب من أعلى صفحة "مستكشف السجلات":
    طلب سجلات التدقيق
  3. انقر على Run query (تنفيذ طلب البحث).
  4. اختَر إحدى إدخالات سجلّ التدقيق وسِّع الحقول لفحص المعلومات المسجّلة في السجلّ.
    يمكنك الاطّلاع على تفاصيل حول طلب البيانات من واجهة برمجة التطبيقات Vertex API، بما في ذلك الطريقة والنموذج المستخدَمَين. يمكنك أيضًا الاطّلاع على هوية المُستخدِم الذي بدأ الطلب والأذونات التي سمحت بإجراء الطلب.

8. تسجيل التفاعلات باستخدام الذكاء الاصطناعي التوليدي

لا يمكنك العثور على مَعلمات طلب البيانات من واجهة برمجة التطبيقات أو بيانات الاستجابة في سجلّات التدقيق. ومع ذلك، يمكن أن تكون هذه المعلومات مهمة لتحديد المشاكل وحلّها في ما يتعلّق بتحليل سير العمل والتطبيقات. في هذه الخطوة، نسدّ هذه الفجوة من خلال إضافة تسجيل التطبيق. تستخدِم ميزة التسجيل حزمة Go log/slog العادية لكتابة السجلات المنظَّمة. لا تعرف حزمة log/slog كيفية كتابة السجلات في Google Cloud. وهو يتيح الكتابة إلى الإخراج العادي. ومع ذلك، تتضمّن خدمة Cloud Run ميزات لتسجيل المعلومات المطبوعة في الإخراج العادي ومعالجتها في "تسجيلات Cloud" تلقائيًا. لتسجيل السجلات المنظَّمة بشكل صحيح، يجب تنسيق السجل المطبوع وفقًا لذلك. اتّبِع التعليمات التالية لإضافة إمكانات التسجيل المُنظَّم إلى تطبيق Go.

  1. ارجع إلى نافذة (أو علامة التبويب) Cloud Shell في المتصفّح.
  2. في المحطة الطرفية، أعِد فتح setup.go:
    cloudshell edit ~/codelab-o11y/setup.go
    
  3. استبدِل الرمز بالإصدار الذي يُعدّ الإعدادات اللازمة لتسجيل البيانات. لاستبدال الرمز، احذف محتوى الملف ثم انسخ الرمز أدناه والصقه في المحرِّر:
    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. ارجع إلى المحطة الطرفية وأعِد فتح main.go:
    cloudshell edit ~/codelab-o11y/main.go
    
  5. استبدِل رمز التطبيق بالإصدار الذي يسجِّل التفاعل مع النموذج. لاستبدال الرمز، احذف محتوى الملف ثم انسخ الرمز أدناه والصقه في المحرِّر:
    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() لكتابة سجلّ منظَّم عند تلقّي الاستجابة من طلب Vertex AI API. يسجِّل السجلّ مَعلمة animal للطلب وطلبات النموذج واستجاباته.

بعد بضع ثوانٍ، يحفظ محرِّر Cloud Shell التغييرات تلقائيًا.

نشر رمز تطبيق الذكاء الاصطناعي التوليدي على Cloud Run

  1. في نافذة الوحدة الطرفية، شغِّل الأمر لنشر رمز المصدر للتطبيق على 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
    
  2. انسخ عنوان URL المعروض لخدمة Cloud Run إلى علامة تبويب أو نافذة منفصلة في المتصفّح. بدلاً من ذلك، يمكنك تنفيذ الأمر التالي في وحدة التحكّم الطرفية لطباعة عنوان URL للخدمة والنقر على عنوان URL المعروض مع الضغط على مفتاح Ctrl لفتح عنوان URL:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    عند فتح عنوان URL، قد يظهر لك الخطأ 500 أو تظهر لك الرسالة التالية:
    Sorry, this is just a placeholder...
    
    يعني ذلك أنّه لم يتم الانتهاء من نشر الخدمات. يُرجى الانتظار بضع دقائق وإعادة تحميل الصفحة. في النهاية، سيظهر لك نص يبدأ بعبارة معلومات طريفة عن الكلاب ويتضمن 10 معلومات طريفة عن الكلاب.

لإنشاء سجلات التطبيقات، افتح عنوان URL للخدمة. أعِد تحميل الصفحة مع تغيير قيمة المَعلمة ?animal= للحصول على نتائج مختلفة.
للاطّلاع على سجلّات التطبيق، اتّبِع الخطوات التالية:

  1. انقر على الزر أدناه لفتح صفحة "مستكشف السجلّات" في وحدة تحكّم Cloud:

  2. الصِق الفلتر التالي في لوحة "طلبات البحث" (#2 في واجهة "مستكشف السجلّات"):
    LOG_ID("run.googleapis.com%2Fstdout") AND
    severity=DEBUG
    
  3. انقر على Run query (تنفيذ طلب البحث).

تعرض نتيجة طلب البحث السجلات التي تتضمّن الطلب وردّ Vertex AI، بما في ذلك تقييمات السلامة.

9. احتساب التفاعلات باستخدام الذكاء الاصطناعي التوليدي

تُسجِّل Cloud Run مقاييس مُدارة يمكن استخدامها لمراقبة الخدمات المنشورة. توفّر مقاييس المراقبة التي يديرها المستخدمون إمكانية التحكّم بشكل أكبر في البيانات ومعدّل تكرار تعديل المقياس. يتطلّب تنفيذ هذا المقياس كتابة رمز برمجي يجمع البيانات ويكتبها في مراقبة السحابة الإلكترونية. اطّلِع على الخطوة التالية (اختيارية) لمعرفة كيفية تنفيذها باستخدام حزمة تطوير البرامج (SDK) OpenTelemetry.

تعرض هذه الخطوة بديلاً لتنفيذ مقياس المستخدِم في الرمز البرمجي، وهو المقاييس المستندة إلى السجلّ. تتيح لك المقاييس المستندة إلى السجلّات إنشاء مقاييس المراقبة من إدخالات السجلّات التي يكتبها تطبيقك في "تسجيلات Cloud". سنستخدم سجلات التطبيق التي نفّذناها في الخطوة السابقة لتحديد مقياس يستند إلى السجلّات لعداد الأنواع. سيحتسِب المقياس عدد طلبات البيانات الناجحة من واجهة برمجة التطبيقات Vertex API.

  1. اطّلِع على نافذة مستكشف السجلّات التي استخدمناها في الخطوة السابقة. ضمن لوحة "طلب البحث"، ابحث عن القائمة المنسدلة الإجراءات وانقر عليها لفتحها. اطّلِع على لقطة الشاشة أدناه للعثور على القائمة:
    شريط أدوات نتائج طلب البحث مع القائمة المنسدلة "الإجراءات"
  2. في القائمة التي تم فتحها، اختَر إنشاء مقياس لفتح لوحة إنشاء مقياس مستند إلى السجلّ.
  3. اتّبِع الخطوات التالية لضبط مقياس عداد جديد في لوحة إنشاء مقياس مستند إلى السجلّ:
    1. اضبط نوع المقياس: اختَر المعدّل.
    2. اضبط الحقول التالية في قسم التفاصيل:
      • اسم مقياس التسجيل: اضبط الاسم على model_interaction_count. تسري بعض القيود على اختيار الأسماء. اطّلِع على تحديد المشاكل وحلّها المتعلّقة بقيود اختيار الأسماء لمعرفة التفاصيل.
      • الوصف: أدخِل وصفًا للمقياس. على سبيل المثال، Number of log entries capturing successful call to model inference.
      • الوحدات: اترك هذا الحقل فارغًا أو أدخِل الرقم 1.
    3. اترك القيم في قسم اختيار الفلتر. يُرجى العِلم أنّ حقل فلتر الإنشاء يتضمّن الفلتر نفسه الذي استخدمناه للاطّلاع على سجلات التطبيقات.
    4. (اختياري) أضِف تصنيفًا يساعد في احتساب عدد المكالمات لكل حيوان. ملاحظة: يمكن أن يؤدي هذا التصنيف إلى زيادة عدد القيم الفريدة للمقياس بشكل كبير، ولا يُنصح باستخدامه في مرحلة الإنتاج:
      1. انقر على إضافة تصنيف.
      2. اضبط الحقول التالية في قسم التصنيفات:
        • اسم التصنيف: اضبط الاسم على animal.
        • الوصف: أدخِل وصف التصنيف. مثلاً: Animal parameter
        • نوع التصنيف: اختَر STRING.
        • اسم الحقل: اكتب jsonPayload.animal.
        • التعبير العادي: اترك هذا الحقل فارغًا.
      3. 3. انقر على تم.
    5. انقر على إنشاء مقياس لإنشاء المقياس.

يمكنك أيضًا إنشاء مقياس مستند إلى السجلّات من صفحة المقاييس المستندة إلى السجلّات، باستخدام gcloud logging metrics create سطر أوامر واجهة سطر الأوامر أو باستخدام google_logging_metric مورد Terraform.

لإنشاء بيانات المقاييس، افتح عنوان URL للخدمة. أعِد تحميل الصفحة المفتوحة عدة مرات لإجراء طلبات متعددة إلى النموذج. كما في السابق، حاوِل استخدام حيوانات مختلفة في المَعلمة.

أدخِل طلب البحث PromQL للبحث عن بيانات المقياس المستندة إلى السجلّ. لإدخال طلب بحث PromQL، اتّبِع الخطوات التالية:

  1. انقر على الزر أدناه لفتح صفحة "مستكشف المقاييس" في Cloud Console:

  2. في شريط أدوات لوحة "أداة إنشاء طلبات البحث"، انقر على الزر الذي يحمل الاسم ‎< > MQL أو ‎< > PromQL. يمكنك الاطّلاع على الصورة أدناه لمعرفة مكان الزر.
    مكان زرّ &quot;العملاء المحتملون المؤهّلون&quot; في &quot;أداة استكشاف المقاييس&quot;
  3. تأكَّد من اختيار PromQL في زر الإيقاف/التفعيل اللغة. يمكنك العثور على زر تبديل اللغة في شريط الأدوات نفسه الذي يتيح لك تنسيق طلب البحث.
  4. أدخِل طلب البحث في محرِّر طلبات البحث:
    sum(rate(logging_googleapis_com:user_model_interaction_count{monitored_resource="cloud_run_revision"}[${__interval}]))
    
    لمزيد من المعلومات حول استخدام PromQL، اطّلِع على PromQL في مراقبة السحابة الإلكترونية.
  5. انقر على تنفيذ الطلب. سيظهر لك رسم بياني خطي مشابه لصورة الشاشة هذه:
    عرض المقاييس التي تمّ الاستعلام عنها

    يُرجى العِلم أنّه عند تفعيل زر الإيقاف/التفعيل التشغيل التلقائي، لا يظهر الزر تنفيذ الطلب.

10. (اختياري) استخدام Open Telemetry للمراقبة والتتبُّع

كما ذكرنا في الخطوة السابقة، من الممكن تنفيذ المقاييس باستخدام حزمة تطوير البرامج (SDK) OpenTelemetry ‏(Otel). يُنصح باستخدام OTel في معماريات الخدمات المصغرة. توضّح هذه الخطوة ما يلي:

  • بدء مكوّنات OTel لتتبُّع التطبيق ومراقبته
  • تعبئة إعدادات OTel بالبيانات الوصفية للموارد في بيئة Cloud Run
  • تجهيز تطبيق Flask بإمكانات التتبّع التلقائي
  • تنفيذ مقياس احتسابي لرصد عدد طلبات النماذج الناجحة
  • ربط التتبُّع بسجلات التطبيقات

إنّ البنية المقترَحة للخدمات على مستوى المنتج هي استخدام OTel collector لجمع جميع بيانات المراقبة ومعالجتها لخدمة واحدة أو أكثر. لا يستخدم الرمز البرمجي في هذه الخطوة أداة جمع البيانات بهدف التبسيط. بدلاً من ذلك، يستخدم عمليات تصدير OTel التي تُسجِّل البيانات مباشرةً في Google Cloud.

إعداد مكوّنات OTel لتتبُّع عمليات الربط ومراقبة المقاييس

  1. ارجع إلى نافذة (أو علامة التبويب) Cloud Shell في المتصفّح.
  2. في المحطة الطرفية، أعِد فتح setup.go:
    cloudshell edit ~/codelab-o11y/setup.go
    
  3. استبدِل الرمز بالإصدار الذي يُنشئ عملية تتبُّع 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)
    }
    
  4. ارجع إلى الوحدة الطرفية ونفِّذ الأمر التالي لتعديل تعريفات وحدة Go في ملف go.mod:
    go mod tidy
    
  5. ارجع إلى المحطة الطرفية وأعِد فتح main.go:
    cloudshell edit ~/codelab-o11y/main.go
    
  6. استبدِل الرمز الحالي بالإصدار الذي يُعدّ أدوات تتبُّع 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)
        }
    }
    

يستخدم التطبيق الآن حزمة تطوير البرامج (SDK) OpenTelemetry لقياس تنفيذ الرمز البرمجي باستخدام التتبّع ولتنفيذ احتساب عدد عمليات التنفيذ الناجحة كمقياس. تم تعديل الطريقة main() لإعداد برامج تصدير OpenTelemetry للتتبّعات والمقاييس من أجل الكتابة إلى ميزة "التتبّع والمراقبة" في Google Cloud مباشرةً. وتعمل أيضًا على إجراء عمليات ضبط إضافية لتعبئة عمليات التتبُّع والمقاييس التي تم جمعها ببيانات وصفية ذات صلة ببيئة Cloud Run. يتم تعديل الدالة Handler() لزيادة عداد المقياس في كل مرة تعرض فيها طلب البيانات من واجهة برمجة التطبيقات Vertex AI API نتائج صالحة.

بعد بضع ثوانٍ، يحفظ محرِّر Cloud Shell التغييرات تلقائيًا.

نشر رمز تطبيق الذكاء الاصطناعي التوليدي على Cloud Run

  1. في نافذة الوحدة الطرفية، شغِّل الأمر لنشر رمز المصدر للتطبيق على 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
    
  2. انسخ عنوان URL المعروض لخدمة Cloud Run إلى علامة تبويب أو نافذة منفصلة في المتصفّح. بدلاً من ذلك، يمكنك تنفيذ الأمر التالي في وحدة التحكّم الطرفية لطباعة عنوان URL للخدمة والنقر على عنوان URL المعروض مع الضغط مع الاستمرار على مفتاح Ctrl لفتح عنوان URL:
    gcloud run services list \
         --format='value(URL)' \
         --filter='SERVICE:"codelab-o11y-service"'
    
    عند فتح عنوان URL، قد يظهر لك الخطأ 500 أو تظهر لك الرسالة التالية:
    Sorry, this is just a placeholder...
    
    يعني ذلك أنّه لم يتم الانتهاء من نشر الخدمات. يُرجى الانتظار بضع دقائق وإعادة تحميل الصفحة. في النهاية، سيظهر لك نص يبدأ بـ معلومات طريفة عن الكلاب ويحتوي على 10 معلومات طريفة عن الكلاب.

لإنشاء بيانات القياس عن بُعد، افتح عنوان URL للخدمة. أعِد تحميل الصفحة مع تغيير قيمة المَعلمة ?animal= للحصول على نتائج مختلفة.

استكشاف عمليات تتبُّع التطبيقات

  1. انقر على الزر أدناه لفتح صفحة "مستكشِف التتبُّع" في Cloud Console:

  2. اختَر أحد أحدث عمليات التتبّع. من المفترض أن تظهر لك 5 أو 6 مقاطع تشبه تلك الواردة في لقطة الشاشة أدناه.
    عرض نطاق التطبيق في &quot;مستكشف التتبّع&quot;
  3. ابحث عن العنصر الذي يتتبّع طلب المعالجة للحدث (طريقة fun_facts). سيكون هذا هو النطاق الأخير الذي يحمل الاسم /.
  4. في لوحة تفاصيل التتبُّع، اختَر السجلّات والأحداث. ستظهر لك سجلات التطبيقات المرتبطة بهذا النطاق المحدّد. يتم رصد الارتباط باستخدام معرّفات التتبُّع ومسار التنفيذ في التتبُّع والسجلّ. من المفترض أن يظهر لك سجلّ التطبيق الذي كتب الطلب وردّ Vertex API.

استكشاف مقياس العداد

  1. انقر على الزر أدناه لفتح صفحة "مستكشف المقاييس" في Cloud Console:

  2. في شريط أدوات لوحة "أداة إنشاء طلبات البحث"، انقر على الزر الذي يحمل الاسم ‎< > MQL أو ‎< > PromQL. يمكنك الاطّلاع على الصورة أدناه لمعرفة مكان الزر.
    مكان زرّ &quot;العملاء المحتملون المؤهّلون&quot; في &quot;أداة استكشاف المقاييس&quot;
  3. تأكَّد من اختيار PromQL في زر الإيقاف/التفعيل اللغة. يمكنك العثور على زر تبديل اللغة في شريط الأدوات نفسه الذي يتيح لك تنسيق طلب البحث.
  4. أدخِل طلب البحث في محرِّر طلبات البحث:
    sum(rate(workload_googleapis_com:model_call_counter{monitored_resource="generic_task"}[${__interval}]))
    
  5. انقر على تنفيذ طلب البحث.عند تفعيل زر الإيقاف/التفعيل التشغيل التلقائي، لا يظهر الزر تنفيذ طلب البحث.

11. (اختياري) المعلومات الحسّاسة المشوشة من السجلات

في الخطوة 10، سجّلنا معلومات عن تفاعل التطبيق مع نموذج Gemini. وتشمل هذه المعلومات اسم الحيوان والطلب الفعلي وردّة الفعل من النموذج. على الرغم من أنّ تخزين هذه المعلومات في السجلّ من المفترض أن يكون آمنًا، إلا أنّ ذلك قد لا يكون صحيحًا في العديد من السيناريوهات الأخرى. قد تتضمّن المطالبة بعض المعلومات الشخصية أو الحسّاسة التي لا يريد المستخدم تخزينها. لحلّ هذه المشكلة، يمكنك تشويش البيانات الحسّاسة التي يتم كتابتها في "سجلّات Cloud". للحدّ من تعديلات الرموز البرمجية، ننصحك بالحلّ التالي.

  1. إنشاء موضوع PubSub لتخزين إدخالات السجلّ الواردة
  2. أنشئ أداة لتجميع السجلّات تعيد توجيه السجلّات التي تم نقلها إلى موضوع PubSub.
  3. أنشئ مسار بيانات Dataflow يعدّل السجلات التي تتم إعادة توجيهها إلى موضوع PubSub باتّباع الخطوات التالية:
    1. قراءة إدخال سجلّ من موضوع PubSub
    2. فحص الحمولة في الإدخال بحثًا عن معلومات حسّاسة باستخدام DLP inspection API
    3. إخفاء المعلومات الحساسة في الحمولة باستخدام إحدى طرق إخفاء البيانات في ميزة "منع فقدان البيانات"
    4. كتابة إدخال السجلّ المشوش في "تسجيلات Cloud"
  4. نشر مسار التعلّم

12. (اختياري) التنظيف

لتجنُّب التعرّض لرسوم مقابل الموارد وواجهات برمجة التطبيقات المستخدَمة في ورشة التطوير، ننصحك بحذفها بعد الانتهاء من الورشة. إنّ أسهل طريقة لإيقاف الفوترة هي حذف المشروع الذي أنشأته في ورشة إعداد الرمز البرمجي.

  1. لحذف المشروع، نفِّذ الأمر delete project في وحدة التحكّم الطرفية:
    PROJECT_ID=$(gcloud config get-value project)
    gcloud projects delete ${PROJECT_ID} --quiet
    
    يؤدي حذف مشروعك على Cloud إلى إيقاف الفوترة لجميع الموارد وواجهات برمجة التطبيقات المستخدَمة في ذلك المشروع. من المفترض أن تظهر لك هذه الرسالة التي سيحلّ فيها 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.
    
  2. (اختياري) إذا ظهرت لك رسالة خطأ، راجِع الخطوة 5 للعثور على رقم تعريف المشروع الذي استخدمته خلال البرنامج التدريبي. استبدِله بالأمر الوارد في التعليمات الأولى. على سبيل المثال، إذا كان رقم تعريف مشروعك هو lab-example-project، سيكون الأمر على النحو التالي:
    gcloud projects delete lab-project-id-example --quiet
    

13. تهانينا

في هذا التمرين المعملي، أنشأت تطبيقًا للذكاء الاصطناعي التوليدي يستخدم نموذج Gemini لوضع التوقّعات. وزوّدنا التطبيق بإمكانات أساسية للمراقبة والتسجيل. لقد نشرت التطبيق وأجريت التغييرات من الرمز المصدر إلى Cloud Run. بعد ذلك، يمكنك استخدام منتجات مراقبة Google Cloud لتتبُّع أداء التطبيق، ما يضمن لك موثوقية التطبيق.

إذا كنت مهتمًا بالمشاركة في دراسة بحثية حول تجربة المستخدم لتحسين المنتجات التي استخدمتها اليوم، يُرجى التسجيل هنا.

في ما يلي بعض الخيارات لمواصلة التعلّم: