ADK और CloudSQL की मदद से, लगातार काम करने वाले एआई एजेंट बनाना

1. परिचय

इस हैंड्स-ऑन सेशन में, आपको बिना किसी जानकारी के काम करने वाले सामान्य चैटबॉट से आगे बढ़कर, स्मार्ट कैफ़े कॉन्शिएर्ज बनाने का तरीका सिखाया जाएगा. यह Gemini की मदद से काम करने वाला एक एआई एजेंट है, जो एक दोस्ताना बारिस्ता की तरह काम करता है. यह कुकी, सेशन की स्थिति में ट्रैक किए गए कॉफ़ी के ऑर्डर लेती है. साथ ही, उपयोगकर्ता के स्कोप वाली स्थिति में लंबे समय तक खाने-पीने की प्राथमिकताओं को याद रखती है. इसके अलावा, यह सभी चीज़ों को Cloud SQL PostgreSQL डेटाबेस में सेव करती है. आखिर में, आपका एजेंट यह याद रखता है कि आपको लैक्टोज़ से एलर्जी है. भले ही, आपने ऐप्लिकेशन को रीस्टार्ट करके बिलकुल नई बातचीत शुरू की हो.

यहां सिस्टम आर्किटेक्चर दिया गया है, जिसे हम बनाएंगे

a98bbd65ddedd29c.jpeg

ज़रूरी शर्तें

  • मुफ़्त में आज़माने के लिए बिलिंग खाते वाला Google Cloud खाता
  • Python की बुनियादी जानकारी
  • इसके लिए, ADK, एआई एजेंट या Cloud SQL का अनुभव होना ज़रूरी नहीं है

आपको क्या सीखने को मिलेगा

  • Google के एजेंट डेवलपमेंट किट (एडीके) का इस्तेमाल करके, एआई एजेंट बनाएं. इसमें अपनी पसंद के टूल इस्तेमाल किए जा सकते हैं
  • ऐसे टूल तय करें जो ToolContext के ज़रिए सेशन की स्थिति को पढ़ते और लिखते हैं
  • सेशन के स्कोप वाली स्थिति और उपयोगकर्ता के स्कोप वाली स्थिति (user: प्रीफ़िक्स) के बीच अंतर करना
  • Cloud SQL PostgreSQL इंस्टेंस प्रोविज़न करना और Cloud Shell से कनेक्ट करना
  • स्थानीय स्टोरेज (adk web कमांड का इस्तेमाल करने पर, यह डिफ़ॉल्ट रूप से सेट होता है) से DatabaseSessionService पर माइग्रेट करें, ताकि डेटा को लंबे समय तक सेव किया जा सके. इसके लिए, एक अलग डेटाबेस का इस्तेमाल किया जाता है
  • पुष्टि करें कि ऐप्लिकेशन को रीस्टार्ट करने और अलग-अलग बातचीत के सेशन के दौरान, एजेंट की मेमोरी बनी रहती है

आपको इन चीज़ों की ज़रूरत होगी

  • एक चालू कंप्यूटर और भरोसेमंद इंटरनेट कनेक्शन.
  • Google Cloud Console को ऐक्सेस करने के लिए, Chrome जैसे ब्राउज़र का इस्तेमाल करें
  • चीज़ों को जानने की दिलचस्पी और सीखने की इच्छा.

2. अपना एनवायरमेंट सेट अप करना

इस चरण में, Cloud Shell एनवायरमेंट तैयार किया जाता है और Google Cloud प्रोजेक्ट को कॉन्फ़िगर किया जाता है

Cloud Shell खोलें

अपने ब्राउज़र में Cloud Shell खोलें. Cloud Shell, पहले से कॉन्फ़िगर किया गया एनवायरमेंट उपलब्ध कराता है. इसमें इस कोडलैब के लिए ज़रूरी सभी टूल शामिल होते हैं. जब कहा जाए, तब अनुमति दें पर क्लिक करें

आपका इंटरफ़ेस कुछ ऐसा दिखना चाहिए

86307fac5da2f077.png

यह हमारा मुख्य इंटरफ़ेस होगा, जिसमें ऊपर की ओर आईडीई और नीचे की ओर टर्मिनल होगा

अपनी वर्किंग डायरेक्ट्री सेट अप करना

अपनी वर्किंग डायरेक्ट्री बनाएं. इस कोडलैब में लिखा गया सारा कोड यहां मौजूद होता है. यह रेफ़रंस रिपो से अलग होता है:

# 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

टर्मिनल को स्पॉन करने के लिए, View -> Terminal पर जाएं

ccc3214812750f1c.png

Google Cloud प्रोजेक्ट और शुरुआती एनवायरमेंट वैरिएबल सेट अप करना

प्रोजेक्ट सेटअप स्क्रिप्ट को अपनी वर्किंग डायरेक्ट्री में डाउनलोड करें:

curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh

स्क्रिप्ट चलाएं. यह आपके मुफ़्त में आज़माने वाले बिलिंग खाते की पुष्टि करता है, एक नया प्रोजेक्ट बनाता है या मौजूदा प्रोजेक्ट की पुष्टि करता है, आपके प्रोजेक्ट आईडी को मौजूदा डायरेक्ट्री में मौजूद .env फ़ाइल में सेव करता है, और टर्मिनल में चालू प्रोजेक्ट सेट करता है

bash setup_verify_trial_project.sh && source .env

इसे चलाने पर, आपको सुझाए गए प्रोजेक्ट आईडी का नाम दिखेगा. जारी रखने के लिए, Enter दबाएं

54b615cd15f2a535.png

कुछ देर इंतज़ार करने के बाद, अगर आपको अपनी कंसोल में यह आउटपुट दिखता है, तो इसका मतलब है कि आप अगले चरण पर जाने के लिए तैयार हैं e576b4c13d595156.png

स्क्रिप्ट को लागू करने के बाद, ये चरण पूरे किए जाते हैं:

  1. पुष्टि करें कि आपके पास मुफ़्त में आज़माने की सुविधा वाला चालू बिलिंग खाता हो
  2. .env में कोई मौजूदा प्रोजेक्ट है या नहीं, यह देखें
  3. कोई नया प्रोजेक्ट बनाएं या मौजूदा प्रोजेक्ट का फिर से इस्तेमाल करें
  4. मुफ़्त में आज़माने की सुविधा वाले बिलिंग खाते को अपने प्रोजेक्ट से लिंक करना
  5. प्रोजेक्ट आईडी को .env में सेव करें
  6. प्रोजेक्ट को gcloud के ऐक्टिव प्रोजेक्ट के तौर पर सेट करें

पुष्टि करें कि प्रोजेक्ट सही तरीके से सेट किया गया है. इसके लिए, Cloud Shell टर्मिनल प्रॉम्प्ट में अपनी वर्किंग डायरेक्ट्री के बगल में मौजूद पीले रंग का टेक्स्ट देखें. इसमें आपका प्रोजेक्ट आईडी दिखना चाहिए.

9e11ee21cd23405f.png

ज़रूरी एपीआई चालू करना

इस कोडलैब के लिए ज़रूरी Google Cloud API चालू करें:

gcloud services enable \
  aiplatform.googleapis.com \
  sqladmin.googleapis.com \
  compute.googleapis.com
  • Vertex AI API (aiplatform.googleapis.com) — आपका एजेंट, Vertex AI के ज़रिए Gemini मॉडल का इस्तेमाल करता है.
  • Cloud SQL Admin API (sqladmin.googleapis.com) — इसकी मदद से, परसिस्टेंट स्टोरेज के लिए PostgreSQL इंस्टेंस को प्रोविज़न और मैनेज किया जाता है.
  • Compute Engine API (compute.googleapis.com) — Cloud SQL इंस्टेंस बनाने के लिए ज़रूरी है.

Gemini और Cloud प्रॉडक्ट के क्षेत्र को कॉन्फ़िगर करना

आगे बढ़ने से पहले, आइए उस प्रॉडक्ट के लिए ज़रूरी जगह/देश का कॉन्फ़िगरेशन भी सेट अप कर लें जिससे हमें इंटरैक्ट करना है. हमारी .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

अगले चरण पर जाएं

3. Cloud SQL सेट अप करना

इस चरण में, Cloud SQL PostgreSQL इंस्टेंस उपलब्ध कराया जाता है. साथ ही, आपके एजेंट को इन-मेमोरी से डेटाबेस-बैक स्टोरेज पर स्विच किया जाता है. इंस्टेंस बनाने में कुछ मिनट लगते हैं. इसलिए, हम इसे पहले शुरू करेंगे. इसके बाद, हम अगले विषय पर चर्चा जारी रख सकते हैं. ऐसा तब तक किया जा सकता है, जब तक इंस्टेंस नहीं बन जाता

इंस्टेंस बनाना शुरू करें

अपनी .env फ़ाइल में डेटाबेस का पासवर्ड जोड़ें और उसे फिर से लोड करें. हम cafe-agent-pwd-2025 को पासवर्ड के तौर पर इस्तेमाल करेंगे.

echo "DB_PASSWORD=cafe-agent-pwd-2025" >> .env
source .env

Cloud SQL PostgreSQL इंस्टेंस बनाने के लिए, यह कमांड चलाएं. इसमें कुछ मिनट लगते हैं. इसे चलने दें और अगले सेक्शन पर जाएं.

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 &

ऊपर दिए गए निर्देश के बारे में कुछ ज़रूरी बातें:

  • db-f1-micro, Cloud SQL का सबसे छोटा (और सबसे सस्ता) टियर है. यह इस कोडलैब के लिए काफ़ी है.
  • --root-password डिफ़ॉल्ट postgres उपयोगकर्ता के लिए पासवर्ड सेट करता है.
  • कमांड में मौजूद & सफ़िक्स, कमांड को बैकग्राउंड में चलाता है, ताकि आप काम जारी रख सकें.

यह प्रोसेस बैकग्राउंड में चलेगी. हालांकि, कंसोल का आउटपुट कभी-कभी मौजूदा टर्मिनल में दिखेगा. आइए, Cloud Shell में नया टर्मिनल टैब खोलें (प्लस आइकॉन पर क्लिक करें), ताकि हम ज़्यादा ध्यान दे सकें.

b01e3fbd89f17332.png

अपनी वर्किंग डायरेक्ट्री पर फिर से जाएं और पिछली सेटअप स्क्रिप्ट का इस्तेमाल करके प्रोजेक्ट को चालू करें.

cd ~/build-agent-adk-cloudsql
bash setup_verify_trial_project.sh && source .env

इसके बाद, अगले सेक्शन पर जाएं

4. कैफ़े के लिए सहायक एजेंट बनाना

इस चरण में, आपके ADK एजेंट के लिए प्रोजेक्ट स्ट्रक्चर बनाया जाता है. साथ ही, मेन्यू टूल के साथ बुनियादी Cafe Concierge तय किया जाता है.

Python प्रोजेक्ट को शुरू करना

यह कोडलैब, uv का इस्तेमाल करता है. यह Python का एक तेज़ पैकेज मैनेजर है. यह एक ही टूल में वर्चुअल एनवायरमेंट और डिपेंडेंसी को मैनेज करता है. यह Cloud Shell में पहले से इंस्टॉल होता है.

Python प्रोजेक्ट शुरू करें और ADK को डिपेंडेंसी के तौर पर जोड़ें:

uv init
uv add google-adk==1.25.0 asyncpg

uv init, pyproject.toml और वर्चुअल एनवायरमेंट बनाता है. uv, डिपेंडेंसी को इंस्टॉल करता है और इसे pyproject.toml में रिकॉर्ड करता है.

एजेंट प्रोजेक्ट स्ट्रक्चर को शुरू करना

ADK को एक खास फ़ोल्डर लेआउट की ज़रूरत होती है: आपके एजेंट के नाम वाली एक डायरेक्ट्री, जिसमें __init__.py, agent.py, और एजेंट डायरेक्ट्री में .env भी शामिल हो

ADK में यह सुविधा तुरंत चालू करने के लिए, पहले से मौजूद कमांड का इस्तेमाल किया जा सकता है. इसके लिए, यह कमांड चलाएं

uv run adk create cafe_concierge \
    --model gemini-2.5-flash \
    --project ${GOOGLE_CLOUD_PROJECT} \
    --region ${GOOGLE_CLOUD_LOCATION}

इस कमांड से, gemini-2.5-flash को एआई के तौर पर इस्तेमाल करके एजेंट का स्ट्रक्चर बनाया जाएगा. अब आपकी डायरेक्ट्री ऐसी दिखनी चाहिए:

build-agent-adk-cloudsql/
├── cafe_concierge/
│   ├── __init__.py
│   ├── agent.py
│   └── .env
├── pyproject.toml
├── .env      
├── .venv/
└── ...

एजेंट को लिखें

Cloud Shell Editor में cafe_concierge/agent.py खोलें

cloudshell edit cafe_concierge/agent.py

और फ़ाइल को इस कोड से बदलें

# 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],
)

इससे एक टूल get_menu() के साथ बुनियादी एजेंट तय होता है. एजेंट, मेन्यू के बारे में सवालों के जवाब दे सकता है. हालांकि, फ़िलहाल वह ऑर्डर ट्रैक नहीं कर सकता या प्राथमिकताओं को याद नहीं रख सकता.

पुष्टि करना कि एजेंट काम कर रहा है या नहीं

अपनी वर्किंग डायरेक्ट्री से ADK dev UI शुरू करें:

cd ~/build-agent-adk-cloudsql
uv run adk web

Cloud Shell की वेब प्रीव्यू सुविधा का इस्तेमाल करके, टर्मिनल में दिखाया गया यूआरएल (आम तौर पर http://localhost:8000) खोलें. सबसे ऊपर बाएं कोने में मौजूद, एजेंट के ड्रॉपडाउन मेन्यू से cafe_concierge चुनें.

चैट बार पर यह टेक्स्ट टाइप करें और पुष्टि करें कि एजेंट, मेन्यू आइटम और उनकी कीमतों के साथ जवाब देता है.

What's on the menu?

376ee6b189657e7a.png

आगे बढ़ने से पहले, Ctrl+C दबाकर DevTools को बंद करें.

5. स्टेटफ़ुल ऑर्डर मैनेजमेंट की सुविधा जोड़ना

एजेंट मेन्यू दिखा सकता है, लेकिन वह न तो ऑर्डर ले सकता है और न ही आपकी प्राथमिकताओं को याद रख सकता है. इस चरण में, चार ऐसे टूल जोड़े जाते हैं जो बातचीत में ऑर्डर ट्रैक करने के लिए, एडीके के स्टेट सिस्टम का इस्तेमाल करते हैं. साथ ही, ये टूल अलग-अलग बातचीत में खाने-पीने की प्राथमिकताओं को सेव करते हैं.

सेशन इवेंट और स्थिति के बारे में जानकारी

ADK की हर बातचीत, Session ऑब्जेक्ट में होती है. सेशन में दो अलग-अलग चीज़ें ट्रैक की जाती हैं: इवेंट और स्टेट. इनके बीच के अंतर को समझना, ऐसे एजेंट बनाने के लिए ज़रूरी है जो सही जानकारी को सही तरीके से याद रख सकें.

इवेंट, बातचीत में होने वाली हर गतिविधि का क्रमवार लॉग होता है. उपयोगकर्ता के हर मैसेज, एजेंट के हर जवाब, हर टूल कॉल, और उसकी रिटर्न वैल्यू को Event के तौर पर रिकॉर्ड किया जाता है. साथ ही, इसे सेशन की events सूची में जोड़ा जाता है. इवेंट में बदलाव नहीं किया जा सकता: रिकॉर्ड होने के बाद, इनमें कभी बदलाव नहीं होता. इवेंट को किसी बातचीत की पूरी ट्रांसक्रिप्ट के तौर पर माना जाता है.

स्टेट एक की-वैल्यू स्क्रैचपैड होता है. बातचीत के दौरान एजेंट इसे पढ़ता है और इसमें लिखता है. इवेंट के उलट, स्टेट में बदलाव किया जा सकता है. बातचीत के आगे बढ़ने के साथ-साथ वैल्यू बदलती रहती हैं. स्टेट वह जगह होती है जहां एजेंट, स्ट्रक्चर्ड डेटा सेव करता है. इस डेटा का इस्तेमाल, एजेंट को कार्रवाई करने के लिए करना होता है. जैसे, मौजूदा ऑर्डर, ग्राहक की प्राथमिकताएं, कुल कीमत. स्टेट को ऐसे स्टिकी नोट के तौर पर समझें जिन्हें एजेंट, ट्रांसक्रिप्ट के बगल में रखता है.

इनके बीच का संबंध यहां बताया गया है:

cd9871699451867d.png

टूल, ToolContext के ज़रिए स्थिति को पढ़ते और लिखते हैं. यह एक ऐसा ऑब्जेक्ट है जिसे ADK, पैरामीटर के तौर पर एलान करने वाले किसी भी टूल फ़ंक्शन में अपने-आप डाल देता है. इसे खुद नहीं बनाया जाता. tool_context.state की मदद से, कोई टूल सेशन की स्थिति वाले स्क्रैचपैड को पढ़ और लिख सकता है. ADK, फ़ंक्शन के सिग्नेचर की जांच करता है: ToolContext टाइप वाले पैरामीटर इंजेक्ट किए जाते हैं. अन्य सभी पैरामीटर, बातचीत के आधार पर एलएलएम भरता है.

जब कोई टूल tool_context.state में बदलाव करता है, तो ADK उस बदलाव को इवेंट में state_delta के तौर पर रिकॉर्ड करता है. इसके बाद, SessionService सेशन की मौजूदा स्थिति में डेल्टा लागू करता है. इसका मतलब है कि स्थिति में हुए बदलावों को हमेशा उस इवेंट से ट्रैक किया जा सकता है जिसकी वजह से वे हुए हैं. यह callback_context जैसे अन्य कॉन्टेक्स्ट के लिए भी सही है

राज्य के हिसाब से प्रीफ़िक्स समझना

स्टेट की, अपने स्कोप को कंट्रोल करने के लिए प्रीफ़िक्स का इस्तेमाल करती हैं:

प्रीफ़िक्स

स्कोप

क्या रीस्टार्ट करने के बाद भी यह कुकी बनी रहती है? (with DB)

(कोई नहीं)

सिर्फ़ मौजूदा सेशन के लिए

हां

user:

इस उपयोगकर्ता के सभी सेशन

हां

app:

सभी सेशन, सभी उपयोगकर्ता

हां

temp:

सिर्फ़ मौजूदा अनुरोध के लिए

नहीं

इस कोडलैब में, इनमें से दो प्रीफ़िक्स का इस्तेमाल किया जाता है: सेशन के स्कोप वाले डेटा के लिए, बिना प्रीफ़िक्स वाली कुंजियां (मौजूदा ऑर्डर — सिर्फ़ इस बातचीत के लिए काम की हैं) और उपयोगकर्ता के स्कोप वाले डेटा के लिए user: कुंजियां (खाने-पीने की प्राथमिकताएं — इस उपयोगकर्ता की सभी बातचीत के लिए काम की हैं).

स्टेटफ़ुल टूल जोड़ना

Cloud Shell Editor में cafe_concierge/agent.py खोलें.

cloudshell edit cafe_concierge/agent.py

इसके बाद, 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."}

इन दो बातों पर ध्यान दें:

  1. place_order और get_order_summary, प्रीफ़िक्स वाली कुंजियों (current_order) का इस्तेमाल करते हैं. यह स्थिति मौजूदा सेशन से जुड़ी होती है. नई बातचीत, खाली ऑर्डर से शुरू होती है.
  2. set_dietary_preference और get_dietary_preferences, user: प्रीफ़िक्स (user:dietary_preferences) का इस्तेमाल करते हैं. यह स्थिति, एक ही उपयोगकर्ता के सभी सेशन के साथ शेयर की जाती है.

एजेंट को नए टूल और निर्देशों के बारे में जानकारी देना

फ़ाइल के सबसे नीचे मौजूद root_agent की मौजूदा परिभाषा को इससे बदलें:

# 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,
    ],
)

इस निर्देश में, स्टेट इंजेक्शन टेंप्लेट {user:dietary_preferences?} का इस्तेमाल किया गया है. इससे, ग्राहक की सेव की गई प्राथमिकताओं को सीधे तौर पर प्रॉम्प्ट में शामिल किया जा सकता है.

पूरी फ़ाइल की पुष्टि करना

आपके cafe_concierge/agent.py में अब यह जानकारी होनी चाहिए:

  • CAFE_MENU डिक्शनरी
  • टूल के पांच फ़ंक्शन: get_menu, place_order, get_order_summary, set_dietary_preference, get_dietary_preferences
  • पांचों टूल के साथ root_agent की परिभाषा

6. ADK Dev UI की मदद से एजेंट की जांच करना

इस चरण में एजेंट चलता है और स्टेटफ़ुल सुविधाओं का इस्तेमाल करता है: ऑर्डर करना, प्राथमिकताओं को ट्रैक करना, और क्रॉस-सेशन मेमोरी (एक ही प्रोसेस में). इसके अलावा, इवेंट और स्टेट पैनल की जांच करके यह भी देखा जा सकता है कि ADK, बातचीत को अंदरूनी तौर पर कैसे ट्रैक करता है.

डेवलपर यूज़र इंटरफ़ेस (यूआई) शुरू करना

cd ~/build-agent-adk-cloudsql
uv run adk web

पोर्ट 8000 पर वेब प्रीव्यू खोलें और ड्रॉपडाउन से cafe_concierge चुनें.

पहली बातचीत: ऑर्डर करना और प्राथमिकताएं सेट करना

इन प्रॉम्प्ट को क्रम से आज़माएं:

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?

सेशन इवेंट की जांच करना

सभी इवेंट कैप्चर किए जाएंगे और वेब यूज़र इंटरफ़ेस (यूआई) पर दिखाए जाएंगे. आपको चैटबॉक्स में दिखेगा कि सिर्फ़ आपका प्रॉम्प्ट और जवाब ही नहीं है, बल्कि tool_call और tool_response भी है

9051b46978c8017b.png

आपको इवेंट की सूची क्रम से दिखेगी. हर इवेंट में एक लेखक होता है (जिसने इसे बनाया है) और एक टाइप होता है (यह किस तरह के इंटरैक्शन को दिखाता है):

लेखक

टाइप

यह क्या दिखाता है

user

message

चैट में टाइप किया गया मैसेज

cafe_concierge

message

एजेंट का टेक्स्ट वाला जवाब

cafe_concierge

tool_call

एजेंट ने किसी टूल को कॉल करने का फ़ैसला किया (इसमें फ़ंक्शन का नाम और आर्ग्युमेंट दिखते हैं)

cafe_concierge

tool_response

टूल कॉल से मिली वैल्यू

tool_call इवेंट में से किसी एक पर क्लिक करें. उदाहरण के लिए, set_dietary_preference कॉल करें. आपको यह दिखना चाहिए:

  • फ़ंक्शन का नाम: set_dietary_preference
  • तर्क: {"preference": "lactose intolerant"}

अब इसके ठीक नीचे मौजूद, tool_response इवेंट पर क्लिक करें. आपको यह वैल्यू दिखेगी:

  • जवाब: {"saved": "lactose intolerant", "all_preferences": ["lactose intolerant"]}

b528f4efd6a9f337.png

tool_response इवेंट में state_delta फ़ील्ड ढूंढें. इससे पता चलता है कि टूल कॉल के बाद, किस स्थिति में बदलाव हुआ है:

state_delta: {"user:dietary_preferences": ["lactose intolerant"]}

स्टेट में हुए हर बदलाव को किसी इवेंट से ट्रैक किया जा सकता है. इस तरह, ADK यह पक्का करता है कि स्टेट स्क्रैचपैड, बातचीत के इतिहास के साथ सिंक रहे.

सेशन की स्थिति की जांच करना

राज्य टैब पर क्लिक करें. इवेंट लॉग में पूरी हिस्ट्री दिखती है. हालांकि, स्टेट टैब में एजेंट को अभी क्या पता है, इसकी खास जानकारी दिखती है. इसमें हर स्टेट की के लिए मौजूदा वैल्यू दिखती है.

5e06fb54f3f0d8d6.png

आपको दो एंट्री दिखेंगी:

  • current_order{"items": ["oat milk latte", "banana bread"], "total": 9.0}
  • user:dietary_preferences["lactose intolerant"]

कुंजी के नामों में अंतर देखें:

  • current_order में कोई प्रीफ़िक्स नहीं है. यह सेशन के स्कोप वाला है. यह सिर्फ़ इस बातचीत में मौजूद होता है और सेशन खत्म होने पर मिट जाता है.
  • user:dietary_preferences में user: प्रीफ़िक्स है. यह उपयोगकर्ता के स्कोप वाला डाइमेंशन है. इसे इस उपयोगकर्ता के हर सेशन के साथ शेयर किया जाता है.

यह अंतर कोड में नहीं दिखता (दोनों tool_context.state का इस्तेमाल करते हैं). हालांकि, इससे यह कंट्रोल होता है कि डेटा कहां तक पहुंचता है. आपको यह बदलाव, अगले टेस्ट में दिखेगा.

दूसरी बातचीत: क्रॉस-सेशन में उपयोगकर्ता की स्थिति की पुष्टि करना

नई बातचीत शुरू करने के लिए, डेवलपर यूज़र इंटरफ़ेस (यूआई) में मौजूद नया सेशन बटन पर क्लिक करें. इससे, उसी उपयोगकर्ता के लिए एक नया सेशन शुरू हो जाता है.

57408cfae5f041ac.png

यह प्रॉम्प्ट आज़माएँ:

What do you recommend for me?

नए सेशन में, स्टेट टैब देखें. user:dietary_preferences कुकी बनी रहती है, लेकिन current_order कुकी हट जाती है. ऐसा इसलिए होता है, क्योंकि यह स्थिति पिछले सेशन से जुड़ी थी.

764eb3885251307d.png

7. लोकल स्टोरेज की सीमा का पालन करना

यह एजेंट, सभी सेशन में प्राथमिकताओं को याद रखता है. हालांकि, ऐसा सिर्फ़ तब तक होता है, जब तक लोकल स्टोरेज मौजूद रहता है. इस चरण में, लोकल स्टोरेज की बुनियादी सीमा के बारे में बताया गया है.

एजेंट को फिर से शुरू करें

आपने पिछले चरण के आखिर में Dev UI को बंद कर दिया हो. अब हम लोकल स्टोरेज को हटाकर फिर से शुरू करेंगे, ताकि सर्वरलेस एनवायरमेंट को सिम्युलेट किया जा सके. यह स्टेटलेस होता है:

cd ~/build-agent-adk-cloudsql
rm -f cafe_concierge/.adk/session.db
uv run adk web

अब पोर्ट 8000 पर वेब प्रीव्यू खोलें और cafe_concierge को चुनें.

पसंद के मुताबिक कॉन्टेंट दिखाने की सुविधा की जांच करना

प्रकार:

Do you remember my dietary preferences?

एजेंट को इस बारे में कोई जानकारी नहीं है. खान-पान से जुड़ी पसंद, ऑर्डर का इतिहास — सब कुछ मिटा दिया जाता है.

82a5e05434cafe83.png

लोकल स्टोरेज मिटाने पर, सब कुछ मिट गया. आम तौर पर, ऐसा तब होता है, जब हम सर्वरलेस एनवायरमेंट का इस्तेमाल करते हैं. session.db प्रोसेस मेमोरी में सभी स्टेट सेव करता है. इसे हटाने पर, पूरा डेटा मिट जाता है.

समाधान: DatabaseSessionService को तय करें. इस ट्यूटोरियल में, यह Cloud SQL डेटाबेस में PostgreSQL में सभी सेशन डेटा को सेव करेगा. एजेंट कोड और टूल में कोई बदलाव नहीं होता. सिर्फ़ स्टोरेज बैकएंड बदलता है.

आगे बढ़ने से पहले, Ctrl+C दबाकर डेवलपर यूज़र इंटरफ़ेस (यूआई) को बंद करें.

8. डेटाबेस सेटअप की जानकारी फिर से देखना

इस समय तक, हमारा डेटाबेस इंस्टेंस बन जाना चाहिए. आइए, इसकी पुष्टि करें. इसके लिए, यह कमांड चलाएं

gcloud sql instances describe cafe-concierge-db --format="value(state)"

आपको यह आउटपुट दिखेगा. इसे 'पढ़ ली' के तौर पर मार्क करें

RUNNABLE

डेटाबेस बनाना

एजेंट के सेशन के डेटा के लिए, एक डेटाबेस बनाएं:

gcloud sql databases create agent_db --instance=cafe-concierge-db

Cloud SQL Auth प्रॉक्सी शुरू करना

Cloud SQL Auth प्रॉक्सी, Cloud Shell से आपके Cloud SQL इंस्टेंस तक सुरक्षित और पुष्टि किया गया कनेक्शन उपलब्ध कराता है. इसके लिए, आईपी पतों को वाइटलिस्ट करने की ज़रूरत नहीं होती. यह क्लाउड शेल पर पहले से इंस्टॉल होता है.

cloud-sql-proxy ${GOOGLE_CLOUD_PROJECT}:${REGION}:cafe-concierge-db --port 5432 &

कमांड में & सफ़िक्स जोड़ने से, प्रॉक्सी बैकग्राउंड में चलती है. आपको नीचे दिए गए उदाहरण की तरह, यह पुष्टि करने वाला आउटपुट दिखेगा कि प्रॉक्सी तैयार है

[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!

कनेक्शन की पुष्टि करना

जांच करें कि प्रॉक्सी के ज़रिए डेटाबेस से कनेक्ट किया जा सकता है या नहीं:

psql "host=127.0.0.1 port=5432 dbname=agent_db user=postgres password=$DB_PASSWORD" -c "SELECT 'Connection ok' AS status;"

आपको यह दिखना चाहिए:

      status
---------------------
 Connection ok
(1 row)

9. सेशन के दौरान लगातार सेव रहने वाली मेमोरी की पुष्टि करना

इस चरण से यह साबित होता है कि रीसेट करने के बाद भी आपके एजेंट की मेमोरी बनी रहती है. ऐसा तब होता है, जब हम यह पक्का करते हैं कि cafe_concierge/.adk/session_db (लोकल डेटाबेस) को हटा दिया गया है और यह बातचीत के सभी सेशन में मौजूद है.

एजेंट शुरू करना

पक्का करें कि Cloud SQL Auth प्रॉक्सी अब भी चल रही हो. इसके लिए, जॉब की जांच करें. अगर ऐसा नहीं है, तो इसे रीस्टार्ट करें:

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

इसके बाद, डेटाबेस को सेशन सेवा के तौर पर सेट करके, ADK dev UI शुरू करें

uv run adk web --session_service_uri postgresql+asyncpg://postgres:${DB_PASSWORD}@127.0.0.1:5432/agent_db

पोर्ट 8000 पर वेब प्रीव्यू खोलें और cafe_concierge को चुनें.

पहला टेस्ट: ऑर्डर करना और प्राथमिकताएं सेट करना

पहले सेशन में, इन प्रॉम्प्ट का इस्तेमाल करें:

Show me the menu
I'm vegan
What can I eat?
I'll have a cold brew and banana bread

दूसरा टेस्ट: रीस्टार्ट होने के बाद भी काम करना

Ctrl+C दबाकर, Dev UI को बंद करें. साथ ही, पक्का करें कि लोकल session.db हटा दिया गया हो

rm -f cafe_concierge/.adk/session.db

इसके बाद, dev UI सर्वर को फिर से चलाएं

uv run adk web --session_service_uri postgresql+asyncpg://postgres:${DB_PASSWORD}@127.0.0.1:5432/agent_db

पोर्ट 8000 पर वेब प्रीव्यू खोलें. इसके बाद, cafe_concierge को चुनें और नया सेशन शुरू करें. इसके बाद,

What are my dietary preferences?

एजेंट, आपकी सेव की गई प्राथमिकताओं के हिसाब से जवाब देता है. जैसे, वीगन. सिस्टम को रीस्टार्ट करने के बाद भी डेटा मौजूद है, क्योंकि अब इसे लोकल स्टोरेज में नहीं, बल्कि PostgreSQL में सेव किया जाता है. अगर हम नया सेशन बनाते हैं, तो भी यही स्थिति होगी, क्योंकि user: की स्थिति इस उपयोगकर्ता के हर नए सेशन में बनी रहती है.

9c139bf89becb748.png

डेटाबेस की सीधे तौर पर जांच करना

Cloud Shell में नया टर्मिनल टैब खोलें और डेटाबेस से क्वेरी करके, सेव किया गया डेटा देखें:

psql "host=127.0.0.1 port=5432 dbname=agent_db user=postgres password=$DB_PASSWORD" -c "\dt"

आपको ऐसी टेबल दिखनी चाहिए जिन्हें ADK ने सेशन, इवेंट, और स्थिति को सेव करने के लिए अपने-आप बनाया है. जैसे, यह उदाहरण

                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)

स्टेट के व्यवहार के बारे में खास जानकारी

स्टेट की

प्रीफ़िक्स

स्कोप

क्या इसे सभी सेशन में शेयर किया जाता है?

current_order

(कोई नहीं)

सेशन

नहीं

user:dietary_preferences

user:

उपयोगकर्ता

हां

10. बधाई हो / जगह खाली करें

बधाई हो! आपने ADK और Cloud SQL का इस्तेमाल करके, लगातार काम करने वाला और स्टेटफ़ुल एआई एजेंट बना लिया है.

आपने क्या सीखा

  • सेशन की स्थिति को पढ़ने और लिखने वाले कस्टम टूल की मदद से, ADK एजेंट बनाने का तरीका
  • सेशन के स्कोप वाले स्टेट (कोई प्रीफ़िक्स नहीं) और उपयोगकर्ता के स्कोप वाले स्टेट (user: प्रीफ़िक्स) के बीच का अंतर
  • डिफ़ॉल्ट adk local session.db सिर्फ़ डेवलपमेंट के लिए सही क्यों है — हटाने पर सारा डेटा मिट जाता है (और इसे आसानी से हटाया जा सकता है, कोई बैकअप नहीं), सर्वरलेस डिप्लॉयमेंट के लिए सही नहीं है, जो स्टेटलेस है
  • Cloud SQL PostgreSQL इंस्टेंस को कैसे प्रोविज़न करें और Cloud SQL Auth प्रॉक्सी का इस्तेमाल करके उससे कैसे कनेक्ट करें
  • CloudSQL पर PostgreSQL के साथ DatabaseSessionService से कनेक्ट करने का तरीका. इसमें कोड में कम से कम बदलाव करना होता है. इसमें एक ही टूल, एक ही एजेंट, और अलग-अलग बैकएंड का इस्तेमाल किया जाता है
  • उपयोगकर्ता के स्कोप वाली स्थिति, अलग-अलग बातचीत के सेशन में कैसे बनी रहती है

खाली करने के लिए जगह

अपने Google Cloud खाते पर शुल्क लगने से बचने के लिए, इस कोडलैब में बनाए गए संसाधनों को हटा दें.

प्रोजेक्ट को मिटाकर, आसानी से साफ़ किया जा सकता है. इससे प्रोजेक्ट से जुड़े सभी संसाधन हट जाते हैं.

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}

दूसरा विकल्प: एक-एक करके संसाधन मिटाना

अगर आपको प्रोजेक्ट रखना है, लेकिन इस कोडलैब में बनाए गए सिर्फ़ संसाधन हटाने हैं, तो:

gcloud sql instances delete cafe-concierge-db --quiet