1. Giới thiệu
Tạo trải nghiệm liền mạch, mang tính tương tác với AI tác nhân mà khách hàng có thể tương tác trực tiếp từ ứng dụng nhắn tin mà họ đã sử dụng. Khám phá cách phát triển và triển khai các ứng dụng thông minh chạy mượt mà trên các giao diện web và kênh nhắn tin hiện đại.
Sản phẩm bạn sẽ tạo ra
Tích hợp giữa "Trợ lý nhà hàng" đầy đủ chức năng (một ứng dụng dựa trên ADK do Gemini hỗ trợ, giúp thực khách duyệt xem thực đơn của nhà hàng và đặt chỗ) và ứng dụng trò chuyện Telegram. Bạn có thể tương tác với bot Telegram và yêu cầu nội dung mô tả bằng ngôn ngữ tự nhiên, chẳng hạn như "Tôi muốn ăn món cay và chay". Sau đó, bot sẽ kết nối với tác nhân ADK để đọc và ghi vào cơ sở dữ liệu Cloud SQL PostgreSQL hoàn toàn thông qua Bộ công cụ MCP dành cho cơ sở dữ liệu. Bộ công cụ này xử lý mọi hoạt động truy cập vào cơ sở dữ liệu (bao gồm cả việc tự động tạo vectơ nhúng để tìm kiếm vectơ). Trong khi đó, người dùng sẽ thấy bot đang xác nhận tin nhắn và nhập ... typing để phản hồi trong khi chờ tác nhân ADK trả về kết quả.

Kiến thức bạn sẽ học được
- Triển khai một ứng dụng "Trợ lý nhà hàng" đang hoạt động, đây là một ứng dụng dựa trên ADK và được hỗ trợ bởi Gemini
- Thiết lập bot trò chuyện Telegram bằng BotFather
- Viết ứng dụng Python để theo dõi lệnh gọi lại của bot
- Gửi thao tác trò chuyện để cung cấp thông báo
... typingtrong Telegram về tin nhắn của người dùng và thực hiện thăm dò ý kiến để gửi... typingđịnh kỳ trong khi chờ phản hồi thực - Gọi điểm cuối
Restaurant Conciergecloud run để xử lý câu hỏi của người dùng - Xử lý dữ liệu trả về từ tác nhân ADK, gửi thông báo đến Telegram và đóng vùng đệm
- Triển khai ứng dụng Python lên Cloud Run
- Tương tác với bot Telegram
Điều kiện tiên quyết
- Tài khoản Google Cloud có tài khoản thanh toán dùng thử
- Hiểu biết cơ bản về Python
- Kinh nghiệm trước đây về việc triển khai ADK và Cloud Run sẽ rất hữu ích
- Tài khoản Telegram
- (Nên làm) Hoàn tất các lớp học lập trình sau :
- Agentic RAG bằng ADK, Bộ công cụ MCP và Cloud SQL –> bạn có thể tiếp tục xây dựng tác nhân của mình từ lớp học lập trình này, mã khởi đầu được cung cấp là giống nhau
- (HOẶC) Tác nhân ở quy mô lớn: Kiến trúc đa tác nhân với giao thức A2A trên thời gian chạy tác nhân và tích hợp ADK –> nếu bạn muốn làm phong phú thêm tác nhân bằng kiến trúc đa tác nhân
2. Thiết lập môi trường – Tiếp tục từ lớp học lập trình trước
Nội dung mà chúng tôi cung cấp trong lớp học lập trình này thực sự là phần tiếp nối của lớp học lập trình tiên quyết này: Agentic RAG bằng ADK, Bộ công cụ MCP và Cloud SQL hoặc Các tác nhân ở quy mô lớn: Cấu trúc đa tác nhân với giao thức A2A trên Thời gian chạy tác nhân và tích hợp ADK. Bạn có thể tiếp tục công việc từ lớp học lập trình trước
Chúng ta có thể bắt đầu tạo trong thư mục làm việc của lớp học lập trình trước ( thư mục làm việc phải là build-agent-adk-toolbox-cloudsql hoặc adk-a2a-agent-runtime-starter). Để tránh nhầm lẫn, hãy đổi tên thư mục thành tên thư mục mà chúng ta dùng khi bắt đầu từ đầu
Nếu bạn đang tiếp tục từ phòng thí nghiệm Agentic RAG bằng ADK, Bộ công cụ MCP và Cloud SQL :
mv ~/build-agent-adk-toolbox-cloudsql ~/build-agent-adk-telegram
Nếu không, bạn đang tiếp tục từ phòng thí nghiệm Các tác nhân ở quy mô lớn: Cấu trúc đa tác nhân có giao thức A2A trên Thời gian chạy tác nhân và tích hợp ADK
mv ~/adk-a2a-agent-runtime-starter ~/build-agent-adk-telegram
Sau đó, hãy thay đổi thư mục đang hoạt động của chúng ta thành thư mục đó
cloudshell workspace ~/build-agent-adk-telegram && cd ~/build-agent-adk-telegram
source .env
Sau đó, hãy xác minh rằng restaurant-agent của bạn đã được triển khai và có URL công khai để truy cập
AGENT_URL=$(gcloud run services describe restaurant-agent \
--region="$REGION" \
--format='value(status.url)')
echo " ✓ Agent service deployed"
echo " Agent URL: $AGENT_URL"
echo ""
Nếu truy cập được vào URL, bạn có thể chuyển sang phần tiếp theo: Create Telegram Bot
3. Thiết lập môi trường – Bắt đầu lại từ đầu bằng kho lưu trữ khởi động
Bước này chuẩn bị môi trường Cloud Shell, định cấu hình dự án trên đám mây Google Cloud và sao chép kho lưu trữ ban đầu.
Mở Cloud Shell
Mở Cloud Shell trong trình duyệt. Cloud Shell cung cấp một môi trường được định cấu hình sẵn với tất cả các công cụ bạn cần cho lớp học lập trình này. Nhấp vào Uỷ quyền khi được nhắc
Sau đó, nhấp vào "View" (Xem) -> "Terminal" (Thiết bị đầu cuối) để mở thiết bị đầu cuối.Giao diện của bạn sẽ trông tương tự như thế này

Đây sẽ là giao diện chính của chúng ta, IDE ở trên cùng, thiết bị đầu cuối ở dưới cùng
Thiết lập thư mục làm việc
Sao chép kho lưu trữ khởi đầu. Tất cả mã bạn viết trong lớp học lập trình này sẽ nằm ở đây:
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
Tạo tệp .env từ mẫu được cung cấp:
cp .env.example .env
Để đơn giản hoá việc thiết lập dự án trong thiết bị đầu cuối, hãy tải tập lệnh thiết lập dự án này xuống thư mục làm việc của bạn:
curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh
Chạy tập lệnh. Lệnh này xác minh tài khoản thanh toán dùng thử của bạn, tạo một dự án mới (hoặc xác thực một dự án hiện có), lưu mã dự án vào một tệp .env trong thư mục hiện tại và đặt dự án đang hoạt động trong gcloud.
bash setup_verify_trial_project.sh && source .env
Tập lệnh sẽ:
- Xác minh rằng bạn có một tài khoản thanh toán dùng thử đang hoạt động
- Kiểm tra xem có dự án nào trong
.envhay không (nếu có) - Tạo dự án mới hoặc sử dụng lại dự án hiện có
- Liên kết tài khoản thanh toán dùng thử với dự án của bạn
- Lưu mã dự án vào
.env - Đặt dự án làm dự án
gcloudđang hoạt động
Xác minh rằng dự án được thiết lập đúng cách bằng cách kiểm tra văn bản màu vàng bên cạnh thư mục làm việc của bạn trong dấu nhắc của thiết bị đầu cuối Cloud Shell. Thẻ này phải hiển thị mã dự án của bạn.

Thiết lập cơ sở hạ tầng cơ bản
Trước tiên, chúng ta cần cài đặt các phần phụ thuộc Python bằng uv. Đây là một trình quản lý dự án và gói Python nhanh được viết bằng Rust ( tài liệu về uv). Lớp học lập trình này sử dụng uv để duy trì dự án Python một cách nhanh chóng và đơn giản
uv sync
Sau đó, hãy chạy tập lệnh thiết lập đầy đủ để tạo phiên bản Cloud SQL, gieo dữ liệu và triển khai dịch vụ Hộp công cụ. Dịch vụ này sẽ đóng vai trò là trạng thái ban đầu của tác nhân nhà hàng
bash scripts/full_setup.sh > logs/full_setup.log 2>&1 &
Thao tác này sẽ:
- Tạo một phiên bản Cloud SQL và gieo hạt cơ sở dữ liệu (Giai đoạn 1)
- Tạo cấu hình môi trường tác nhân và khởi động dịch vụ Toolbox cục bộ (Giai đoạn 2)
- Triển khai các dịch vụ Toolbox và Agent lên Cloud Run (Giai đoạn 3)
Sau khi quá trình triển khai này hoàn tất, bạn có thể truy cập vào giao diện người dùng dành cho nhà phát triển ADK trên 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 ""
Mở giao diện người dùng dành cho nhà phát triển ADK, chọn restaurant_agent rồi kiểm thử bằng các truy vấn như ví dụ sau:
What Italian dishes do you have?
Hoặc
I want something spicy and creamy
Giờ đây, hành động tiếp theo là làm cách nào để chuyển từ chỉ có giao diện phát triển web sang kênh nhắn tin Telegram
4. Tạo bot Telegram
Telegram là một nền tảng nhắn tin miễn phí nổi tiếng và được sử dụng rộng rãi cho hoạt động tương tác dựa trên cộng đồng. Một trong những lý do là nền tảng này cung cấp nhiều cách để tích hợp một cách dễ dàng. Do đó, mọi người có thể dễ dàng tạo bot của riêng mình với nhiều chức năng đa dạng.
Trong trường hợp này, chúng ta sẽ sử dụng BotFather để tạo bot của riêng mình lần đầu tiên. Xin lưu ý rằng mặc dù chúng ta đang sử dụng Telegram cho phiên này, nhưng bạn có thể sử dụng phương thức tương tự cho WhatsApp hoặc các nền tảng nhắn tin khác mà bạn chọn.
Sử dụng BotFather để tạo bot của riêng bạn
Truy cập https://telegram.me/BotFather bằng trình duyệt web để bắt đầu tạo bot Telegram của riêng bạn.

Bắt đầu tương tác với The BotFather
Gửi lệnh /start
Để bắt đầu sử dụng BotFather và bắt đầu tạo bot đầu tiên, bạn cần gửi thông báo /start đến BotFather. Sau đó, BotFather sẽ chia sẻ tất cả các lệnh mà bot này có để bạn tương tác thêm.
/start
Bắt đầu tạo bot bằng lệnh /newbot
Hãy tạo bot mới bằng cách gửi lệnh /newbot đến BotFather. Công cụ này sẽ yêu cầu bạn đặt tên cho bot, sau đó yêu cầu bạn cung cấp cho bot username. Yêu cầu này luôn đòi hỏi bot phải kết thúc bằng bot. Ví dụ: TetrisBot hoặc tetris_bot. Giá trị này phải là duy nhất.

Sau khi tạo bot thành công, bạn sẽ nhận được thông báo sau đây từ 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
Hãy lưu ý đến YOUR_TELEGRAM_API_KEY, chúng ta sẽ sử dụng nó trong phần tiếp theo.
5. Phát triển ứng dụng Webhook Telegram
Hãy chuẩn bị thư mục làm việc để bắt đầu phát triển ứng dụng webhook telegram
mkdir ~/build-agent-adk-telegram/telegram-integration
cd ~/build-agent-adk-telegram
Thêm các phần phụ thuộc bắt buộc
Tạo tập lệnh requirements.txt với nội dung sau để cung cấp các phần phụ thuộc thích hợp cho tập lệnh trình nghe webhook của Telegram.
cloudshell edit ./telegram-integration/requirements.txt
Sau đó, hãy thêm các phần phụ thuộc sau
python-telegram-bot[webhooks]
httpx
Tạo tập lệnh cho Trình nghe webhook của Telegram
Sau khi chúng ta cài đặt phần phụ thuộc. Giờ đây, chúng ta có thể tạo một tập lệnh Python main.py cho ứng dụng tích hợp
cloudshell edit ~/build-agent-adk-telegram/telegram-integration/main.py
Sau đó, sao chép mã sau vào tệp đó
# ./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()
Tìm hiểu về mã tích hợp Bot Telegram

Khi người dùng gửi một thông báo, quy trình sau đây sẽ chạy trong handle_message()
Bước 1: Xác định danh tính và phiên
Bot này liên kết Mã nhận dạng người dùng Telegram với các giá trị nhận dạng ADK riêng biệt để phân biệt các phiên người dùng:
user_id = f"tg_{raw_user_id}"
session_id = f"tg_sess_{raw_user_id}"
Bước 2: Trạng thái "Đang nhập" không đồng bộ (Dòng 53–58)
Để đảm bảo trải nghiệm người dùng có độ phản hồi cao trong khi tác nhân ADK xử lý câu lệnh (có thể mất vài giây), bot sẽ bắt đầu một vòng lặp không đồng bộ ở chế độ nền:
asyncio.Eventđược khởi tạo dưới dạngstop_event.asyncio.create_tasktạo rasend_typing_loop(...)ở chế độ nền.- Vòng lặp sẽ gửi thao tác
ChatAction.TYPINGđến Telegram sau mỗi 4 giây cho đến khistop_eventđược đặt.
Bước 3: Xác minh và tạo phiên ADK (Dòng 61 – 72)
Trước khi thực thi tác nhân, bot sẽ kiểm tra xem đã có phiên nào hay chưa:
- Gửi yêu cầu
GETđến/apps/{appName}/users/{userId}/sessions/{sessionId}. - Nếu phản hồi là
404 Not Found, thì yêu cầu này sẽ tạo phiên thông qua yêu cầuPOSTđến cùng một URL với nội dung JSON trống. - Nếu một trạng thái khác với
200hoặc404được trả về, thì một ngoại lệ sẽ được gửi.
Bước 4: Gửi yêu cầu đến trợ lý (Dòng 74 – 85)
Tải trọng thông báo được chuyển tiếp đến điểm cuối /run của ADK:
- Điểm cuối:
POST /run - Thời gian chờ yêu cầu được đặt thành
60.0giây để cho phép suy luận phức tạp hoặc độ trễ ở nguồn. - Cấu trúc tải trọng:
{
"appName": "restaurant_agent",
"userId": "tg_<user_id>",
"sessionId": "tg_sess_<user_id>",
"newMessage": {
"role": "user",
"parts": [{"text": "<user_message>"}]
}
}
Bước 5: Phân tích cú pháp Phản hồi (Dòng 87–101)
Máy chủ ADK trả về danh sách các sự kiện thông báo. Bot kiểm tra mảng được trả về:
- Thao tác này sẽ truy xuất sự kiện cuối cùng trong danh sách (
events[-1]). - Thao tác này sẽ chuyển đến nội dung văn bản thông qua
event["content"]["parts"][0]["text"]. - Nếu không có sự kiện nào được trả về hoặc thiếu cấu trúc văn bản, thì hệ thống sẽ đặt một văn bản giữ chỗ mang tính mô tả.
Bước 6: Phân tích và gửi phản hồi (Dòng 103 – 111)
- Trong khối
finally,stop_eventđược đặt, ngăn chặn vòng lặp thao tác nhập. - Bot sẽ chờ hoàn tất quá trình
typing_taskđể đảm bảo tài nguyên được dọn dẹp. - Cuối cùng, bot sẽ trả lời cuộc trò chuyện trên Telegram bằng văn bản phản hồi đã phân tích cú pháp.
6. Triển khai ứng dụng Telegram Webhook lên Cloud Run
Tiếp theo, chúng ta sẽ triển khai Trình nghe Webhook Telegram cho Cloud Run để bot của chúng ta có thể giao tiếp với trình nghe này
Tạo tệp Docker
Trước tiên, chúng ta cần tạo Dockerfile.
cloudshell edit ~/build-agent-adk-telegram/telegram-integration/Dockerfile
Sau đó, sao chép mã sau vào tệp đó
# 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"]
Dịch vụ này được chứa trong vùng chứa bằng cách sử dụng python:3.11-slim để giữ cho dấu vết hình ảnh nhỏ:
- Cài đặt các phần phụ thuộc từ
requirements.txt(python-telegram-bot[webhooks]vàhttpx). - Hiển thị cổng tiêu chuẩn
8080. - Ra mắt
python main.py.
Chuẩn bị các biến môi trường
Sau đó, hãy kiểm tra lại xem tác nhân của chúng ta đã triển khai thành công hay chưa
AGENT_URL=$(gcloud run services describe restaurant-agent \
--region="$REGION" \
--format='value(status.url)')
echo " ✓ Agent service deployed"
echo " Agent URL: $AGENT_URL"
echo ""
Tiếp theo, hãy đặt TELEGRAM_BOT_TOKEN mà chúng ta đã lấy trước đó vào .env
echo "TELEGRAM_BOT_TOKEN=YOUR_TELEGRAM_API_KEY" >> .env
Sau đó, hãy điền dữ liệu .env bằng các giá trị khác mà chúng ta cần.
echo "ADK_SERVER_URL=$AGENT_URL" >> .env
echo "ADK_APP_NAME=restaurant_agent" >> .env
echo "SERVICE_NAME=telegram-integration" >> .env
source .env
Tạo tập lệnh triển khai
Hãy tạo tập lệnh triển khai để cung cấp các bước kiểm tra hoàn chỉnh và triển khai ứng dụng vào Cloud Run
cloudshell edit ~/build-agent-adk-telegram/telegram-integration/deploy.sh
Và sao chép mã sau đây vào tệp
#!/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."
Tập lệnh triển khai kép (deploy.sh)
Khi triển khai đến Google Cloud Run, bot cần chỉ định URL riêng (SERVICE_URL) trong môi trường của mình để có thể đăng ký URL đó làm mục tiêu webhook với Telegram. Để giải quyết sự phụ thuộc vòng tròn này (URL không xác định cho đến khi triển khai, nhưng dịch vụ yêu cầu URL khởi động mà không gặp lỗi kiểm tra tình trạng), deploy.sh sẽ thực hiện quy trình triển khai gồm 2 giai đoạn:
- Bước 1: Triển khai ban đầu: Khởi động vùng chứa bằng một DNS giữ chỗ (
https://google.com) để dịch vụ khởi động thành công, liên kết với cổng cục bộ và vượt qua các quy trình kiểm tra tình trạng ban đầu của Cloud Run. - Bước 2: Tìm nạp URL: Trích xuất theo chương trình điểm cuối Cloud Run mới tạo bằng cách sử dụng
gcloud run services describe. - Bước 3: Cập nhật cấu hình: Cập nhật các biến môi trường bằng URL thực tế của dịch vụ đang hoạt động. Thao tác này sẽ kích hoạt một bản cập nhật luân phiên sạch trong Cloud Run và đăng ký an toàn mục tiêu webhook chính xác bằng Telegram API.
Triển khai lên Cloud Run
Tập lệnh triển khai sẽ in URL của Nhân viên hỗ trợ. Mở tệp này trong trình duyệt để truy cập vào cùng một giao diện người dùng dành cho nhà phát triển ADK đang chạy trên Cloud Run.
cd ~/build-agent-adk-telegram
bash ./telegram-integration/deploy.sh
Nếu mọi thứ diễn ra suôn sẻ, đây là thời điểm bạn có thể bắt đầu trò chuyện với bot ngay trong ứng dụng trò chuyện Telegram, tìm bot mà bạn vừa tạo và bắt đầu tương tác với bot đó:
What Italian dishes do you have?
Hoặc
I want something spicy and creamy
Xem trạng thái gửi của bot "...đang nhập" và sau đó, bot sẽ sớm trả về thông báo từ ADK mà bạn đã tạo trước đó!

7. Xin chúc mừng!
Bạn đã tạo, triển khai và tích hợp hoàn toàn tác nhân AI ADK trợ lý thực đơn thông minh với Telegram thông qua giao tiếp máy khách-máy chủ HTTP, đồng thời cho phép mọi người truy vấn thực đơn yêu thích và đặt chỗ tại nhà hàng.
Kiến thức bạn học được
- Triển khai và định cấu hình Trợ lý nhà hàng, tác nhân dựa trên ADK và Bộ công cụ MCP cho Cloud Run
- Cách thiết lập bot Telegram bằng BotFather
- Cách viết tập lệnh Python để theo dõi webhook Telegram và tương tác với tác nhân ADK để truyền truy vấn và phản hồi của người dùng một cách phù hợp
- Cách triển khai
"... typing"trong Telegram để báo hiệu rằng tin nhắn đang được xử lý dưới dạng ý kiến phản hồi theo thời gian thực cho người dùng trong khi chờ tác nhân ADK phản hồi. - Cách triển khai tập lệnh Python vào Cloud Run và có thể tương tác với tập lệnh đó
Dọn dẹp
Để tránh bị tính phí vào tài khoản Google Cloud của bạn, hãy xoá các tài nguyên đã tạo trong lớp học lập trình này.
Cách 1: Xoá dự án (nên dùng)
gcloud projects delete $GOOGLE_CLOUD_PROJECT
Cách 2: Xoá từng tài nguyên
# 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
