1. מבוא
בשיעור ה-Lab הזה תבנו שירות אינטרנט ליצירת חידונים של טריוויה ותשלבו אותו באפליקציה כיפית ופעילה. תשתמשו בשפת תכנות שונה מזו שאולי השתמשתם בה בעבר: אנגלית!
מה עושים?
- תנסחו הנחיה ליצירת חידון טריוויה לפי קבוצת קריטריונים.
- תבנו אפליקציית אינטרנט פשוטה ותוודאו שהיא פועלת כצפוי בסביבת הפיתוח שלכם.
- תוסיפו בהדרגה לוגיקה לאפליקציית האינטרנט כדי להפוך אותה לשרת API שיוצר חידונים לפי קבוצה של פרמטרים לקלט.
- תלמדו כמה קל לפרוס את שירות יצירת החידונים בענן באמצעות Google Cloud Run.
- לבסוף, תגדירו אפליקציה אמיתית ( quizaic.com) לשימוש בשירות שיצרתם ליצירת חידונים, ותוכלו לשחק בחידונים בזמן אמת על סמך הפלט.
מה תלמדו...
- איך יוצרים הנחיה מבוססת-תבנית למודל שפה גדול (LLM).
- איך יוצרים אפליקציית שרת אינטרנט פשוטה ב-Python.
- איך מוסיפים תמיכה ב-LLM של Google לאפליקציית האינטרנט.
- איך פורסים את האפליקציה בענן כדי שכל אחד יוכל לנסות את היצירה החדשה.
- איך לשלב את מחולל הבוחנים באפליקציה גדולה יותר.
מה צריך...
- דפדפן האינטרנט Chrome
- חשבון Google
- פרויקט ב-Cloud עם חיוב מופעל
שיעור ה-Lab הזה מיועד למפתחים בכל הרמות, כולל מתחילים. אמנם תשתמשו ב-Python, אבל לא צריך להכיר את התכנות ב-Python כדי להבין מה קורה, כי נסביר את כל הקוד שיוצג.
2. הגדרה

בקטע הזה מפורט כל מה שצריך לעשות כדי להתחיל את שיעור ה-Lab.
הגדרת סביבה בקצב אישי
- נכנסים ל-מסוף Google Cloud ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. אם עדיין אין לכם חשבון Gmail או Google Workspace, אתם צריכים ליצור חשבון.



- שם הפרויקט הוא השם המוצג למשתתפים בפרויקט. זו מחרוזת תווים שלא נמצאת בשימוש ב-Google APIs. תמיד אפשר לעדכן את המיקום.
- מזהה הפרויקט הוא ייחודי לכל הפרויקטים ב-Google Cloud ואי אפשר לשנות אותו אחרי שהוא מוגדר. מסוף Cloud יוצר באופן אוטומטי מחרוזת ייחודית, ובדרך כלל לא צריך לדעת מה היא. ברוב ה-Codelabs, תצטרכו להפנות למזהה הפרויקט (בדרך כלל מסומן כ-
PROJECT_ID). אם אתם לא אוהבים את המזהה שנוצר, אתם יכולים ליצור מזהה אקראי אחר. אפשר גם לנסות שם משתמש משלכם ולבדוק אם הוא זמין. אי אפשר לשנות את ההגדרה הזו אחרי השלב הזה, והיא נשארת לאורך הפרויקט. - לידיעתכם, יש ערך שלישי, מספר פרויקט, שחלק מממשקי ה-API משתמשים בו. מידע נוסף על שלושת הערכים האלה מופיע במאמרי העזרה.
- בשלב הבא, תצטרכו להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבי Cloud או בממשקי API של Cloud. השלמת ה-codelab הזה לא תעלה לכם הרבה, אם בכלל. כדי להשבית את המשאבים ולמנוע חיובים נוספים אחרי שתסיימו את המדריך הזה, תוכלו למחוק את המשאבים שיצרתם או למחוק את הפרויקט. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.
הפעלת Cloud Shell
בשיעור ה-Lab הזה תעבדו בסשן של Cloud Shell, שהוא מתורגמן פקודות שמתארח במכונה וירטואלית שפועלת בענן של Google. אפשר להריץ את הקטע הזה בקלות במחשב שלכם, אבל השימוש ב-Cloud Shell מאפשר לכולם גישה לחוויה שניתנת לשחזור בסביבה עקבית. אחרי המעבדה, אתם מוזמנים לנסות שוב את החלק הזה במחשב שלכם.

הפעלת Cloud Shell
- ב-Cloud Console, לוחצים על Activate Cloud Shell
.

אם זו הפעם הראשונה שאתם מפעילים את Cloud Shell, יוצג לכם מסך ביניים עם תיאור של השירות. אם מוצג לכם מסך ביניים, לוחצים על המשך.

יחלפו כמה רגעים עד שההקצאה והחיבור ל-Cloud Shell יושלמו.

המכונה הווירטואלית הזו כוללת את כל הכלים הדרושים למפתחים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר מאוד את הביצועים והאימות של הרשת. אפשר לבצע את רוב העבודה ב-codelab הזה, אם לא את כולה, באמצעות דפדפן.
אחרי שמתחברים ל-Cloud Shell, אמור להופיע אימות ושהפרויקט מוגדר לפי מזהה הפרויקט.
- מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שאתם מאומתים:
gcloud auth list
פלט הפקודה
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
- מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שפקודת gcloud מכירה את הפרויקט:
gcloud config list project
פלט הפקודה
[core] project = <PROJECT_ID>
אם לא, אפשר להגדיר אותו באמצעות הפקודה הזו:
gcloud config set project <PROJECT_ID>
פלט הפקודה
Updated property [core/project].
הפעלת חלק מממשקי ה-API
בשלבים הבאים תראו איפה השירותים האלה נדרשים (ולמה), אבל בינתיים, מריצים את הפקודה הזו כדי לתת לפרויקט גישה ל-Cloud Build, ל-Artifact Registry, ל-Vertex AI ול-Cloud Run:
gcloud services enable cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
aiplatform.googleapis.com \
run.googleapis.com
אמורה להופיע הודעת הצלחה שדומה לזו:
Operation "operations/acf.cc11852d-40af-47ad-9d59-477a12847c9e" finished successfully.
3. יצירת הנחיות – תכנות בשפה טבעית

נתחיל בלימוד איך לפתח הנחיה למודל שפה גדול (LLM). עוברים אל מסוף Google Cloud > Vertex AI > Vertex AI Studio (Language). אתם אמורים לראות דף כמו זה:

בקטע Generate Text, לוחצים על הלחצן Text Prompt. בתיבת הדו-שיח הבאה, מזינים הנחיה שלדעתכם תהיה יעילה ליצירת חידון טריוויה בהתאם לדרישות הבאות:
- נושא: היסטוריה עולמית
- מספר השאלות: 5
- רמת הקושי: בינונית
- שפה: אנגלית
לוחצים על הלחצן 'שליחה' כדי לראות את הפלט.
כפי שמוצג בצילום המסך הבא, בחלונית הימנית אפשר לבחור את המודל שרוצים להשתמש בו ולשנות חלק מההגדרות:

ההגדרות הבאות זמינות:
- האזור הוא המקום שבו הבקשה ליצירת התוכן צריכה לפעול.
- בקטע Model (מודל) בוחרים את מודל השפה הגדול (LLM) שרוצים להשתמש בו. ב-codelab הזה, כדאי להשתמש ב-gemini-1.0-pro-001.
- הפרמטר Temperature שולט במידת האקראיות בבחירת האסימון. טמפרטורות נמוכות טובות להנחיות עם ציפייה לתשובה נכונה או מדויקת, ואילו טמפרטורות גבוהות יכולות להוביל לתוצאות יותר מגוונות או לא צפויות.
- מגבלת הטוקנים קובעת את כמות הטקסט המקסימלית שמתקבלת מהנחיה אחת. טוקן הוא בערך ארבעה תווים. ערך ברירת המחדל הוא 1024.
- ההגדרה Top-k משנה את האופן שבו המודל בוחר אסימונים לפלט. ערך של 1 בפרמטר top-k אומר שהטוקן שנבחר הוא הטוקן הסביר ביותר מבין כל הטוקנים באוצר המילים של המודל (נקרא גם פענוח חמדן), בעוד שערך של 3 בפרמטר top-k אומר שהטוקן הבא נבחר מבין 3 הטוקנים הסבירים ביותר (באמצעות רמת אקראיות). ערך ברירת המחדל של top-k הוא 40.
- הפרמטר Top-p משנה את האופן שבו המודל בוחר אסימונים לפלט. הטוקנים נבחרים מהסבירים ביותר לסבירים פחות עד שסכום ההסתברויות שלהם שווה לערך של top-p.
- מספר התשובות המקסימלי הוא מספר התשובות המקסימלי של המודל שנוצרות לכל פרומפט.
- רצף עצירה הוא סדרה של תווים (כולל רווחים) שמפסיקה את תהליך יצירת התשובות אם המודל נתקל בה.
- ההגדרה 'הצגת התשובות באופן שוטף' קובעת אם התשובות יוצגו כשהן מוכנות או כשהן נוצרות.
- הסף של מסנן הבטיחות קובע את הסבירות שתראו תשובות שעלולות להיות מזיקות.
אחרי שיוצרים הנחיה שנראה שמפיקה חידון סביר בהתאם לדרישות שצוינו למעלה, אפשר לנתח את החידון הזה באמצעות קוד מותאם אישית. אבל לא יהיה נחמד יותר אם ה-LLM ייצור את החידון בפורמט מובנה שנוכל לטעון ישירות לתוכנית שלנו? התוכנית שבה נשתמש בהמשך המעבדה הזו כדי להפעיל את הגנרטור מצפה שהחידונים ייוצגו בפורמט JSON, שהוא פורמט פופולרי חוצה-שפות לייצוג נתונים מובְנים.
החידונים במעבדה הזו מוגדרים כמערך של אובייקטים, שכל אובייקט מכיל שאלה, מערך של תשובות אפשריות לשאלה ותשובה נכונה. הנה קידוד ה-JSON לחידונים בשיעור ה-Lab הזה:
[
{
"question": "Who was the first person to walk on the moon?",
"responses": [
"Neil Armstrong",
"Buzz Aldrin",
"Michael Collins",
"Yuri Gagarin"
],
"correct": "Neil Armstrong"
},
{
"question": "What was the name of the war that took place between the British and the French in North America from 1754 to 1763??",
"responses": [
"The French and Indian War",
"The Seven Years' War",
"The War of the Austrian Succession",
"The Great War"
],
"correct": "The French and Indian War"
},
...
]
נסו לשנות את ההנחיה כך שהבוחן יוצג בפורמט JSON הנדרש.
- מציינים במילים את הפורמט המדויק שאתם מחפשים (לדוגמה, המשפט המוטה שלמעלה).
- בהנחיה, כדאי לכלול דוגמה לפורמט JSON הרצוי.
אחרי שיוצרים הנחיה ליצירת חידונים לפי המפרט הרצוי, לוחצים על הלחצן GET CODE בפינה השמאלית העליונה של הדף כדי לראות קוד Python שאפשר להשתמש בו כדי לשלוח את ההנחיה באופן אוטומטי למודל LLM של Vertex AI. אם אתם רוצים להשתמש בשפת תכנות אחרת מלבד Python, תוכלו לעיין בכתובת https://cloud.google.com/vertex-ai/docs/samples?text=generative.
4. בניית שרת אינטרנט פשוט

עכשיו שיש לנו הנחיה שעובדת, אנחנו רוצים לשלב אותה באפליקציה גדולה יותר. כמובן שאפשר להטמיע את ההנחיה בקוד המקור של האפליקציה הגדולה יותר, אבל אנחנו רוצים שהגנרטור יפעל כמיקרו-שירות שמספק שירות ליצירת חידונים לאפליקציות אחרות. כדי לעשות את זה, נצטרך ליצור שרת אינטרנט פשוט ולהפוך אותו לזמין לציבור. בשלבים הבאים נסביר איך עושים את זה.
כדי להתחיל, לוחצים על הלחצן Open Editor בחלק העליון של חלונית Cloud Shell. כך הוא נראה:

לאחר מכן תועברו לסביבת IDE שדומה ל-Visual Studio Code, שבה תוכלו ליצור פרויקטים, לערוך קוד מקור, להריץ את התוכניות וכו'.
אם המסך צפוף מדי, אפשר להרחיב או לצמצם את הקו המפריד בין המסוף לבין חלון העריכה או חלון הטרמינל. כדי לעשות זאת, גוררים את הקו האופקי שבין שני האזורים האלה, שמודגש כאן:

אפשר לעבור בין העורך לבין הטרמינל בלחיצה על הלחצנים Open Editor ו-Open Terminal, בהתאמה. עכשיו נסו לעבור הלוך ושוב בין שתי הסביבות האלה.
לאחר מכן, יוצרים תיקייה לאחסון העבודה ב-Lab הזה. לשם כך, לוחצים על לחצן הוספת התיקייה
, מזינים quiz-generator ומקישים על Enter. כל הקבצים שתיצרו בשיעור ה-Lab הזה וכל העבודה שתבצעו ב-Cloud Shell יתבצעו בתיקייה הזו.
עכשיו יוצרים קובץ requirements.txt. הקובץ הזה מציין ל-Python באילו ספריות האפליקציה תלויה. באפליקציית האינטרנט הפשוטה הזו, תשתמשו במודול פופולרי של Python לבניית שרתי אינטרנט שנקרא Flask, ספריית הלקוח google-cloud-aiplatform, ובמסגרת של שרת אינטרנט שנקראת gunicorn. בחלונית הניווט של הקבצים, לוחצים לחיצה ימנית על התיקייה quiz-generator ובוחרים באפשרות New file בתפריט, כמו שמוצג כאן:

כשמופיעה בקשה להזין את השם החדש של הקובץ, מזינים requirements.txt ומקישים על מקש Enter. מוודאים שהקובץ החדש מגיע לתיקיית הפרויקט quiz-generator.
מדביקים את השורות הבאות בקובץ החדש כדי לציין שהאפליקציה תלויה בחבילת Python flask, בשרת האינטרנט gunicorn ובספריית הלקוח google-cloud-aiplatform, וגם בגרסאות המשויכות של כל אחת מהן.
flask==3.0.0 gunicorn==21.2.0 google-cloud-aiplatform==1.47.0
אין צורך לשמור את הקובץ באופן מפורש כי Cloud Editor שומר את השינויים באופן אוטומטי.
באמצעות אותה טכניקה, יוצרים קובץ חדש נוסף בשם main.py. זה יהיה קובץ המקור הראשי (והיחיד) של האפליקציה ב-Python. שוב, מוודאים שהקובץ החדש נמצא בתיקייה quiz-generator.
מוסיפים את הקוד הבא לקובץ הזה:
from flask import Flask
import os
app = Flask(__name__) # Create a Flask object.
PORT = os.environ.get("PORT") # Get PORT setting from environment.
if not PORT:
PORT = 8080
# The app.route decorator routes any GET requests sent to the root path
# to this function, which responds with a "Hello world!" HTML document.
@app.route("/", methods=["GET"])
def say_hello():
html = "<h1>Hello world!</h1>"
return html
# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT)
חוזרים לטרמינל ועוברים לתיקיית הפרויקט באמצעות הפקודה הבאה:
cd quiz-generator
מריצים את הפקודה הבאה כדי להתקין את יחסי התלות של הפרויקט:
pip3 install -r requirements.txt
אחרי התקנת יחסי התלות, הפלט אמור להסתיים כך:
Successfully installed flask-3.0.0
עכשיו מפעילים את האפליקציה על ידי הרצת הפקודה הבאה בטרמינל:
flask --app main.py --debug run --port 8080
בשלב הזה, האפליקציה פועלת במכונה הווירטואלית שמוקדשת לסשן שלכם ב-Cloud Shell. Cloud Shell כולל מנגנון proxy שמאפשר לכם לגשת לשרתי אינטרנט (כמו זה שהפעלתם עכשיו) שפועלים במכונה הוירטואלית שלכם מכל מקום באינטרנט הגלובלי.
לוחצים על הלחצן web preview ואז על פריט התפריט Preview on Port 8080, כמו שמוצג כאן:

תיפתח כרטיסייה בדפדפן האינטרנט עם האפליקציה הפועלת, והיא אמורה להיראות בערך כך:

5. הוספת שיטת יצירה עם ניתוח פרמטרים
עכשיו אנחנו רוצים להוסיף תמיכה בהפעלת שיטה חדשה בשם generate. כדי לעשות זאת, מוסיפים הצהרת ייבוא כדי לשנות את בקשת ה-HTTP ומשנים את המסלול הראשי כדי לנתח את הבקשה הזו ולהדפיס פרמטרים, באופן הבא:
from flask import Flask
from flask import request #<-CHANGED
import os
app = Flask(__name__) # Create a Flask object.
PORT = os.environ.get("PORT") # Get PORT setting from environment.
if not PORT:
PORT = 8080
# The app.route decorator routes any GET requests sent to the /generate
# path to this function, which responds with "Generating:" followed by
# the body of the request.
@app.route("/", methods=["GET"]) #<-CHANGED
def generate(): #<-CHANGED
params = request.args.to_dict() #<-CHANGED
html = f"<h1>Quiz Generator</h1>" #<-CHANGED
for param in params: #<-CHANGED
html += f"<br>{param}={params[param]}" #<-CHANGED
return html #<-CHANGED
# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT)
עכשיו טוענים מחדש את הכרטיסייה הקיימת בדפדפן האינטרנט כדי לראות את התוצאות. הפעם אמור להופיע הכלי 'יצירת חידון', יחד עם פרמטר שאילתה שנוסף אוטומטית לכתובת ה-URL (authuser). נסו להוסיף עוד שני פרמטרים על ידי הוספת המחרוזת '`¶m1=val1¶m2=val2`' לסוף כתובת ה-URL בסרגל הכתובות של הדפדפן, טעינה מחדש של הדף, ואמור להופיע משהו כזה:

אחרי שראינו איך לשלוח ולנתח פרמטרים של שאילתות בכתובת URL, נוסיף תמיכה בפרמטרים הספציפיים שנרצה לשלוח לגנרטור החידונים שלנו, שהם:
-
topic– נושא הבוחן הרצוי -
num_q– מספר השאלות הרצוי -
diff– רמת הקושי הרצויה (קלה, בינונית, קשה) -
lang– שפת הבוחן הרצויה
from flask import Flask
from flask import request
import os
# Default quiz settings #<-CHANGED
TOPIC = "History" #<-CHANGED
NUM_Q = "5" #<-CHANGED
DIFF = "intermediate" #<-CHANGED
LANG = "English" #<-CHANGED
app = Flask(__name__) # Create a Flask object.
PORT = os.environ.get("PORT") # Get PORT setting from environment.
if not PORT:
PORT = 8080
# This function takes a dictionary, a name, and a default value.
# If the name exists as a key in the dictionary, the corresponding
# value is returned. Otherwise, the default value is returned.
def check(args, name, default): #<-CHANGED
if name in args: #<-CHANGED
return args[name] #<-CHANGED
return default #<-CHANGED
# The app.route decorator routes any GET requests sent to the /generate
# path to this function, which responds with "Generating:" followed by
# the body of the request.
@app.route("/", methods=["GET"])
# This function generates a quiz using Vertex AI.
def generate():
args = request.args.to_dict() #<-CHANGED
topic = check(args, "topic", TOPIC) #<-CHANGED
num_q = check(args, "num_q", NUM_Q) #<-CHANGED
diff = check(args, "diff", DIFF) #<-CHANGED
lang = check(args, "lang", LANG) #<-CHANGED
html = f"""
<h1>Quiz Generator</h1><br>
{topic=}<br>
{num_q=}<br>
{diff=}<br>
{lang=}""" #<-CHANGED
return html
# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT)
עכשיו טוענים מחדש את הכרטיסייה הקיימת בדפדפן האינטרנט כדי לראות את התוצאות. אתם אמורים לראות דף אינטרנט שדומה לזה:

כדאי לנסות לשנות את כתובת ה-URL כדי להגדיר ערכים לפרמטרים שונים. לדוגמה, נסו להשתמש בסיומת ?authuser=0&topic=Literature&num_q=10&diff=easy&lang=French בסוף כתובת ה-URL בסרגל הכתובות:

6. הוספה ועיצוב של הפרומפט
בשלב הבא, נוסיף תמיכה בפרמטרים הספציפיים שנרצה לשלוח לגנרטור החידונים שלנו, והם:
-
topic– נושא הבוחן הרצוי -
num_q– מספר השאלות הרצוי -
diff– רמת הקושי הרצויה (קלה, בינונית, קשה) -
lang– שפת הבוחן הרצויה
מעתיקים את ההנחיה שפיתחתם באמצעות Vertex Generative AI Studio בשלב קודם, אבל משנים את הערכים שמוגדרים בקוד לנושא, למספר השאלות ולרמת הקושי באמצעות המחרוזות הבאות:
- {topic}
- {num_q}
- {diff}
- {lang}
from flask import Flask
from flask import request
import os
# Default quiz settings
TOPIC = "History"
NUM_Q = 5
DIFF = "intermediate"
LANG = "English"
PROMPT = """
Generate a quiz according to the following specifications:
- topic: {topic}
- num_q: {num_q}
- diff: {diff}
- lang: {lang}
Output should be (only) an unquoted json array of objects with keys:
"Question", "responses", and "correct".
""" #<-CHANGED
app = Flask(__name__) # Create a Flask object.
PORT = os.environ.get("PORT") # Get PORT setting from environment.
if not PORT:
PORT = 8080
# This function takes a dictionary, a name, and a default value.
# If the name exists as a key in the dictionary, the corresponding
# value is returned. Otherwise, the default value is returned.
def check(args, name, default):
if name in args:
return args[name]
return default
# The app.route decorator routes any GET requests sent to the /generate
# path to this function, which responds with "Generating:" followed by
# the body of the request.
@app.route("/", methods=["GET"])
# This function generates a quiz using Vertex AI.
def generate():
args = request.args.to_dict()
topic = check(args, "topic", TOPIC)
num_q = check(args, "num_q", NUM_Q)
diff = check(args, "diff", DIFF)
lang = check(args, "lang", LANG)
prompt = PROMPT.format(topic=topic, num_q=num_q, diff=diff, lang=lang) #<-CHANGED
html = f"<h1>Prompt:</h1><br><pre>{prompt}</pre>" #<-CHANGED
return html
# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT)
עכשיו טוענים מחדש את הכרטיסייה הקיימת בדפדפן האינטרנט כדי לראות את התוצאות. אתם אמורים לראות דף אינטרנט שדומה לזה:

אפשר לנסות לשנות את כתובת ה-URL כדי לשנות את ארבעת הפרמטרים האלה.
7. הוספת ספריית הלקוח של Vertex AI
עכשיו אפשר להשתמש בספריית הלקוח של Vertex AI Python כדי ליצור את הבוחן. הפעולה הזו תבצע אוטומטית את ההנחיות האינטראקטיביות שביצעתם בשלב 3, ותעניק לשירות הגנרטור גישה פרוגרמטית ליכולות ה-LLM של Google. מעדכנים את הקובץ main.py באופן הבא:
חשוב להחליף את YOUR_PROJECT במזהה הפרויקט בפועל.
from flask import Flask
from flask import request
from flask import Response #<-CHANGED
import os
import vertexai
from vertexai.generative_models import GenerativeModel #<-CHANGED
# Default quiz settings
TOPIC = "History"
NUM_Q = 5
DIFF = "intermediate"
LANG = "English"
MODEL = "gemini-1.0-pro" #<-CHANGED
PROMPT = """
Generate a quiz according to the following specifications:
- topic: {topic}
- num_q: {num_q}
- diff: {diff}
- lang: {lang}
Output should be (only) an unquoted json array of objects with keys "question", "responses", and "correct".
"""
app = Flask(__name__) # Create a Flask object.
PORT = os.environ.get("PORT") # Get PORT setting from environment.
if not PORT:
PORT = 8080
# Initialize Vertex AI access.
vertexai.init(project="YOUR_PROJECT", location="us-central1") #<-CHANGED
parameters = { #<-CHANGED
"candidate_count": 1, #<-CHANGED
"max_output_tokens": 1024, #<-CHANGED
"temperature": 0.5, #<-CHANGED
"top_p": 0.8, #<-CHANGED
"top_k": 40, #<-CHANGED
} #<-CHANGED
model = GenerativeModel(MODEL) #<-CHANGED
# This function takes a dictionary, a name, and a default value.
# If the name exists as a key in the dictionary, the corresponding
# value is returned. Otherwise, the default value is returned.
def check(args, name, default):
if name in args:
return args[name]
return default
# The app.route decorator routes any GET requests sent to the /generate
# path to this function, which responds with "Generating:" followed by
# the body of the request.
@app.route("/", methods=["GET"])
# This function generates a quiz using Vertex AI.
def generate():
args = request.args.to_dict()
topic = check(args, "topic", TOPIC)
num_q = check(args, "num_q", NUM_Q)
diff = check(args, "diff", DIFF)
lang = check(args, "lang", LANG)
prompt = PROMPT.format(topic=topic, num_q=num_q, diff=diff, lang=lang)
response = model.generate_content(prompt, generation_config=parameters) #<-CHANGED
print(f"Response from Model: {response.text}") #<-CHANGED
html = f"{response.text}" #<-CHANGED
return Response(html, mimetype="application/json") #<-CHANGED
# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT)
עכשיו טוענים מחדש את הכרטיסייה הקיימת בדפדפן האינטרנט כדי לראות את התוצאות. שימו לב: התהליך עשוי להימשך כמה שניות כי עכשיו אתם שולחים בקשה ל-LLM. אתם אמורים לראות דף אינטרנט שדומה לזה:

אפשר לשנות את כתובת ה-URL כדי לבקש נושא אחר לבוחן, מספר שאלות אחר ורמת קושי אחרת.
בזה מסתיים המיקרו-שירות שלכם – מזל טוב! בשלב הבא תלמדו איך לפרוס את השירות בענן כדי שכל אחד יוכל לגשת אליו מכל מקום.
8. לענן!

עכשיו, אחרי שבניתם מחולל חידונים משלכם, אתם רוצים לשתף את הכלי המדהים הזה עם שאר העולם, ולכן הגיע הזמן לפרוס אותו בענן. אבל אתם רוצים לעשות יותר מסתם שיתוף. אתם רוצים לוודא שהיא:
- פועלת בצורה מהימנה – אתם מקבלים סבילות אוטומטית לתקלות במקרה שמחשב שמריץ את האפליקציה שלכם קורס
- התאמה אוטומטית של קנה המידה – האפליקציה תעמוד בקצב של נפחי תנועה גדולים, ותצמצם אוטומטית את טביעת הרגל שלה כשהיא לא בשימוש
- מצמצם את העלויות, כי אתם לא מחויבים על משאבים שאתם לא משתמשים בהם – אתם מחויבים רק על משאבים שנצרכים בזמן התגובה לתנועה
- אפשר לגשת אליו דרך שם דומיין מותאם אישית – יש לכם גישה לפתרון בלחיצה אחת להקצאת שם דומיין מותאם אישית לשירות
- זמן התגובה מצוין – התגובה במצב התחלתי (cold start) סבירה, אבל אפשר לשפר אותה על ידי הגדרת מינימום מופעים
- תומך בהצפנה מקצה לקצה באמצעות אבטחת אינטרנט רגילה של SSL/TLS – כשפורסים שירות, מקבלים הצפנה רגילה של האינטרנט ואת האישורים הנדרשים המתאימים, בחינם ובאופן אוטומטי
כשפורסים את האפליקציה ב-Google Cloud Run, מקבלים את כל היתרונות שצוינו למעלה ועוד. האבן הבסיסית לשיתוף האפליקציה עם Cloud Run היא קונטיינר.
קונטיינרים מאפשרים לנו ליצור תיבה מודולרית שבה אפשר להריץ אפליקציה עם כל התלויות שלה. אפשר להשתמש בקונטיינרים כמעט בכל שרת וירטואלי או אמיתי, ולכן הם מאפשרים לנו לפרוס את האפליקציה שלכם בכל מקום שתרצו, החל משרתים מקומיים ועד לענן, ואפילו להעביר את האפליקציה מספק שירותים אחד לאחר.
כדי לקבל מידע נוסף על קונטיינרים ועל אופן הפעולה שלהם ב-Google Cloud Run, אפשר לעיין ב-codelab בנושא מעבר מפיתוח לייצור בשלושה שלבים פשוטים באמצעות Cloud Run.
פריסת האפליקציה ב-Cloud Run
Cloud Run הוא שירות אזורי, כלומר התשתית שמריצה את שירותי Cloud Run ממוקמת באזור ספציפי ומנוהלת על ידי Google כך שתהיה זמינה באופן יתירתי בכל האזורים בתוך אותו אזור. כדי לפשט את התהליך, בשיעור ה-Lab הזה נשתמש באזור us-central1 שמוגדר מראש.
אנחנו נשתמש בכלי שנקרא buildpack כדי ליצור את הקונטיינר באופן אוטומטי. יוצרים קובץ חדש בשם Procfile בכלי Cloud Editor ומזינים בו את שורת הטקסט הבאה:
web: gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
ההגדרה הזו אומרת למערכת buildpack איך להריץ את האפליקציה בקונטיינר שנוצר אוטומטית. לאחר מכן, מריצים את הפקודה הבאה בטרמינל של Cloud Shell (מאותה ספרייה quiz-generator) :
gcloud run deploy quiz-generator \
--source . \
--region us-central1 \
--allow-unauthenticated
הפקודה gcloud מציינת שרוצים להשתמש ב-Buildpacks כדי ליצור את קובץ אימג' של קונטיינר, על סמך קובצי המקור שנמצאים בספרייה הנוכחית (הסימן dot ב---source . הוא קיצור של הספרייה הנוכחית). מכיוון שהשירות מטפל בקובץ אימג' של קונטיינר באופן מרומז, לא צריך לציין קובץ אימג' של קונטיינר בפקודה gcloud הזו.
מחכים כמה רגעים עד שהפריסה תסתיים. אם הפקודה gcloud מסתיימת ללא שגיאות, היא מחזירה את כתובת ה-URL של השירות החדש:
Building using Buildpacks and deploying container to Cloud Run service [quiz-generator] in project [YOUR_PROJECT] region [YOUR_REGION] OK Building and deploying new service... Done. OK Creating Container Repository... OK Uploading sources... OK Building Container... Logs are available at [https://console.cloud.google.com/cloud-build/builds/0cf1383f-35db-412d -a973-557d5e2cd4a4?project=780573810218]. OK Creating Revision... OK Routing traffic... OK Setting IAM Policy... Done. Service [quiz-generator] revision [quiz-generator-00001-xnr] has been deployed and is serving 100 percent of traffic. Service URL: https://quiz-generator-co24gukjmq-uc.a.run.app
אפשר גם לאחזר את כתובת ה-URL של השירות באמצעות הפקודה הבאה:
gcloud run services describe quiz-generator \ --region us-central1 \ --format "value(status.url)"
אמור להופיע פלט שדומה לזה:
https://quiz-generator-co24gukjmq-uc.a.run.app
הקישור הזה הוא כתובת URL ייעודית עם אבטחת TLS לשירות Cloud Run שלכם. הקישור הזה הוא קבוע (כל עוד לא משביתים את השירות) ואפשר להשתמש בו בכל מקום באינטרנט. הוא לא משתמש במנגנון ה-proxy של Cloud Shell שצוין קודם, שהיה תלוי במכונה וירטואלית זמנית.
לוחצים על Service URL המודגש כדי לפתוח כרטיסייה בדפדפן האינטרנט עם האפליקציה הפועלת. מוודאים שהתוצאה זהה למה שראיתם בסביבת הפיתוח. כדאי גם לוודא שאפשר לשנות את החידון שנוצר על ידי הוספת פרמטרים בסוף כתובת ה-URL.
מעולה! האפליקציה שלך פועלת עכשיו ב-Google Cloud. האפליקציה שלכם זמינה לציבור, עם הצפנת TLS (HTTPS) והתאמה אוטומטית לעומס לרמות תעבורת נתונים מדהימות, בלי שתצטרכו לחשוב על זה.
9. חיבור כל החלקים
בשלב האחרון הזה, אנחנו מוכנים להריץ את מחולל החידונים כחלק מאפליקציית quizaic. נכנסים לכתובת ה-URL של quizaic, מתחברים לחשבון Google ועוברים לכרטיסייה Create Quiz. בוחרים את סוג הגנרטור Custom, מדביקים את כתובת ה-URL של Cloud Run בשדה כתובת ה-URL, ממלאים את שדות החובה האחרים ושולחים את הטופס.

אחרי כמה רגעים, אמור להיווצר חידון חדש (כמו 'החידון החדש שלי' בתמונה שלמטה), עם תמונה ממוזערת שנוצרה על ידי AI. אפשר לערוך, להפעיל, לשכפל או למחוק את החידון באמצעות הלחצנים המתאימים. הבוחן החדש הזה נוצר באמצעות שירות האינטרנט שפרסת הרגע על סמך ההנחיה המבוססת על תבנית!

10. ניקוי

ב-Cloud Run לא מחויבים כשלא משתמשים בשירות, אבל יכול להיות שתחויבו על אחסון של קובץ אימג' של קונטיינר.
כדי להימנע מחיובים, אפשר למחוק את פרויקט GCP. פעולה כזו תפסיק את החיוב על כל המשאבים שנעשה בהם שימוש בפרויקט. אפשרות אחרת היא למחוק את קובץ אימג' של קונטיינר באמצעות הפקודה הבאה:
gcloud config set artifacts/repository cloud-run-source-deploy gcloud config set artifacts/location us-central1 gcloud artifacts docker images list # Note image tag for resulting list gcloud artifacts docker images delete <IMAGE-TAG>
כדי למחוק את שירות Cloud Run, משתמשים בפקודה הבאה:
gcloud run services delete quiz-generator --region us-central1 --quiet
11. כל הכבוד!

כל הכבוד – יצרתם הנחיה למודל LLM ופרסתם מיקרו-שירות ב-Cloud Run באמצעות ההנחיה הזו. עכשיו אפשר לתכנת בשפה טבעית ולשתף את היצירות עם העולם!
אני רוצה להשאיר אותך עם שאלה חשובה אחת:
אחרי שגרמת לאפליקציה לפעול בסביבת הפיתוח, כמה שורות קוד היית צריך לשנות כדי לפרוס אותה בענן, עם כל המאפיינים ברמת הייצור שמוצעים על ידי Cloud Run?
התשובה היא אפס. :)
עוד codelabs שכדאי לבדוק…
- מעבר מפיתוח לייצור בשלושה שלבים פשוטים באמצעות Cloud Run
- אפליקציה לסיכום טקסט עם Vertex AI ו-Svelte Kit
- אפליקציית Chat עם PaLM API ב-Cloud Run
- פונקציה של Cloud Functions שעוטפת את מודלי PaLM Text Bison
- העברת נתונים ל-AI גנרטיבי באמצעות Spanner ו-Vertex AI Imagen API
מסמכי עזר...
12. קריאה לפעולה
אם נהניתם משיעור ה-Codelab הזה ואתם מתכוונים להשקיע עוד זמן בהתנסות מעשית עם Google Cloud, כדאי לכם להצטרף ל-Google Cloud Innovators עוד היום!

התוכנית Google Cloud Innovators היא בחינם וכוללת:
- דיונים בשידור חי, מפגשי שאלות ותשובות ומפגשי תכנון כדי ללמוד ישירות מעובדי Google
- החדשות האחרונות מ-Google Cloud ישירות לתיבת הדואר הנכנס
- תג דיגיטלי ורקע לשיחות ועידה בווידאו
- 500 קרדיטים לשיעורי Lab ולמידה ב-Skills Boost
כדי להירשם, לוחצים כאן.
