1. Giới thiệu
Trong buổi thực hành này, bạn sẽ vượt qua các chatbot cơ bản, không trạng thái để tạo một Lễ tân quán cà phê thông minh – một tác nhân AI do Gemini hỗ trợ, đóng vai trò là một nhân viên pha chế thân thiện. Ứng dụng này nhận các đơn đặt hàng cà phê được theo dõi trong trạng thái phiên, ghi nhớ các lựa chọn ưu tiên về chế độ ăn uống dài hạn trong trạng thái theo phạm vi người dùng và duy trì mọi thứ trong cơ sở dữ liệu Cloud SQL PostgreSQL. Đến cuối cùng, trợ lý của bạn sẽ nhớ rằng bạn không dung nạp được đường lactose ngay cả sau khi bạn khởi động lại ứng dụng và bắt đầu một cuộc trò chuyện hoàn toàn mới.
Sau đây là kiến trúc hệ thống mà chúng ta sẽ xây dựng

Đ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
- Không cần có kinh nghiệm sử dụng ADK, các tác nhân AI hoặc Cloud SQL
Kiến thức bạn sẽ học được
- Tạo một tác nhân AI bằng Bộ công cụ phát triển tác nhân (ADK) của Google với các công cụ tuỳ chỉnh
- Xác định những công cụ đọc và ghi trạng thái phiên thông qua
ToolContext - Phân biệt giữa trạng thái trong phạm vi phiên và trạng thái trong phạm vi người dùng (tiền tố
user:) - Cung cấp một phiên bản Cloud SQL PostgreSQL và kết nối với phiên bản đó từ Cloud Shell
- Di chuyển từ bộ nhớ cục bộ (theo mặc định khi bạn dùng lệnh
adk web) sangDatabaseSessionServiceđể lưu trữ ổn định bằng cơ sở dữ liệu chuyên dụng - Xác minh rằng bộ nhớ của tác nhân vẫn tồn tại khi ứng dụng khởi động lại và trong các phiên trò chuyện riêng biệt
Bạn cần có
- Máy tính hoạt động và kết nối Internet ổn định.
- Một trình duyệt, chẳng hạn như Chrome, để truy cập vào Google Cloud Console
- Có tư duy tò mò và ham học hỏi.
2. Thiết lập môi trường
Bước này chuẩn bị môi trường Cloud Shell và định cấu hình dự án của bạn trên Google Cloud
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
Giao diện của bạn sẽ có dạng như sau

Đâ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
Tạo thư mục làm việc. Tất cả mã bạn viết trong lớp học lập trình này đều nằm ở đây, tách biệt với kho lưu trữ tham chiếu:
# Create your working directory
mkdir -p ~/build-agent-adk-cloudsql
# Change cloudshell workspace and working directory into previously created dir
cloudshell workspace ~/build-agent-adk-cloudsql && cd ~/build-agent-adk-cloudsql
Để tạo cửa sổ dòng lệnh, hãy tìm View -> Terminal (Xem -> Cửa sổ dòng lệnh)

Thiết lập dự án trên Google Cloud và các biến môi trường ban đầu
Tải tập lệnh thiết lập dự án 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. Thao tác này sẽ 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 tệp .env trong thư mục hiện tại và đặt dự án đang hoạt động trong thiết bị đầu cuối
bash setup_verify_trial_project.sh && source .env
Khi chạy lệnh này, bạn sẽ thấy lời nhắc về tên mã dự án được đề xuất, bạn có thể nhấn Enter để tiếp tục

Sau một thời gian chờ đợi, nếu thấy kết quả này trong bảng điều khiển, thì bạn đã sẵn sàng chuyển sang bước tiếp theo 
Tập lệnh đã thực thi sẽ thực hiện các bước sau:
- 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 sẽ hiển thị mã dự án của bạn.

Bật các API bắt buộc
Bật các API Google Cloud cần thiết cho lớp học lập trình này:
gcloud services enable \
aiplatform.googleapis.com \
sqladmin.googleapis.com \
compute.googleapis.com
- Vertex AI API (
aiplatform.googleapis.com) – tác nhân của bạn sử dụng các mô hình Gemini thông qua Vertex AI. - Cloud SQL Admin API (
sqladmin.googleapis.com) – bạn cung cấp và quản lý một phiên bản PostgreSQL để lưu trữ liên tục. - Compute Engine API (
compute.googleapis.com) – bắt buộc để tạo phiên bản Cloud SQL.
Định cấu hình khu vực cho Gemini và các sản phẩm của Cloud
Trước khi tiếp tục, hãy thiết lập cấu hình vị trí/khu vực cần thiết cho sản phẩm mà chúng ta tương tác. Thêm cấu hình sau vào tệp .env
# This is for our Gemini endpoint
echo "GOOGLE_CLOUD_LOCATION=global" >> .env
# This is for our other Cloud products
echo "REGION=us-central1" >> .env
source .env
Hãy tiếp tục chuyển sang bước tiếp theo
3. Thiết lập Cloud SQL
Bước này sẽ cung cấp một phiên bản Cloud SQL PostgreSQL và chuyển tác nhân của bạn từ bộ nhớ trong sang bộ nhớ dựa trên cơ sở dữ liệu. Việc tạo phiên bản mất vài phút, vì vậy, trước tiên bạn sẽ bắt đầu tạo phiên bản và chúng ta vẫn có thể tiếp tục thảo luận về chủ đề tiếp theo trong khi chờ quá trình này hoàn tất
Bắt đầu tạo phiên bản
Thêm mật khẩu cơ sở dữ liệu vào tệp .env và tải lại tệp đó. Chúng ta sẽ sử dụng cafe-agent-pwd-2025 làm mật khẩu.
echo "DB_PASSWORD=cafe-agent-pwd-2025" >> .env
source .env
Chạy lệnh này để tạo một phiên bản Cloud SQL PostgreSQL. Quá trình này sẽ mất vài phút. Hãy để quá trình này chạy và tiếp tục chuyển sang phần tiếp theo.
gcloud sql instances create cafe-concierge-db \
--database-version=POSTGRES_17 \
--edition=ENTERPRISE \
--region=${REGION} \
--availability-type=ZONAL \
--project=${GOOGLE_CLOUD_PROJECT} \
--tier=db-f1-micro \
--root-password=${DB_PASSWORD} \
--quiet &
Một số lưu ý về lệnh trên:
db-f1-microlà cấp Cloud SQL nhỏ nhất (và rẻ nhất) – đủ cho lớp học lập trình này.--root-passwordđặt mật khẩu cho người dùng postgres mặc định.- Hậu tố
&trong lệnh này sẽ chạy lệnh ở chế độ nền để bạn có thể tiếp tục làm việc.
Quy trình này sẽ chạy ở chế độ nền, tuy nhiên, đầu ra của bảng điều khiển đôi khi sẽ xuất hiện trong thiết bị đầu cuối hiện tại. Hãy mở một thẻ dòng lệnh mới trong Cloud Shell (nhấp vào biểu tượng +) để chúng ta có thể tập trung hơn.

Chuyển đến thư mục làm việc của bạn một lần nữa và kích hoạt dự án bằng tập lệnh thiết lập trước đó.
cd ~/build-agent-adk-cloudsql
bash setup_verify_trial_project.sh && source .env
Sau đó, hãy tiếp tục chuyển sang phần tiếp theo
4. Xây dựng tác nhân hướng dẫn khách tại quán cà phê
Bước này sẽ tạo cấu trúc dự án cho tác nhân ADK của bạn và xác định một Cafe Concierge cơ bản bằng công cụ trình đơn.
Khởi chạy dự án Python
Lớp học lập trình này sử dụng uv, một trình quản lý gói Python nhanh chóng, xử lý các môi trường ảo và phần phụ thuộc trong một công cụ. Công cụ này được cài đặt sẵn trong Cloud Shell.
Khởi chạy một dự án Python và thêm ADK làm phần phụ thuộc:
uv init
uv add google-adk==1.25.0 asyncpg
uv init tạo một pyproject.toml và một môi trường ảo. uv sẽ thêm phần phụ thuộc và ghi lại phần phụ thuộc đó trong pyproject.toml.
Khởi tạo cấu trúc dự án của tác nhân
ADK yêu cầu một bố cục thư mục cụ thể: một thư mục được đặt tên theo tác nhân của bạn chứa __init__.py, agent.py và cả .env bên trong thư mục tác nhân
ADK có lệnh tích hợp giúp bạn thiết lập nhanh chóng, hãy chạy lệnh sau
uv run adk create cafe_concierge \
--model gemini-2.5-flash \
--project ${GOOGLE_CLOUD_PROJECT} \
--region ${GOOGLE_CLOUD_LOCATION}
Lệnh này sẽ tạo một cấu trúc tác nhân với gemini-2.5-flash làm bộ não. Thư mục của bạn hiện sẽ có dạng như sau:
build-agent-adk-cloudsql/ ├── cafe_concierge/ │ ├── __init__.py │ ├── agent.py │ └── .env ├── pyproject.toml ├── .env ├── .venv/ └── ...
Viết nhân viên hỗ trợ
Mở cafe_concierge/agent.py trong Trình chỉnh sửa Cloud Shell
cloudshell edit cafe_concierge/agent.py
và ghi đè tệp bằng đoạn mã sau
# cafe_concierge/agent.py
from google.adk.agents import LlmAgent
from google.adk.tools import ToolContext
CAFE_MENU = {
"espresso": {
"price": 3.50,
"description": "Rich and bold single shot",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"latte": {
"price": 5.00,
"description": "Espresso with steamed milk",
"tags": ["gluten-free"],
},
"oat milk latte": {
"price": 5.50,
"description": "Espresso with steamed oat milk",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"cappuccino": {
"price": 4.50,
"description": "Espresso with equal parts steamed milk and foam",
"tags": ["gluten-free"],
},
"cold brew": {
"price": 4.00,
"description": "Slow-steeped for 12 hours, served over ice",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"matcha latte": {
"price": 5.50,
"description": "Ceremonial grade matcha with steamed milk",
"tags": ["gluten-free"],
},
"croissant": {
"price": 3.00,
"description": "Buttery, flaky French pastry",
"tags": [],
},
"banana bread": {
"price": 3.50,
"description": "Homemade with walnuts",
"tags": ["vegan"],
},
}
def get_menu() -> dict:
"""Returns the full cafe menu with prices, descriptions, and dietary tags.
Use this tool when the customer asks what's available, wants to see
the menu, or asks about specific items.
"""
return CAFE_MENU
root_agent = LlmAgent(
name="cafe_concierge",
model="gemini-2.5-flash",
instruction="""You are a friendly and knowledgeable barista at "The Cloud Cafe".
Your job:
- Help customers browse the menu and answer questions about items.
- Take coffee and food orders.
- Remember and respect dietary preferences.
Be conversational, warm, and concise. If a customer mentions a dietary
restriction, acknowledge it and suggest suitable options from the menu.
""",
tools=[get_menu],
)
Thao tác này xác định một tác nhân cơ bản có một công cụ: get_menu(). Trợ lý ảo có thể trả lời các câu hỏi về thực đơn nhưng chưa thể theo dõi đơn đặt hàng hoặc ghi nhớ các lựa chọn ưu tiên.
Xác minh rằng nhân viên hỗ trợ đang chạy
Khởi động giao diện người dùng dành cho nhà phát triển ADK từ thư mục làm việc của bạn:
cd ~/build-agent-adk-cloudsql
uv run adk web
Mở URL xuất hiện trong thiết bị đầu cuối (thường là http://localhost:8000) bằng tính năng Xem trước trên web của Cloud Shell. Chọn cafe_concierge trong trình đơn thả xuống của nhân viên hỗ trợ ở góc trên cùng bên trái.
Nhập văn bản sau vào thanh trò chuyện và xác minh rằng trợ lý ảo phản hồi bằng các mục trong trình đơn và giá.
What's on the menu?

Dừng giao diện người dùng dành cho nhà phát triển bằng tổ hợp phím Ctrl+C trước khi tiếp tục.
5. Thêm tính năng Quản lý đơn đặt hàng có trạng thái
Trợ lý có thể cho bạn xem thực đơn nhưng không thể nhận đơn đặt hàng hoặc ghi nhớ lựa chọn ưu tiên. Bước này sẽ thêm 4 công cụ sử dụng hệ thống trạng thái của ADK để theo dõi đơn đặt hàng trong một cuộc trò chuyện và lưu trữ các lựa chọn ưu tiên về chế độ ăn uống trong các cuộc trò chuyện.
Tìm hiểu về sự kiện và trạng thái phiên
Mọi cuộc trò chuyện ADK đều nằm trong một đối tượng Session. Một phiên theo dõi 2 điều riêng biệt: sự kiện và trạng thái. Hiểu rõ sự khác biệt là yếu tố then chốt để xây dựng các tác nhân ghi nhớ đúng những điều cần thiết theo cách phù hợp.
Sự kiện là nhật ký theo trình tự thời gian của mọi hoạt động diễn ra trong một cuộc trò chuyện. Mỗi tin nhắn của người dùng, mỗi câu trả lời của nhân viên hỗ trợ, mỗi lệnh gọi công cụ và giá trị trả về của lệnh gọi đó đều được ghi lại dưới dạng một Event và được thêm vào danh sách events của phiên. Các sự kiện là bất biến: sau khi được ghi lại, chúng sẽ không bao giờ thay đổi. Hãy coi các sự kiện là bản chép lời đầy đủ của một cuộc trò chuyện.
Trạng thái là một bản nháp khoá-giá trị mà tác nhân đọc và ghi trong cuộc trò chuyện. Không giống như sự kiện, trạng thái có thể thay đổi – các giá trị sẽ thay đổi khi cuộc trò chuyện diễn ra. Trạng thái là nơi nhân viên hỗ trợ lưu trữ dữ liệu có cấu trúc mà nhân viên hỗ trợ cần để thực hiện hành động: đơn đặt hàng hiện tại, lựa chọn ưu tiên của khách hàng, tổng số tiền đang chạy. Hãy coi trạng thái như những tờ giấy nhớ mà nhân viên hỗ trợ giữ bên cạnh bản chép lời.
Mối quan hệ giữa các chỉ số này như sau:

Các công cụ đọc và ghi trạng thái thông qua ToolContext – một đối tượng mà ADK tự động chèn vào mọi hàm công cụ khai báo đối tượng này dưới dạng tham số. Bạn không tự tạo mã này. Thông qua tool_context.state, một công cụ có thể đọc và ghi vào bảng nháp trạng thái của phiên. ADK kiểm tra chữ ký hàm: các tham số có kiểu ToolContext sẽ được chèn, tất cả các tham số khác sẽ được LLM điền dựa trên cuộc trò chuyện.
Khi một công cụ ghi vào tool_context.state, ADK sẽ ghi lại thay đổi đó dưới dạng state_delta trong sự kiện. Sau đó, SessionService sẽ áp dụng mức chênh lệch cho trạng thái hiện tại của phiên. Điều này có nghĩa là bạn luôn có thể truy nguyên các thay đổi về trạng thái trở lại sự kiện đã gây ra những thay đổi đó. Điều này cũng đúng với các loại ngữ cảnh khác như callback_context
Tìm hiểu về tiền tố trạng thái
Các khoá trạng thái sử dụng tiền tố để kiểm soát phạm vi của chúng:
Tiền tố | Phạm vi | Có tồn tại sau khi khởi động lại không? (với DB) |
(không có) | Chỉ phiên hiện tại | Có |
| Tất cả các phiên của người dùng này | Có |
| Tất cả phiên, tất cả người dùng | Có |
| Chỉ lệnh gọi hiện tại | Không |
Trong lớp học lập trình này, bạn sẽ sử dụng 2 tiền tố trong số này: khoá không có tiền tố cho dữ liệu ở phạm vi phiên (đơn đặt hàng hiện tại – chỉ liên quan đến cuộc trò chuyện này) và khoá user: cho dữ liệu ở phạm vi người dùng (lựa chọn ưu tiên về chế độ ăn uống – liên quan đến tất cả cuộc trò chuyện của người dùng này).
Thêm các công cụ có trạng thái
Mở cafe_concierge/agent.py trong Trình chỉnh sửa Cloud Shell.
cloudshell edit cafe_concierge/agent.py
Sau đó, hãy thêm 4 hàm sau phía trên định nghĩa root_agent:
# cafe_concierge/agent.py (add below get_menu, above root_agent)
def place_order(tool_context: ToolContext, items: list[str]) -> dict:
"""Places an order for the specified menu items.
Use this tool when the customer confirms they want to order something.
Args:
tool_context: Provided automatically by ADK.
items: A list of menu item names the customer wants to order.
"""
valid_items = []
invalid_items = []
total = 0.0
for item in items:
item_lower = item.lower()
if item_lower in CAFE_MENU:
valid_items.append(item_lower)
total += CAFE_MENU[item_lower]["price"]
else:
invalid_items.append(item)
if not valid_items:
return {"error": f"None of these items are on our menu: {invalid_items}"}
order = {"items": valid_items, "total": round(total, 2)}
tool_context.state["current_order"] = order
result = {"order": order}
if invalid_items:
result["warning"] = f"These items are not on our menu: {invalid_items}"
return result
def get_order_summary(tool_context: ToolContext) -> dict:
"""Returns the current order summary for this session.
Use this tool when the customer asks about their current order,
wants to review what they ordered, or asks for the total.
Args:
tool_context: Provided automatically by ADK.
"""
order = tool_context.state.get("current_order")
if order:
return {"order": order}
return {"message": "No order has been placed yet in this session."}
def set_dietary_preference(tool_context: ToolContext, preference: str) -> dict:
"""Saves a dietary preference that persists across all conversations.
Use this tool when the customer mentions a dietary restriction or
preference (e.g., "I'm vegan", "I'm lactose intolerant",
"I have a nut allergy").
Args:
tool_context: Provided automatically by ADK.
preference: The dietary preference to save (e.g., "vegan",
"lactose intolerant", "nut allergy").
"""
existing = tool_context.state.get("user:dietary_preferences", [])
if not isinstance(existing, list):
existing = []
preference_lower = preference.lower().strip()
if preference_lower not in existing:
existing.append(preference_lower)
tool_context.state["user:dietary_preferences"] = existing
return {
"saved": preference_lower,
"all_preferences": existing,
}
def get_dietary_preferences(tool_context: ToolContext) -> dict:
"""Retrieves the customer's saved dietary preferences.
Use this tool when you need to check the customer's dietary
restrictions before making recommendations.
Args:
tool_context: Provided automatically by ADK.
"""
preferences = tool_context.state.get("user:dietary_preferences", [])
if preferences:
return {"preferences": preferences}
return {"message": "No dietary preferences saved yet."}
Hai điều cần lưu ý:
place_ordervàget_order_summarysử dụng các khoá không có tiền tố (current_order). Trạng thái này gắn liền với phiên hiện tại – một cuộc trò chuyện mới bắt đầu bằng một đơn đặt hàng trống.set_dietary_preferencevàget_dietary_preferencessử dụng tiền tốuser:(user:dietary_preferences). Trạng thái này được chia sẻ trên tất cả các phiên của cùng một người dùng.
Cập nhật cho nhân viên hỗ trợ các công cụ và hướng dẫn mới
Thay thế định nghĩa root_agent hiện có ở cuối tệp bằng:
# cafe_concierge/agent.py (replace the existing root_agent)
root_agent = LlmAgent(
name="cafe_concierge",
model="gemini-2.5-flash",
instruction="""You are a friendly and knowledgeable barista at "The Cloud Cafe".
Your job:
- Help customers browse the menu and answer questions about items.
- Take coffee and food orders.
- Remember and respect dietary preferences.
The customer's saved dietary preferences are: {user:dietary_preferences?}
IMPORTANT RULES:
- When a customer mentions a dietary restriction, ALWAYS save it using the
set_dietary_preference tool before doing anything else.
- Before recommending items, check the customer's dietary preferences. If they
have preferences saved, only recommend items compatible with those
restrictions. Check the menu item tags to determine compatibility.
- When placing an order, confirm the items and total with the customer.
Be conversational, warm, and concise.
""",
tools=[
get_menu,
place_order,
get_order_summary,
set_dietary_preference,
get_dietary_preferences,
],
)
Hướng dẫn này sử dụng mẫu chèn trạng thái {user:dietary_preferences?} để chèn trực tiếp các lựa chọn ưu tiên đã lưu của khách hàng này vào câu lệnh.
Xác minh toàn bộ tệp
cafe_concierge/agent.py của bạn hiện phải chứa:
- Từ điển
CAFE_MENU - 5 chức năng của công cụ:
get_menu,place_order,get_order_summary,set_dietary_preference,get_dietary_preferences - Định nghĩa về
root_agentvới cả 5 công cụ
6. Kiểm thử Agent bằng giao diện người dùng dành cho nhà phát triển ADK
Bước này chạy tác nhân và thực hiện tất cả các tính năng có trạng thái: sắp xếp, theo dõi lựa chọn ưu tiên và bộ nhớ trên nhiều phiên (trong cùng một quy trình). Bạn cũng sẽ kiểm tra các bảng điều khiển Sự kiện và Trạng thái để xem ADK theo dõi cuộc trò chuyện như thế nào.
Khởi động giao diện người dùng dành cho nhà phát triển
cd ~/build-agent-adk-cloudsql
uv run adk web
Mở Web Preview (Xem trước trên web) trên cổng 8000 và chọn cafe_concierge trong trình đơn thả xuống.
Cuộc trò chuyện 1: Đặt hàng và thiết lập lựa chọn ưu tiên
Hãy thử các câu lệnh sau theo trình tự:
What's on the menu?
I'm lactose intolerant
What would you recommend?
I'll have an oat milk latte and a banana bread
What's my order?
Kiểm tra các sự kiện trong phiên
Tất cả Sự kiện sẽ được ghi lại và hiển thị trên giao diện người dùng web. Bạn sẽ thấy rằng trong hộp trò chuyện, không chỉ có câu lệnh và câu trả lời của bạn mà còn có tool_call và tool_response

Bạn sẽ thấy danh sách các sự kiện theo thứ tự. Mỗi sự kiện có một tác giả (người tạo ra sự kiện đó) và một loại (loại tương tác mà sự kiện đó đại diện):
Tác giả | Loại | Ý nghĩa |
|
| Tin nhắn bạn nhập trong cuộc trò chuyện |
|
| Phản hồi bằng văn bản của nhân viên hỗ trợ |
|
| Trợ lý quyết định gọi một công cụ (hiển thị tên hàm + đối số) |
|
| Giá trị trả về từ một lệnh gọi công cụ |
Nhấp vào một trong các sự kiện tool_call, ví dụ: cuộc gọi set_dietary_preference. Bạn sẽ thấy:
- Tên hàm:
set_dietary_preference - Đối số:
{"preference": "lactose intolerant"}
Giờ đây, hãy nhấp vào sự kiện tool_response tương ứng ngay bên dưới. Bạn sẽ thấy giá trị trả về:
- Phản hồi:
{"saved": "lactose intolerant", "all_preferences": ["lactose intolerant"]}

Tìm trường state_delta bên trong sự kiện tool_response. Điều này cho thấy chính xác trạng thái nào đã thay đổi do lệnh gọi công cụ này:
state_delta: {"user:dietary_preferences": ["lactose intolerant"]}
Mọi thay đổi về trạng thái đều có thể truy nguyên đến một sự kiện cụ thể. Đây là cách ADK đảm bảo bảng nháp trạng thái luôn đồng bộ hoá với nhật ký trò chuyện.
Kiểm tra trạng thái phiên
Nhấp vào thẻ Trạng thái. Không giống như nhật ký sự kiện (cho biết toàn bộ nhật ký), thẻ trạng thái cho thấy ảnh chụp nhanh về những gì mà tác nhân biết ngay bây giờ – giá trị hiện tại của mọi khoá trạng thái.

Bạn sẽ thấy 2 mục:
current_order–{"items": ["oat milk latte", "banana bread"], "total": 9.0}user:dietary_preferences–["lactose intolerant"]
Hãy lưu ý sự khác biệt về tên khoá:
current_orderkhông có tiền tố – đó là phương diện trong phạm vi phiên hoạt động. Thông tin này chỉ tồn tại trong cuộc trò chuyện này và sẽ biến mất khi phiên kết thúc.user:dietary_preferencescó tiền tốuser:– đây là phương diện trong phạm vi người dùng. Giá trị này được dùng chung cho mọi phiên của người dùng này.
Sự khác biệt này không xuất hiện trong mã (cả hai đều sử dụng tool_context.state), nhưng nó kiểm soát phạm vi tiếp cận của dữ liệu. Bạn sẽ thấy điều này diễn ra trong bài kiểm thử tiếp theo.
Cuộc trò chuyện 2: Xác minh trạng thái người dùng trên nhiều phiên
Nhấp vào nút Phiên mới trong giao diện người dùng dành cho nhà phát triển để bắt đầu một cuộc trò chuyện mới. Thao tác này sẽ tạo một phiên mới cho cùng một người dùng.

Hãy thử câu lệnh này:
What do you recommend for me?
Kiểm tra thẻ Trạng thái trong phiên mới. Khoá user:dietary_preferences vẫn được giữ lại, nhưng current_order đã biến mất – trạng thái đó được liên kết với phiên trước.

7. Tuân thủ giới hạn về bộ nhớ cục bộ
Trợ lý sẽ ghi nhớ các lựa chọn ưu tiên giữa các phiên – nhưng chỉ khi bộ nhớ cục bộ tồn tại. Bước này minh hoạ hạn chế cơ bản của bộ nhớ cục bộ.
Khởi động lại tác nhân
Bạn đã dừng giao diện người dùng dành cho nhà phát triển ở cuối bước trước. Bây giờ, hãy xoá bộ nhớ cục bộ rồi khởi động lại để mô phỏng môi trường không máy chủ không có trạng thái:
cd ~/build-agent-adk-cloudsql
rm -f cafe_concierge/.adk/session.db
uv run adk web
Bây giờ, hãy mở Web Preview trên cổng 8000 rồi chọn cafe_concierge.
Kiểm tra khả năng ghi nhớ lựa chọn ưu tiên
Loại:
Do you remember my dietary preferences?
Nhân viên hỗ trợ không nhớ gì cả. Lựa chọn ưu tiên về chế độ ăn uống, nhật ký đơn đặt hàng – tất cả đều biến mất.

Mọi thứ đều bị xoá sạch khi chúng tôi xoá bộ nhớ cục bộ. Việc này thường xảy ra khi chúng tôi sử dụng một môi trường không có máy chủ. session.db lưu trữ tất cả trạng thái trong bộ nhớ quy trình. Khi bạn xoá, tất cả dữ liệu sẽ bị xoá.
Giải pháp: chỉ định DatabaseSessionService. Trong hướng dẫn này, DatabaseSessionService sẽ lưu trữ tất cả dữ liệu phiên trong cơ sở dữ liệu PostgreSQL trong Cloud SQL. Mã và công cụ của tác nhân vẫn hoàn toàn giống nhau – chỉ có phần phụ trợ lưu trữ thay đổi.
Dừng giao diện người dùng dành cho nhà phát triển bằng tổ hợp phím Ctrl+C trước khi tiếp tục.
8. Xem lại chế độ thiết lập cơ sở dữ liệu
Tại thời điểm này, quá trình tạo thực thể cơ sở dữ liệu của chúng ta đã hoàn tất. Hãy xác minh bằng cách chạy lệnh sau
gcloud sql instances describe cafe-concierge-db --format="value(state)"
Bạn sẽ thấy kết quả sau đây, hãy đánh dấu là đã đọc xong
RUNNABLE
Tạo cơ sở dữ liệu
Tạo một cơ sở dữ liệu chuyên dụng cho dữ liệu phiên của tác nhân:
gcloud sql databases create agent_db --instance=cafe-concierge-db
Khởi động Proxy xác thực Cloud SQL
Cloud SQL Auth Proxy cung cấp một kết nối an toàn, được xác thực từ Cloud Shell đến thực thể Cloud SQL mà không cần đưa địa chỉ IP vào danh sách cho phép. Công cụ này đã được cài đặt sẵn trên Cloud Shell.
cloud-sql-proxy ${GOOGLE_CLOUD_PROJECT}:${REGION}:cafe-concierge-db --port 5432 &
Hậu tố & trong lệnh này giúp proxy chạy ở chế độ nền. Bạn sẽ thấy kết quả xác nhận rằng proxy đã sẵn sàng như minh hoạ bên dưới
[your-project-id:your-region:cafe-concierge-db] Listening on 127.0.0.1:5432 The proxy has started successfully and is ready for new connections!
Xác minh kết nối
Kiểm tra xem bạn có thể kết nối với cơ sở dữ liệu thông qua proxy hay không:
psql "host=127.0.0.1 port=5432 dbname=agent_db user=postgres password=$DB_PASSWORD" -c "SELECT 'Connection ok' AS status;"
Bạn sẽ thấy:
status --------------------- Connection ok (1 row)
9. Xác minh bộ nhớ liên tục trên các phiên
Bước này chứng minh rằng bộ nhớ của trợ lý ảo vẫn hoạt động sau khi đặt lại khi chúng ta đảm bảo rằng cafe_concierge/.adk/session_db (cơ sở dữ liệu cục bộ) bị xoá và trải rộng trên các phiên trò chuyện.
Khởi động tác nhân
Đảm bảo rằng Cloud SQL Auth Proxy vẫn đang chạy (kiểm tra bằng các lệnh). Nếu không, hãy khởi động lại thiết bị:
if ss -tlnp | grep -q ':5432 '; then
echo "Cloud SQL Auth Proxy is already running."
else
cloud-sql-proxy ${GOOGLE_CLOUD_PROJECT}:${REGION}:cafe-concierge-db --port 5432 &
fi
Sau đó, hãy bắt đầu giao diện người dùng dành cho nhà phát triển ADK bằng cách chỉ định cơ sở dữ liệu làm dịch vụ phiên
uv run adk web --session_service_uri postgresql+asyncpg://postgres:${DB_PASSWORD}@127.0.0.1:5432/agent_db
Mở Web Preview (Xem trước trên web) trên cổng 8000 rồi chọn cafe_concierge.
Thử nghiệm 1: Đặt hàng và thiết lập lựa chọn ưu tiên
Trong phiên đầu tiên, hãy chạy các câu lệnh sau:
Show me the menu
I'm vegan
What can I eat?
I'll have a cold brew and banana bread
Bài kiểm thử 2: Vượt qua quá trình khởi động lại
Dừng giao diện người dùng dành cho nhà phát triển bằng tổ hợp phím Ctrl+C và đảm bảo rằng session.db cục bộ đã bị xoá
rm -f cafe_concierge/.adk/session.db
Sau đó, hãy chạy lại máy chủ giao diện người dùng dành cho nhà phát triển
uv run adk web --session_service_uri postgresql+asyncpg://postgres:${DB_PASSWORD}@127.0.0.1:5432/agent_db
Mở Web Preview (Xem trước trên web) trên cổng 8000, chọn cafe_concierge rồi bắt đầu một phiên mới. Sau đó, hãy hỏi
What are my dietary preferences?
Trợ lý sẽ phản hồi bằng lựa chọn ưu tiên đã lưu của bạn – thuần chay. Dữ liệu vẫn còn sau khi khởi động lại vì hiện được lưu trữ trong PostgreSQL chứ không phải trong bộ nhớ cục bộ. Điều này cũng xảy ra nếu chúng ta tạo phiên mới vì trạng thái user: sẽ được chuyển sang mọi phiên mới của người dùng này.

Kiểm tra trực tiếp cơ sở dữ liệu
Mở một thẻ thiết bị đầu cuối mới trong Cloud Shell và truy vấn cơ sở dữ liệu để xem dữ liệu đã lưu trữ:
psql "host=127.0.0.1 port=5432 dbname=agent_db user=postgres password=$DB_PASSWORD" -c "\dt"
Bạn sẽ thấy các bảng mà ADK tự động tạo để lưu trữ các phiên, sự kiện và trạng thái như ví dụ này
List of relations Schema | Name | Type | Owner --------+-----------------------+-------+---------- public | adk_internal_metadata | table | postgres public | app_states | table | postgres public | events | table | postgres public | sessions | table | postgres public | user_states | table | postgres (5 rows)
Tóm tắt hành vi của trạng thái
Khoá trạng thái | Tiền tố | Phạm vi | Được chia sẻ giữa các phiên? |
| (không có) | Phiên | Không |
|
| Người dùng | Có |
10. Chúc mừng / Dọn dẹp
Xin chúc mừng! Bạn đã tạo thành công một tác nhân AI có trạng thái và duy trì bằng cách sử dụng ADK và Cloud SQL.
Kiến thức bạn học được
- Cách tạo một tác nhân ADK bằng các công cụ tuỳ chỉnh có thể đọc và ghi trạng thái phiên
- Sự khác biệt giữa trạng thái trong phạm vi phiên (không có tiền tố) và trạng thái trong phạm vi người dùng (tiền tố
user:) - Tại sao adk local
session.dbmặc định chỉ phù hợp cho quá trình phát triển – tất cả dữ liệu sẽ bị mất khi xoá (và dễ xoá, không có bản sao lưu), không phù hợp với việc triển khai không cần máy chủ (không trạng thái) - Cách cung cấp một phiên bản Cloud SQL PostgreSQL và kết nối với phiên bản đó bằng Cloud SQL Auth Proxy
- Cách kết nối với DatabaseSessionService bằng PostgreSQL trên CloudSQL với mức thay đổi mã tối thiểu – cùng công cụ, cùng tác nhân, hệ thống phụ trợ khác
- Cách trạng thái ở phạm vi người dùng duy trì trong các phiên trò chuyện riêng biệt
Dọn dẹp
Để tránh bị tính phí vào tài khoản Google Cloud của bạn, hãy dọn dẹp các tài nguyên được tạo trong lớp học lập trình này.
Cách 1: Xoá dự án (nên dùng)
Cách dọn dẹp dễ nhất là xoá dự án. Thao tác này sẽ xoá tất cả tài nguyên liên kết với dự án.
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
Cách 2: Xoá từng tài nguyên
Nếu bạn muốn giữ lại dự án nhưng chỉ xoá các tài nguyên được tạo trong lớp học lập trình này, hãy làm như sau:
gcloud sql instances delete cafe-concierge-db --quiet