מאב טיפוס לסוכן באמצעות ADK

1. סקירה כללית

איפה מתחילים לבנות באמצעות AI? אצל רובנו, זה מתחיל בשאלה פשוטה: "האם המודל יכול לעזור לי לפתור את הבעיה הזו שאני חושב עליה?". בדיוק בשביל זה יש את Google AI Studio. זה מקום שבו אפשר ליצור אב-טיפוס במהירות לכל דבר. רציתי לשפץ את המטבח ואני בטוח ש-Gemini יכול לעזור לי – אבל אני מהנדס, לא קבלן כללי. אני לא בטוח מה לבקש – יש כל כך הרבה דברים שצריך לקחת בחשבון: תקנות, מתקנים וכו'. בוא נפרק את זה וניתן ל-Gemini ליצור הנחיה מפורטת במיוחד, ואז ליצור תוכנית שיפוץ מלאה וגם להמחיש את השיפוץ! אבל רגע. איך אוכל לעזור לעסקים להתרחב? מזינים את הנציגים!!!

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

ערכת פיתוח סוכנים (ADK)

Agent Development Kit (ADK) היא מסגרת גמישה ומודולרית לפיתוח ולפריסה של סוכני AI. ה-ADK תומך בבניית אפליקציות מורכבות על ידי שילוב של כמה מופעים נפרדים של סוכנים במערכת מרובת סוכנים (MAS).

ב-ADK, מערכת מרובת סוכנים היא אפליקציה שבה סוכנים שונים, שלעתים קרובות יוצרים היררכיה, משתפים פעולה או מתאמים כדי להשיג מטרה גדולה יותר. למבנה כזה של האפליקציה יש יתרונות משמעותיים, כולל מודולריות משופרת, התמחות, שימוש חוזר, תחזוקה ואפשרות להגדיר זרימות בקרה מובנות באמצעות סוכני זרימת עבודה ייעודיים.

מה תפַתחו

רוצה לעבור מהאב-טיפוס של ה-PROMPT שלנו לבניית סוכן??? ניצור סוכן שיעזור ליצור את מסמך ההצעה לפרויקט שיפוץ המטבח. במסגרת ה-Lab הזה:

  1. יצירת סוכן פשוט ליצירת מסמך הצעת שיפוץ באמצעות ADK
  2. אחסון מסמך הצעת השיפוץ שנוצר בקטגוריה של Cloud Storage
  3. בדיקת הסוכן ב-Cloud Shell ובפלט האינטרנטי של הסוכן

דרישות

  • דפדפן, כמו Chrome או Firefox
  • פרויקט ב-Google Cloud שהחיוב בו מופעל.

‫2. לפני שמתחילים

יצירת פרויקט

  1. ב-Google Cloud Console, בדף לבחירת הפרויקט, בוחרים או יוצרים פרויקט ב-Google Cloud.
  2. הקפידו לוודא שהחיוב מופעל בפרויקט שלכם ב-Cloud. כך בודקים אם החיוב מופעל בפרויקט
  3. אם אתם קוראים את המאמר הזה ורוצים לקבל קרדיטים כדי להתחיל להשתמש ב-Google Cloud וב-ADK, אתם יכולים לממש קרדיטים באמצעות הקישור הזה.
  4. אפשר לפעול לפי ההוראות שמופיעות כאן כדי לממש את השובר. לתשומת ליבך, הקישור הזה תקף למימוש רק עד 15 ביולי 2025.
  5. לוחצים על הקישור כדי להפעיל את Cloud Shell. אפשר לעבור בין Cloud Shell Terminal (כדי להפעיל פקודות בענן) לבין Editor (כדי ליצור פרויקטים) בלחיצה על הכפתור המתאים ב-Cloud Shell.
  6. אחרי שמתחברים ל-Cloud Shell, אפשר לבדוק שכבר בוצע אימות ושהפרויקט מוגדר למזהה הפרויקט שלכם באמצעות הפקודה הבאה:
gcloud auth list
  1. מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שפקודת gcloud מכירה את הפרויקט.
gcloud config list project
  1. אם הפרויקט לא מוגדר, משתמשים בפקודה הבאה כדי להגדיר אותו:
gcloud config set project <YOUR_PROJECT_ID>
  1. מוודאים שמותקנת גרסה Python 3.9 ואילך

אפשר לעיין במאמרי העזרה בנושא פקודות gcloud אחרות ושימוש בהן.

3. אב טיפוס

עוברים אל Google AI Studio. מתחילים להקליד את ההנחיה. זו ההנחיה שלי:

I want to renovate my kitchen, basically just remodel it. I don't know where to start. So I want to use Gemini to generate a plan. For that I need a good prompt. Give me a short yet detailed prompt that I can use.

כדי לקבל תגובה אופטימלית, משנים ומגדירים את הפרמטרים בצד שמאל.

על סמך התיאור הפשוט הזה, Gemini יצר בשבילי הנחיה מפורטת במיוחד כדי להתחיל את השיפוץ! בפועל, אנחנו משתמשים ב-Gemini כדי לקבל תשובות טובות עוד יותר מ-AI Studio ומהמודלים שלנו. אפשר גם לבחור מודלים שונים לשימוש, בהתאם לתרחיש השימוש.

בחרנו ב-Gemini 2.5 Pro. זהו מודל חשיבה, כלומר אנחנו מקבלים עוד יותר טוקנים של פלט, במקרה הזה עד 65,000 טוקנים, לניתוחים ארוכים ולמסמכים מפורטים. תיבת החשיבה של Gemini מופיעה כשמפעילים את Gemini 2.5 Pro, שיש לו יכולות חשיבה רציונלית טבעיות והוא יכול לקבל בקשות עם הקשר ארוך.

קטע מהתשובה:

4e4361663df80964.png

‫AI Studio ניתח את הנתונים שלי ויצר את כל הדברים האלה כמו ארונות, משטחי עבודה, חיפוי קיר, ריצוף, כיור, לכידות, לוח צבעים ובחירת חומרים. ‫Gemini אפילו מצטט מקורות!

עכשיו ננסה להחיות את הרעיון עם הנחיה אחרת.

  1. מעתיקים את ההנחיה הזו ומדביקים אותה בכלי לעריכת הנחיות:
Add flat and circular light accessories above the island area for my current kitchen in the attached image.
  1. מצרפים תמונה של המטבח הנוכחי (או שאפשר להשתמש בתמונה לדוגמה של מטבח).
  2. משנים את המודל ל-Gemini 2.0 Flash Preview Image Generation כדי לקבל גישה ליצירת תמונות.

קיבלתי את הפלט הזה:

fb33e7b1f6560a0c.png

זו העוצמה של Gemini!

מפענוח סרטונים, דרך יצירת תמונות מקוריות ועד אימות מידע אמיתי באמצעות חיפוש Google – יש דברים שאפשר ליצור רק באמצעות Gemini.

מ-AI Studio אפשר לקחת את אב הטיפוס הזה, להשיג את מפתח ה-API ולהפוך אותו לאפליקציה מלאה שמבוססת על סוכנים באמצעות היכולות של Vertex AI ADK.

4. הגדרת ADK

עכשיו נעבור לטרמינל של Cloud Shell שהפעלנו בקטע 'לפני שמתחילים':

  1. יצירה והפעלה של סביבה וירטואלית (מומלץ)

בטרמינל של Cloud Shell, יוצרים סביבה וירטואלית:

python -m venv .venv

מפעילים את הסביבה הווירטואלית:

source .venv/bin/activate
  1. התקנת ADK
pip install google-adk

5. מבנה הפרויקט

  1. במסוף Cloud Shell, יוצרים ספריית בסיס לאפליקציות מבוססות-סוכנים במיקום הרצוי בפרויקט:
mkdir agentic-apps
  1. בתוך הספרייה הראשית, יוצרים תיקייה אחת שספציפית לפרויקט הנוכחי:
mkdir renovation-agent
  1. עוברים אל Cloud Shell Editor ויוצרים את מבנה הפרויקט הבא על ידי יצירת הקבצים (ריקים בהתחלה):
renovation-agent/
        __init__.py
        agent.py
        requirements.txt
        .env

6. קוד המקור

  1. עוברים אל init.py ומעדכנים אותו עם התוכן הבא:
from . import agent
  1. עוברים אל agent.py ומעדכנים את הקובץ עם התוכן הבא מהנתיב הבא:

ב-agent.py, מייבאים את יחסי התלות הדרושים, מאחזרים פרמטרים של הגדרות מקובץ ‎ .env ומגדירים את root_agent שיוצר מסמך הצעה ושומר אותו בקטגוריה של Cloud Storage. כדי לבצע את השלב של Cloud Storage, אנחנו משתמשים בכלי שנקרא store_pdf.

הערה: נכון לעכשיו, קובץ ה-PDF הוא ללא עיצוב! בהתבסס על PR של קהילת המפתחים, הוספנו כאן את קטע הקוד הבא [לא נבדק], אתם יכולים להוסיף אותו לשיטה store_pdf:

doc = SimpleDocTemplate(
        pdf_buffer,
        pagesize=letter,
        rightMargin=0.75 * inch,
        leftMargin=0.75 * inch,
        topMargin=0.75 * inch,
        bottomMargin=0.75 * inch
    )

    styles = getSampleStyleSheet()
    story = []

    # --- CUSTOM STYLES FOR HEADERS ---
    # Define a new style for section headers
    styles.add(ParagraphStyle(name='SectionHeader',
                              parent=styles['Normal'],
                              fontName='Helvetica-Bold', # Make it bolder
                              fontSize=14,               # Make it slightly larger
                              leading=16,                # Line spacing
                              spaceAfter=0.15 * inch,    # Space after the header
                              spaceBefore=0.25 * inch,   # Space before the header
                              textColor=black            # Ensure color is bright/black (default is usually black, but explicit is good)
                             ))

    # Define a style for the main document title
    styles.add(ParagraphStyle(name='DocumentTitle',
                              parent=styles['Normal'],
                              fontName='Helvetica-Bold',
                              fontSize=20,
                              leading=24,
                              spaceAfter=0.25 * inch,
                              alignment=TA_CENTER, # Center align the title
                              textColor=black
                             ))
    # ---------------------------------

    paragraphs_raw = pdf_text.split('\n\n')

    # Heuristic for the garbled line issue (as before, temporary)
    if paragraphs_raw and len(paragraphs_raw[-1]) < 50 and any(char in paragraphs_raw[-1] for char in ['io', 'og', 'al', 'op']):
         logger.warning("Detected potentially garbled last paragraph. Attempting to trim/omit.")
         paragraphs_raw[-1] = "11. Entire Agreement:\nThis proposal constitutes the entire agreement between the parties and supersedes all prior discussions and agreements."


    for i, para_text in enumerate(paragraphs_raw):
        para_text = para_text.strip()
        if not para_text:
            continue

        # Special handling for the main document title (PROPOSAL DOCUMENT)
        if i == 0 and "PROPOSAL DOCUMENT" in para_text.upper():
            p = Paragraph("PROPOSAL DOCUMENT", styles['DocumentTitle'])
            story.append(p)
            story.append(Spacer(1, 0.15 * inch)) # Add space after the title
            # Skip the rest of this initial block if it's just the title
            remaining_text_lines = para_text.splitlines()[1:]
            if remaining_text_lines:
                formatted_text = "<br/>".join(remaining_text_lines)
                p = Paragraph(formatted_text, styles['Normal'])
                story.append(p)
                story.append(Spacer(1, 0.1 * inch))
            continue # Move to the next paragraph

        # Check if the paragraph looks like a section header (e.g., starts with a number and dot or just bold text)
        # This is a heuristic and might need fine-tuning based on actual proposal content variability.
        is_section_header = False
        # Check for numbered sections (e.g., "1. Scope of Work:")
        if para_text.startswith(('1.', '2.', '3.', '4.', '5.', '6.', '7.', '8.', '9.', '10.', '11.')):
            is_section_header = True
        # Check for Exhibit headers (e.g., "Exhibit A: Cabinet Design") or Roman numeral headings
        elif para_text.startswith(('Exhibit ', 'I.', 'II.', 'III.', 'IV.', 'V.', 'VI.', 'VII.')):
            is_section_header = True
        # Check for specific known headers
        elif para_text.strip().upper() in ["IN WITNESS WHEREOF,", "EXHIBITS:"]:
            is_section_header = True


        if is_section_header:
            p = Paragraph(para_text, styles['SectionHeader'])
            story.append(p)
            # No additional Spacer here, as SectionHeader style has spaceAfter
        else:
            formatted_text = para_text.replace('\n', '<br/>')
            p = Paragraph(formatted_text, styles['Normal'])
            story.append(p)
            story.append(Spacer(1, 0.1 * inch)) # Standard space after body paragraphs

    doc.build(story)

    pdf_buffer.seek(0)

    # Upload the PDF to GCS
    storage_client = storage.Client()
    bucket = storage_client.bucket(STORAGE_BUCKET)
    blob = bucket.blob(PROPOSAL_DOCUMENT_FILE_NAME)

    blob.upload_from_file(pdf_buffer, content_type="application/pdf")

    logger.info(f"Successfully uploaded PDF to gs://{STORAGE_BUCKET}/{PROPOSAL_DOCUMENT_FILE_NAME}")

except Exception as e:
    logger.error(f"Error writing text to PDF and uploading: {e}")
    raise
finally:
    if 'pdf_buffer' in locals():
        pdf_buffer.close()
return "Successfully uploaded PDF to GCS!!"
  1. מוודאים שיש לכם קטגוריה של Cloud Storage

התיקייה הזו משמשת לאחסון מסמך ההצעה שהסוכן יוצר. יוצרים אותו ומקצים הרשאות גישה כדי שהמערכת האקטיבית שיוצרים באמצעות Vertex AI תוכל לגשת אליו. כך עושים את זה:

https://cloud.google.com/storage/docs/creating-buckets#console

נותנים שם למאגר next-demo-store. אם נותנים לו שם אחר, צריך לעדכן את הערך של STORAGE_BUCKET בקובץ ‎ .env (בשלב הגדרת משתני הסביבה).

  1. כדי להגדיר גישה לקטגוריה, עוברים אל מסוף Cloud Storage ואל קטגוריית האחסון (במקרה שלנו, שם הקטגוריה הוא next-demo-storage): https://console.cloud.google.com/storage/browser/next-demo-storage.

עוברים אל 'הרשאות' -> 'הצגת גורמים מרכזיים' -> 'הענקת גישה'. בוחרים את העקרונות בתור allUsers ואת התפקיד בתור Storage Object User.

Make sure to not enable "prevent public access". Since this is a demo/study application we are going with a public bucket. Remember to configure permission settings appropriately when you are building your application.
  1. יצירת רשימת תלויות

מפרטים את כל יחסי התלות בקובץ requirements.txt. אפשר להעתיק את הקוד ממאגר.

הסבר על קוד המקור של מערכת עם סוכן יחיד

הקובץ agent.py מגדיר את המבנה וההתנהגות של מערכת מרובת סוכנים לשיפוץ מטבח באמצעות Agent Development Kit‏ (ADK). נפרט את הרכיבים העיקריים:

הגדרת נציג

סוכן ראשי (כלי תזמור): proposal_agent

הסוכן root_agent פועל כמתזמן של מערכת הסוכן היחיד הזו. הוא מקבל את בקשת השיפוץ הראשונית וקובע אילו כלים להפעיל בהתאם לצרכים של הבקשה.

לאחר מכן, סוכן הבסיס אוסף את התשובות מהכלים ומשלב אותן כדי לספק למשתמש תשובה מקיפה. במקרה הזה יש לנו רק כלי אחד, store_pdf.

7. זרימת נתונים ומושגי מפתח

המשתמש יוזם בקשה דרך הממשק של ADK (הטרמינל או ממשק המשתמש האינטרנטי).

  1. הבקשה מתקבלת על ידי הסוכן הראשי.
  2. הסוכן הראשי מנתח את הבקשה ומפנה אותה לכלי לפי הצורך.
  3. הכלי store_pdf נועד לכתוב את תוכן הטקסט המשופץ לקובץ PDF, ואז להעלות אותו ל-Google Cloud Storage.
  4. התשובה מוחזרת ל-root_agent.
  5. הסוכן הראשי משלב את התשובות ומספק למשתמש פלט סופי.

מודלים גדולים של שפה (LLM)

הסוכנים מסתמכים במידה רבה על LLM כדי ליצור טקסט, לענות על שאלות ולבצע משימות של הסקת מסקנות. מודלים מסוג LLM הם ה"מוח" שמאפשר לסוכנים להבין את בקשות המשתמשים ולהגיב להן. אנחנו משתמשים ב-Gemini 2.5 באפליקציה הזו.

Google Cloud Storage

משמש לאחסון המסמכים של הצעת השיפוץ שנוצרו. צריך ליצור קטגוריה ולהעניק לסוכנים את ההרשאות הנדרשות כדי לגשת אליה.

Cloud Run (אופציונלי)

הסוכן OrderingAgent משתמש בפונקציית Cloud Run כדי ליצור אינטראקציה עם AlloyDB. ‫Cloud Run מספק סביבה ללא שרתים להרצת קוד בתגובה לבקשות HTTP.

AlloyDB

אם אתם משתמשים ב-OrderingAgent, תצטרכו להגדיר מסד נתונים של AlloyDB כדי לאחסן את פרטי ההזמנה.

קובץ ‎.env

בקובץ ‎ .env מאוחסן מידע רגיש כמו מפתחות API, פרטי כניסה למסד נתונים ושמות של דליים. חשוב לשמור על אבטחת הקובץ הזה ולא להוסיף אותו למאגר. בנוסף, הוא מאחסן את הגדרות התצורה של הסוכנים ושל פרויקט Google Cloud. בדרך כלל, הפונקציות root_agent או supporting קוראות ערכים מהקובץ הזה. מוודאים שכל המשתנים הנדרשים מוגדרים בצורה תקינה בקובץ ‎ .env. כולל שם הקטגוריה של Cloud Storage

8. הגדרת המודל

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

  1. מקבלים מפתח API מ-Google AI Studio.
  2. בשלב הבא, שבו מגדירים את קובץ ‎ .env, מחליפים את <<your API KEY>> בערך מפתח ה-API בפועל.

9. הגדרת משתני סביבה

  1. מגדירים את הערכים של הפרמטרים בקובץ התבנית ‎ .env במאגר הזה. במקרה שלי, בקובץ ‎ .env יש את המשתנים הבאים:
GOOGLE_GENAI_USE_VERTEXAI=FALSE
GOOGLE_API_KEY=<<your API KEY>>
GOOGLE_CLOUD_LOCATION = us-central1 <<or your region>>
GOOGLE_CLOUD_PROJECT = <<your project id>>
PROJECT_ID = <<your project id>>
GOOGLE_CLOUD_REGION=us-central1 <<or your region>>
STORAGE_BUCKET = next-demo-store <<or your storage bucket name>>

מחליפים את ה-placeholders בערכים שלכם.

10. הרצת הסוכן

  1. בטרמינל, עוברים אל ספריית האב של פרויקט הנציג:
cd agentic-apps/renovation-agent
  1. התקנת כל יחסי התלות
pip install -r requirements.txt
  1. כדי להפעיל את הסוכן, מריצים את הפקודה הבאה בטרמינל של Cloud Shell:
adk run .
  1. כדי להריץ אותו בממשק משתמש אינטרנטי שהוקצה ל-ADK, מריצים את הפקודה הבאה:

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

adk web
  1. הנחיות לדוגמה:
user>> 

Hello. Generate Proposal Document for the kitchen remodel requirement in a proper format that applies to a renovation contract. Remember this text will eventually be stored as a pdf file so make sure to have the formatting appropriate. I have no other specification.

11. תוצאה

עבור הפקודה adk run . התוצאה היא"

2703603a907329ae.png

ae56b38cc6da9afe.png

...

91452a4de933a75b.png

אפשר לוודא שהמסמך Renovation Proposal נוצר בקטגוריית Cloud Storage.

12. פריסה ב-Cloud Run

  1. יוצרים קובץ בשם Dockerfile בתוך תיקיית הבסיס של הפרויקט:
cd agentic-apps/renovation-agent
  1. מעתיקים את התוכן ממאגר GitHub.
https://github.com/AbiramiSukumaran/adk-renovation-single-agent/blob/main/Dockerfile

לקובץ Dockerfile הזה.

  1. פורסים ב-Cloud Run באמצעות הפקודה הבאה:
adk deploy cloud_run --project=abis-345004 --region=us-central1 --service_name=renovation-agent --app_name=renovation-app --with_ui .

זה הכול. אחרי הפריסה, נקודת הקצה אמורה להופיע במסוף, והיא תהיה מוכנה לשימוש.

13. הסרת המשאבים

כדי לא לצבור חיובים לחשבון Google Cloud על המשאבים שבהם השתמשתם במאמר הזה:

  1. במסוף Google Cloud, עוברים לדף Manage resources.
  2. ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete.
  3. כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.

14. מזל טוב

מעולה! יצרתם אפליקציה מרובת סוכנים וקיימתם איתה אינטראקציה באמצעות ADK! מערכת מרובת הסוכנים נועדה לייעל את תהליך שיפוץ המטבח על ידי אוטומציה של משימות כמו יצירת הצעות, בדיקת היתרים ומעקב אחר סטטוס ההזמנה. לכל סוכן יש תפקיד ספציפי, והסוכן הראשי מתאם את הפעילויות שלהם כדי לספק פתרון מקיף. המערכת משתמשת במודלים גדולים של שפה (LLM), בשירותי Google Cloud ובממשקי API חיצוניים כדי לספק את הפונקציונליות שלה. כאן יש קישור למסמכי העזרה של המוצר.