1. סקירה כללית
בחלק 1, הצלחנו להפוך קובצי PDF לא מובְנים ומבולגנים לטבלאות נקיות, חכמות ומובְנות ב-BigQuery באמצעות Knowledge Catalog ו-DataScan. עכשיו יש לנו מחסן נתונים חזק. בחלק 2 הגדרנו את AlloyDB כבסיס טרנזקציוני ואיחדנו את הטבלאות ב-BigQuery לתוכו, ויצרנו שכבת נתונים מאוחדת בלי לשכפל אף בייט.
היום אנחנו בונים את המוח. אנחנו יוצרים אפליקציה עם כמה סוכנים – FroyoOS Store Manager – שפועלת מעל שכבת הנתונים הזו כדי לענות על שאלות, לבדוק אלרגנים ולעבד הזמנות בזמן אמת.
האתגר: הפרדת ה-AI מהנציג
כשבונים סוכן AI שצריך לתקשר עם מסדי נתונים, האנטי-דפוס הנפוץ ביותר הוא הכנסה של הנתונים והלוגיקה של ה-AI ישירות לאפליקציית Python. כך האפליקציה הופכת לפגיעה, לא מאובטחת וקשה מאוד לתחזוקה ככל שארכיטקטורת הנתונים גדלה.
כדי לפתור את הבעיה הזו, אנחנו משתמשים ב-Model Context Protocol (MCP) Toolbox. MCP Toolbox פועל כשכבת הפשטה מאוחדת של הנתונים. אנחנו מגדירים את פעולות מסד הנתונים שלנו באופן הצהרתי בקובץ tools.yaml פשוט. אנחנו פורסים את ערכת הכלים הזו כנקודת קצה מאובטחת בלי שרת ב-Google Cloud Run. סוכן ה-AI שלנו פשוט מתחבר לנקודת הקצה הזו ואומר: 'תפעיל את הכלי place_order'.
הכוח של HTAP
לפני שנתחיל לבנות את הסוכן, נסביר למה בכותרת של הפוסט הזה ציינו במיוחד HTAP (עיבוד היברידי של טרנזקציות וניתוחים).
בארכיטקטורה מסורתית, אם סוכן AI צריך לעבד הזמנה של משתמש בזמן אמת (עומס עבודה של OLTP טרנזקציוני) ולבצע הפניה צולבת לאלפי מיפויי רכיבים מורכבים (עומס עבודה של OLAP אנליטי), אפליקציית Python צריכה לנהל חיבורים לשני מסדי נתונים שונים לחלוטין. התוצאה היא זמן אחזור גבוה, תקורה של אבטחה וניהול מצב לא יציב.
הפכנו את AlloyDB למערכת HTAP עוצמתית על ידי איחוד מקורי של מחסן הנתונים שלנו ב-BigQuery ישירות לתוך PostgreSQL. בגלל ארכיטקטורת ה-HTAP הזו, נציג ה-AI שלנו צריך היום לתקשר רק עם נקודת קצה אחת של מסד נתונים. הוא יכול להוסיף טרנזקציות בזמן אמת לטבלה live_orders ולהריץ סריקות אנליטיות כבדות על קבוצת הנתונים המאוחדת froyo_data ב-BigQuery, בלי לשכפל אף בייט של נתונים. נראה איך אנחנו חושפים את המנוע הזה ל-AI שלנו.
בואו נתחיל לבנות!

מה תלמדו
- איך מגדירים אשכול, מכונה ורשת של AlloyDB בלחיצת כפתור
- איך מגדירים את התוסף כדי להתכונן לאיחוד
- איך מגדירים פדרציה מ-BigQuery ל-AlloyDB
- אני רוצה לנסות
דרישות
2. לפני שמתחילים
יצירת פרויקט
- ב-מסוף Google Cloud, בדף לבחירת הפרויקט, בוחרים או יוצרים פרויקט ב-Google Cloud.
- מוודאים שהחיוב מופעל בפרויקט ב-Cloud. כך בודקים אם החיוב מופעל בפרויקט.
- תשתמשו ב-Cloud Shell, סביבת שורת פקודה שפועלת ב-Google Cloud. לוחצים על 'הפעלת Cloud Shell' בחלק העליון של מסוף Google Cloud.

- אחרי שמתחברים ל-Cloud Shell, בודקים שכבר בוצע אימות ושהפרויקט מוגדר למזהה הפרויקט באמצעות הפקודה הבאה:
gcloud auth list
- מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שפקודת gcloud מכירה את הפרויקט.
gcloud config list project
- אם רוצים לבצע אימות
gcloud auth login
- אם הפרויקט לא מוגדר, משתמשים בפקודה הבאה כדי להגדיר אותו:
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project <YOUR_PROJECT_ID>
- מפעילים את ממשקי ה-API הנדרשים: מריצים את הפקודה הבאה כדי להפעיל את כל ממשקי ה-API הנדרשים:
gcloud services enable \
alloydb.googleapis.com \
bigquery.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
iam.googleapis.com \
secretmanager.googleapis.com \
compute.googleapis.com \
servicenetworking.googleapis.com
נקודות חשובות ופתרון בעיות
תסמונת 'פרויקט הרפאים' | הפעלת את הפקודה |
מחסום בחיוב | הפעלתם את הפרויקט, אבל שכחתם להוסיף חשבון לחיוב. AlloyDB הוא מנוע עם ביצועים גבוהים, והוא לא יופעל אם 'מיכל הדלק' (החיוב) ריק. |
השהיה בהפצת API | לחצתם על 'הפעלת ממשקי API', אבל בשורת הפקודה עדיין מופיעה ההודעה |
מכסה Quags | אם אתם משתמשים בחשבון חדש לתקופת ניסיון, יכול להיות שתגיעו למכסה אזורית של מופעי AlloyDB. אם הפעולה |
3. הכנת הנתונים
מוודאים שהנתונים המובְנים שחולצו מקובצי PDF לא מובְנים זמינים ב-BigQuery, ושהפדרציה של נתוני BigQuery ב-AlloyDB נוצרה ונבדקה. אם לא השלמתם את השלבים האלה, זה הזמן לבצע את השלבים הפשוטים האלה מכאן ומכאן לחלקים 1 ו-2 בהתאמה.
הערה:
אם אתם מנסים את ה-Codelab הזה, אל תבצעו את שלב הניקוי של חלק 2 (מחיקת האשכול ושלב המכונה), כי אנחנו צריכים את תזמור AlloyDB כדי להדגים את המערכת הסוכנית שלנו כאן.
בנוסף לנתונים האלה שכבר יצרנו בחלק 2, אנחנו צריכים ליצור עוד טבלה אחת במכונת AlloyDB. עוברים אל AlloyDB Studio באמצעות הקישור:
https://console.cloud.google.com/alloydb/locations/us-central1/clusters/my-alloydb-cluster/studio
אם אתם משתמשים באשכול אחר, אתם יכולים לשנות את שם האשכול בקישור שלמעלה.
ב-AlloyDB Studio, בכרטיסייה חדשה של עורך השאילתות, מריצים את ההצהרה הבאה:
CREATE TABLE live_orders (
order_id SERIAL PRIMARY KEY,
customer_name VARCHAR(100),
product_id VARCHAR(100),
quantity INT,
order_status VARCHAR(50) DEFAULT 'Pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
הפעולה הזו אמורה ליצור את הטבלה live_orders במסד הנתונים.
4. הגדרת ההפשטה (הקובץ tools.yaml)
קודם כול, אנחנו רושמים באופן רשמי את פעולות מסד הנתונים שלנו. אנחנו יוצרים קובץ tools.yaml שמגדיר איך הסוכן שלנו מקיים אינטראקציה עם AlloyDB, שכולל גם נתונים טרנזקציוניים וגם נתונים אנליטיים (נתונים אנליטיים מאיחוד BigQuery).
- עוברים אל טרמינל Cloud Shell. עוברים למצב עריכה.
- יוצרים תיקייה חדשה בספריית הבסיס: froyo-agent
- בתוך התיקייה, יוצרים קובץ tools.yaml ומדביקים את התוכן הבא: (מחליפים את הערכים הזמניים לשמירת מקום (placeholder) בערכים שלכם לגבי project, cluster, instance ו-password)
# tools.yaml
sources:
alloydb-source:
kind: "alloydb-postgres"
project: "*******"
region: "us-central1"
cluster: "my-alloydb-cluster"
instance: "my-primary-inst"
database: "postgres"
user: "postgres"
password: "*******"
ipType: "private"
tools:
check_allergens:
kind: postgres-sql
source: alloydb-source
description: Queries the federated BigQuery tables to find allergens for a product.
statement: |
SELECT a.allergen_name
FROM consistsof c
INNER JOIN product p ON c.product_id = p.product_id
INNER JOIN ingredient i ON c.ingredient_id = i.ingredient_name
INNER JOIN containsallergen a ON i.ingredient_id = a.ingredient_id
WHERE UPPER(p.product_name) LIKE UPPER($1)
parameters:
- name: product_name
type: string
description: The name of the product to check. (e.g., '%Midnight%')
place_order:
kind: postgres-sql
source: alloydb-source
description: Inserts a new live transaction into the native AlloyDB orders table.
statement: |
INSERT INTO live_orders (customer_name, product_id, quantity)
VALUES ($1, (SELECT product_id FROM product WHERE product_name ILIKE '%' || $2 || '%' LIMIT 1), $3) RETURNING order_id;
parameters:
- name: customer_name
type: string
description: The name of the customer placing the order.
- name: product_name
type: string
description: The name of the product being ordered.
- name: quantity
type: integer
description: The quantity of the product being ordered.
toolsets:
alloydb_tools:
- check_allergens
- place_order
הגבלנו את היכולות של הסוכן ל-2 כלים – בדיקת אלרגנים וביצוע הזמנה.
5. פריסת ערכת הכלים ב-Cloud Run
כדי להפוך את ארגז הכלים הזה לזמין לאפליקציה שלנו, אנחנו פורסים אותו בצורה מאובטחת באמצעות ה-CLI של gcloud. הפעולה הזו יוצרת את נקודת הקצה של שכבת ההפשטה.
- עוברים אל Cloud Shell Terminal ונכנסים לספריית העבודה באמצעות הפעלת הפקודה:
cd froyo-agent
- שומרים את הקובץ tools.yaml בסוד בשם tools-froyo:
gcloud secrets create tools-froyo --data-file=tools.yaml
- פריסת קונטיינר MCP Toolbox ל-Cloud Run
export IMAGE=us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest
gcloud run deploy toolbox-froyo \
--image $IMAGE \
--service-account toolbox-identity \
--region us-central1 \
--set-secrets "/app/tools.yaml=tools-froyo:latest" \
--args="--config=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
--network easy-alloydb-vpc \
--subnet easy-alloydb-subnet \
--allow-unauthenticated \
--vpc-egress private-ranges-only
צריך להחליף את הערכים של network ו-subnet אם השתמשתם בערכים שונים מאלה שהגדרנו ב-Part 2 codelab.
- רושמים את כתובת ה-URL של Cloud Run שמתקבלת (לדוגמה, https://toolbox-froyo-xxx.run.app).
6. הקצה העורפי של הסוכן (app.py)
המסד הנתונים שלנו מופשט, כך שקוד ה-Python יכול להתמקד לחלוטין בתיאום ובהסקה.
אנחנו משתמשים ב-Agent Development Kit (ADK) לצד Flask. ערכת ה-ADK מספקת זיכרון סשן ברמה ארגונית (InMemorySessionService), כלומר הסוכן זוכר את הקשר השיחה. הוא משתלב באופן טבעי עם ToolboxSyncClient כדי לשלוף את הכלים שלנו מ-Cloud Run בצורה חלקה.
הנה הקובץ app.py:
https://github.com/AbiramiSukumaran/froyo-data/blob/main/app.py
אפליקציית Python Flask הפשוטה מחברת את סוכן ה-ADK לכלים שהגדרנו ב-Toolbox, שבתורו מתקשר עם AlloyDB (וגם עם נתונים מאוחדים של BigQuery) ומגיב למשתמש.
7. ממשק המשתמש והפעלת האפליקציה
כדי לספק חוויה טובה למנהלי החנויות, יצרנו ממשק משתמש אלגנטי עם אפקט זכוכית (templates/index.html) שכולל סרגל צד עם קטלוג מוצרים בזמן אמת וממשק צ'אט אינטראקטיבי.
אפשר למצוא את הקובץ index.html בקובץ המאגר כאן:
https://github.com/AbiramiSukumaran/froyo-data/blob/main/templates/index.html
לפני שמריצים את האפליקציה, צריך לוודא שהתקנתם את התלותיות שלה. לשם כך, יוצרים את הקובץ requirements.txt עם התוכן הבא:
Flask>=3.0.0
google-genai>=0.1.0
mcp>=1.0.0
google-adk
toolbox-core
toolbox-langchain
python-dotenv
וקובץ .env מאוכלס:
GOOGLE_API_KEY=***
MCP_TOOLBOX_SERVER_URL=***
בטרמינל של Cloud Shell, מוודאים שאתם בתיקיית הפרויקט ומריצים את הפקודות הבאות אחת אחרי השנייה:
יחסי תלות של התקנות:
pip install -r requirements.txt
מריצים את קובץ ה-Python:
python app.py
לוחצים על הקישור שמופיע במסוף או פותחים את http://localhost:8080.

8. המבחן האולטימטיבי
נלחץ על מוצר מהקטלוג כדי לשאול את הנציג:
Does Midnight Swirl have any allergens?
אתם אמורים לראות את התשובה:

מאחורי הקלעים:
- הסוכן ADK מקבל את ההנחיה ומחליט להשתמש בכלי check_allergens.
- הוא קורא באופן מאובטח ל-MCP Toolbox ב-Cloud Run.
- ערכת הכלים מריצה את השאילתה ב-AlloyDB, שמתאחדת באופן מיידי עם BigQuery כדי לסרוק את הקשרים המורכבים שיצרנו בחלק 1.
- מסד הנתונים מחזיר את התוצאה 'סויה', והסוכן מסכם אותה בצורה מסודרת בממשק המשתמש.
בשלב הבא, אומרים:
Order 2 Midnight Swirls for Alice.

הנציג מעביר את המחרוזת Midnight Swirl (מערבולת חצות) לארגז הכלים. ה-SQL הבסיסי פותר באופן דינמי את המחרוזת למזהה מספר שלם באמצעות BigQuery, מוסיף את ההזמנה הפעילה ל-AlloyDB ומאשר את העסקה.
Code Repo
9. הסרת המשאבים
אחרי שמסיימים את ה-Lab הזה, חשוב למחוק את אשכול AlloyDB ואת המכונה.
הוא אמור לנקות את האשכול יחד עם המופעים שלו.
10. מזל טוב על הנציג!
בואו נחשוב על מה שהשגנו עכשיו:
המערכת שלנו מבוססת-סוכנים ומתקשרת רק עם MCP Toolbox for Databases. הפעולות האלה מתבצעות מאחורי הקלעים: המערכת מטפלת בקריאה לכלי ובנתונים, ומעבירה אותם ללוגיקת ה-AI של האפליקציה. כך התהליך נשאר פשוט:
- האפליקציה העסקית שלנו (שפועלת ב-AlloyDB) יכולה לטפל בביקורים מהירים בו-זמנית של משתמשים.
- כשהוא צריך נתונים אנליטיים מפורטים או הקשר היסטורי (כמו פרטי ספקים או מיפויים מורכבים של רכיבים), הוא שולח שאילתה ל-froyo_dataschema ב-BigQuery.
- Zero ETL. אין פייפליינים שמופעלים. אין מסדי נתונים לא מסונכרנים. אנחנו מאחסנים את הנתונים פעם אחת (ב-BQ) ומבצעים את החישובים במקום שבו אנחנו צריכים אותם.
עכשיו, אחרי שהשלמנו את הבסיס של הסוכן והנתונים – גם הנתונים האנליטיים וגם הנתונים של העסקאות – אפשר לעבור לחלק הבא.
מה השלב הבא?
הסוכן שלנו פועל בצורה מושלמת… בנתיב הרגיל. בחלק 4, נבנה צינור להערכת סוכנים כדי לבדוק באופן קפדני את התוקף, ההצמדה והביצועים של המערכת האג'נטית שלנו. נתראה שם!