1. סקירה כללית
אפליקציות של AI גנרטיבי דורשות יכולת צפייה כמו כל אפליקציה אחרת. האם יש טכניקות מיוחדות של יכולת צפייה שנדרשות ל-AI גנרטיבי?
בשיעור ה-Lab הזה תיצרו אפליקציית AI גנרטיבית פשוטה. פורסים אותו ב-Cloud Run. בנוסף, תוכלו להשתמש במוצרים ובשירותים של Google Cloud Observability כדי להוסיף לו יכולות חיוניות של מעקב ורישום ביומן.
מה תלמדו
- כתיבת אפליקציה שמשתמשת ב-Vertex AI עם Cloud Shell Editor
- שמירת קוד האפליקציה ב-GitHub
- משתמשים ב-ה-CLI של gcloud כדי לפרוס את קוד המקור של האפליקציה ב-Cloud Run
- הוספת יכולות מעקב ורישום ביומן לאפליקציית ה-AI הגנרטיבי
- שימוש במדדים מבוססי-יומנים
- הטמעה של רישום ביומן ומעקב באמצעות Open Telemetry SDK
- קבלת תובנות לגבי טיפול בנתונים בהתאם לאתיקה של בינה מלאכותית
2. דרישות מוקדמות
אם עדיין אין לכם חשבון Google, אתם צריכים ליצור חשבון חדש.
3. הגדרת הפרויקט
- נכנסים למסוף Google Cloud באמצעות חשבון Google.
- יוצרים פרויקט חדש או בוחרים להשתמש מחדש בפרויקט קיים. רושמים את מזהה הפרויקט שיצרתם או בחרתם.
- מפעילים את החיוב בפרויקט.
- העלות של השלמת ה-Lab הזה צריכה להיות פחות מ-5 $בעלויות החיוב.
- כדי למחוק משאבים ולמנוע חיובים נוספים, אפשר לבצע את השלבים בסוף ה-Lab הזה.
- משתמשים חדשים זכאים לתקופת ניסיון בחינם בשווי 300$.
- מוודאים שהחיוב מופעל בדף My projects (הפרויקטים שלי) בחיוב ב-Cloud
- אם הפרויקט החדש מופיע עם הערך
Billing is disabledבעמודהBilling account:- לוחצים על סמל האפשרויות הנוספות (3 נקודות) בעמודה
Actions. - לוחצים על שינוי פרטי החיוב.
- בוחרים את החשבון לחיוב שבו רוצים להשתמש.
- לוחצים על סמל האפשרויות הנוספות (3 נקודות) בעמודה
- אם אתם משתתפים באירוע בשידור חי, סביר להניח שהחשבון ייקרא חשבון לחיוב ב-Google Cloud Platform לניסיון
- אם הפרויקט החדש מופיע עם הערך
4. הכנת Cloud Shell Editor
- עוברים אל Cloud Shell Editor. אם מוצגת ההודעה הבאה, שבה מתבקש אישור ל-Cloud Shell להתקשר אל gcloud עם פרטי הכניסה שלכם, לוחצים על Authorize כדי להמשיך.

- פותחים חלון טרמינל
- לוחצים על סמל האפשרויות הנוספות (3 קווים)
. - לוחצים על Terminal (מסוף).
- לוחצים על New Terminal
(טרמינל חדש).
- לוחצים על סמל האפשרויות הנוספות (3 קווים)
- במסוף, מגדירים את מזהה הפרויקט:
מחליפים אתgcloud config set project [PROJECT_ID][PROJECT_ID]במזהה הפרויקט. לדוגמה, אם מזהה הפרויקט הואlab-example-project, הפקודה תהיה: אם מוצגת ההודעה הבאה, שבה נאמר ש-gcloud מבקש את פרטי הכניסה שלכם ל-GCPI API, לוחצים על Authorize (אישור) כדי להמשיך.gcloud config set project lab-project-id-example

אם ההפעלה מצליחה, תוצג ההודעה הבאה: אם מופיעUpdated property [core/project].
WARNINGומוצגת השאלהDo you want to continue (Y/N)?, כנראה שהזנתם את מזהה הפרויקט בצורה שגויה. מקישים עלN, מקישים עלEnterומנסים להריץ שוב את הפקודהgcloud config set projectאחרי שמאתרים את מזהה הפרויקט הנכון. - (אופציונלי) אם אתם מתקשים למצוא את מזהה הפרויקט, אתם יכולים להריץ את הפקודה הבאה כדי לראות את מזהה הפרויקט של כל הפרויקטים שלכם, ממוין לפי זמן היצירה בסדר יורד:
gcloud projects list \ --format='value(projectId,createTime)' \ --sort-by=~createTime
5. הפעלת ממשקי Google APIs
במסוף, מפעילים את ממשקי Google API שנדרשים ל-Lab הזה:
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. יצירת אפליקציית AI גנרטיבית
בשלב הזה תכתבו קוד של אפליקציה פשוטה שמבוססת על בקשות ומשתמשת במודל Gemini כדי להציג 10 עובדות מעניינות על חיה שתבחרו. כדי ליצור את קוד האפליקציה:
- בטרמינל, יוצרים את הספרייה
codelab-o11y:mkdir "${HOME}/codelab-o11y" - משנים את הספרייה הנוכחית ל-
codelab-o11y:cd "${HOME}/codelab-o11y" - מורידים את קוד ה-bootstrap של אפליקציית Java באמצעות Spring framework starter:
curl https://start.spring.io/starter.zip \ -d dependencies=web \ -d javaVersion=17 \ -d type=maven-project \ -d bootVersion=3.4.1 -o java-starter.zip - מבטלים את הארכיון של קוד ה-bootstrap לתיקייה הנוכחית:
unzip java-starter.zip - מסירים את קובץ הארכיון מהתיקייה:
rm java-starter.zip - יוצרים קובץ
project.tomlכדי להגדיר את גרסת Java Runtime שבה יש להשתמש כשפורסים את הקוד ב-Cloud Run:cat > "${HOME}/codelab-o11y/project.toml" << EOF [[build.env]] name = "GOOGLE_RUNTIME_VERSION" value = "17" EOF - מוסיפים את יחסי התלות של Google Cloud SDK לקובץ
pom.xml:- מוסיפים את חבילת הליבה של Google Cloud:
sed -i 's/<dependencies>/<dependencies>\ \ <dependency>\ <groupId>com.google.cloud<\/groupId>\ <artifactId>google-cloud-core<\/artifactId>\ <version>2.49.1<\/version>\ <\/dependency>\ /g' "${HOME}/codelab-o11y/pom.xml" - מוסיפים חבילה של Vertex AI מ-Google Cloud:
sed -i 's/<dependencies>/<dependencies>\ \ <dependency>\ <groupId>com.google.cloud<\/groupId>\ <artifactId>google-cloud-vertexai<\/artifactId>\ <version>1.16.0<\/version>\ <\/dependency>\ /g' "${HOME}/codelab-o11y/pom.xml"
- מוסיפים את חבילת הליבה של Google Cloud:
- פותחים את הקובץ
DemoApplication.javaב-Cloud Shell Editor: קוד מקור עם פיגומים של הקובץcloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/DemoApplication.java"DemoApplication.javaאמור להופיע עכשיו בחלון העריכה מעל הטרמינל. קוד המקור של הקובץ ייראה כך:package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } - מחליפים את הקוד בעורך בגרסה שמוצגת למטה. כדי להחליף את הקוד, מוחקים את התוכן של הקובץ ומעתיקים את הקוד שלמטה אל העורך:
אחרי כמה שניות, Cloud Shell Editor ישמור את הקוד באופן אוטומטי.package com.example.demo; import java.io.IOException; import java.util.Collections; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.google.cloud.ServiceOptions; import com.google.cloud.vertexai.VertexAI; import com.google.cloud.vertexai.api.GenerateContentResponse; import com.google.cloud.vertexai.generativeai.GenerativeModel; import com.google.cloud.vertexai.generativeai.ResponseHandler; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { String port = System.getenv().getOrDefault("PORT", "8080"); SpringApplication app = new SpringApplication(DemoApplication.class); app.setDefaultProperties(Collections.singletonMap("server.port", port)); app.run(args); } } @RestController class HelloController { private final String projectId = ServiceOptions.getDefaultProjectId(); private VertexAI vertexAI; private GenerativeModel model; @PostConstruct public void init() { vertexAI = new VertexAI(projectId, "us-central1"); model = new GenerativeModel("gemini-1.5-flash", vertexAI); } @PreDestroy public void destroy() { vertexAI.close(); } @GetMapping("/") public String getFacts(@RequestParam(defaultValue = "dog") String animal) throws IOException { String prompt = "Give me 10 fun facts about " + animal + ". Return this as html without backticks."; GenerateContentResponse response = model.generateContent(prompt); return ResponseHandler.getText(response); } }
פריסת הקוד של אפליקציית ה-AI הגנרטיבי ב-Cloud Run
- בחלון הטרמינל, מריצים את הפקודה לפריסת קוד המקור של האפליקציה ב-Cloud Run.
אם מוצגת ההודעה הבאה, שמציינת שהפקודה תיצור מאגר חדש. לוחצים עלgcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticatedEnter. תהליך הפריסה עשוי להימשך כמה דקות. אחרי שתהליך הפריסה יושלם, יוצגו נתונים שדומים לאלה שמופיעים בדוגמה הבאה:Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [us-central1] will be created. Do you want to continue (Y/n)?
Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic. Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
- מעתיקים את כתובת ה-URL של שירות Cloud Run שמוצגת לכרטיסייה או לחלון נפרדים בדפדפן. לחלופין, מריצים את הפקודה הבאה בטרמינל כדי להדפיס את כתובת ה-URL של השירות, ולוחצים על כתובת ה-URL שמוצגת תוך כדי החזקת המקש Ctrl כדי לפתוח את כתובת ה-URL:
כשפותחים את כתובת האתר, יכול להיות שתופיע שגיאה 500 או ההודעה:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"' המשמעות היא שהפריסה של השירותים לא הסתיימה. ממתינים כמה רגעים ומרעננים את הדף. בסוף תראו טקסט שמתחיל במילים עובדות מעניינות על כלבים ומכיל 10 עובדות מעניינות על כלבים.Sorry, this is just a placeholder...
נסו לקיים אינטראקציה עם האפליקציה כדי לקבל עובדות מעניינות על בעלי חיים שונים. כדי לעשות זאת, מוסיפים את הפרמטר animal לכתובת ה-URL, כמו ?animal=[ANIMAL], כאשר [ANIMAL] הוא שם של חיה. לדוגמה, מוסיפים ?animal=cat כדי לקבל 10 עובדות משעשעות על חתולים או ?animal=sea turtle כדי לקבל 10 עובדות משעשעות על צבי ים.
7. ביקורת על הקריאות ל-Vertex API
ביקורת על קריאות ל-Google API מספקת תשובות לשאלות כמו "מי קרא ל-API מסוים, איפה ומתי?". ביקורת היא חשובה כשמנסים לפתור בעיות באפליקציה, כשבודקים את צריכת המשאבים או כשמבצעים ניתוח משפטי של תוכנה.
יומני ביקורת מאפשרים לעקוב אחרי פעילויות אדמין ופעילויות מערכת, וגם לרשום ביומן קריאות לפעולות API של 'קריאת נתונים' ו'כתיבת נתונים'. כדי לבצע ביקורת על בקשות ל-Vertex AI ליצירת תוכן, צריך להפעיל יומני ביקורת של 'קריאת נתונים' במסוף Cloud.
- לוחצים על הלחצן שלמטה כדי לפתוח את הדף Audit Logs במסוף Cloud
- מוודאים שהפרויקט שיצרתם לשיעור ה-Lab הזה נבחר בדף. הפרויקט שנבחר מוצג בפינה הימנית העליונה של הדף, מימין לתפריט ההמבורגר:

אם צריך, בוחרים את הפרויקט הנכון מתיבת הבחירה. - בטבלה Data Access audit logs configuration, בעמודה Service, מוצאים את השירות
Vertex AI APIומסמנים את התיבה שמשמאל לשם השירות כדי לבחור אותו.
- בחלונית המידע שמשמאל, בוחרים בסוג הביקורת 'קריאת נתונים'.

- לוחצים על שמירה.
כדי ליצור יומני ביקורת, פותחים את כתובת ה-URL של השירות. כדי לקבל תוצאות שונות, צריך לרענן את הדף תוך כדי שינוי הערך של הפרמטר ?animal=.
עיון ביומני ביקורת
- לוחצים על הלחצן שלמטה כדי לפתוח את הדף Logs Explorer במסוף Cloud:
- מדביקים את המסנן הבא בחלונית Query (שאילתה).
חלונית השאילתה היא עורך שנמצא בחלק העליון של הדף Logs Explorer:LOG_ID("cloudaudit.googleapis.com%2Fdata_access") AND protoPayload.serviceName="aiplatform.googleapis.com"
- לוחצים על Run query.
- בוחרים באחת מהרשומות ביומן הביקורת ומרחיבים את השדות כדי לבדוק את המידע שמתועד ביומן.
אפשר לראות פרטים על קריאה ל-Vertex API, כולל השיטה והמודל שנעשה בהם שימוש. אפשר גם לראות את הזהות של מי שהפעיל את השיטה ואילו הרשאות אישרו את הקריאה.
8. רישום אינטראקציות עם AI גנרטיבי
אי אפשר למצוא ביומני הביקורת פרמטרים של בקשות API או נתוני תגובה. עם זאת, המידע הזה יכול להיות חשוב לפתרון בעיות באפליקציה ולניתוח תהליכי עבודה. בשלב הזה אנחנו ממלאים את הפער הזה על ידי הוספת רישום ביומן של האפליקציה.
ההטמעה משתמשת ב-Logback עם Spring Boot כדי להדפיס יומנים של אפליקציות לפלט רגיל. השיטה הזו כוללת את היכולת של Cloud Run לתעד מידע שמוצג בפלט רגיל ולהטמיע אותו ב-Cloud Logging באופן אוטומטי. כדי לתעד מידע כנתונים מובְנים, צריך לעצב את היומנים המודפסים בהתאם. כדי להוסיף לאפליקציה יכולות של רישום ביומן במבנה, פועלים לפי ההוראות שבהמשך.
- חוזרים לחלון (או לכרטיסייה) Cloud Shell בדפדפן.
- יוצרים ופותחים קובץ חדש
LoggingEventGoogleCloudEncoder.javaב-Cloud Shell Editor:cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/LoggingEventGoogleCloudEncoder.java" - מעתיקים ומדביקים את הקוד הבא כדי להטמיע מקודד Logback שמקודד את היומן כ-JSON עם מחרוזת, לפי פורמט היומן המובנה של Google Cloud:
package com.example.demo; import static ch.qos.logback.core.CoreConstants.UTF_8_CHARSET; import java.time.Instant; import ch.qos.logback.core.encoder.EncoderBase; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import java.util.HashMap; import com.google.gson.Gson; public class LoggingEventGoogleCloudEncoder extends EncoderBase<ILoggingEvent> { private static final byte[] EMPTY_BYTES = new byte[0]; private final Gson gson = new Gson(); @Override public byte[] headerBytes() { return EMPTY_BYTES; } @Override public byte[] encode(ILoggingEvent e) { var timestamp = Instant.ofEpochMilli(e.getTimeStamp()); var fields = new HashMap<String, Object>() { { put("timestamp", timestamp.toString()); put("severity", severityFor(e.getLevel())); put("message", e.getMessage()); } }; var params = e.getKeyValuePairs(); if (params != null && params.size() > 0) { params.forEach(kv -> fields.putIfAbsent(kv.key, kv.value)); } var data = gson.toJson(fields) + "\n"; return data.getBytes(UTF_8_CHARSET); } @Override public byte[] footerBytes() { return EMPTY_BYTES; } private static String severityFor(Level level) { switch (level.toInt()) { case Level.TRACE_INT: return "DEBUG"; case Level.DEBUG_INT: return "DEBUG"; case Level.INFO_INT: return "INFO"; case Level.WARN_INT: return "WARNING"; case Level.ERROR_INT: return "ERROR"; default: return "DEFAULT"; } } } - יוצרים ופותחים קובץ חדש
logback.xmlב-Cloud Shell Editor:cloudshell edit "${HOME}/codelab-o11y/src/main/resources/logback.xml" - מעתיקים ומדביקים את קובץ ה-XML הבא כדי להגדיר את Logback לשימוש במקודד עם Logback appender שמדפיס יומנים לפלט רגיל:
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true"> <appender name="Console" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="com.example.demo.LoggingEventGoogleCloudEncoder"/> </appender> <root level="info"> <appender-ref ref="Console" /> </root> </configuration> - פותחים מחדש את הקובץ
DemoApplication.javaב-Cloud Shell Editor:cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/DemoApplication.java" - כדי לרשום ביומן את הבקשה והתשובה של ה-AI הגנרטיבי, מחליפים את הקוד בעורך בגרסה שמוצגת בהמשך. כדי להחליף את הקוד, מוחקים את התוכן של הקובץ ומעתיקים את הקוד שלמטה אל העורך:
package com.example.demo; import java.io.IOException; import java.util.Collections; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.google.cloud.ServiceOptions; import com.google.cloud.vertexai.VertexAI; import com.google.cloud.vertexai.api.GenerateContentResponse; import com.google.cloud.vertexai.generativeai.GenerativeModel; import com.google.cloud.vertexai.generativeai.ResponseHandler; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { String port = System.getenv().getOrDefault("PORT", "8080"); SpringApplication app = new SpringApplication(DemoApplication.class); app.setDefaultProperties(Collections.singletonMap("server.port", port)); app.run(args); } } @RestController class HelloController { private final String projectId = ServiceOptions.getDefaultProjectId(); private VertexAI vertexAI; private GenerativeModel model; private final Logger LOGGER = LoggerFactory.getLogger(HelloController.class); @PostConstruct public void init() { vertexAI = new VertexAI(projectId, "us-central1"); model = new GenerativeModel("gemini-1.5-flash", vertexAI); } @PreDestroy public void destroy() { vertexAI.close(); } @GetMapping("/") public String getFacts(@RequestParam(defaultValue = "dog") String animal) throws IOException { String prompt = "Give me 10 fun facts about " + animal + ". Return this as html without backticks."; GenerateContentResponse response = model.generateContent(prompt); LOGGER.atInfo() .addKeyValue("animal", animal) .addKeyValue("prompt", prompt) .addKeyValue("response", response) .log("Content is generated"); return ResponseHandler.getText(response); } }
אחרי כמה שניות, Cloud Shell Editor שומר את השינויים באופן אוטומטי.
פריסת הקוד של אפליקציית ה-AI הגנרטיבי ב-Cloud Run
- בחלון הטרמינל, מריצים את הפקודה לפריסת קוד המקור של האפליקציה ב-Cloud Run.
אם מוצגת ההודעה הבאה, שמציינת שהפקודה תיצור מאגר חדש. לוחצים עלgcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticatedEnter. תהליך הפריסה עשוי להימשך כמה דקות. אחרי שתהליך הפריסה יושלם, יוצגו נתונים שדומים לאלה שמופיעים בדוגמה הבאה:Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [us-central1] will be created. Do you want to continue (Y/n)?
Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic. Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
- מעתיקים את כתובת ה-URL של שירות Cloud Run שמוצגת לכרטיסייה או לחלון נפרדים בדפדפן. לחלופין, מריצים את הפקודה הבאה בטרמינל כדי להדפיס את כתובת ה-URL של השירות, ולוחצים על כתובת ה-URL שמוצגת תוך כדי החזקת המקש Ctrl כדי לפתוח את כתובת ה-URL:
כשפותחים את כתובת האתר, יכול להיות שתופיע שגיאה 500 או ההודעה:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"' המשמעות היא שהפריסה של השירותים לא הסתיימה. ממתינים כמה רגעים ומרעננים את הדף. בסוף תראו טקסט שמתחיל במילים עובדות מעניינות על כלבים ומכיל 10 עובדות מעניינות על כלבים.Sorry, this is just a placeholder...
כדי ליצור יומני אפליקציות, פותחים את כתובת ה-URL של השירות. כדי לקבל תוצאות שונות, צריך לרענן את הדף תוך כדי שינוי הערך של הפרמטר ?animal=.
כדי לראות את יומני האפליקציה:
- לוחצים על הלחצן שלמטה כדי לפתוח את הדף Logs Explorer במסוף Cloud:
- מדביקים את המסנן הבא בחלונית Query (#2 בממשק Log explorer):
LOG_ID("run.googleapis.com%2Fstdout") AND severity=DEBUG - לוחצים על Run query.
תוצאת השאילתה מציגה יומנים עם ההנחיה והתשובה של Vertex AI, כולל דירוגי בטיחות.
9. ספירת אינטראקציות עם AI גנרטיבי
Cloud Run כותב מדדים מנוהלים שאפשר להשתמש בהם כדי לעקוב אחרי שירותים שנפרסו. מדדי מעקב בניהול המשתמשים מאפשרים שליטה רבה יותר בנתונים ובתדירות העדכון של המדדים. כדי להטמיע מדד כזה, צריך לכתוב קוד שאוסף נתונים וכותב אותם ל-Cloud Monitoring. בשלב הבא (אופציונלי) מוסבר איך ליישם את התכונה באמצעות OpenTelemetry SDK.
בשלב הזה מוצגת חלופה להטמעת מדד משתמש בקוד – מדדים מבוססי-יומן. מדדים מבוססי-יומן מאפשרים לכם ליצור מדדי מעקב מתוך רשומות היומן שהאפליקציה שלכם כותבת ל-Cloud Logging. נשתמש ביומני האפליקציה שהטמענו בשלב הקודם כדי להגדיר מדד מבוסס-יומן מסוג counter. המדד יספור את מספר הקריאות ל-Vertex API שבוצעו בהצלחה.
- בודקים את החלון של Logs explorer שבו השתמשנו בשלב הקודם. בחלונית Query (שאילתה), מאתרים את התפריט הנפתח Actions (פעולות) ולוחצים עליו כדי לפתוח אותו. בצילום המסך שלמטה אפשר לראות איפה נמצא התפריט:

- בתפריט שנפתח, בוחרים באפשרות Create metric כדי לפתוח את החלונית Create log-based metric.
- כדי להגדיר מדד חדש של מונה בחלונית Create log-based metric (יצירת מדד שמבוסס על יומן):
- מגדירים את סוג המדד: בוחרים באפשרות מונה.
- מגדירים את השדות הבאים בקטע פרטים:
- שם מדד היומן: מגדירים את השם לערך
model_interaction_count. יש הגבלות מסוימות על שמות. פרטים נוספים זמינים במאמר פתרון בעיות בנושא הגבלות על שמות. - תיאור: מזינים תיאור למדד. לדוגמה,
Number of log entries capturing successful call to model inference.. - יחידות: משאירים את השדה הזה ריק או מזינים את הספרה
1.
- שם מדד היומן: מגדירים את השם לערך
- משאירים את הערכים בקטע בחירת מסנן. שימו לב שבשדה Build filter (יצירת מסנן) מופיע אותו מסנן שבו השתמשנו כדי לראות את יומני האפליקציה.
- (אופציונלי) מוסיפים תווית שתעזור לספור את מספר השיחות לכל חיה. הערה: התווית הזו יכולה להגדיל מאוד את הקרדינליות של המדד, ולא מומלץ להשתמש בה בסביבת הייצור:
- לוחצים על הוספת תווית.
- מגדירים את השדות הבאים בקטע תוויות:
- שם התווית: מגדירים את השם לערך
animal. - תיאור: מזינים את התיאור של התווית. לדוגמה,
Animal parameter. - סוג התווית: בוחרים באפשרות
STRING. - שם השדה: סוג
jsonPayload.animal. - ביטוי רגולרי: משאירים את השדה ריק.
- שם התווית: מגדירים את השם לערך
- לוחצים על סיום
- לוחצים על יצירת מדד כדי ליצור את המדד.
אפשר גם ליצור מדד מבוסס-יומן מהדף מדדים מבוססי-יומן, באמצעות gcloud logging metrics create פקודת CLI או באמצעות google_logging_metric משאב Terraform.
כדי ליצור נתוני מדדים, פותחים את כתובת ה-URL של השירות. כדי לבצע כמה קריאות למודל, מרעננים את הדף הפתוח כמה פעמים. כמו קודם, נסו להשתמש בפרמטר בבעלי חיים שונים.
מזינים את שאילתת PromQL כדי לחפש את נתוני המדדים שמבוססים על יומנים. כדי להזין שאילתת PromQL:
- לוחצים על הלחצן שלמטה כדי לפתוח את הדף Metrics Explorer במסוף Cloud:
- בסרגל הכלים של החלונית ליצירת שאילתות, לוחצים על הלחצן ששמו < > MQL או < > PromQL. התמונה שלמטה מראה איפה נמצא הכפתור.

- מוודאים שהאפשרות PromQL נבחרה במתג שפה. המתג לשפה נמצא באותה סרגל כלים שבו אפשר לעצב את השאילתה.
- מזינים את השאילתה בעורך השאילתות:
מידע נוסף על השימוש ב-PromQL זמין במאמר PromQL ב-Cloud Monitoring.sum(rate(logging_googleapis_com:user_model_interaction_count{monitored_resource="cloud_run_revision"}[${__interval}])) - לוחצים על הרצת השאילתה. יוצג תרשים קו שדומה לצילום המסך הזה:

שימו לב: כשהמתג הפעלה אוטומטית מופעל, הכפתור הפעלת שאילתה לא מוצג.
10. (אופציונלי) שימוש בטלמטריה פתוחה למעקב ולתיעוד
כמו שצוין בשלב הקודם, אפשר להטמיע מדדים באמצעות OpenTelemetry (Otel) SDK. מומלץ להשתמש ב-OTel בארכיטקטורות מרובות שירותים. בשלב הזה נראה איך מוסיפים אינסטרומנטציה של OTel לאפליקציית Spring Boot. בשלב הזה תבצעו את הפעולות הבאות:
- הטמעה של יכולות מעקב אוטומטי באפליקציית Spring Boot
- הטמעה של מדד מונה כדי לעקוב אחרי מספר הקריאות המוצלחות למודל
- קורלציה בין מעקב לבין יומני אפליקציות
הארכיטקטורה המומלצת לשירותים ברמת המוצר היא שימוש ב-OTel collector כדי לאסוף את כל נתוני יכולת התצפית מכמה שירותים ולהטמיע אותם. הקוד בשלב הזה לא משתמש ב-collector כדי לפשט את התהליך. במקום זאת, הוא משתמש בייצוא OTel שכותב נתונים ישירות ל-Google Cloud.
הגדרת אפליקציית Spring Boot עם רכיבי OTel ומעקב אוטומטי
- חוזרים לחלון (או לכרטיסייה) Cloud Shell בדפדפן.
- בטרמינל, מעדכנים את הקובץ
application.permissionsעם פרמטרים נוספים של הגדרות: הפרמטרים האלה מגדירים ייצוא של נתוני יכולת צפייה ל-Cloud Trace ול-Cloud Monitoring, ומחילים דגימה של כל העקבות.cat >> "${HOME}/codelab-o11y/src/main/resources/application.properties" << EOF otel.logs.exporter=none otel.traces.exporter=google_cloud_trace otel.metrics.exporter=google_cloud_monitoring otel.resource.attributes.service.name=codelab-o11y-service otel.traces.sampler=always_on EOF - מוסיפים את יחסי התלות הנדרשים של OpenTelemetry לקובץ
pom.xml:sed -i 's/<dependencies>/<dependencies>\ \ <dependency>\ <groupId>io.opentelemetry.instrumentation<\/groupId>\ <artifactId>opentelemetry-spring-boot-starter<\/artifactId>\ <\/dependency>\ <dependency>\ <groupId>com.google.cloud.opentelemetry<\/groupId>\ <artifactId>exporter-auto<\/artifactId>\ <version>0.33.0-alpha<\/version>\ <\/dependency>\ <dependency>\ <groupId>com.google.cloud.opentelemetry<\/groupId>\ <artifactId>exporter-trace<\/artifactId>\ <version>0.33.0<\/version>\ <\/dependency>\ <dependency>\ <groupId>com.google.cloud.opentelemetry<\/groupId>\ <artifactId>exporter-metrics<\/artifactId>\ <version>0.33.0<\/version>\ <\/dependency>\ /g' "${HOME}/codelab-o11y/pom.xml" - מוסיפים את OpenTelemetry BOM לקובץ
pom.xml:sed -i 's/<\/properties>/<\/properties>\ <dependencyManagement>\ <dependencies>\ <dependency>\ <groupId>io.opentelemetry.instrumentation<\/groupId>\ <artifactId>opentelemetry-instrumentation-bom<\/artifactId>\ <version>2.12.0<\/version>\ <type>pom<\/type>\ <scope>import<\/scope>\ <\/dependency>\ <\/dependencies>\ <\/dependencyManagement>\ /g' "${HOME}/codelab-o11y/pom.xml" - פותחים מחדש את הקובץ
DemoApplication.javaב-Cloud Shell Editor:cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/DemoApplication.java" - מחליפים את הקוד הנוכחי בגרסה שמגדילה מדד לבדיקת ביצועים. כדי להחליף את הקוד, מוחקים את התוכן של הקובץ ומעתיקים את הקוד שלמטה אל העורך:
package com.example.demo; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.metrics.LongCounter; import java.io.IOException; import java.util.Collections; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.google.cloud.ServiceOptions; import com.google.cloud.vertexai.VertexAI; import com.google.cloud.vertexai.api.GenerateContentResponse; import com.google.cloud.vertexai.generativeai.GenerativeModel; import com.google.cloud.vertexai.generativeai.ResponseHandler; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { String port = System.getenv().getOrDefault("PORT", "8080"); SpringApplication app = new SpringApplication(DemoApplication.class); app.setDefaultProperties(Collections.singletonMap("server.port", port)); app.run(args); } } @RestController class HelloController { private final String projectId = ServiceOptions.getDefaultProjectId(); private VertexAI vertexAI; private GenerativeModel model; private final Logger LOGGER = LoggerFactory.getLogger(HelloController.class); private static final String INSTRUMENTATION_NAME = "genai-o11y/java/workshop/example"; private static final AttributeKey<String> ANIMAL = AttributeKey.stringKey("animal"); private final LongCounter counter; public HelloController(OpenTelemetry openTelemetry) { this.counter = openTelemetry.getMeter(INSTRUMENTATION_NAME) .counterBuilder("model_call_counter") .setDescription("Number of successful model calls") .build(); } @PostConstruct public void init() { vertexAI = new VertexAI(projectId, "us-central1"); model = new GenerativeModel("gemini-1.5-flash", vertexAI); } @PreDestroy public void destroy() { vertexAI.close(); } @GetMapping("/") public String getFacts(@RequestParam(defaultValue = "dog") String animal) throws IOException { String prompt = "Give me 10 fun facts about " + animal + ". Return this as html without backticks."; GenerateContentResponse response = model.generateContent(prompt); LOGGER.atInfo() .addKeyValue("animal", animal) .addKeyValue("prompt", prompt) .addKeyValue("response", response) .log("Content is generated"); counter.add(1, Attributes.of(ANIMAL, animal)); return ResponseHandler.getText(response); } } - פותחים מחדש את הקובץ
LoggingEventGoogleCloudEncoder.javaב-Cloud Shell Editor:cloudshell edit "${HOME}/codelab-o11y/src/main/java/com/example/demo/LoggingEventGoogleCloudEncoder.java" - מחליפים את הקוד הנוכחי בגרסה שמוסיפה מאפייני מעקב ליומני הרישום שנכתבו. הוספת המאפיינים מאפשרת לקשר בין היומנים לבין טווחי המעקב הנכונים. כדי להחליף את הקוד, מוחקים את התוכן של הקובץ ומעתיקים את הקוד שלמטה אל העורך:
package com.example.demo; import static ch.qos.logback.core.CoreConstants.UTF_8_CHARSET; import java.time.Instant; import java.util.HashMap; import ch.qos.logback.core.encoder.EncoderBase; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import com.google.cloud.ServiceOptions; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.context.Context; import com.google.gson.Gson; public class LoggingEventGoogleCloudEncoder extends EncoderBase<ILoggingEvent> { private static final byte[] EMPTY_BYTES = new byte[0]; private final Gson gson; private final String projectId; private final String tracePrefix; public LoggingEventGoogleCloudEncoder() { this.gson = new Gson(); this.projectId = lookUpProjectId(); this.tracePrefix = "projects/" + (projectId == null ? "" : projectId) + "/traces/"; } private static String lookUpProjectId() { return ServiceOptions.getDefaultProjectId(); } @Override public byte[] headerBytes() { return EMPTY_BYTES; } @Override public byte[] encode(ILoggingEvent e) { var timestamp = Instant.ofEpochMilli(e.getTimeStamp()); var fields = new HashMap<String, Object>() { { put("timestamp", timestamp.toString()); put("severity", severityFor(e.getLevel())); put("message", e.getMessage()); SpanContext context = Span.fromContext(Context.current()).getSpanContext(); if (context.isValid()) { put("logging.googleapis.com/trace", tracePrefix + context.getTraceId()); put("logging.googleapis.com/spanId", context.getSpanId()); put("logging.googleapis.com/trace_sampled", Boolean.toString(context.isSampled())); } } }; var params = e.getKeyValuePairs(); if (params != null && params.size() > 0) { params.forEach(kv -> fields.putIfAbsent(kv.key, kv.value)); } var data = gson.toJson(fields) + "\n"; return data.getBytes(UTF_8_CHARSET); } @Override public byte[] footerBytes() { return EMPTY_BYTES; } private static String severityFor(Level level) { switch (level.toInt()) { case Level.TRACE_INT: return "DEBUG"; case Level.DEBUG_INT: return "DEBUG"; case Level.INFO_INT: return "INFO"; case Level.WARN_INT: return "WARNING"; case Level.ERROR_INT: return "ERROR"; default: return "DEFAULT"; } } }
אחרי כמה שניות, Cloud Shell Editor שומר את השינויים באופן אוטומטי.
פריסת הקוד של אפליקציית ה-AI הגנרטיבי ב-Cloud Run
- בחלון הטרמינל, מריצים את הפקודה לפריסת קוד המקור של האפליקציה ב-Cloud Run.
אם מוצגת ההודעה הבאה, שמציינת שהפקודה תיצור מאגר חדש. לוחצים עלgcloud run deploy codelab-o11y-service \ --source="${HOME}/codelab-o11y/" \ --region=us-central1 \ --allow-unauthenticatedEnter. תהליך הפריסה עשוי להימשך כמה דקות. אחרי שתהליך הפריסה יושלם, יוצגו נתונים שדומים לאלה שמופיעים בדוגמה הבאה:Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [us-central1] will be created. Do you want to continue (Y/n)?
Service [codelab-o11y-service] revision [codelab-o11y-service-00001-t2q] has been deployed and is serving 100 percent of traffic. Service URL: https://codelab-o11y-service-12345678901.us-central1.run.app
- מעתיקים את כתובת ה-URL של שירות Cloud Run שמוצגת לכרטיסייה או לחלון נפרדים בדפדפן. לחלופין, מריצים את הפקודה הבאה בטרמינל כדי להדפיס את כתובת ה-URL של השירות, ולוחצים על כתובת ה-URL שמוצגת תוך כדי החזקת המקש Ctrl כדי לפתוח את כתובת ה-URL:
כשפותחים את כתובת האתר, יכול להיות שתופיע שגיאה 500 או ההודעה:gcloud run services list \ --format='value(URL)' \ --filter='SERVICE:"codelab-o11y-service"' המשמעות היא שהפריסה של השירותים לא הסתיימה. ממתינים כמה רגעים ומרעננים את הדף. בסוף תראו טקסט שמתחיל במילים עובדות מעניינות על כלבים ומכיל 10 עובדות מעניינות על כלבים.Sorry, this is just a placeholder...
כדי ליצור נתוני טלמטריה, פותחים את כתובת ה-URL של השירות. כדי לקבל תוצאות שונות, צריך לרענן את הדף תוך כדי שינוי הערך של הפרמטר ?animal=.
עיון בנתוני מעקב של אפליקציות
- כדי לפתוח את הדף Trace explorer במסוף Cloud, לוחצים על הלחצן שלמטה:
- בוחרים באחד מהמעקבים האחרונים. אמורים להופיע 5 או 6 טווחי כתובות IP שדומים למה שרואים בצילום המסך שלמטה.

- מחפשים את היחידה הלוגית למעקב שעוקבת אחרי הקריאה לגורם המטפל באירועים (השיטה
fun_facts). זה יהיה התג האחרון עם השם/. - בחלונית פרטי המעקב, בוחרים באפשרות יומנים ואירועים. יוצגו יומני אפליקציות שקשורים ליחידה הלוגית למעקב הספציפית הזו. הקורלציה מזוהה באמצעות מזהי העקבות והטווחים בעקבות וביומן. אמור להופיע יומן האפליקציה שכתבה את ההנחיה ואת התשובה של Vertex API.
עיון במדד של מונה
- לוחצים על הלחצן שלמטה כדי לפתוח את הדף Metrics Explorer במסוף Cloud:
- בסרגל הכלים של החלונית ליצירת שאילתות, לוחצים על הלחצן ששמו < > MQL או < > PromQL. התמונה שלמטה מראה איפה נמצא הכפתור.

- מוודאים שהאפשרות PromQL נבחרה במתג שפה. המתג לשפה נמצא באותה סרגל כלים שבו אפשר לעצב את השאילתה.
- מזינים את השאילתה בעורך השאילתות:
sum(rate(workload_googleapis_com:model_call_counter{monitored_resource="generic_task"}[${__interval}])) - לוחצים על Run Query (הפעלת שאילתה). אם המתג Auto-run (הרצה אוטומטית) מופעל, הכפתור Run Query (הפעלת שאילתה) לא מוצג.
11. (אופציונלי) מידע רגיש מוסתר מיומנים
בשלב 10 רשמנו מידע על האינטראקציה של האפליקציה עם מודל Gemini. המידע הזה כלל את שם החיה, את ההנחיה בפועל ואת התשובה של המודל. אמנם שמירת המידע הזה ביומן אמורה להיות בטוחה, אבל זה לא בהכרח נכון לגבי תרחישים רבים אחרים. יכול להיות שההנחיה תכלול מידע אישי או מידע רגיש אחר שהמשתמש לא רוצה שיישמר. כדי לפתור את הבעיה הזו, אפשר לערפל את המידע האישי הרגיש שנכתב ב-Cloud Logging. כדי לצמצם את השינויים בקוד, מומלץ להשתמש בפתרון הבא.
- יצירת נושא PubSub לאחסון רשומות ביומן
- יוצרים sink ביומן שמפנה יומנים שהועברו לנושא PubSub.
- יוצרים צינור Dataflow שמשנה יומנים שמופנים לנושא PubSub באמצעות השלבים הבאים:
- קריאת רשומה ביומן מנושא PubSub
- בדיקת מטען הייעודי (payload) של הרשומה למידע רגיש באמצעות DLP inspection API
- מצנזרים את המידע הרגיש במטען הייעודי (payload) באמצעות אחת משיטות הצנזור של DLP
- כתיבת רשומה ביומן שעברה טשטוש ב-Cloud Logging
- פריסת צינור עיבוד הנתונים
12. (אופציונלי) ניקוי
כדי למנוע את הסיכון לחיובים על משאבים וממשקי API שנעשה בהם שימוש ב-codelab, מומלץ למחוק את המשאבים אחרי שמסיימים את ה-lab. הדרך הקלה ביותר לבטל את החיוב היא למחוק את הפרויקט שיצרתם בשביל ה-codelab.
- כדי למחוק את הפרויקט, מריצים את הפקודה למחיקת פרויקט בטרמינל:
אם מוחקים את פרויקט ה-Cloud, החיוב על כל המשאבים וממשקי ה-API שנעשה בהם שימוש באותו פרויקט מופסק. ההודעה הבאה תוצג לכם, כש-PROJECT_ID=$(gcloud config get-value project) gcloud projects delete ${PROJECT_ID} --quietPROJECT_IDהוא מזהה הפרויקט שלכם:Deleted [https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID]. You can undo this operation for a limited period by running the command below. $ gcloud projects undelete PROJECT_ID See https://cloud.google.com/resource-manager/docs/creating-managing-projects for information on shutting down projects. - (אופציונלי) אם מופיעה שגיאה, צריך לעיין בשלב 5 כדי למצוא את מזהה הפרויקט שבו השתמשתם במהלך הסדנה. מחליפים אותו בפקודה שמופיעה בהוראה הראשונה. לדוגמה, אם מזהה הפרויקט הוא
lab-example-project, הפקודה תהיה:gcloud projects delete lab-project-id-example --quiet
13. מזל טוב
בשיעור ה-Lab הזה יצרתם אפליקציית AI גנרטיבי שמשתמשת במודל Gemini כדי לבצע חיזויים. והגדרנו באפליקציה יכולות בסיסיות של מעקב ורישום ביומן. פרסתם את האפליקציה ואת השינויים מקוד המקור ל-Cloud Run. אחר כך תוכלו להשתמש במוצרי Google Cloud Observability כדי לעקוב אחרי הביצועים של האפליקציה, וכך לוודא שהיא אמינה.
אם אתם רוצים להשתתף במחקר על חוויית המשתמש (UX) כדי לעזור לנו לשפר את המוצרים שעבדתם איתם היום, אתם יכולים להירשם כאן.
ריכזנו כאן כמה אפשרויות להמשך הלמידה:
- Codelab How to deploy gemini powered chat app on Cloud Run
- Codelab How to use Gemini function calling with Cloud Run
- איך משתמשים ב-Cloud Run Jobs Video Intelligence API כדי לעבד סרטון סצנה אחר סצנה
- סדנה על פי דרישה Google Kubernetes Engine Onboard
- מידע נוסף על הגדרת מדדי מונה והפצה באמצעות יומני אפליקציות
- כתיבת מדדים של OTLP באמצעות OpenTelemetry sidecar
- הפניה לשימוש בטלמטריה פתוחה ב-Google Cloud