Membangun Agen AI Persisten dengan ADK dan CloudSQL

1. Pengantar

Dalam sesi praktik ini, Anda akan melampaui chatbot dasar tanpa status untuk membuat Smart Cafe Concierge–agen AI yang didukung oleh Gemini yang bertindak sebagai barista yang ramah. Aplikasi ini mengambil pesanan kopi yang dilacak dalam status sesi, mengingat preferensi diet jangka panjang dalam status cakupan pengguna, dan mempertahankan semuanya ke database Cloud SQL PostgreSQL. Pada akhirnya, agen Anda akan mengingat bahwa Anda intoleran terhadap laktosa meskipun Anda memulai ulang aplikasi dan memulai percakapan baru.

Berikut adalah arsitektur sistem yang akan kita bangun

a98bbd65ddedd29c.jpeg

Prasyarat

  • Akun Google Cloud dengan akun penagihan uji coba
  • Pemahaman dasar tentang Python
  • Tidak diperlukan pengalaman sebelumnya dengan ADK, agen AI, atau Cloud SQL

Yang akan Anda pelajari

  • Membuat agen AI menggunakan Agent Development Kit (ADK) Google dengan alat kustom
  • Menentukan alat yang membaca dan menulis status sesi melalui ToolContext
  • Membedakan antara status cakupan sesi dan status cakupan pengguna (awalan user:)
  • Menyediakan instance Cloud SQL PostgreSQL dan menghubungkannya dari Cloud Shell
  • Migrasikan dari penyimpanan lokal (yang merupakan default saat Anda menggunakan perintah adk web) ke DatabaseSessionService untuk penyimpanan persisten dengan database khusus
  • Memastikan memori agen tetap ada di seluruh proses mulai ulang aplikasi dan di seluruh sesi percakapan terpisah

Yang Anda butuhkan

  • Komputer yang berfungsi dan koneksi internet yang andal.
  • Browser, seperti Chrome, untuk mengakses Konsol Google Cloud
  • Pikiran yang ingin tahu dan semangat untuk belajar.

2. Menyiapkan Lingkungan Anda

Langkah ini akan menyiapkan lingkungan Cloud Shell dan mengonfigurasi project Google Cloud Anda

Buka Cloud Shell

Buka Cloud Shell di browser Anda. Cloud Shell menyediakan lingkungan yang telah dikonfigurasi sebelumnya dengan semua alat yang Anda perlukan untuk codelab ini. Klik Authorize saat diminta untuk

Antarmuka Anda akan terlihat seperti ini

86307fac5da2f077.png

Ini akan menjadi antarmuka utama kita, IDE di atas, terminal di bawah

Menyiapkan direktori kerja Anda

Buat direktori kerja Anda. Semua kode yang Anda tulis dalam codelab ini ada di sini — terpisah dari repo referensi:

# 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

Untuk memunculkan terminal, cari View -> Terminal

ccc3214812750f1c.png

Menyiapkan project Google Cloud dan variabel lingkungan awal

Download skrip penyiapan project ke direktori kerja Anda:

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

Jalankan skrip. Skrip ini memverifikasi akun penagihan uji coba Anda, membuat project baru (atau memvalidasi project yang ada), menyimpan ID project Anda ke file .env di direktori saat ini, dan menetapkan project aktif di terminal

bash setup_verify_trial_project.sh && source .env

Saat menjalankan perintah ini, Anda akan diminta untuk memasukkan nama project ID yang disarankan. Anda dapat menekan Enter untuk melanjutkan

54b615cd15f2a535.png

Setelah menunggu beberapa saat, jika Anda melihat output ini di konsol, Anda siap melanjutkan ke langkah berikutnya e576b4c13d595156.png

Skrip yang dijalankan akan melakukan langkah-langkah berikut:

  1. Pastikan Anda memiliki akun penagihan uji coba yang aktif
  2. Periksa project yang ada di .env (jika ada)
  3. Buat project baru atau gunakan kembali project yang sudah ada
  4. Menautkan akun penagihan uji coba ke project Anda
  5. Simpan project ID ke .env
  6. Tetapkan project sebagai project gcloud aktif

Pastikan project disetel dengan benar dengan memeriksa teks berwarna kuning di samping direktori kerja Anda di perintah terminal Cloud Shell. Project ID Anda akan ditampilkan.

9e11ee21cd23405f.png

Aktifkan API yang diperlukan

Aktifkan Google Cloud API yang diperlukan untuk codelab ini:

gcloud services enable \
  aiplatform.googleapis.com \
  sqladmin.googleapis.com \
  compute.googleapis.com
  • Vertex AI API (aiplatform.googleapis.com) — agen Anda menggunakan model Gemini melalui Vertex AI.
  • Cloud SQL Admin API (sqladmin.googleapis.com) — Anda menyediakan dan mengelola instance PostgreSQL untuk penyimpanan persisten.
  • Compute Engine API (compute.googleapis.com) — diperlukan untuk membuat instance Cloud SQL.

Mengonfigurasi wilayah produk Gemini dan Cloud

Sebelum melanjutkan, mari kita siapkan juga konfigurasi lokasi/wilayah yang diperlukan untuk produk yang berinteraksi dengan kita. Tambahkan konfigurasi berikut ke file .env kita

# 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

Lanjutkan ke langkah berikutnya

3. Menyiapkan Cloud SQL

Langkah ini menyediakan instance Cloud SQL PostgreSQL dan mengalihkan agen Anda dari penyimpanan dalam memori ke penyimpanan yang didukung database. Pembuatan instance memerlukan waktu beberapa menit, jadi Anda akan memulainya terlebih dahulu dan kita dapat melanjutkan diskusi ke topik berikutnya sambil menunggu prosesnya selesai

Mulai pembuatan instance

Tambahkan sandi database ke file .env Anda dan muat ulang, kita akan menggunakan cafe-agent-pwd-2025 sebagai sandi.

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

Jalankan perintah ini untuk membuat instance Cloud SQL PostgreSQL. Proses ini memerlukan waktu beberapa menit untuk diselesaikan — biarkan proses ini berjalan dan lanjutkan ke bagian berikutnya.

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 &

Beberapa catatan tentang perintah di atas:

  • db-f1-micro adalah tingkat Cloud SQL terkecil (dan termurah) — cukup untuk codelab ini.
  • --root-password menyetel sandi untuk pengguna postgres default.
  • Sufiks & dalam perintah menjalankan perintah di latar belakang sehingga Anda dapat terus bekerja.

Proses akan dijalankan di latar belakang, tetapi output konsol akan sesekali ditampilkan di terminal saat ini. Mari buka tab terminal baru di Cloud Shell (klik ikon +) agar kita bisa lebih fokus.

b01e3fbd89f17332.png

Buka direktori kerja Anda lagi dan aktifkan project menggunakan skrip penyiapan sebelumnya.

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

Kemudian, lanjutkan ke bagian berikutnya

4. Membangun Agen Cafe Concierge

Langkah ini membuat struktur project untuk agen ADK Anda dan menentukan Concierge Kafe dasar dengan alat menu.

Lakukan inisialisasi project Python

Codelab ini menggunakan uv, pengelola paket Python cepat yang menangani lingkungan virtual dan dependensi dalam satu alat. Alat ini sudah terinstal di Cloud Shell.

Lakukan inisialisasi project Python dan tambahkan ADK sebagai dependensi:

uv init
uv add google-adk==1.25.0 asyncpg

uv init membuat pyproject.toml dan lingkungan virtual. uv add menginstal dependensi dan mencatatnya di pyproject.toml.

Menginisialisasi struktur project agen

ADK mengharapkan tata letak folder tertentu: direktori yang dinamai sesuai agen Anda yang berisi __init__.py, agent.py, dan juga .env di dalam direktori agen

ADK memiliki perintah bawaan untuk membantu Anda melakukannya dengan cepat. Jalankan perintah berikut

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

Perintah ini akan membuat struktur agen dengan gemini-2.5-flash sebagai otak. Direktori Anda sekarang akan terlihat seperti ini:

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

Menulis agen

Buka cafe_concierge/agent.py di Cloud Shell Editor

cloudshell edit cafe_concierge/agent.py

dan menimpa file dengan kode berikut

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

Ini menentukan agen dasar dengan satu alat: get_menu(). Agen dapat menjawab pertanyaan tentang menu, tetapi belum dapat melacak pesanan atau mengingat preferensi.

Memverifikasi agen berjalan

Mulai UI dev ADK dari direktori kerja Anda:

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

Buka URL yang ditampilkan di terminal (biasanya http://localhost:8000) menggunakan fitur Pratinjau Web Cloud Shell. Pilih cafe_concierge dari dropdown agen di sudut kiri atas.

Ketik teks berikut di kolom chat dan verifikasi bahwa agen merespons dengan item menu dan harga.

What's on the menu?

376ee6b189657e7a.png

Hentikan UI dev dengan Ctrl+C sebelum melanjutkan.

5. Menambahkan Pengelolaan Pesanan Stateful

Agen dapat menampilkan menu, tetapi tidak dapat menerima pesanan atau mengingat preferensi. Langkah ini menambahkan empat alat yang menggunakan sistem status ADK untuk melacak pesanan dalam percakapan dan menyimpan preferensi diet di seluruh percakapan.

Memahami peristiwa dan status sesi

Setiap percakapan ADK berada di dalam objek Session. Sesi melacak dua hal yang berbeda: peristiwa dan status. Memahami perbedaan ini adalah kunci untuk membangun agen yang mengingat hal yang tepat dengan cara yang tepat.

Peristiwa adalah log kronologis dari semua yang terjadi dalam percakapan. Setiap pesan pengguna, setiap respons agen, setiap panggilan alat dan nilai kembaliannya — masing-masing dicatat sebagai Event dan ditambahkan ke daftar events sesi. Peristiwa tidak dapat diubah: setelah dicatat, peristiwa tidak akan pernah berubah. Anggap peristiwa sebagai transkrip lengkap percakapan.

Status adalah area kerja nilai kunci yang dibaca dan ditulis agen selama percakapan. Tidak seperti peristiwa, status dapat berubah — nilai berubah seiring berkembangnya percakapan. Status adalah tempat agen menyimpan data terstruktur yang perlu ditindaklanjuti: pesanan saat ini, preferensi pelanggan, total yang sedang berjalan. Anggap status sebagai catatan tempel yang disimpan agen di samping transkrip.

Berikut cara kerjanya:

cd9871699451867d.png

Alat membaca dan menulis status melalui ToolContext — objek yang otomatis disuntikkan ADK ke dalam fungsi alat yang mendeklarasikannya sebagai parameter. Anda tidak membuatnya sendiri. Melalui tool_context.state, alat dapat membaca dan menulis scratchpad status sesi. ADK memeriksa tanda tangan fungsi: parameter dengan jenis ToolContext disisipkan, semua parameter lainnya diisi oleh LLM berdasarkan percakapan.

Saat alat menulis ke tool_context.state, ADK mencatat perubahan tersebut sebagai state_delta di dalam peristiwa. Kemudian, SessionService menerapkan delta ke status sesi saat ini. Artinya, perubahan status selalu dapat dilacak kembali ke peristiwa yang menyebabkannya. Hal ini juga berlaku untuk bentuk konteks lain seperti callback_context

Memahami awalan status

Kunci status menggunakan awalan untuk mengontrol cakupannya:

Awalan

Cakupan

Tetap ada setelah dimulai ulang? (dengan DB)

(tidak ada)

Khusus sesi saat ini

Ya

user:

Semua sesi untuk pengguna ini

Ya

app:

Semua sesi, semua pengguna

Ya

temp:

Hanya pemanggilan saat ini

Tidak

Dalam codelab ini, Anda menggunakan dua awalan tersebut: kunci tanpa awalan untuk data cakupan sesi (pesanan saat ini — hanya relevan dengan percakapan ini) dan kunci user: untuk data cakupan pengguna (preferensi diet — relevan di semua percakapan untuk pengguna ini).

Menambahkan alat stateful

Buka cafe_concierge/agent.py di Cloud Shell Editor.

cloudshell edit cafe_concierge/agent.py

Kemudian, tambahkan empat fungsi berikut di atas definisi 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."}

Dua hal yang perlu diperhatikan:

  1. place_order dan get_order_summary menggunakan kunci tanpa awalan (current_order). Status ini terkait dengan sesi saat ini — percakapan baru dimulai dengan pesanan kosong.
  2. set_dietary_preference dan get_dietary_preferences menggunakan awalan user: (user:dietary_preferences). Status ini dibagikan di semua sesi untuk pengguna yang sama.

Memperbarui agen dengan alat dan petunjuk baru

Ganti definisi root_agent yang ada di bagian bawah file dengan:

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

Petunjuk ini menggunakan template injeksi status {user:dietary_preferences?} untuk menyuntikkan preferensi tersimpan pelanggan ini langsung ke dalam perintah.

Memverifikasi file yang lengkap

cafe_concierge/agent.py Anda sekarang harus berisi:

  • Kamus CAFE_MENU
  • Lima fungsi alat: get_menu, place_order, get_order_summary, set_dietary_preference, get_dietary_preferences
  • Definisi root_agent dengan kelima alat

6. Menguji Agen dengan UI Dev ADK

Langkah ini menjalankan agen dan melatih semua fitur stateful: pemesanan, pelacakan preferensi, dan memori lintas sesi (dalam proses yang sama). Anda juga akan memeriksa panel Peristiwa dan Status untuk melihat cara ADK melacak percakapan secara internal.

Mulai UI dev

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

Buka Pratinjau Web di port 8000 dan pilih cafe_concierge dari dropdown.

Percakapan 1: Melakukan pemesanan dan menyetel preferensi

Coba perintah ini secara berurutan:

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?

Memeriksa peristiwa sesi

Semua Peristiwa akan direkam dan ditampilkan di UI web. Anda akan melihat bahwa di kotak chat, tidak hanya ada perintah dan respons Anda, tetapi juga tool_call dan tool_response

9051b46978c8017b.png

Anda akan melihat daftar acara secara berurutan. Setiap peristiwa memiliki penulis (yang membuatnya) dan jenis (jenis interaksi yang diwakilinya):

Author

Jenis

Yang diwakilinya

user

message

Pesan yang Anda ketik dalam chat

cafe_concierge

message

Respons teks agen

cafe_concierge

tool_call

Agen memutuskan untuk memanggil alat (menampilkan nama fungsi + argumen)

cafe_concierge

tool_response

Nilai yang ditampilkan dari panggilan alat

Klik salah satu peristiwa tool_call, misalnya, panggilan set_dietary_preference. Anda akan melihat:

  • Nama fungsi: set_dietary_preference
  • Argumen: {"preference": "lactose intolerant"}

Sekarang klik acara tool_response yang sesuai tepat di bawahnya. Anda akan melihat nilai yang ditampilkan:

  • Respons: {"saved": "lactose intolerant", "all_preferences": ["lactose intolerant"]}

b528f4efd6a9f337.png

Cari kolom state_delta di dalam peristiwa tool_response. Bagian ini menunjukkan secara persis status apa yang berubah sebagai hasil dari panggilan alat ini:

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

Setiap perubahan status dapat dilacak ke peristiwa tertentu. Dengan demikian, ADK memastikan bahwa scratchpad status tetap sinkron dengan histori percakapan.

Memeriksa status sesi

Klik tab State. Tidak seperti log peristiwa (yang menampilkan histori lengkap), tab status menampilkan ringkasan tentang apa yang diketahui agen saat ini — nilai saat ini dari setiap kunci status.

5e06fb54f3f0d8d6.png

Anda akan melihat dua entri:

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

Perhatikan perbedaan nama kunci:

  • current_order tidak memiliki awalan — cakupannya adalah sesi. Pesan ini hanya ada dalam percakapan ini dan akan hilang saat sesi berakhir.
  • user:dietary_preferences memiliki awalan user: — cakupannya adalah pengguna. Nilai ini dibagikan di setiap sesi untuk pengguna ini.

Perbedaan ini tidak terlihat dalam kode (keduanya menggunakan tool_context.state), tetapi mengontrol seberapa jauh data dijangkau. Anda akan melihatnya di pengujian berikutnya.

Percakapan 2: Memverifikasi status pengguna lintas sesi

Klik tombol New Session di UI developer untuk memulai percakapan baru. Tindakan ini akan membuat sesi baru untuk pengguna yang sama.

57408cfae5f041ac.png

Coba perintah ini:

What do you recommend for me?

Periksa tab State di sesi baru. Kunci user:dietary_preferences tetap ada, tetapi current_order sudah tidak ada — status tersebut terikat dengan sesi sebelumnya.

764eb3885251307d.png

7. Mematuhi Batasan Penyimpanan Lokal

Agen mengingat preferensi di seluruh sesi, tetapi hanya selama penyimpanan lokal ada. Langkah ini menunjukkan batasan mendasar penyimpanan lokal.

Mulai agen lagi

Anda menghentikan UI dev di akhir langkah sebelumnya. Sekarang, hapus penyimpanan lokal dan mulai lagi, untuk menyimulasikan lingkungan serverless yang stateless:

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

Sekarang, buka Pratinjau Web di port 8000 dan pilih cafe_concierge.

Menguji ingatan preferensi

Jenis:

Do you remember my dietary preferences?

Agen tidak ingat. Preferensi diet, histori pesanan — semuanya hilang.

82a5e05434cafe83.png

Semua data dihapus saat kita menghapus penyimpanan lokal, yang biasanya terjadi saat kita menggunakan lingkungan serverless. session.db menyimpan semua status dalam memori proses. Menghapusnya akan menghapus semuanya.

Solusinya: tentukan DatabaseSessionService, yang dalam tutorial ini akan menyimpan semua data sesi dalam database PostgreSQL di Cloud SQL. Kode dan alat agen tetap sama persis — hanya backend penyimpanan yang berubah.

Hentikan UI dev dengan Ctrl+C sebelum melanjutkan.

8. Membuka Kembali Penyiapan Database

Pada tahap ini, pembuatan instance database kita seharusnya sudah selesai. Mari kita verifikasi, jalankan perintah berikut

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

Anda akan melihat output berikut, tandai sebagai selesai

RUNNABLE

Membuat database

Buat database khusus untuk data sesi agen:

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

Mulai Proxy Auth Cloud SQL.

Proxy Auth Cloud SQL menyediakan koneksi yang aman dan diautentikasi dari Cloud Shell ke instance Cloud SQL Anda tanpa perlu memasukkan alamat IP ke daftar yang diizinkan. Alat ini sudah diinstal sebelumnya di Cloud Shell.

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

Sufiks & dalam perintah membuat proxy berjalan di latar belakang. Anda akan melihat output yang mengonfirmasi bahwa proxy sudah siap seperti yang ditunjukkan di bawah

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

Memverifikasi koneksi

Uji bahwa Anda dapat terhubung ke database melalui proxy:

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

Anda akan melihat:

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

9. Memverifikasi Memori Persisten di Seluruh Sesi

Langkah ini membuktikan bahwa memori agen Anda tetap ada setelah direset saat kita memastikan bahwa cafe_concierge/.adk/session_db (database lokal) dihapus dan mencakup sesi percakapan.

Mulai agen

Pastikan Proxy Auth Cloud SQL masih berjalan (periksa dengan tugas). Jika tidak, mulai ulang:

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

Kemudian, mulai UI dev ADK dengan menentukan database sebagai layanan sesi

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

Buka Pratinjau Web di port 8000 dan pilih cafe_concierge.

Pengujian 1: Lakukan pemesanan dan tetapkan preferensi

Di sesi pertama, jalankan perintah berikut:

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

Pengujian 2: Bertahan saat dimulai ulang

Hentikan UI dev dengan Ctrl+C dan pastikan session.db lokal dihapus

rm -f cafe_concierge/.adk/session.db

Kemudian, jalankan kembali server UI dev

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

Buka Pratinjau Web di port 8000, pilih cafe_concierge, dan mulai sesi baru. Kemudian tanyakan

What are my dietary preferences?

Agen akan merespons dengan preferensi tersimpan Anda — vegan. Data tetap ada setelah dimulai ulang karena kini disimpan di PostgreSQL, bukan di penyimpanan lokal. Hal yang sama akan terjadi jika kita membuat sesi baru karena status user: akan diteruskan ke setiap sesi baru untuk pengguna ini.

9c139bf89becb748.png

Memeriksa database secara langsung

Buka tab terminal baru di Cloud Shell dan kueri database untuk melihat data yang disimpan:

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

Anda akan melihat tabel yang dibuat ADK secara otomatis untuk menyimpan sesi, peristiwa, dan status seperti contoh ini

                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)

Ringkasan perilaku status

Kunci status

Awalan

Cakupan

Dibagikan di seluruh sesi?

current_order

(tidak ada)

Sesi

Tidak

user:dietary_preferences

user:

Pengguna

Ya

10. Selamat / Pembersihan

Selamat! Anda telah berhasil membangun agen AI persisten dan stateful menggunakan ADK dan Cloud SQL.

Yang telah Anda pelajari

  • Cara membuat agen ADK dengan alat kustom yang membaca dan menulis status sesi
  • Perbedaan antara status cakupan sesi (tanpa awalan) dan status cakupan pengguna (awalan user:)
  • Mengapa adk lokal session.db default hanya cocok untuk pengembangan — semua data akan hilang saat dihapus (dan mudah dihapus, tidak ada cadangan), tidak cocok untuk deployment serverless yang stateless
  • Cara menyediakan instance Cloud SQL PostgreSQL dan terhubung ke instance tersebut dengan Proxy Auth Cloud SQL
  • Cara terhubung ke DatabaseSessionService dengan PostgreSQL di CloudSQL dengan perubahan kode minimal — alat yang sama, agen yang sama, backend yang berbeda
  • Cara status cakupan pengguna dipertahankan di seluruh sesi percakapan terpisah

Pembersihan

Agar tidak menimbulkan biaya pada akun Google Cloud Anda, bersihkan resource yang dibuat dalam codelab ini.

Cara termudah untuk membersihkan adalah dengan menghapus project. Tindakan ini akan menghapus semua resource yang terkait dengan project.

gcloud projects delete ${GOOGLE_CLOUD_PROJECT}

Opsi 2: Menghapus resource satu per satu

Jika Anda ingin mempertahankan project, tetapi hanya menghapus resource yang dibuat di codelab ini:

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