1. מבוא
אתם יכולים ליצור חוויות AI אקטיבי אינטראקטיביות וחלקות שבהן הלקוחות יכולים להשתמש ישירות באפליקציית העברת ההודעות שכבר נמצאת בשימוש שלהם. כאן תלמדו איך לפתח ולפרוס אפליקציות חכמות שפועלות בצורה חלקה בממשקי אינטרנט ובערוצי העברת הודעות מודרניים.
מה תפַתחו
שילוב בין אפליקציה מלאה מבוססת-ADK שמופעלת על ידי Gemini ועוזרת לסועדים לעיין בתפריט של מסעדה ולהזמין מקומות, לבין אפליקציית הצ'אט Telegram. אתם יכולים לקיים אינטראקציה עם בוט Telegram ולבקש תיאורים בשפה טבעית כמו "אני רוצה משהו חריף וצמחוני". הבוט יתחבר לסוכן ADK שקורא מתוך מסד נתונים של Cloud SQL PostgreSQL וכותב בו, והכול דרך MCP Toolbox for Databases, שמטפל בכל הגישה למסד הנתונים – כולל יצירה אוטומטית של הטמעה לחיפוש וקטורי. בינתיים, המשתמש יוכל לראות שהבוט מאשר את קבלת ההודעה ומקליד ... typing לתשובה בזמן ההמתנה לחזרה מסוכן ADK.

מה תלמדו
- פריסת אפליקציה פעילה מבוססת-ADK בשם 'מלצר וירטואלי במסעדה' שמבוססת על Gemini
- הגדרת בוט צ'אט של Telegram באמצעות BotFather
- כתיבת אפליקציות Python להאזנה ל-webhook של הבוט
- שליחת פעולת צ'אט כדי לספק התראה
... typingבטלגרם על הודעת משתמש, וביצוע דגימה כדי לשלוח... typingמעת לעת בזמן ההמתנה לתשובה האמיתית - התקשרות לנקודת הקצה של Cloud Run כדי לעבד את הפנייה של המשתמש
Restaurant Concierge - טיפול בחזרה מסוכן ADK ושליחת הודעה ל-Telegram וסגירת המאגר
- פריסת אפליקציית Python ב-Cloud Run
- איך מתקשרים עם בוט טלגרם
דרישות מוקדמות
- חשבון Google Cloud עם חשבון לחיוב בתקופת ניסיון
- היכרות בסיסית עם Python
- ניסיון קודם בפריסה של ADK ו-Cloud Run יעזור לכם
- חשבון טלגרם
- (מומלץ) השלמתם את ה-Codelabs הבאים :
- Agentic RAG with ADK, MCP Toolbox, and Cloud SQL -> אפשר להמשיך לבנות את הסוכן מתוך ה-Codelab הזה, קוד לתחילת הדרך שסופק זהה
- (או) סוכנים בהיקף נרחב: ארכיטקטורה מרובת סוכנים עם פרוטוקול A2A ב-Agent Runtime ושילוב ADK – אם רוצים להעשיר את הסוכן באמצעות ארכיטקטורה מרובת סוכנים
2. הגדרת סביבה – המשך מה-codelab הקודם
התיאורים שאנחנו מספקים ב-Codelab הזה הם למעשה המשך של ה-Codelab הזה בנושא RAG אג'נטי עם ADK, MCP Toolbox ו-Cloud SQL או של ה-Codelab הזה בנושא סוכנים בהיקף נרחב: ארכיטקטורה מרובת סוכנים עם פרוטוקול A2A ב-Agent Runtime ושילוב ADK. אפשר להמשיך לעבוד מהנקודה שבה הפסקתם ב-codelab הקודם
אפשר להתחיל לבנות בספריית העבודה של ה-codelab הקודם ( ספריית העבודה צריכה להיות build-agent-adk-toolbox-cloudsql או adk-a2a-agent-runtime-starter). כדי למנוע בלבול, נשנה את שם הספרייה לשם הספרייה שבה נשתמש כשהתחלנו מחדש.
אם אתם ממשיכים משיעור ה-Lab Agentic RAG with ADK, MCP Toolbox, and Cloud SQL :
mv ~/build-agent-adk-toolbox-cloudsql ~/build-agent-adk-telegram
אחרת, אם אתם ממשיכים משיעור ה-Lab Agents at Scale: Multi-Agent Architecture with A2A Protocol on Agent Runtime and ADK Integration
mv ~/adk-a2a-agent-runtime-starter ~/build-agent-adk-telegram
לאחר מכן, משנים את ספריית העבודה לספרייה הזו
cloudshell workspace ~/build-agent-adk-telegram && cd ~/build-agent-adk-telegram
source .env
לאחר מכן, מוודאים ש-restaurant-agent כבר נפרס ושיש לו כתובת URL ציבורית שאפשר לגשת אליה
AGENT_URL=$(gcloud run services describe restaurant-agent \
--region="$REGION" \
--format='value(status.url)')
echo " ✓ Agent service deployed"
echo " Agent URL: $AGENT_URL"
echo ""
אם יש לכם גישה לכתובת ה-URL, אתם יכולים לעבור לקטע הבא: Create Telegram Bot
3. הגדרת סביבה – התחלה חדשה עם מאגר המתחילים
בשלב הזה מכינים את סביבת Cloud Shell, מגדירים את הפרויקט ב-Google Cloud ומשכפלים את מאגר התבניות.
פתיחת Cloud Shell
פותחים את Cloud Shell בדפדפן. Cloud Shell מספקת סביבה שהוגדרה מראש עם כל הכלים שדרושים ל-Codelab הזה. כשמופיעה בקשה, לוחצים על Authorize.
אחר כך לוחצים על View (תצוגה) -> Terminal (טרמינל) כדי לפתוח את הטרמינל.הממשק אמור להיראות בערך כך:

זה יהיה הממשק הראשי שלנו, סביבת הפיתוח המשולבת (IDE) בחלק העליון והטרמינל בחלק התחתון
הגדרת ספריית העבודה
משכפלים את מאגר המתחילים, כל הקוד שכותבים ב-codelab הזה נמצא כאן:
rm -rf ~/build-agent-adk-telegram
git clone https://github.com/alphinside/adk-a2a-agent-runtime-starter.git build-agent-adk-telegram
cloudshell workspace ~/build-agent-adk-telegram && cd ~/build-agent-adk-telegram
יוצרים את קובץ .env מהתבנית שסופקה:
cp .env.example .env
כדי לפשט את הגדרת הפרויקט במסוף, מורידים את סקריפט הגדרת הפרויקט הזה לספריית העבודה:
curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh
מריצים את הסקריפט. הוא מאמת את החשבון לחיוב של תקופת הניסיון, יוצר פרויקט חדש (או מאמת פרויקט קיים), שומר את מזהה הפרויקט בקובץ .env בספרייה הנוכחית ומגדיר את הפרויקט הפעיל ב-gcloud.
bash setup_verify_trial_project.sh && source .env
הסקריפט:
- אימות שיש לכם חשבון לחיוב עם תקופת ניסיון פעילה
- בודקים אם יש פרויקט קיים ב-
.env(אם יש) - יוצרים פרויקט חדש או משתמשים בפרויקט קיים
- קישור החשבון לחיוב בתקופת הניסיון לפרויקט
- שומרים את מזהה הפרויקט ב-
.env - הגדרת הפרויקט כפרויקט פעיל ב-
gcloud
כדי לוודא שהפרויקט מוגדר בצורה נכונה, בודקים את הטקסט הצהוב שליד ספריית העבודה בהנחיית הטרמינל של Cloud Shell. מזהה הפרויקט צריך להופיע בו.

הגדרה של תשתית Starter
קודם כל, נצטרך להתקין יחסי תלות של Python באמצעות uv, שהוא מנהל מהיר של חבילות ופרויקטים של Python שנכתב ב-Rust ( מסמכי uv). בשיעור Codelab הזה אנחנו משתמשים בו כדי לשמור על מהירות ופשטות בתחזוקת פרויקט Python.
uv sync
לאחר מכן, מריצים את סקריפט ההגדרה המלא, שיוצר את מכונת Cloud SQL, מטמיע נתונים ופורס את שירות Toolbox שישמש כמצב ההתחלתי של סוכן המסעדה שלנו.
bash scripts/full_setup.sh > logs/full_setup.log 2>&1 &
כתוצאה מכך, יקרו הדברים הבאים:
- יצירת מכונה של Cloud SQL ואכלוס מסד הנתונים (שלב 1)
- יצירת הגדרת סביבת סוכן והפעלת שירות Toolbox מקומי (שלב 2)
- פריסת שירותי Toolbox וסוכן ב-Cloud Run (שלב 3)
אחרי שהפריסה הזו תסתיים, תוכלו לגשת לממשק המשתמש של ADK Dev בכתובת ה-URL של Cloud Run
source .env
AGENT_URL=$(gcloud run services describe restaurant-agent \
--region="$REGION" \
--format='value(status.url)')
echo " ✓ Agent service deployed"
echo " Agent URL: $AGENT_URL"
echo ""
פותחים את ממשק המשתמש של ADK למפתחים, בוחרים באפשרות restaurant_agent ומריצים בדיקה עם שאילתות כמו בדוגמה הבאה:
What Italian dishes do you have?
או,
I want something spicy and creamy
עכשיו, הפעולה הבאה היא איך אפשר לעבור מממשק פיתוח אתרים בלבד לערוץ הודעות בטלגרם
4. יצירת בוט לטלגרם
Telegram היא פלטפורמת הודעות חינמית מוכרת, שמשמשת בעיקר ליצירת אינטראקציה עם קהילות. אחת הסיבות לכך היא שהיא מציעה דרכים רבות לשילוב קל, ולכן אנשים יכולים ליצור בקלות בוט משלהם עם מגוון רחב של פונקציות שונות.
במקרה שלנו, נשתמש ב-BotFather כדי ליצור בוט משלנו בפעם הראשונה. חשוב לזכור שאף על פי שאנחנו משתמשים בטלגרם בסשן הזה, אפשר להשתמש באותה שיטה גם בוואטסאפ או בפלטפורמות אחרות של העברת הודעות.
שימוש ב-BotFather ליצירת בוט משלכם
פותחים דפדפן אינטרנט ונכנסים לכתובת https://telegram.me/BotFather כדי להתחיל ליצור בוט משלכם לטלגרם.

איך מתחילים אינטראקציה עם BotFather
שליחת הפקודה /start
כדי להתחיל להשתמש ב-BotFather וליצור את הבוט הראשון, צריך להפעיל את ההודעה /start אל BotFather. לאחר מכן, הוא ישתף את כל הפקודות שזמינות לכם כדי להמשיך את האינטראקציה איתו.
/start
איך מתחילים ליצור בוט באמצעות הפקודה /newbot
כדי ליצור בוט חדש, שולחים את הפקודה /newbot אל BotFather. תתבקשו לתת שם לבוט, ואז תתבקשו לתת לבוט username, שתמיד צריך להסתיים ב-bot . לדוגמה, TetrisBot או tetris_bot. הערך הזה צריך להיות ייחודי.

אחרי שהבוט ייווצר בהצלחה, תקבלו את ההודעה הבאה מ-BotFather
Done! Congratulations on your new bot. You will find it at t.me/AdkTelegramTest_bot. You can now add a description, about section and profile picture for your bot, see /help for a list of commands. By the way, when you've finished creating your cool bot, ping our Bot Support if you want a better username for it. Just make sure the bot is fully operational before you do this. Use this token to access the HTTP API:
<YOUR_TELEGRAM_API_KEY>
Keep your token secure and store it safely, it can be used by anyone to control your bot. For a description of the Bot API, see this page: https://core.telegram.org/bots/api
חשוב לשים לב ל-YOUR_TELEGRAM_API_KEY כי נשתמש בו בקטע הבא.
5. פיתוח אפליקציית Telegram Webhook
נתחיל להכין את ספריית העבודה כדי לפתח את אפליקציית ה-webhook של טלגרם
mkdir ~/build-agent-adk-telegram/telegram-integration
cd ~/build-agent-adk-telegram
הוספת יחסי תלות נדרשים
כדי לספק תלות מתאימה לסקריפט של מאזין ה-webhook של Telegram, יוצרים סקריפט requirements.txt עם התוכן הבא.
cloudshell edit ./telegram-integration/requirements.txt
לאחר מכן מוסיפים את יחסי התלות הבאים
python-telegram-bot[webhooks]
httpx
יצירת סקריפט עבור Telegram Webhook Listener
אחרי שמתקינים את יחסי התלות. עכשיו אפשר ליצור סקריפט Python main.py לאפליקציית השילוב
cloudshell edit ~/build-agent-adk-telegram/telegram-integration/main.py
לאחר מכן, מעתיקים את הקוד הבא לתוכו
# ./telegram-integration/main.py
import asyncio
import os
import sys
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, CallbackContext
from telegram.constants import ChatAction
import httpx
# Read token from environment variable
TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN")
ADK_SERVER_URL = os.environ.get("ADK_SERVER_URL", "http://localhost:8000")
ADK_APP_NAME = os.environ.get("ADK_APP_NAME", "restaurant_agent")
# Parse base URL out of ADK_SERVER_URL
BASE_URL = ADK_SERVER_URL.rstrip('/')
if BASE_URL.endswith('/run'):
BASE_URL = BASE_URL[:-4]
elif BASE_URL.endswith('/query'):
BASE_URL = BASE_URL[:-6]
if not TOKEN:
print("Error: TELEGRAM_BOT_TOKEN environment variable not set.")
print("Please set it before running the application.")
sys.exit(1)
async def start(update: Update, context: CallbackContext) -> None:
"""Send a message when the command /start is issued."""
await update.message.reply_text('Hi! I am your ADK Integration Bot. Send me a message and I will forward it to the ADK server.')
async def send_typing_loop(chat_id: int, bot, stop_event: asyncio.Event):
"""Send typing action periodically until the stop event is set."""
while not stop_event.is_set():
try:
await bot.send_chat_action(chat_id=chat_id, action=ChatAction.TYPING)
# The research suggested repeating every 4 seconds
await asyncio.sleep(4)
except Exception as e:
print(f"Error sending chat action: {e}")
await asyncio.sleep(1) # Wait a bit before retrying if error
async def handle_message(update: Update, context: CallbackContext) -> None:
"""Handle incoming user messages."""
user_message = update.message.text
chat_id = update.message.chat_id
raw_user_id = str(update.message.from_user.id)
# Derive unique user_id and session_id for this user
user_id = f"tg_{raw_user_id}"
session_id = f"tg_sess_{raw_user_id}"
print(f"Received message from {user_id}: {user_message}")
# Create a stop event for the typing loop
stop_event = asyncio.Event()
# Start the typing loop as a background task
typing_task = asyncio.create_task(send_typing_loop(chat_id, context.bot, stop_event))
try:
async with httpx.AsyncClient() as client:
# 1. Check if the session exists
session_url = f"{BASE_URL}/apps/{ADK_APP_NAME}/users/{user_id}/sessions/{session_id}"
session_check = await client.get(session_url, timeout=10.0)
if session_check.status_code == 404:
# 2. If session doesn't exist, create it
print(f"Session {session_id} not found. Creating session...")
session_create = await client.post(session_url, json={}, timeout=10.0)
if session_create.status_code != 200:
raise Exception(f"Failed to create session: {session_create.status_code} {session_create.text}")
elif session_check.status_code != 200:
raise Exception(f"Error checking session: {session_check.status_code} {session_check.text}")
# 3. Run the ADK agent
run_url = f"{BASE_URL}/run"
payload = {
"appName": ADK_APP_NAME,
"userId": user_id,
"sessionId": session_id,
"newMessage": {
"role": "user",
"parts": [{"text": user_message}]
}
}
response = await client.post(run_url, json=payload, timeout=60.0)
if response.status_code == 200:
events = response.json()
if isinstance(events, list) and len(events) > 0:
# The last event contains the final text response
last_event = events[-1]
content = last_event.get("content", {})
parts = content.get("parts", [])
if parts and "text" in parts[0]:
reply_text = parts[0]["text"]
else:
reply_text = "ADK agent returned an empty or non-text response."
else:
reply_text = "No events returned from ADK agent."
else:
reply_text = f"Error communicating with ADK server (Status: {response.status_code})."
except Exception as e:
reply_text = f"Failed to connect to ADK server: {e}"
finally:
# Stop the typing loop
stop_event.set()
await typing_task
# Send the final response back to the user
await update.message.reply_text(reply_text)
def main() -> None:
"""Start the bot."""
# Create the Application and pass it your bot's token.
application = Application.builder().token(TOKEN).build()
# on different commands - answer in Telegram
application.add_handler(CommandHandler("start", start))
# on non command i.e message - echo the message on Telegram
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
# Check if running in webhook mode (e.g., on Cloud Run)
port = os.environ.get("PORT")
service_url = os.environ.get("SERVICE_URL")
if port and service_url:
if not service_url.startswith("http"):
service_url = f"https://{service_url}"
print(f"Starting bot in WEBHOOK mode on port {port} with url {service_url}")
application.run_webhook(
listen="0.0.0.0",
port=int(port),
url_path=TOKEN,
webhook_url=f"{service_url}/{TOKEN}",
allowed_updates=Update.ALL_TYPES
)
else:
print("Starting bot in POLLING mode")
# Run the bot until the user presses Ctrl-C
application.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == "__main__":
main()
הסבר על קוד השילוב של בוט Telegram

כשמשתמש שולח הודעה, צינור הנתונים הבא מופעל בקטע handle_message()
שלב 1: זיהוי וקביעת סשן
הבוט ממפה את מזהה המשתמש ב-Telegram למזהים ייחודיים של ADK כדי לשמור על סשנים נפרדים של משתמשים:
user_id = f"tg_{raw_user_id}"
session_id = f"tg_sess_{raw_user_id}"
שלב 2: סטטוס 'הקלדה' אסינכרוני (שורות 53 עד 58)
כדי להבטיח חוויית משתמש רספונסיבית מאוד בזמן שהסוכן של ADK מעבד את ההנחיה (תהליך שיכול להימשך כמה שניות), הבוט מתחיל לולאה אסינכרונית ברקע:
- המופע
asyncio.Eventנוצר בתורstop_event. -
asyncio.create_taskיוצרת אתsend_typing_loop(...)ברקע. - הלולאה שולחת פעולה של
ChatAction.TYPINGל-Telegram כל 4 שניות עד שהמשתנהstop_eventמוגדר.
שלב 3: אימות ויצירה של סשן ADK (שורות 61-72)
לפני הפעלת הנציג, הבוט בודק אם כבר קיימת סשן:
- שליחת בקשת
GETאל/apps/{appName}/users/{userId}/sessions/{sessionId}. - אם התגובה היא
404 Not Found, המערכת יוצרת את הסשן באמצעות בקשתPOSTלאותה כתובת URL עם גוף JSON ריק. - אם מוחזר סטטוס ששונה מ-
200או מ-404, נוצר חריג.
שלב 4: שליחת בקשה לסוכן (שורות 74 עד 85)
מטען הייעודי (payload) של ההודעה מועבר לנקודת הקצה של ה-ADK /run:
- נקודת קצה:
POST /run - הזמן הקצוב לתפוגת הבקשה מוגדר ל-
60.0שניות כדי לאפשר חשיבה רציונלית מורכבת או זמן טעינה במעלה הזרם. - מבנה המטען הייעודי (payload):
{
"appName": "restaurant_agent",
"userId": "tg_<user_id>",
"sessionId": "tg_sess_<user_id>",
"newMessage": {
"role": "user",
"parts": [{"text": "<user_message>"}]
}
}
שלב 5: ניתוח התגובה (שורות 87 עד 101)
שרת ה-ADK מחזיר רשימה של אירועי הודעות. הבוט בודק את המערך שמוחזר:
- הפונקציה מאחזרת את האירוע האחרון ברשימה (
events[-1]). - המעבר לתוכן הטקסט מתבצע באמצעות
event["content"]["parts"][0]["text"]. - אם לא מוחזרים אירועים או אם חסרה מבנה טקסט, מוצג טקסט placeholder תיאורי.
שלב 6: ניתוח ושיגור תגובה (שורות 103 עד 111)
- בבלוק
finally, הערךstop_eventמוגדר, והלולאה של פעולת ההקלדה נעצרת. - הבוט ממתין להשלמת
typing_taskכדי לוודא שהמשאבים נקיים. - לבסוף, הבוט משיב לשיחה ב-Telegram עם הטקסט של התשובה המנותחת.
6. פריסת אפליקציית ה-Webhook של Telegram ב-Cloud Run
בשלב הבא נציב את Telegram Webhook Listener ב-Cloud Run, כדי שהבוט יוכל לתקשר איתו
יצירת קובץ Dockerfile
קודם צריך ליצור את קובץ ה-Dockerfile.
cloudshell edit ~/build-agent-adk-telegram/telegram-integration/Dockerfile
לאחר מכן, מעתיקים את הקוד הבא לתוכו
# Use an official Python runtime as a parent image
FROM python:3.11-slim
# Prevent Python from writing pyc files to disc and buffering stdout/stderr
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Set the working directory in the container
WORKDIR /app
# Install system dependencies if needed
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Copy the dependencies file to the working directory
COPY requirements.txt .
# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application code
COPY main.py .
# Expose the port that Cloud Run will provide via environment variable
EXPOSE 8080
# Run main.py when the container launches
CMD ["python", "main.py"]
השירות מועבר לקונטיינר באמצעות python:3.11-slim כדי לשמור על גודל קטן של קובץ האימג':
- מתקין יחסי תלות מ-
requirements.txt(python-telegram-bot[webhooks]ו-httpx). - חושף יציאה רגילה
8080. - השקות
python main.py.
הכנת משתני הסביבה
אחרי זה, נבדוק שוב אם הסוכן שלנו נפרס בהצלחה
AGENT_URL=$(gcloud run services describe restaurant-agent \
--region="$REGION" \
--format='value(status.url)')
echo " ✓ Agent service deployed"
echo " Agent URL: $AGENT_URL"
echo ""
בשלב הבא, נזין את ה-TELEGRAM_BOT_TOKEN שקיבלנו קודם ל-.env
echo "TELEGRAM_BOT_TOKEN=YOUR_TELEGRAM_API_KEY" >> .env
לאחר מכן, נמלא את נתוני .env בערכים אחרים שדרושים לנו.
echo "ADK_SERVER_URL=$AGENT_URL" >> .env
echo "ADK_APP_NAME=restaurant_agent" >> .env
echo "SERVICE_NAME=telegram-integration" >> .env
source .env
יצירת סקריפט פריסה
ניצור סקריפט פריסה שיבצע בדיקות מלאות ויפרוס את האפליקציה ב-Cloud Run
cloudshell edit ~/build-agent-adk-telegram/telegram-integration/deploy.sh
מעתיקים את הקוד הבא לקובץ
#!/usr/bin/env bash
# ./telegram-integration/deploy.sh
# Exit immediately if a command exits with a non-zero status
set -euo pipefail
# Color codes for neat terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0;37m' # No Color
# Load environment variables from .env if it exists
if [ -f .env ]; then
echo -e "${GREEN}✔ Loading environment variables from .env...${NC}"
export $(grep -v '^#' .env | xargs)
fi
echo -e "${BLUE}====================================================${NC}"
echo -e "${BLUE} Google Cloud Run Deployment: Telegram Bot ${NC}"
echo -e "${BLUE}====================================================${NC}"
# 1. Check for gcloud CLI
if ! command -v gcloud &> /dev/null; then
echo -e "${RED}Error: 'gcloud' CLI is not installed.${NC}"
echo "Please install the Google Cloud SDK and try again."
echo "See: https://cloud.google.com/sdk/docs/install"
exit 1
fi
# 2. Check active gcloud account/auth
ACTIVE_ACCOUNT=$(gcloud auth list --filter=status:ACTIVE --format="value(account)" 2>/dev/null || true)
if [ -z "$ACTIVE_ACCOUNT" ]; then
echo -e "${RED}Error: No active Google Cloud account found.${NC}"
echo "Please run: gcloud auth login"
exit 1
fi
# 3. Detect / Prompt for GCP Project
DEFAULT_PROJECT=${GCP_PROJECT_ID:-$(gcloud config get-value project 2>/dev/null || true)}
if [ -n "${DEFAULT_PROJECT}" ]; then
echo -e "${GREEN}✔ Using GCP Project: $DEFAULT_PROJECT${NC}"
GCP_PROJECT="$DEFAULT_PROJECT"
else
echo -n "Enter GCP Project ID: "
read -r GCP_PROJECT
fi
if [ -z "$GCP_PROJECT" ]; then
echo -e "${RED}Error: GCP Project ID is required.${NC}"
exit 1
fi
# Set active project
gcloud config set project "$GCP_PROJECT" &> /dev/null
# 4. Configure Service Parameters
DEFAULT_SERVICE=${SERVICE_NAME:-"telegram-integration"}
if [ -n "${SERVICE_NAME:-}" ]; then
echo -e "${GREEN}✔ Using Cloud Run Service Name: $SERVICE_NAME${NC}"
else
echo -n "Enter Cloud Run Service Name [Default: $DEFAULT_SERVICE]: "
read -r SERVICE_NAME
SERVICE_NAME=${SERVICE_NAME:-$DEFAULT_SERVICE}
fi
DEFAULT_REGION=${REGION:-"us-central1"}
if [ -n "${REGION:-}" ]; then
echo -e "${GREEN}✔ Using Cloud Run Region: $REGION${NC}"
else
echo -n "Enter Cloud Run Region [Default: $DEFAULT_REGION]: "
read -r REGION
REGION=${REGION:-$DEFAULT_REGION}
fi
DEFAULT_ADK_APP=${ADK_APP_NAME:-"restaurant_agent"}
if [ -n "${ADK_APP_NAME:-}" ]; then
echo -e "${GREEN}✔ Using ADK App Name: $ADK_APP_NAME${NC}"
ADK_APP="$ADK_APP_NAME"
else
echo -n "Enter ADK App Name [Default: $DEFAULT_ADK_APP]: "
read -r ADK_APP
ADK_APP=${ADK_APP:-$DEFAULT_ADK_APP}
fi
# 5. Retrieve/Prompt for Telegram Bot Token
if [ -n "${TELEGRAM_BOT_TOKEN:-}" ]; then
echo -e "${GREEN}✔ Found TELEGRAM_BOT_TOKEN in environment.${NC}"
BOT_TOKEN="$TELEGRAM_BOT_TOKEN"
else
echo -e "${YELLOW}TELEGRAM_BOT_TOKEN is not set in your environment.${NC}"
echo -n "Enter your Telegram Bot Token (input will be hidden): "
read -s -r BOT_TOKEN
echo ""
fi
if [ -z "$BOT_TOKEN" ]; then
echo -e "${RED}Error: Telegram Bot Token is required.${NC}"
exit 1
fi
# 6. Retrieve/Prompt for ADK Server URL
DEFAULT_ADK_URL="http://localhost:8000"
if [ -n "${ADK_SERVER_URL:-}" ]; then
echo -e "${GREEN}✔ Found ADK_SERVER_URL in environment: $ADK_SERVER_URL${NC}"
ADK_URL="$ADK_SERVER_URL"
else
echo -n "Enter your ADK Server URL [Default: $DEFAULT_ADK_URL]: "
read -r ADK_URL
ADK_URL=${ADK_URL:-$DEFAULT_ADK_URL}
fi
# Enable required GCP services
echo -e "\n${YELLOW}Checking and enabling required GCP services...${NC}"
gcloud services enable run.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com --project "$GCP_PROJECT"
# Determine source directory dynamically
SOURCE_DIR="."
if [ -d "telegram-integration" ]; then
SOURCE_DIR="telegram-integration"
echo -e "${GREEN}✔ Found source directory: telegram-integration${NC}"
elif [ -f "Dockerfile" ]; then
SOURCE_DIR="."
echo -e "${GREEN}✔ Dockerfile found in current directory. Using current directory as source.${NC}"
else
echo -e "${RED}Error: Could not find source directory 'telegram-integration' or Dockerfile in current directory.${NC}"
exit 1
fi
# 7. First-pass Deployment with placeholder SERVICE_URL
# This boots the container in Webhook mode (so health check binds to port)
# but uses a high-reliability placeholder URL (google.com) to pass DNS verification checks.
echo -e "\n${YELLOW}Deploying to Cloud Run (Step 1/2: Initial Deploy)...${NC}"
gcloud run deploy "$SERVICE_NAME" \
--source "$SOURCE_DIR" \
--region "$REGION" \
--allow-unauthenticated \
--set-env-vars "TELEGRAM_BOT_TOKEN=$BOT_TOKEN,ADK_SERVER_URL=$ADK_URL,ADK_APP_NAME=$ADK_APP,SERVICE_URL=https://google.com" \
--project "$GCP_PROJECT"
# 8. Retrieve the actual service URL
echo -e "\n${YELLOW}Retrieving service URL...${NC}"
SERVICE_URL=$(gcloud run services describe "$SERVICE_NAME" --region "$REGION" --project "$GCP_PROJECT" --format 'value(status.url)')
echo -e "${GREEN}✔ Service URL is: $SERVICE_URL${NC}"
# 9. Update service environment variables with the real SERVICE_URL
# This triggers a rolling update and registers the correct webhook with Telegram automatically!
echo -e "\n${YELLOW}Updating configuration with final Webhook URL (Step 2/2)...${NC}"
gcloud run services update "$SERVICE_NAME" \
--region "$REGION" \
--set-env-vars "TELEGRAM_BOT_TOKEN=$BOT_TOKEN,ADK_SERVER_URL=$ADK_URL,ADK_APP_NAME=$ADK_APP,SERVICE_URL=$SERVICE_URL" \
--project "$GCP_PROJECT"
echo -e "\n${GREEN}====================================================${NC}"
echo -e "${GREEN} Deployment Completed Successfully! 🎉 ${NC}"
echo -e "${GREEN}====================================================${NC}"
echo -e "Service Name: ${BLUE}$SERVICE_NAME${NC}"
echo -e "Region: ${BLUE}$REGION${NC}"
echo -e "Active URL: ${BLUE}$SERVICE_URL${NC}"
echo -e "Webhook Path: ${BLUE}$SERVICE_URL/<bot-token>${NC}"
echo -e "ADK Backend: ${BLUE}$ADK_URL${NC}"
echo -e "ADK App Name: ${BLUE}$ADK_APP${NC}"
echo -e "${GREEN}====================================================${NC}"
echo "Your Telegram Bot has been configured to use webhooks."
echo "Any message sent to your bot will now trigger this Cloud Run instance."
סקריפט פריסה כפולה (deploy.sh)
כשפורסים את הבוט ב-Google Cloud Run, הבוט צריך לציין את כתובת ה-URL שלו (SERVICE_URL) בסביבה שלו כדי שיוכל לרשום אותה כיעד של ה-webhook ב-Telegram. כדי לפתור את התלות המעגלית הזו (כתובת ה-URL לא ידועה עד הפריסה, אבל השירות דורש את כתובת ה-URL כדי להפעיל את האתחול בלי שייכשלו בדיקות תקינות), deploy.sh מבצע פריסה דו-שלבית:
- שלב 1: פריסה ראשונית: המערכת מפעילה את הקונטיינר עם DNS של placeholder (
https://google.com) כדי שהשירות יופעל בהצלחה, יתחבר ליציאה המקומית ויעבור את בדיקות התקינות הראשוניות של Cloud Run. - שלב 2: אחזור כתובת URL: חילוץ תוכניתי של נקודת הקצה החדשה שנוצרה ב-Cloud Run באמצעות
gcloud run services describe. - שלב 3: עדכון ההגדרה: מעדכנים את משתני הסביבה עם כתובת ה-URL של השירות בפועל. הפעולה הזו מפעילה עדכון בהדרגה נקי ב-Cloud Run ורושמת בבטחה את יעד ה-webhook הנכון ב-Telegram API.
פריסה ב-Cloud Run
סקריפט הפריסה מדפיס את כתובת ה-URL של הסוכן. פותחים אותו בדפדפן כדי לגשת לאותו ממשק משתמש של ADK dev שפועל ב-Cloud Run.
cd ~/build-agent-adk-telegram
bash ./telegram-integration/deploy.sh
אם הכול ילך כשורה, תוכלו להתחיל לשוחח עם הבוט ישירות מאפליקציית הצ'אט של טלגרם. כדי לעשות זאת, צריך למצוא את הבוט שיצרתם ולהתחיל לנהל איתו אינטראקציה:
What Italian dishes do you have?
או,
I want something spicy and creamy
תראו את הסטטוס של הבוט '...כותב', ואז בקרוב הוא יחזיר את ההודעה מ-ADK שיצרתם קודם.

7. מעולה!
יצרת, פרסת ושילבת באופן מלא את סוכן ה-AI של ADK, שהוא עוזר חכם לתפריט מסעדה, עם טלגרם, באמצעות תקשורת בין שרת לקוח HTTP, ואתה מאפשר לאנשים לשאול שאלות על התפריט המועדף עליהם ולהזמין מקום במסעדה.
מה למדתם
- פריסה והגדרה של סוכן מבוסס-ADK, של כלי MCP Toolbox ושל סוכן מסעדת היוקרה ב-Cloud Run
- איך מגדירים בוט של Telegram באמצעות BotFather
- איך לכתוב סקריפטים של Python כדי להאזין ל-webhook של Telegram וליצור אינטראקציה עם סוכן ADK כדי להעביר את השאילתה והתשובה של המשתמש בהתאם
- איך מטמיעים את
"... typing"ב-Telegram כדי לסמן שההודעות עוברות עיבוד כמשוב בזמן אמת למשתמשים בזמן שהם מחכים לתגובה מהסוכן של ADK. - איך פורסים את סקריפט Python ב-Cloud Run ויוצרים איתו אינטראקציה
פינוי נפח
כדי להימנע מחיובים בחשבון Google Cloud, מוחקים את המשאבים שנוצרו ב-codelab הזה.
אפשרות 1: מחיקת הפרויקט (מומלץ)
gcloud projects delete $GOOGLE_CLOUD_PROJECT
אפשרות 2: מחיקת משאבים ספציפיים
# If you follow from previous A2A Agent Runtime codelab
# Delete the Agent Runtime deployment (skip if not found)
uv run python -c "
import vertexai
from google.genai import types
vertexai.init(project='$GOOGLE_CLOUD_PROJECT', location='$REGION')
client = vertexai.Client(
project='$GOOGLE_CLOUD_PROJECT', location='$REGION',
http_options=types.HttpOptions(api_version='v1beta1'),
)
try:
agent = client.agent_engines.get(name='$RESERVATION_AGENT_RESOURCE_NAME')
agent.delete(force=True)
print('Agent Runtime deployment deleted.')
except Exception as e:
print(f'No agent deployment found or already deleted, skipping. ({e})')
"
# Delete GCS staging bucket (skip if STAGING_BUCKET is not set)
if [ -n "$STAGING_BUCKET" ]; then
gsutil rm -r gs://$STAGING_BUCKET
else
echo "STAGING_BUCKET not set, skipping bucket deletion."
fi
# Delete Cloud Run services
gcloud run services delete restaurant-agent --region=$REGION --quiet
gcloud run services delete toolbox-service --region=$REGION --quiet
gcloud run services delete telegram-integration --region=$REGION --quiet
# Delete Cloud SQL instance
gcloud sql instances delete $DB_INSTANCE --quiet
