Cara Kerja Stack Agen Google: ADK, A2A, MCP di Google Cloud

1. Yang akan Anda pelajari

Selamat datang! Kita akan memulai perjalanan yang cukup keren hari ini. Mari kita mulai dengan memikirkan platform acara sosial populer, InstaVibe. Meskipun berhasil, kami tahu bahwa bagi sebagian pengguna, perencanaan aktivitas kelompok yang sebenarnya bisa terasa seperti tugas yang membosankan. Bayangkan Anda mencoba mencari tahu apa yang diminati semua teman Anda, lalu memilah-milah berbagai opsi acara atau tempat, dan akhirnya mengoordinasikan semuanya. Banyak sekali! Di sinilah kita dapat memperkenalkan AI, dan khususnya, agen cerdas, untuk membuat perbedaan nyata.

Idenya adalah membangun sistem tempat agen ini dapat menangani tugas berat, seperti 'mendengarkan' dengan cerdas untuk memahami preferensi pengguna dan teman, lalu secara proaktif menyarankan aktivitas fantastis yang disesuaikan. Tujuan kami adalah mengubah perencanaan sosial di InstaVibe menjadi sesuatu yang lancar dan menyenangkan. Untuk mulai membangun asisten pintar ini, kita perlu meletakkan dasar yang kuat dengan alat yang tepat.

Berikut konsep yang akan Anda lihat:

Judul Halaman

Dasar-Dasar dengan ADK Google: Kuasai dasar-dasar membangun agen cerdas pertama Anda menggunakan Agent Development Kit (ADK) Google. Pahami komponen penting, siklus proses agen, dan cara memanfaatkan alat bawaan framework secara efektif.

Memperluas Kemampuan Agen dengan Model Context Protocol (MCP): Pelajari cara melengkapi agen Anda dengan alat dan konteks kustom, sehingga agen dapat melakukan tugas khusus dan mengakses informasi tertentu. Memperkenalkan konsep Model Context Protocol (MCP). Anda akan mempelajari cara menyiapkan server MCP untuk memberikan konteks ini.

Mendesain Interaksi & Orkestrasi Agen: Melampaui agen tunggal untuk memahami orkestrasi agen. Merancang pola interaksi mulai dari alur kerja berurutan sederhana hingga skenario kompleks yang melibatkan loop, logika bersyarat, dan pemrosesan paralel. Memperkenalkan konsep sub-agen dalam framework ADK untuk mengelola tugas modular.

Membangun Sistem Multi-Agen Kolaboratif: Temukan cara merancang sistem tempat beberapa agen berkolaborasi untuk mencapai tujuan yang kompleks. Pelajari dan terapkan protokol komunikasi Agent-to-Agent (A2A), yang menetapkan cara standar bagi agen terdistribusi (yang berpotensi berjalan di mesin atau layanan yang berbeda) untuk berinteraksi secara andal.

Menyiapkan Agen untuk Produksi di Google Cloud: Transisikan aplikasi agen Anda dari lingkungan pengembangan ke cloud. Pelajari praktik terbaik untuk merancang dan men-deploy sistem multi-agen yang skalabel dan tangguh di Google Cloud Platform (GCP). Dapatkan insight tentang cara memanfaatkan layanan GCP seperti Cloud Run dan pelajari kemampuan Google Agent Engine terbaru untuk menghosting dan mengelola agen Anda.

2. Arsitektur

Perencanaan Sosial yang Didukung AI dengan InstaVibe

Apa yang dimaksud dengan Pemantauan Media Sosial?

Social listening adalah proses memantau percakapan digital di berbagai platform seperti media sosial, forum, dan situs berita untuk memahami apa yang dibicarakan orang tentang suatu topik, merek, atau industri. Data ini memberikan insight berharga tentang sentimen publik, tren, dan kebutuhan pengguna. Dalam workshop ini, kita akan memanfaatkan konsep ini dalam sistem berbasis agen.

Anda adalah bagian dari Tim di InstaVibe

Bayangkan Anda bekerja di "InstaVibe", sebuah startup sukses dengan platform acara sosial populer yang menargetkan kaum dewasa muda. Semuanya berjalan lancar, tetapi seperti banyak perusahaan teknologi lainnya, tim Anda menghadapi tekanan dari investor untuk berinovasi menggunakan AI. Secara internal, Anda juga melihat segmen pengguna yang tidak berinteraksi sebanyak pengguna lain – mungkin mereka kurang cenderung memulai aktivitas grup atau merasa proses perencanaan sulit. Bagi perusahaan Anda, hal ini berarti daya tarik platform yang lebih rendah di antara grup pengguna penting ini.

Riset tim Anda menunjukkan bahwa bantuan yang didukung AI dapat meningkatkan pengalaman pengguna ini secara signifikan. Idenya adalah menyederhanakan proses perencanaan acara sosial dengan secara proaktif menyarankan aktivitas yang relevan berdasarkan minat pengguna dan teman-temannya. Pertanyaan yang dihadapi Anda dan rekan kerja Anda adalah: Bagaimana agen AI dapat mengotomatiskan tugas-tugas yang sering kali memakan waktu seperti penemuan minat, riset aktivitas, dan berpotensi koordinasi awal?

Solusi Berbasis Agen (Konsep Prototipe)

Anda mengusulkan pengembangan fitur prototipe yang didukung oleh sistem multi-agen. Berikut perincian konseptualnya:

Kasus penggunaan

  • Agen pembuatan profil sosial: Agen ini menggunakan teknik mendengarkan media sosial untuk menganalisis koneksi, interaksi pengguna, dan potensi tren publik yang lebih luas terkait preferensi pengguna. Tujuannya adalah untuk mengidentifikasi minat bersama dan karakteristik aktivitas yang sesuai (misalnya, preferensi untuk pertemuan yang lebih tenang, hobi tertentu).
  • Agen Perencanaan Acara: Dengan menggunakan insight dari Agen Pemrofilan media sosial, agen ini menelusuri referensi online untuk menemukan acara, tempat, atau ide tertentu yang sesuai dengan kriteria yang diidentifikasi (seperti lokasi, minat).
  • Agen Interaksi Platform (menggunakan MCP): Agen ini mengambil rencana akhir dari Agen Perencanaan Aktivitas. Fungsi utamanya adalah berinteraksi langsung dengan platform InstaVibe menggunakan alat MCP (Model Context Protocol) yang telah ditentukan sebelumnya. Alat ini memberi agen kemampuan khusus untuk membuat draf saran acara dan membuat postingan yang menguraikan rencana.
  • Agen Orkestrator: Agen ini bertindak sebagai koordinator pusat. Sistem ini menerima permintaan pengguna awal dari platform InstaVibe, memahami tujuan keseluruhan (misalnya, "rencanakan acara untuk saya dan teman-teman saya"), lalu mendelegasikan tugas tertentu ke agen khusus yang sesuai dalam urutan logis. Alat ini mengelola aliran informasi antara agen dan memastikan hasil akhir dikirim kembali kepada pengguna.

Elemen dan Teknologi Arsitektur Utama

Arsitektur

Google Cloud Platform (GCP):

  • Vertex AI:
    • Model Gemini: Memberikan akses ke Model Bahasa Besar (LLM) tercanggih Google seperti Gemini, yang mendukung kemampuan penalaran dan pengambilan keputusan agen kami.
    • Vertex AI Agent Engine: Layanan terkelola yang digunakan untuk men-deploy, menghosting, dan menskalakan agen orkestrator kami, sehingga menyederhanakan produksi dan mengabstraksi kompleksitas infrastruktur.
  • Cloud Run: Platform serverless untuk men-deploy aplikasi dalam container. Kami menggunakannya untuk:
    • Menghosting aplikasi web InstaVibe utama.
    • Men-deploy setiap agen yang kompatibel dengan A2A (Planner, Social Profiling, Platform Interaction) sebagai microservice independen.
    • Jalankan Server Alat MCP, sehingga API internal InstaVibe tersedia untuk agen.
  • Spanner: Database relasional terkelola sepenuhnya, yang didistribusikan secara global, dan sangat konsisten. Dalam workshop ini, kita akan memanfaatkan kemampuannya sebagai Database Grafik menggunakan fitur kueri dan DDL GRAPH untuk:
    • Memodelkan dan menyimpan hubungan sosial yang kompleks (pengguna, persahabatan, kehadiran acara, postingan).
    • Mengaktifkan kueri yang efisien atas hubungan ini untuk agen Pemrofilan Sosial.
  • Artifact Registry: Layanan terkelola sepenuhnya untuk menyimpan, mengelola, dan mengamankan image container.
  • Cloud Build: Layanan yang menjalankan build Anda di Google Cloud. Kita menggunakannya untuk otomatis membangun image container Docker dari kode sumber agen dan aplikasi kita.
  • Cloud Storage: Digunakan oleh layanan seperti Cloud Build untuk menyimpan artefak build dan oleh Agent Engine untuk kebutuhan operasionalnya.
  • Framework & Protokol Agen Inti:
    • Agent Development Kit (ADK) Google: Framework utama untuk:
      • Menentukan logika inti, perilaku, dan set instruksi untuk setiap agen cerdas.
      • Mengelola siklus proses, status, dan memori agen (status sesi jangka pendek dan pengetahuan jangka panjang).
      • Mengintegrasikan alat (seperti Google Penelusuran atau alat buatan khusus) yang dapat digunakan agen untuk berinteraksi dengan dunia.
      • Mengatur alur kerja multi-agen, termasuk eksekusi sub-agen secara berurutan, loop, dan paralel.
    • Protokol Komunikasi Agent-to-Agent (A2A): Standar terbuka yang memungkinkan:
      • Komunikasi dan kolaborasi langsung yang terstandarisasi antara berbagai agen AI, meskipun agen tersebut berjalan sebagai layanan terpisah atau di komputer yang berbeda.
      • Agen dapat menemukan kemampuan satu sama lain (melalui Kartu Agen) dan mendelegasikan tugas. Hal ini sangat penting agar agen Orchestrator kami dapat berinteraksi dengan agen Planner, Social, dan Platform khusus.
    • Library Python A2A (a2a-python): Library konkret yang digunakan untuk membuat agen ADK kami berbicara dengan protokol A2A. Library ini menyediakan komponen sisi server yang diperlukan untuk:
      • Mengekspos agen kami sebagai server yang kompatibel dengan A2A.
      • Menangani penyajian "Kartu Agen" untuk penemuan secara otomatis.
      • Menerima dan mengelola permintaan tugas masuk dari agen lain (seperti Orchestrator).
    • Model Context Protocol (MCP): Standar terbuka yang memungkinkan agen:
      • Menghubungkan dan memanfaatkan alat, sumber data, dan sistem eksternal dengan cara yang standar.
      • Agen Interaksi Platform kami menggunakan klien MCP untuk berkomunikasi dengan server MCP, yang pada gilirannya mengekspos alat untuk berinteraksi dengan API InstaVibe yang ada.
  • Alat Debugging:
    • A2A Inspector: A2A Inspector adalah alat debug berbasis web yang digunakan di seluruh workshop ini untuk terhubung ke, memeriksa, dan berinteraksi dengan agen yang mendukung A2A. Meskipun bukan bagian dari arsitektur produksi akhir, ini adalah bagian penting dari alur kerja pengembangan kami. Fitur ini menyediakan:
      • Pelihat Kartu Agen: Untuk mengambil dan memvalidasi kemampuan publik agen.
      • Antarmuka Live Chat: Untuk mengirim pesan langsung ke agen yang di-deploy untuk pengujian segera.
      • Konsol Debug: Untuk melihat pesan JSON-RPC mentah yang dipertukarkan antara pemeriksa dan agen.
  • Model Bahasa (LLM): "Otak" Sistem:
    • Model Gemini Google: Secara khusus, kami menggunakan versi seperti gemini-2.0-flash. Model ini dipilih untuk:
      • Kemampuan Penalaran & Mengikuti Petunjuk Tingkat Lanjut: Kemampuan mereka untuk memahami perintah yang kompleks, mengikuti petunjuk yang mendetail, dan bernalar tentang tugas membuat mereka cocok untuk mendukung pengambilan keputusan agen.
      • Penggunaan Alat (Pemanggilan Fungsi): Model Gemini unggul dalam menentukan kapan dan cara menggunakan alat yang disediakan melalui ADK, sehingga memungkinkan agen mengumpulkan informasi atau melakukan tindakan.
      • Efisiensi (Model Flash): Varian "flash" menawarkan keseimbangan yang baik antara performa dan efektivitas biaya, cocok untuk banyak tugas agen interaktif yang memerlukan respons cepat.

Perlu Kredit Google Cloud?

3. Sebelum memulai

👉Klik Activate Cloud Shell di bagian atas konsol Google Cloud (Ikonnya berbentuk terminal di bagian atas panel Cloud Shell), Cloud Shell

👉Klik tombol "Buka Editor" (terlihat seperti folder terbuka dengan pensil). Tindakan ini akan membuka Editor Kode Cloud Shell di jendela. Anda akan melihat file explorer di sisi kiri. Cloud Shell

👉Klik tombol Cloud Code Sign-in di status bar bawah seperti yang ditunjukkan. Otorisasi plugin seperti yang ditunjukkan. Jika Anda melihat Cloud Code - no project di status bar, pilih opsi tersebut, lalu pilih ‘Select a Google Cloud Project' di drop-down, lalu pilih Project Google Cloud tertentu dari daftar project yang Anda buat. Cloud Shell

👉 Temukan Project ID Google Cloud Anda:

  • Buka Konsol Google Cloud: https://console.cloud.google.com
  • Pilih project yang ingin Anda gunakan untuk workshop ini dari dropdown project di bagian atas halaman.
  • Project ID Anda ditampilkan di kartu Info project di Dasbor

Cloud Shell

👉Buka terminal di IDE cloud, Cloud Shell

👉💻 Di terminal, verifikasi bahwa Anda sudah diautentikasi dan project ditetapkan ke project ID Anda menggunakan perintah berikut:

gcloud auth list

👉💻 Clone project instavibe-bootstrap dari GitHub:

git clone -b adk-1.2.1-a2a-0.2.7 https://github.com/weimeilin79/instavibe-bootstrap.git
chmod +x ~/instavibe-bootstrap/init.sh
chmod +x ~/instavibe-bootstrap/set_env.sh

Memahami Struktur Project

Sebelum kita mulai membangun, mari luangkan waktu sejenak untuk memahami tata letak project instavibe-bootstrap yang baru saja Anda clone. Hal ini akan membantu Anda mengetahui tempat menemukan dan mengedit file selama workshop.

instavibe-bootstrap/
├── agents/
   ├── orchestrate/
   ├── planner/
   ├── platform_mcp_client/
   └── social/
├── instavibe/
   ├── static/
   └── templates/
├── tools/
   └── instavibe/
├── utils/
├── init.sh
└── set_env.sh

Berikut perincian direktori utama:

  • agents/: Ini adalah inti dari sistem AI kami. Setiap subdirektori (planner/, social/, dll.) berisi kode sumber untuk agen cerdas tertentu.
    • agent.py: Di dalam folder setiap agen, ini adalah file utama tempat logika agen berada.
    • a2a_server.py: File ini membungkus agen ADK dengan server Agent-to-Agent (A2A).
    • Dockerfile: Menentukan cara membangun image container untuk men-deploy agen ke Cloud Run atau Agent Engine.
  • instavibe/: Direktori ini berisi seluruh kode sumber untuk aplikasi web InstaVibe.
  • tools/: Direktori ini digunakan untuk membuat alat eksternal yang dapat digunakan oleh agen kami.
    • instavibe/ berisi Server Model Context Protocol (MCP).

Struktur modular ini memisahkan aplikasi web dari berbagai komponen AI, sehingga seluruh sistem lebih mudah dikelola, diuji, dan di-deploy.

👉💻 Jalankan skrip inisialisasi:

Skrip ini akan meminta Anda memasukkan Project ID Google Cloud Anda.

Masukkan Google Cloud Project ID yang Anda temukan dari langkah terakhir saat diminta oleh skrip init.sh:

cd ~/instavibe-bootstrap
./init.sh

👉💻 Tetapkan Project ID yang diperlukan:

gcloud config set project $(cat ~/project_id.txt) --quiet

👉💻 Jalankan perintah berikut untuk mengaktifkan Google Cloud API yang diperlukan:

gcloud services enable  run.googleapis.com \
                        cloudfunctions.googleapis.com \
                        cloudbuild.googleapis.com \
                        artifactregistry.googleapis.com \
                        spanner.googleapis.com \
                        apikeys.googleapis.com \
                        iam.googleapis.com \
                        compute.googleapis.com \
                        aiplatform.googleapis.com \
                        cloudresourcemanager.googleapis.com \
                        maps-backend.googleapis.com

👉💻 Tetapkan semua variabel lingkungan yang diperlukan:

export PROJECT_ID=$(gcloud config get project)
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
export SERVICE_ACCOUNT_NAME=$(gcloud compute project-info describe --format="value(defaultServiceAccount)")
export SPANNER_INSTANCE_ID="instavibe-graph-instance"
export SPANNER_DATABASE_ID="graphdb"
export GOOGLE_CLOUD_PROJECT=$(gcloud config get project)
export GOOGLE_GENAI_USE_VERTEXAI=TRUE
export GOOGLE_CLOUD_LOCATION="us-central1"

Menyiapkan izin

👉💻 Berikan Izin. Di terminal, jalankan :

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/spanner.admin"

# Spanner Database User
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/spanner.databaseUser"

# Artifact Registry Admin
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/artifactregistry.admin"

# Cloud Build Editor
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/cloudbuild.builds.editor"

# Cloud Run Admin
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/run.admin"

# IAM Service Account User
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/iam.serviceAccountUser"

# Vertex AI User
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/aiplatform.user"

# Logging Writer (to allow writing logs)
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/logging.logWriter"


gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/logging.viewer"


👉 Validasi hasil di konsol IAM AndaCloud Shell

👉💻 Jalankan perintah berikut di terminal untuk membuat repositori Artifact Registry. Semua image Docker untuk agen, server MCP, dan aplikasi InstaVibe disimpan di sini sebelum di-deploy ke Cloud Run atau Agent Engine.

export REPO_NAME="introveally-repo"
gcloud artifacts repositories create $REPO_NAME \
  --repository-format=docker \
  --location=us-central1 \
  --description="Docker repository for InstaVibe workshop"

Menyiapkan platform Peta untuk Kunci API

Untuk menggunakan layanan Google Maps di aplikasi InstaVibe, Anda harus membuat kunci API dan membatasinya dengan tepat.

👉 Di tab baru, buka API & Layanan > Kredensial. Di halaman "Credentials", klik tombol + CREATE CREDENTIALS di bagian atas. Pilih Kunci API dari menu dropdown. Teks alternatif

👉 Kotak dialog akan muncul yang menampilkan kunci API yang baru dibuat. Anda akan memerlukannya nanti untuk konfigurasi aplikasi Anda.

👉 Klik TUTUP pada dialog "API key created".

👉 Anda akan melihat kunci API baru Anda tercantum (misalnya, "API key 1"). Klik tiga titik di sebelah kanan, lalu pilih Edit API key untuk membuka halaman "Membatasi dan mengganti nama kunci API". Teks alternatif

👉 Di kolom Name di bagian atas, ubah nama default menjadi: Maps Platform API Key (🚨🚨PENTING🚨🚨 Harap gunakan nama ini!)

Maps Platform API Key

👉 Di bagian "Application restrictions", pastikan None dipilih.

👉 Di bagian "Pembatasan API", pilih tombol pilihan Batasi kunci.

👉 Klik menu drop-down Pilih API. Di kotak penelusuran yang muncul, ketik Maps JavaScript API dan pilih dari daftar. Teks alternatif

👉 Klik Oke.

👉 Klik tombol SIMPAN di bagian bawah halaman.

Hasil Utama

Anda kini telah berhasil membuat kunci API bernama "Maps Platform API Key", membatasinya agar hanya mengizinkan penggunaan "Maps JavaScript API", dan memastikan API diaktifkan untuk project Anda.

4. Menyiapkan Database Grafik

Sebelum dapat membangun agen cerdas, kita memerlukan cara untuk menyimpan dan memahami koneksi yang kaya dalam jaringan sosial InstaVibe. Di sinilah Database Grafik berperan. Tidak seperti database relasional tradisional yang menyimpan data dalam tabel baris dan kolom, database grafik dirancang khusus untuk merepresentasikan dan mengkueri data dalam hal node (seperti orang, acara, atau postingan) dan hubungan (edge) yang menghubungkannya (seperti persahabatan, kehadiran acara, atau sebutan). Struktur ini sangat efektif untuk aplikasi media sosial karena mencerminkan cara jaringan sosial dunia nyata disusun, sehingga memudahkan untuk mempelajari cara berbagai entitas saling terhubung.

Kami menerapkan database grafik ini menggunakan Google Cloud Spanner. Meskipun terutama dikenal sebagai database relasional yang didistribusikan secara global dan sangat konsisten, Spanner juga memungkinkan kita menentukan dan membuat kueri struktur grafik secara langsung di atas tabel relasional.

Hal ini memberi kami manfaat gabungan dari skalabilitas, konsistensi transaksional, dan antarmuka SQL yang sudah dikenal dari Spanner, beserta kemampuan ekspresif kueri grafik untuk menganalisis dinamika sosial yang kompleks dan penting untuk fitur yang didukung AI kami.

👉💻 Di terminal Cloud Shell IDE. Sediakan infrastruktur yang diperlukan di Google Cloud. Kita akan mulai dengan membuat Instance Spanner, yang berfungsi sebagai container khusus untuk database kita. Setelah instance siap, kita akan membuat Database Spanner yang sebenarnya di dalamnya, yang akan menyimpan semua tabel dan data grafik untuk InstaVibe:

. ~/instavibe-bootstrap/set_env.sh

gcloud spanner instances create $SPANNER_INSTANCE_ID \
  --config=regional-us-central1 \
  --description="GraphDB Instance InstaVibe" \
  --processing-units=100 \
  --edition=ENTERPRISE

gcloud spanner databases create $SPANNER_DATABASE_ID \
  --instance=$SPANNER_INSTANCE_ID \
  --database-dialect=GOOGLE_STANDARD_SQL

👉💻 Berikan akses baca/tulis Spanner ke akun layanan default

echo "Granting Spanner read/write access to ${SERVICE_ACCOUNT_NAME} for database ${SPANNER_DATABASE_ID}..."

gcloud spanner databases add-iam-policy-binding ${SPANNER_DATABASE_ID} \
  --instance=${SPANNER_INSTANCE_ID} \
  --member="serviceAccount:${SERVICE_ACCOUNT_NAME}" \
  --role="roles/spanner.databaseUser" \
  --project=${PROJECT_ID}

👉💻 Sekarang. Kita akan menyiapkan lingkungan virtual Python, menginstal paket Python yang diperlukan, lalu menyiapkan skema Graph Database dalam Spanner, memuatnya dengan data awal, dan menjalankan skrip setup.py.

. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap
python -m venv env
source env/bin/activate
pip install -r requirements.txt
cd instavibe
python setup.py

👉 Di tab browser baru, buka Konsol Google Cloud, lalu buka Spanner. Anda akan melihat daftar instance Spanner Anda. Klik instavibe-graph-instance. instance spanner 👉 Di halaman ringkasan instance, Anda akan melihat daftar database dalam instance tersebut. Klik graphdbspanner db

👉 Di panel navigasi kiri untuk database Anda, klik Spanner Studio spanner studio

👉 Di editor kueri (tab Untitled query), tempel kueri Graph SQL berikut. Kueri ini akan menemukan semua node Person dan hubungan Persahabatan langsung mereka dengan node Person lainnya. Kemudian, klik RUN untuk melihat hasilnya.

Graph SocialGraph
MATCH result_paths = ((p:Person)-[f:Friendship]-(friend:Person))
RETURN SAFE_TO_JSON(result_paths) AS result_paths

grafik spanner

👉 Di editor kueri yang sama, ganti DDL sebelumnya untuk menemukan orang yang menghadiri acara yang sama, yang menyiratkan koneksi tidak langsung melalui aktivitas bersama.

Graph SocialGraph
MATCH result_paths =  (p1:Person)-[:Attended]->(e:Event)<-[:Attended]-(p2:Person)
WHERE p1.person_id < p2.person_id
RETURN SAFE_TO_JSON(result_paths) AS result_paths

grafik spanner

👉 Kueri ini mengeksplorasi jenis koneksi yang berbeda, di mana orang yang disebutkan dalam postingan yang ditulis oleh teman orang tertentu, menjalankan kueri berikut di editor kueri.

Graph SocialGraph
MATCH result_paths =  (user:Person {name: "Alice"})-[:Friendship]-(friend:Person)-[:Wrote]->(post:Post)-[:Mentioned]->(mentioned_person:Person)
WHERE user <> mentioned_person AND friend <> mentioned_person -- Avoid self-mentions or friend mentioning themselves in their own post if not intended
RETURN SAFE_TO_JSON(result_paths) AS result_paths

grafik spanner

Kueri ini hanya memberikan gambaran sekilas tentang keunggulan penggunaan Spanner sebagai database grafik untuk aplikasi InstaVibe kami. Dengan memodelkan data media sosial kami sebagai grafik yang saling terhubung, kami memungkinkan analisis yang canggih terhadap hubungan dan aktivitas, yang akan menjadi dasar bagi agen AI kami untuk memahami konteks pengguna, menemukan minat, dan pada akhirnya memberikan bantuan perencanaan media sosial yang cerdas.

Setelah struktur data dasar kita diterapkan dan diuji, mari kita perhatikan aplikasi InstaVibe yang ada dan akan digunakan oleh agen kita.

5. Status InstaVibe saat ini

Untuk memahami di mana posisi agen AI kita, kita harus men-deploy dan menjalankan aplikasi web InstaVibe yang ada terlebih dahulu. Aplikasi ini menyediakan antarmuka pengguna dan fungsi dasar yang terhubung ke database grafik Spanner yang telah kita siapkan.

beranda

Aplikasi InstaVibe menggunakan Google Maps untuk menampilkan lokasi acara secara visual di halaman detail acaranya. Untuk mengaktifkan fungsi ini, aplikasi memerlukan kunci API yang kita buat sebelumnya. Skrip berikut akan mengambil string kunci sebenarnya menggunakan nama tampilan yang kita tetapkan ("Maps Platform API Key").

halaman acara

👉💻 Kembali di Cloud Shell IDE. Jalankan skrip di bawah. Setelah itu, periksa output dengan cermat untuk memastikan GOOGLE_MAPS_API_KEY yang ditampilkan cocok dengan kunci yang Anda buat dan salin dari Konsol Google Cloud sebelumnya.

. ~/instavibe-bootstrap/set_env.sh
export KEY_DISPLAY_NAME="Maps Platform API Key"

GOOGLE_MAPS_KEY_ID=$(gcloud services api-keys list \
  --project="${PROJECT_ID}" \
  --filter="displayName='${KEY_DISPLAY_NAME}'" \
  --format="value(uid)" \
  --limit=1)

GOOGLE_MAPS_API_KEY=$(gcloud services api-keys get-key-string "${GOOGLE_MAPS_KEY_ID}" \
    --project="${PROJECT_ID}" \
    --format="value(keyString)")

echo "${GOOGLE_MAPS_API_KEY}" > ~/mapkey.txt

echo "Retrieved GOOGLE_MAPS_API_KEY: ${GOOGLE_MAPS_API_KEY}"

hasil utama

👉💻 Sekarang, mari kita bangun image container untuk aplikasi web InstaVibe dan kirimkan ke repositori Artifact Registry kita.

. ~/instavibe-bootstrap/set_env.sh

cd ~/instavibe-bootstrap/instavibe/
export IMAGE_TAG="latest"
export APP_FOLDER_NAME="instavibe"
export IMAGE_NAME="instavibe-webapp"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="instavibe"

gcloud builds submit . \
  --tag=${IMAGE_PATH} \
  --project=${PROJECT_ID}

👉💻 Deploy image aplikasi web InstaVibe build baru ke Cloud Run

. ~/instavibe-bootstrap/set_env.sh

cd ~/instavibe-bootstrap/instavibe/
export IMAGE_TAG="latest"
export APP_FOLDER_NAME="instavibe"
export IMAGE_NAME="instavibe-webapp"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="instavibe"

gcloud run deploy ${SERVICE_NAME} \
  --image=${IMAGE_PATH} \
  --platform=managed \
  --region=${REGION} \
  --allow-unauthenticated \
  --set-env-vars="SPANNER_INSTANCE_ID=${SPANNER_INSTANCE_ID}" \
  --set-env-vars="SPANNER_DATABASE_ID=${SPANNER_DATABASE_ID}" \
  --set-env-vars="APP_HOST=0.0.0.0" \
  --set-env-vars="APP_PORT=8080" \
  --set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}" \
  --set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
  --set-env-vars="GOOGLE_MAPS_API_KEY=${GOOGLE_MAPS_API_KEY}" \
  --project=${PROJECT_ID} \
  --min-instances=1

Setelah deployment berhasil diselesaikan, log Cloud Run akan menampilkan URL publik untuk aplikasi InstaVibe yang sedang berjalan.

URL

Anda juga dapat menemukan URL ini dengan membuka bagian Cloud Run di Konsol Google Cloud dan memilih layanan instavibe. DaftarURL

Buka URL tersebut di browser web Anda sekarang untuk menjelajahi platform InstaVibe dasar. Lihat postingan, acara, dan koneksi pengguna yang didukung oleh database grafik yang kita siapkan.

Setelah aplikasi target berjalan, mari kita mulai membangun agen cerdas pertama untuk meningkatkan kemampuannya.

6. Basic Agent,Event Planner dengan ADK

Framework ADK

Pengantar Framework ADK Google Setelah fondasi kita (aplikasi dan database InstaVibe) ditetapkan, kita dapat mulai membangun agen cerdas pertama menggunakan Agent Development Kit (ADK) Google.

Agent Development Kit (ADK) adalah framework fleksibel dan modular yang dirancang khusus untuk mengembangkan dan men-deploy agen AI. Prinsip desainnya adalah membuat pengembangan agen terasa lebih seperti pengembangan software tradisional, yang bertujuan untuk mempermudah developer membuat, men-deploy, dan mengatur arsitektur berbasis agen yang dapat menangani semuanya, mulai dari tugas sederhana dan satu tujuan hingga alur kerja multi-agen yang kompleks.

Intinya, ADK berkisar pada konsep Agent, yang mencakup petunjuk, konfigurasi (seperti model bahasa yang dipilih, misalnya, Gemini), dan serangkaian Tools yang dapat digunakan untuk melakukan tindakan atau mengumpulkan informasi.

06-agent.png

Agen awal kita adalah "Perencana Acara". Tujuan utamanya adalah menerima permintaan pengguna untuk acara sosial (dengan menentukan lokasi, tanggal, dan minat) serta membuat saran yang kreatif dan disesuaikan. Untuk memastikan saran relevan dan didasarkan pada informasi terkini (seperti acara tertentu yang berlangsung pada akhir pekan tersebut), kami akan memanfaatkan salah satu alat bawaan ADK: Google Penelusuran. Dengan demikian, agen dapat mendasarkan responsnya pada hasil web real-time, dengan mengambil detail terbaru tentang tempat, acara, dan aktivitas yang cocok dengan kriteria pengguna.

👉📝 Kembali di IDE Cloud Shell, di ~/instavibe-bootstrap/agents/planner/agent.py, tambahkan perintah dan petunjuk berikut untuk membuat agen

from google.adk.agents import Agent
from google.adk.tools import google_search

root_agent = Agent(
    name="planner_agent",
    model="gemini-2.0-flash",
    description="Agent tasked with generating creative and fun dating plan suggestions",
    instruction="""

        You are a specialized AI assistant tasked with generating creative and fun plan suggestions.

        Request:
        For the upcoming weekend, specifically from **[START_DATE_YYYY-MM-DD]** to **[END_DATE_YYYY-MM-DD]**, in the location specified as **[TARGET_LOCATION_NAME_OR_CITY_STATE]** (if latitude/longitude are provided, use these: Lat: **[TARGET_LATITUDE]**, Lon: **[TARGET_LONGITUDE]**), please generate a distinct dating plan suggestions.

        Constraints and Guidelines for Suggestions:
        1.  Creativity & Fun: Plans should be engaging, memorable, and offer a good experience for a date.
        2.  Budget: All generated plans should aim for a moderate budget (conceptually "$$"), meaning they should be affordable yet offer good value, without being overly cheap or extravagant. This budget level should be *reflected in the choice of activities and venues*, but **do not** explicitly state "Budget: $$" in the `plan_description`.
        3.  Interest Alignment:
               Consider the following user interests: **[COMMA_SEPARATED_LIST_OF_INTERESTS, e.g., outdoors, arts & culture, foodie, nightlife, unique local events, live music, active/sports]**. Tailor suggestions specifically to these where possible. The plan should *embody* these interests.
               Fallback: If specific events or venues perfectly matching all listed user interests cannot be found for the specified weekend, you should create a creative and fun generic dating plan that is still appealing, suitable for the location, and adheres to the moderate budget. This plan should still sound exciting and fun, even if it's more general.
        4.  Current & Specific: Prioritize finding specific, current events, festivals, pop-ups, or unique local venues operating or happening during the specified weekend dates. If exact current events cannot be found, suggest appealing evergreen options or implement the fallback generic plan.
        5.  Location Details: For each place or event mentioned within a plan, you MUST provide its name, precise latitude, precise longitude, and a brief, helpful description.
        6.  Maximum Activities: The plan must contain a maximum of 3 distinct activities.

        RETURN PLAN in MARKDOWN FORMAT 
    """,
    tools=[google_search]
)

Dan itulah agen pertama kita yang ditentukan. Salah satu keunggulan ADK adalah sifatnya yang intuitif dan alat praktis yang disediakan. Salah satu yang sangat berguna adalah UI Dev ADK, yang memungkinkan Anda menguji agen secara interaktif dan melihat responsnya secara real-time.

👉💻 Mari kita mulai. Perintah berikut akan meluncurkan UI DEV ADK:

. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
cd  ~/instavibe-bootstrap/agents
sed -i "s|^\(O\?GOOGLE_CLOUD_PROJECT\)=.*|GOOGLE_CLOUD_PROJECT=${PROJECT_ID}|" ~/instavibe-bootstrap/agents/planner/.env
adk web

Setelah menjalankan perintah, Anda akan melihat output di terminal yang menunjukkan bahwa Server Web ADK telah dimulai, mirip dengan ini:

+-----------------------------------------------------------------------------+
| ADK Web Server started                                                      |
|                                                                             |
| For local testing, access at http://localhost:8000.                         |
+-----------------------------------------------------------------------------+

INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

👉 Selanjutnya, untuk mengakses UI Dev ADK dari browser Anda:

Dari ikon Pratinjau web (sering kali terlihat seperti mata atau persegi dengan panah) di toolbar Cloud Shell (biasanya di kanan atas), pilih Ubah port. Di jendela pop-up, tetapkan port ke 8000, lalu klik "Ubah dan Pratinjau". Kemudian, Cloud Shell akan membuka tab atau jendela browser baru yang menampilkan UI Dev ADK.

pratinjau web

Setelah UI Dev ADK terbuka di browser Anda: Di menu dropdown kanan atas UI, pilih planner sebagai agen yang ingin Anda ajak berinteraksi. Sekarang, di dialog chat di sebelah kanan, coba berikan tugas kepada agen Anda. Misalnya, lakukan percakapan dengan agen:

Search and plan something in Seattle for me this weekend
This weekend and I enjoy food and anime

Sarankan tanggal (Preferensi Anda)

July 12 2025

Anda akan melihat agen memproses permintaan Anda dan memberikan rencana berdasarkan hasil Google Penelusurannya.

UI pengembangan ADK

Sekarang, berinteraksi dengan agen adalah satu hal, tetapi bagaimana kita tahu apakah agen tersebut berperilaku sesuai harapan secara konsisten, terutama saat kita melakukan perubahan?

Metode pengujian software tradisional sering kali tidak memadai untuk agen AI karena sifatnya yang generatif dan non-deterministik. Untuk menjembatani kesenjangan dari demo yang keren ke agen produksi yang andal, strategi evaluasi yang solid sangat penting. Tidak seperti sekadar memeriksa output akhir model generatif, mengevaluasi agen sering kali melibatkan penilaian proses pengambilan keputusannya dan kemampuannya untuk menggunakan alat dengan benar atau mengikuti petunjuk di berbagai skenario. ADK menyediakan fitur untuk membantu hal ini.

Evaluasi

👉 Di UI Dev ADK, klik tab "Eval" di navigasi sebelah kiri. Anda akan melihat file pengujian yang telah dimuat sebelumnya bernama plan_eval. File ini berisi input dan kriteria yang telah ditentukan sebelumnya untuk menguji agen perencana kami.

👉 Pilih skenario, seperti "boston", lalu klik tombol Run Evaluation. Di jendela pop-up yang muncul, turunkan skor kecocokan menjadi 0,3, lalu klik Mulai.

Skor kecocokan

Tindakan ini akan menjalankan agen dengan input pengujian dan memeriksa apakah outputnya memenuhi ekspektasi yang ditentukan. Hal ini memberi Anda cara untuk menguji performa agen Anda secara sistematis.

evaluasi UI dev ADK

👉 Sekarang, mari kita lihat apa yang terjadi dengan nilai minimum yang lebih ketat. Pilih skenario "nyc" dan klik Run Evaluation lagi. Kali ini, biarkan skor kecocokan pada nilai defaultnya (Skor kecocokan respons: 0,7), lalu klik Mulai. Anda akan melihat bahwa hasilnya adalah Gagal. Hal ini sudah diperkirakan, karena output kreatif agen tidak cocok dengan jawaban "emas" yang telah ditentukan sebelumnya.

evaluasi adk dev ui gagal

👉 Untuk memahami alasan kegagalannya, klik ikon gagal di baris "nyc". UI kini menampilkan perbandingan berdampingan antara Respons aktual dari agen dan Respons yang diharapkan dari kasus pengujian. Tampilan ini penting untuk proses debug, sehingga Anda dapat melihat dengan tepat di mana output agen berbeda dan menyempurnakan instruksinya dengan tepat.

Setelah selesai menjelajahi UI dan evaluasi, kembali ke terminal Cloud Shell Editor dan tekan Ctrl+C untuk menghentikan UI Dev ADK.

Meskipun output teks bentuk bebas adalah awal yang baik, untuk aplikasi seperti InstaVibe agar dapat dengan mudah menggunakan saran agen, data terstruktur (seperti JSON) jauh lebih praktis. Mari kita ubah agen kita untuk menampilkan rencananya dalam format JSON yang konsisten.

👉📝 Di ~/instavibe-bootstrap/agents/planner/agent.py, temukan baris yang saat ini bertuliskan RETURN PLAN in MARKDOWN FORMAT dalam string petunjuk agen. Ganti baris tersebut dengan struktur JSON mendetail berikut:

Return your response *exclusively* as a single JSON object. This object should contain a top-level key, "fun_plans", which holds a plan objects. Each plan object in the list must strictly adhere to the following structure:

        --json--
        {
          "plan_description": "A summary of the overall plan, consisting of **exactly three sentences**. Craft these sentences in a friendly, enthusiastic, and conversational tone, as if you're suggesting this awesome idea to a close friend. Make it sound exciting and personal, highlighting the positive aspects and appeal of the plan without explicitly mentioning budget or listing interest categories.",
          "locations_and_activities": [
              {
              "name": "Name of the specific place or event",
              "latitude": 0.000000,  // Replace with actual latitude
              "longitude": 0.000000, // Replace with actual longitude
              "description": "A brief description of this place/event, why it's suitable for the date, and any specific details for the weekend (e.g., opening hours, event time)."
              }
              // Add more location/activity objects here if the plan involves multiple stops/parts
          ]
        }

Setelah memperbarui petunjuk agen untuk secara khusus meminta output JSON, mari kita verifikasi perubahan tersebut.

👉💻 Luncurkan kembali UI Dev ADK menggunakan perintah yang sama seperti sebelumnya:

. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
cd  ~/instavibe-bootstrap/agents
adk web

Muat ulang tab jika Anda sudah membukanya. Atau, ikuti langkah-langkah yang sama seperti sebelumnya untuk membuka UI Dev ADK di browser Anda (melalui Pratinjau Web Cloud Shell di port 8000). Setelah UI dimuat, pastikan agen perencana dipilih.

👉 Kali ini, mari kita berikan permintaan yang berbeda. Di dialog chat, masukkan:

Plan an event Boston this weekend with art and coffee

Periksa respons agen dengan cermat. Daripada balasan teks yang murni berupa percakapan, Anda sekarang akan melihat respons yang diformat secara ketat sebagai objek JSON, yang cocok dengan struktur yang kami tentukan dalam petunjuk (berisi fun_plans, plan_description, locations_and_activities, dll.). Hal ini mengonfirmasi bahwa agen kini dapat menghasilkan output terstruktur yang sesuai untuk penggunaan terprogram oleh aplikasi InstaVibe kami.

adk dev ui json

Setelah mengonfirmasi output JSON, kembali ke terminal Cloud Shell dan tekan Ctrl+C untuk menghentikan UI Dev ADK.

Komponen ADK

Meskipun UI Dev ADK sangat bagus untuk pengujian interaktif, kita sering kali perlu menjalankan agen secara terprogram, mungkin sebagai bagian dari aplikasi atau layanan backend yang lebih besar. Untuk memahami cara kerjanya, mari kita lihat beberapa konsep ADK inti yang terkait dengan pengelolaan runtime dan konteks.

Percakapan bolak-balik yang bermakna mengharuskan agen memahami konteks – mengingat apa yang telah dikatakan dan dilakukan untuk menjaga kontinuitas. ADK menyediakan cara terstruktur untuk mengelola konteks ini melalui Session, State, dan Memory:

  • Sesi: Saat pengguna mulai berinteraksi dengan agen, Sesi akan dibuat. Anggap saja sebagai penampung untuk satu rangkaian percakapan tertentu. Objek ini menyimpan ID unik, histori interaksi (Peristiwa), data kerja saat ini (Status), dan metadata seperti waktu pembaruan terakhir.
  • Status: Ini adalah memori kerja jangka pendek agen dalam satu Sesi. Ini adalah kamus yang dapat diubah tempat agen dapat menyimpan informasi sementara yang diperlukan untuk menyelesaikan tugas saat ini (misalnya, preferensi pengguna yang dikumpulkan sejauh ini, hasil sementara dari panggilan alat).
  • Memori: Ini menunjukkan potensi agen untuk mengingat jangka panjang di berbagai sesi atau akses ke basis pengetahuan eksternal. Meskipun Sesi dan Status menangani percakapan langsung, Memori (sering dikelola oleh MemoryService) memungkinkan agen mengambil informasi dari interaksi sebelumnya atau sumber data terstruktur, sehingga memberikan konteks pengetahuan yang lebih luas. (Catatan: Klien sederhana kami menggunakan layanan dalam memori agar lebih mudah, yang berarti memori/status hanya tetap ada saat skrip berjalan).
  • Peristiwa: Setiap interaksi dalam Sesi (pesan pengguna, respons agen, permintaan penggunaan alat, hasil alat, perubahan status, error) dicatat sebagai Peristiwa yang tidak dapat diubah. Tindakan ini akan membuat log kronologis, yang pada dasarnya adalah transkrip dan histori tindakan percakapan.

Jadi, bagaimana cara mengelola hal ini saat agen berjalan? Itulah tugas Runner.

  • Runner: Runner adalah mesin eksekusi inti yang disediakan oleh ADK. Anda menentukan agen dan alat yang digunakannya, dan Runner mengatur proses pemenuhan permintaan pengguna. Kode ini mengelola Sesi, menangani alur Peristiwa, memperbarui Status, memanggil model bahasa pokok, mengoordinasikan panggilan alat, dan berpotensi berinteraksi dengan MemoryService. Anggap saja seperti konduktor yang memastikan semua bagian yang berbeda berfungsi dengan benar.

Kita dapat menggunakan Runner untuk menjalankan agen sebagai aplikasi Python mandiri, yang sepenuhnya terpisah dari UI Dev.

Mari buat skrip klien sederhana untuk memanggil agen perencana kita secara terprogram.

👉📝 Di file ~/instavibe-bootstrap/agents/planner/planner_client.py, tambahkan kode Python berikut di bawah impor yang ada. Di planner_client.py, di bagian impor, tambahkan kode berikut:

async def async_main():
  session_service = InMemorySessionService()

  session = await session_service.create_session(
      state={}, app_name='planner_app', user_id='user_dc'
  )

  query = "Plan Something for me in San Francisco this weekend on wine and fashion "
  print(f"User Query: '{query}'")
  content = types.Content(role='user', parts=[types.Part(text=query)])

  root_agent = agent.root_agent
  runner = Runner(
        app_name='planner_app',
        agent=root_agent,
        session_service=session_service,
  )
  print("Running agent...")
  events_async =  runner.run_async(
    session_id=session.id, user_id=session.user_id, new_message=content
  )

  async for event in events_async:
    print(f"Event received: {event}")


if __name__ == '__main__':
  try:
    asyncio.run(async_main())
  except Exception as e:
    print(f"An error occurred: {e}")

Kode ini menyiapkan layanan dalam memori untuk pengelolaan sesi dan artefak (agar tetap sederhana untuk contoh ini), membuat sesi, menentukan kueri pengguna, mengonfigurasi Runner dengan agen kita, lalu menjalankan agen secara asinkron, mencetak setiap peristiwa yang dihasilkan selama eksekusi.

👉💻 Sekarang, jalankan skrip klien ini dari terminal Anda:

. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
cd  ~/instavibe-bootstrap/agents
python -m planner.planner_client

👀 Amati outputnya. Selain rencana JSON akhir, Anda akan melihat struktur mendetail setiap objek Peristiwa yang dihasilkan selama alur eksekusi agen. Hal ini mencakup peristiwa pesan pengguna awal, potensi peristiwa terkait panggilan alat (seperti Google Penelusuran), dan terakhir, peristiwa respons model yang berisi rencana JSON. Aliran peristiwa mendetail ini sangat berguna untuk melakukan proses debug dan memahami pemrosesan langkah demi langkah yang terjadi dalam ADK Runtime.

Running agent...
Event received: content=Content(parts=[Part(video_metadata=None, thought=None, code_execution_result=None, executable_code=None, file_data=None, function_call=None, function_response=None, inline_data=None, text='```json\n{\n "fun_plans": [\n  {\n   "plan_description": "Embark on a stylish adventure through Hayes Valley, 
...(turncated)
, offering a variety of fashion styles to browse and enjoy."\n    }\n   ]\n  }\n ]\n}\n```')], role='model') grounding_metadata=GroundingMetadata(grounding_chunks=[GroundingChunk(retrieved_context=None, web=GroundingChunkWeb(domain='islands.com', title='islands.com', uri='http
...(turncated)
QyTpPV7jS6wUt-Ix7GuP2mC9J4eY_8Km6Vv44liF9cb2VSs='))], grounding_supports=[GroundingSupport(confide
...(turncated)
>\n', sdk_blob=None), web_search_queries=['..e']) partial=None turn_complete=None error_code=None error_message=None interrupted=None custom_metadata=None invocation_id='e-04d97b8b-9021-47a5-ab41-17b5cbb4bf03' author='location_search_agent' actions=EventActions(skip_summarization=None, state_delta={}, artifact_delta={}, transfer_to_agent=None, escalate=None, requested_auth_configs={}) long_running_tool_ids=None branch=None id='CInHdkKw' timestamp=1746978846.232674

Jika skrip berjalan terus-menerus atau berhenti merespons, Anda mungkin perlu menghentikannya secara manual dengan menekan Ctrl+C.

7. Agen Interaksi Platform - berinteraksi dengan Server MCP

Meskipun ADK membantu menyusun agen kami, agen tersebut sering kali perlu berinteraksi dengan sistem atau API eksternal untuk melakukan tindakan di dunia nyata.

Model Context Protocol (MCP)

Model Context Protocol (MCP) adalah standar terbuka yang dirancang untuk menstandardisasi cara aplikasi AI seperti agen, terhubung dengan sumber data, alat, dan sistem eksternal. Tujuannya adalah untuk memecahkan masalah kebutuhan integrasi kustom untuk setiap kombinasi aplikasi AI dan sumber data dengan menyediakan antarmuka universal. MCP menggunakan arsitektur klien-server tempat klien MCP, yang berada dalam aplikasi AI (host), mengelola koneksi ke server MCP. Server ini adalah program eksternal yang mengekspos fungsi tertentu seperti mengakses data lokal, berinteraksi dengan layanan jarak jauh melalui API, atau memberikan perintah yang telah ditentukan sebelumnya, sehingga memungkinkan model AI mengakses informasi terkini dan melakukan tugas di luar pelatihan awalnya. Struktur ini memungkinkan model AI menemukan dan berinteraksi dengan kemampuan eksternal secara standar, sehingga integrasi menjadi lebih sederhana dan lebih skalabel.

Membangun dan men-deploy server MCP InstaVibe

07-mcp-server.png

Pada akhirnya, agen kita perlu berinteraksi dengan platform InstaVibe itu sendiri.Khususnya, untuk membuat postingan dan mendaftarkan acara menggunakan API yang ada di platform. Aplikasi InstaVibe sudah mengekspos fungsi ini melalui endpoint HTTP standar:

Enpoint

URL

Metode HTTP

Deskripsi

Buat Postingan

api/posts

POST

Endpoint API untuk menambahkan postingan baru. Mengharapkan isi JSON:
{"author_name": "...", "text": "...", "sentiment": "..." (optional)}

Buat Peristiwa

api/events

POST

Endpoint API untuk menambahkan acara baru dan peserta acara (skema yang disederhanakan).
Mengharapkan isi JSON: { "event_name": "...", "description": "...", "event_date": "YYYY-MM-DDTHH:MM:SSZ", "locations": [ {"name": "...", "description": "...", "latitude": 0.0, "longitude": 0.0, "address": "..."} ], "attendee_names": ["...", "..."] }

Agar kemampuan ini tersedia bagi agen kami melalui MCP, pertama-tama kita perlu membuat fungsi Python sederhana yang bertindak sebagai wrapper di sekitar panggilan API ini. Fungsi ini akan menangani logika permintaan HTTP.

👉 Pertama, mari kita terapkan fungsi wrapper untuk membuat postingan. Buka file ~/instavibe-bootstrap/tools/instavibe/instavibe.py dan ganti komentar #REPLACE ME CREATE POST dengan kode Python berikut:

def create_post(author_name: str, text: str, sentiment: str, base_url: str = BASE_URL):
    """
    Sends a POST request to the /posts endpoint to create a new post.

    Args:
        author_name (str): The name of the post's author.
        text (str): The content of the post.
        sentiment (str): The sentiment associated with the post (e.g., 'positive', 'negative', 'neutral').
        base_url (str, optional): The base URL of the API. Defaults to BASE_URL.

    Returns:
        dict: The JSON response from the API if the request is successful.
              Returns None if an error occurs.

    Raises:
        requests.exceptions.RequestException: If there's an issue with the network request (e.g., connection error, timeout).
    """
    url = f"{base_url}/posts"
    headers = {"Content-Type": "application/json"}
    payload = {
        "author_name": author_name,
        "text": text,
        "sentiment": sentiment
    }

    try:
        response = requests.post(url, headers=headers, json=payload)
        response.raise_for_status()  # Raise an exception for bad status codes (4xx or 5xx)
        print(f"Successfully created post. Status Code: {response.status_code}")
        return response.json()
    except requests.exceptions.RequestException as e:
        print(f"Error creating post: {e}")
        # Optionally re-raise the exception if the caller needs to handle it
        # raise e
        return None
    except json.JSONDecodeError:
        print(f"Error decoding JSON response from {url}. Response text: {response.text}")
        return None

👉📝 Selanjutnya, kita akan membuat fungsi wrapper untuk API pembuatan peristiwa. Di file ~/instavibe-bootstrap/tools/instavibe/instavibe.py yang sama, ganti komentar #REPLACE ME CREATE EVENTS dengan kode ini:

def create_event(event_name: str, description: str, event_date: str, locations: list, attendee_names: list[str], base_url: str = BASE_URL):
    """
    Sends a POST request to the /events endpoint to create a new event registration.

    Args:
        event_name (str): The name of the event.
        description (str): The detailed description of the event.
        event_date (str): The date and time of the event (ISO 8601 format recommended, e.g., "2025-06-10T09:00:00Z").
        locations (list): A list of location dictionaries. Each dictionary should contain:
                          'name' (str), 'description' (str, optional),
                          'latitude' (float), 'longitude' (float),
                          'address' (str, optional).
        attendee_names (list[str]): A list of names of the people attending the event.
        base_url (str, optional): The base URL of the API. Defaults to BASE_URL.

    Returns:
        dict: The JSON response from the API if the request is successful.
              Returns None if an error occurs.

    Raises:
        requests.exceptions.RequestException: If there's an issue with the network request (e.g., connection error, timeout).
    """
    url = f"{base_url}/events"
    headers = {"Content-Type": "application/json"}
    payload = {
        "event_name": event_name,
        "description": description,
        "event_date": event_date,
        "locations": locations,
        "attendee_names": attendee_names,
    }

    try:
        response = requests.post(url, headers=headers, json=payload)
        response.raise_for_status()  # Raise an exception for bad status codes (4xx or 5xx)
        print(f"Successfully created event registration. Status Code: {response.status_code}")
        return response.json()
    except requests.exceptions.RequestException as e:
        print(f"Error creating event registration: {e}")
        # Optionally re-raise the exception if the caller needs to handle it
        # raise e
        return None
    except json.JSONDecodeError:
        print(f"Error decoding JSON response from {url}. Response text: {response.text}")
        return None

Seperti yang dapat Anda lihat, fungsi ini adalah wrapper langsung di sekitar InstaVibe API yang ada. Pola ini berguna. Jika sudah memiliki API untuk layanan, Anda dapat dengan mudah mengekspos fungsinya sebagai alat untuk agen dengan membuat wrapper tersebut.

Penerapan Server MCP

Setelah memiliki fungsi Python yang melakukan tindakan (memanggil InstaVibe API), kita perlu membangun komponen MCP Server. Server ini akan mengekspos fungsi ini sebagai "alat" sesuai dengan standar MCP, sehingga klien MCP (seperti agen kami) dapat menemukan dan memanggilnya.

Server MCP biasanya mengimplementasikan dua fungsi utama:

  • list_tools: bertanggung jawab untuk memungkinkan klien menemukan alat yang tersedia di server, menyediakan metadata seperti nama, deskripsi, dan parameter yang diperlukan, yang sering kali ditentukan menggunakan JSON Schema
  • call_tool: menangani eksekusi alat tertentu yang diminta oleh klien, menerima nama dan argumen alat, serta melakukan tindakan yang sesuai, seperti dalam kasus kita berinteraksi dengan API

Server MCP digunakan untuk memberi model AI akses ke data dan tindakan dunia nyata, sehingga memungkinkan tugas seperti mengirim email, membuat tugas dalam sistem pengelolaan proyek, menelusuri database, atau berinteraksi dengan berbagai software dan layanan web. Meskipun penerapan awal sering kali berfokus pada server lokal yang berkomunikasi melalui input/output (stdio) standar agar lebih sederhana, terutama di lingkungan pengembangan atau "studio", peralihan ke server jarak jauh yang menggunakan protokol seperti HTTP dengan Server-Sent Events (SSE) lebih masuk akal untuk adopsi yang lebih luas dan kasus penggunaan perusahaan.

Arsitektur jarak jauh, meskipun memiliki lapisan komunikasi jaringan tambahan, menawarkan keuntungan yang signifikan: memungkinkan beberapa klien AI berbagi akses ke satu server, memusatkan pengelolaan dan update alat, meningkatkan keamanan dengan menyimpan data sensitif dan kunci API di sisi server, bukan didistribusikan ke banyak mesin klien, dan memisahkan model AI dari spesifikasi integrasi sistem eksternal, sehingga seluruh ekosistem lebih skalabel, aman, dan mudah dikelola daripada mengharuskan setiap instance AI mengelola integrasi langsungnya sendiri.

07-mcp-server.png

Kita akan menerapkan server MCP menggunakan HTTP dan Server-Sent Events (SSE) untuk komunikasi, yang cocok untuk eksekusi alat yang berpotensi berjalan lama dan skenario perusahaan.

👉📝 Pertama, mari kita terapkan endpoint list_tools. Buka file ~/instavibe-bootstrap/tools/instavibe/mcp_server.py dan ganti komentar #REPLACE ME - LIST TOOLS dengan kode berikut. :

@app.list_tools()
async def list_tools() -> list[mcp_types.Tool]:
  """MCP handler to list available tools."""
  # Convert the ADK tool's definition to MCP format
  mcp_tool_schema_event = adk_to_mcp_tool_type(event_tool)
  mcp_tool_schema_post = adk_to_mcp_tool_type(post_tool)
  print(f"MCP Server: Received list_tools request. \n MCP Server: Advertising tool: {mcp_tool_schema_event.name} and {mcp_tool_schema_post}")
  return [mcp_tool_schema_event,mcp_tool_schema_post]

Fungsi ini menentukan alat (create_event, create_post) dan memberi tahu klien yang terhubung tentang alat tersebut.

👉📝 Selanjutnya, terapkan endpoint call_tool, yang menangani permintaan eksekusi sebenarnya dari klien. Di file ~/instavibe-bootstrap/tools/instavibe/mcp_server.py yang sama, ganti komentar #REPLACE ME - CALL TOOLS dengan kode ini.

@app.call_tool()
async def call_tool(
    name: str, arguments: dict
) -> list[mcp_types.TextContent | mcp_types.ImageContent | mcp_types.EmbeddedResource]:
  """MCP handler to execute a tool call."""
  print(f"MCP Server: Received call_tool request for '{name}' with args: {arguments}")

  # Look up the tool by name in our dictionary
  tool_to_call = available_tools.get(name)
  if tool_to_call:
    try:
      adk_response = await tool_to_call.run_async(
          args=arguments,
          tool_context=None, # No ADK context available here
      )
      print(f"MCP Server: ADK tool '{name}' executed successfully.")
      
      response_text = json.dumps(adk_response, indent=2)
      return [mcp_types.TextContent(type="text", text=response_text)]

    except Exception as e:
      print(f"MCP Server: Error executing ADK tool '{name}': {e}")
      # Creating a proper MCP error response might be more robust
      error_text = json.dumps({"error": f"Failed to execute tool '{name}': {str(e)}"})
      return [mcp_types.TextContent(type="text", text=error_text)]
  else:
      # Handle calls to unknown tools
      print(f"MCP Server: Tool '{name}' not found.")
      error_text = json.dumps({"error": f"Tool '{name}' not implemented."})
      return [mcp_types.TextContent(type="text", text=error_text)]

Fungsi ini menerima nama dan argumen alat, menemukan fungsi wrapper Python yang sesuai yang kita tentukan sebelumnya, mengeksekusinya, dan menampilkan hasilnya

👉💻 Setelah logika server MCP ditentukan, kita perlu memaketkannya sebagai container. Di terminal, jalankan skrip berikut untuk mem-build image Docker menggunakan Cloud Build:

. ~/instavibe-bootstrap/set_env.sh

cd ~/instavibe-bootstrap/tools/instavibe

export IMAGE_TAG="latest"
export MCP_IMAGE_NAME="mcp-tool-server"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${MCP_IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="mcp-tool-server"
export INSTAVIBE_BASE_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep instavibe)/api

gcloud builds submit . \
  --tag=${IMAGE_PATH} \
  --project=${PROJECT_ID}

👉💻 Deploy image sebagai layanan di Google Cloud Run.

. ~/instavibe-bootstrap/set_env.sh

cd ~/instavibe-bootstrap/tools/instavibe

export IMAGE_TAG="latest"
export MCP_IMAGE_NAME="mcp-tool-server"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${MCP_IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="mcp-tool-server"
export INSTAVIBE_BASE_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep instavibe)/api

gcloud run deploy ${SERVICE_NAME} \
  --image=${IMAGE_PATH} \
  --platform=managed \
  --region=${REGION} \
  --allow-unauthenticated \
  --set-env-vars="INSTAVIBE_BASE_URL=${INSTAVIBE_BASE_URL}" \
  --set-env-vars="APP_HOST=0.0.0.0" \
  --set-env-vars="APP_PORT=8080" \
  --set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=TRUE" \
  --set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}" \
  --set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
  --project=${PROJECT_ID} \
  --min-instances=1

👉💻 Setelah deployment berhasil diselesaikan, server MCP akan berjalan dan dapat diakses melalui URL publik. Kita perlu mengambil URL ini agar agen kita (yang bertindak sebagai klien MCP) mengetahui tempat untuk terhubung.

export MCP_SERVER_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep mcp-tool-server)/sse

Sekarang Anda juga dapat melihat layanan mcp-tool-server yang tercantum sebagai "Running" di bagian Cloud Run di Konsol Google Cloud Anda.

Cloud Run

Setelah server MCP di-deploy dan URL-nya diambil, kita kini dapat menerapkan agen yang akan bertindak sebagai klien MCP dan menggunakan alat yang diekspos oleh server ini.

8. Agen Interaksi Platform (menggunakan MCP)

Klien MCP Klien MCP adalah komponen yang berada dalam aplikasi atau agen AI, yang bertindak sebagai antarmuka antara model AI dan satu atau beberapa Server MCP; dalam penerapan kami, klien ini akan diintegrasikan langsung dalam agen kami. Fungsi utama klien ini adalah berkomunikasi dengan Server MCP untuk menemukan alat yang tersedia melalui fungsi list_tools dan selanjutnya meminta eksekusi alat tertentu menggunakan fungsi call_tool, dengan meneruskan argumen yang diperlukan yang disediakan oleh model AI atau agen yang mengatur panggilan.

Klien MCP

Sekarang kita akan membangun agen yang bertindak sebagai Klien MCP. Agen ini, yang berjalan dalam framework ADK, akan bertanggung jawab untuk berkomunikasi dengan mcp-tool-server yang baru saja kita deploy.

👉 Pertama, kita perlu mengubah definisi agen untuk mengambil alat secara dinamis dari server MCP yang sedang berjalan. Di agents/platform_mcp_client/agent.py, ganti #REPLACE ME - FETCH TOOLS dengan kode berikut:

"""Gets tools from the File System MCP Server."""
  tools =  MCPToolset(
      connection_params=SseServerParams(url=MCP_SERVER_URL, headers={})
  )

Kode ini menggunakan metode MCPToolset.from_server untuk terhubung ke MCP_SERVER_URL (yang kita tetapkan sebagai variabel lingkungan sebelumnya) dan mengambil daftar alat yang tersedia.

Selanjutnya, kita perlu memberi tahu definisi agen ADK untuk benar-benar menggunakan alat yang diambil secara dinamis ini.

👉 Di agents/platform_mcp_client/agent.py, ganti #REPLACE ME - SET TOOLs dengan kode berikut:

  tools=[tools],

👉💻 Sekarang, mari kita uji agen ini secara lokal menggunakan UI Dev ADK untuk melihat apakah agen dapat terhubung dengan benar ke server MCP dan menggunakan alat untuk berinteraksi dengan aplikasi InstaVibe yang sedang berjalan.

. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
export MCP_SERVER_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep mcp-tool-server)/sse

cd  ~/instavibe-bootstrap/agents
sed -i "s|^\(O\?GOOGLE_CLOUD_PROJECT\)=.*|GOOGLE_CLOUD_PROJECT=${PROJECT_ID}|" ~/instavibe-bootstrap/agents/platform_mcp_client/.env
sed -i "s|^\(O\?MCP_SERVER_URL\)=.*|MCP_SERVER_URL=${MCP_SERVER_URL}|" ~/instavibe-bootstrap/agents/platform_mcp_client/.env
adk web

Buka lagi UI Dev ADK di browser Anda (menggunakan Pratinjau Web Cloud Shell di port 8000). Kali ini, di dropdown kanan atas, pilih agen platform_mcp_client.

Mari kita uji alat create_post. Dalam dialog chat, masukkan permintaan berikut:

Create a post saying "Y'all I just got the cutest lil void baby 😭✨ Naming him Abyss bc he's deep, mysterious, and lowkey chaotic 🔥🖤 #VoidCat #NewRoomie" I'm Julia

Postingan UI Dev ADK

Agen akan memprosesnya, mengidentifikasi kebutuhan untuk menggunakan alat create_post, berkomunikasi dengan server MCP, yang pada gilirannya memanggil InstaVibe API.

👉 Langkah Verifikasi: Setelah agen mengonfirmasi tindakan, buka tab tempat aplikasi InstaVibe Anda berjalan (atau muat ulang). Anda akan melihat postingan baru dari "Julia" muncul di feed utama.

Postingan InstaVibe

👉💻 Jalankan skrip ini di terminal terpisah untuk mendapatkan link Instavibe jika diperlukan:

gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep instavibe

👉📝 Sekarang, mari kita uji alat create_event. Masukkan permintaan multi-baris berikut ke dalam dialog chat:

Hey, can you set up an event for Hannah and George and me, and I'm Julia? Let's call it 'Mexico City Culinary & Art Day'.
here are more info
  {"event_name": "Mexico City Culinary & Art Day",
  "description": "A vibrant day in Mexico City for Hannah and George, starting with lunch at one of the city's best taco spots in the hip Condesa neighborhood, followed by an inspiring afternoon exploring the Museo Soumaya's stunning art collection.",
  "event_date": "2025-10-17T12:00:00-06:00",
  "locations": [
    {
      "name": "El Tizoncito",
      "description": "Considered one of the original creators of tacos al pastor, El Tizoncito offers a legendary taco experience in the heart of Condesa. Their flavorful meats, house salsas, and casual vibe make it a must-visit for foodies.",
      "latitude": 19.412179,
      "longitude": -99.171308,
      "address": "Av. Tamaulipas 122, Hipódromo, Cuauhtémoc, 06100 Ciudad de México, CDMX, Mexico"
    },
    {
      "name": "Museo Soumaya",
      "description": "An architectural icon in Mexico City, Museo Soumaya houses over 66,000 works of art, including pieces by Rodin, Dalí, and Rivera. The striking silver structure is a cultural landmark and a visual feast inside and out.",
      "latitude": 19.440056,
      "longitude": -99.204281,
      "address": "Plaza Carso, Blvd. Miguel de Cervantes Saavedra 303, Granada, Miguel Hidalgo, 11529 Ciudad de México, CDMX, Mexico"
    }
  ],
  "attendee_names": ["Hannah", "George", Julia],
}

Sekali lagi, agen harus menggunakan alat yang sesuai melalui server MCP. Di tab Peristiwa, klik setiap peristiwa, Anda akan melihat rekaman langkah demi langkah yang mendetail tentang eksekusi.

Peristiwa UI Dev ADK

👉 Langkah Verifikasi: Kembali ke aplikasi InstaVibe yang sedang berjalan dan buka bagian "Events" (atau yang setara). Sekarang Anda akan melihat acara "Mexico City Culinary & Art Day" yang baru dibuat tercantum.

Acara InstaVibe

Hal ini berhasil menunjukkan cara MCP memungkinkan agen kami memanfaatkan alat eksternal (dalam hal ini, API InstaVibe) dengan cara yang standar.

Setelah Anda memverifikasi kedua tindakan, kembali ke terminal Cloud Shell dan tekan Ctrl+C untuk menghentikan UI Dev ADK.

9. Agen Alur Kerja dan Multi-Agen di ADK

Agen kami sejauh ini dapat merencanakan perjalanan dan berinteraksi dengan platform. Namun, perencanaan yang benar-benar dipersonalisasi memerlukan pemahaman tentang lingkaran sosial pengguna. Bagi pengguna yang sibuk dan mungkin tidak mengikuti aktivitas teman mereka secara cermat, mengumpulkan konteks ini secara manual akan sulit. Untuk mengatasi hal ini, kami akan membuat agen Pemrofilan Sosial yang memanfaatkan Spanner Graph Database kami untuk menganalisis aktivitas dan minat teman, sehingga memungkinkan saran yang lebih disesuaikan.

Agen Pemrofilan Sosial

Pertama, kita memerlukan alat agar agen ini dapat mengakses data grafik.

👉📝 Tambahkan fungsi Python berikut ke akhir file ~/instavibe-bootstrap/agents/social/instavibe.py:

def get_person_attended_events(person_id: str)-> list[dict]:
    """
    Fetches events attended by a specific person using Graph Query.
    Args:
       person_id (str): The ID of the person whose posts to fetch.
    Returns: list[dict] or None.
    """
    if not db_instance: return None

    graph_sql = """
        Graph SocialGraph
        MATCH (p:Person)-[att:Attended]->(e:Event)
        WHERE p.person_id = @person_id
        RETURN e.event_id, e.name, e.event_date, att.attendance_time
        ORDER BY e.event_date DESC
    """
    params = {"person_id": person_id}
    param_types_map = {"person_id": param_types.STRING}
    fields = ["event_id", "name", "event_date", "attendance_time"]

    results = run_graph_query( graph_sql, params=params, param_types=param_types_map, expected_fields=fields)

    if results is None: return None

    for event in results:
        if isinstance(event.get('event_date'), datetime):
            event['event_date'] = event['event_date'].isoformat()
        if isinstance(event.get('attendance_time'), datetime):
            event['attendance_time'] = event['attendance_time'].isoformat()
    return results

def get_person_id_by_name( name: str) -> str:
    """
    Fetches the person_id for a given name using SQL.

    Args:
       name (str): The name of the person to search for.

    Returns:
        str or None: The person_id if found, otherwise None.
                     Returns the ID of the *first* match if names are duplicated.
    """
    if not db_instance: return None

    sql = """
        SELECT person_id
        FROM Person
        WHERE name = @name
        LIMIT 1 -- Return only the first match in case of duplicate names
    """
    params = {"name": name}
    param_types_map = {"name": param_types.STRING}
    fields = ["person_id"]

    # Use the standard SQL query helper
    results = run_sql_query( sql, params=params, param_types=param_types_map, expected_fields=fields)

    if results: # Check if the list is not empty
        return results[0].get('person_id') # Return the ID from the first dictionary
    else:
        return None # Name not found


def get_person_posts( person_id: str)-> list[dict]:
    """
    Fetches posts written by a specific person using Graph Query.

    Args:
        person_id (str): The ID of the person whose posts to fetch.


    Returns:
        list[dict] or None: List of post dictionaries with ISO date strings,
                           or None if an error occurs.
    """
    if not db_instance: return None

    # Graph Query: Find the specific Person node, follow 'Wrote' edge to Post nodes
    graph_sql = """
        Graph SocialGraph
        MATCH (author:Person)-[w:Wrote]->(post:Post)
        WHERE author.person_id = @person_id
        RETURN post.post_id, post.author_id, post.text, post.sentiment, post.post_timestamp, author.name AS author_name
        ORDER BY post.post_timestamp DESC
    """
    # Parameters now include person_id and limit
    params = {
        "person_id": person_id
    }
    param_types_map = {
        "person_id": param_types.STRING
    }
    # Fields returned remain the same
    fields = ["post_id", "author_id", "text", "sentiment", "post_timestamp", "author_name"]

    results = run_graph_query(graph_sql, params=params, param_types=param_types_map, expected_fields=fields)

    if results is None:
        return None

    # Convert datetime objects to ISO format strings
    for post in results:
        if isinstance(post.get('post_timestamp'), datetime):
            post['post_timestamp'] = post['post_timestamp'].isoformat()

    return results


def get_person_friends( person_id: str)-> list[dict]:
    """
    Fetches friends for a specific person using Graph Query.
    Args:
        person_id (str): The ID of the person whose posts to fetch.
    Returns: list[dict] or None.
    """
    if not db_instance: return None

    graph_sql = """
        Graph SocialGraph
        MATCH (p:Person {person_id: @person_id})-[f:Friendship]-(friend:Person)
        RETURN DISTINCT friend.person_id, friend.name
        ORDER BY friend.name
    """
    params = {"person_id": person_id}
    param_types_map = {"person_id": param_types.STRING}
    fields = ["person_id", "name"]

    results = run_graph_query( graph_sql, params=params, param_types=param_types_map, expected_fields=fields)

    return results

Sekarang, mari kita bahas cara menyusun agen kita. Menganalisis beberapa profil teman, lalu meringkas temuan tersebut melibatkan beberapa langkah. Ini adalah skenario yang tepat untuk menggunakan kemampuan multi-agen ADK, khususnya Agen Alur Kerja.

Di ADK Google, Agen Alur Kerja tidak melakukan tugasnya sendiri, tetapi mengatur agen lain, yang disebut sub-agen. Hal ini memungkinkan desain modular, yang menguraikan masalah kompleks menjadi komponen khusus. ADK menyediakan jenis alur kerja bawaan seperti

  • Berurutan (langkah demi langkah)
  • Paralel (eksekusi serentak)
  • dan Loop (eksekusi berulang)

Agen Pemrofilan Sosial

Untuk tugas pembuatan profil sosial, desain kita menggunakan Loop Agent untuk membuat alur kerja iteratif. Tujuannya adalah memproses satu orang dalam satu waktu: profile_agent mengumpulkan data, summary_agent memperbarui analisis, dan check_agent menentukan apakah kita harus mengulang proses.

Mari kita tentukan sub-agen yang diperlukan untuk alur kerja ini.

👉📝 Di ~/instavibe-bootstrap/agents/social/agent.py, ganti #REPLACE FOR profile_agent dengan kode berikut:

profile_agent = LlmAgent(
    name="profile_agent",
    model="gemini-2.5-flash",
    description=(
        "Agent to answer questions about the this person social profile. Provide the person's profile using their name, make sure to fetch the id before getting other data."
    ),
    instruction=(
        "You are a helpful agent to answer questions about the this person social profile. You'll be given a list of names, provide the person's profile using their name, make sure to fetch the id before getting other data. Get one person at a time, start with the first one on the list, and skip if already provided. return this person's result"
    ),
    tools=[get_person_posts,get_person_friends,get_person_id_by_name,get_person_attended_events],
)

Selanjutnya, agen yang mengambil informasi profil yang dikumpulkan (dikumpulkan di seluruh iterasi loop) dan membuat ringkasan akhir, mengidentifikasi kesamaan jika beberapa orang dianalisis.

👉📝 Di ~/instavibe-bootstrap/agents/social/agent.py yang sama, ganti #REPLACE FOR summary_agent dengan kode berikut:

summary_agent = LlmAgent(
    name="summary_agent",
    model="gemini-2.5-flash",
    description=(
        "Generate a comprehensive social summary as a single, cohesive paragraph. This summary should cover the activities, posts, friend networks, and event participation of one or more individuals. If multiple profiles are analyzed, the paragraph must also identify and integrate any common ground found between them."
    ),
    instruction=(
        """
        Your primary task is to synthesize social profile information into a single, comprehensive paragraph.

            **Input Scope & Default Behavior:**
            *   If specific individuals are named by the user, focus your analysis on them.
            *   **If no individuals are specified, or if the request is general, assume the user wants an analysis of *all relevant profiles available in the current dataset/context*.**

            **For each profile (whether specified or determined by default), you must analyze:**

            1.  **Post Analysis:**
                *   Systematically review their posts (e.g., content, topics, frequency, engagement).
                *   Identify recurring themes, primary interests, and expressed sentiments.

            2.  **Friendship Relationship Analysis:**
                *   Examine their connections/friends list.
                *   Identify key relationships, mutual friends (especially if comparing multiple profiles), and the general structure of their social network.

            3.  **Event Participation Analysis:**
                *   Investigate their past (and if available, upcoming) event participation.
                *   Note the types of events, frequency of attendance, and any notable roles (e.g., organizer, speaker).

            **Output Generation (Single Paragraph):**

            *   **Your entire output must be a single, cohesive summary paragraph.**
                *   **If analyzing a single profile:** This paragraph will detail their activities, interests, and social connections based on the post, friend, and event analysis.
                *   **If analyzing multiple profiles:** This paragraph will synthesize the key findings regarding posts, friends, and events for each individual. Crucially, it must then seamlessly integrate or conclude with an identification and description of the common ground found between them (e.g., shared interests from posts, overlapping event attendance, mutual friends). The aim is a unified narrative within this single paragraph.

            **Key Considerations:**
            *   Base your summary strictly on the available data.
            *   If data for a specific category (posts, friends, events) is missing or sparse for a profile, you may briefly acknowledge this within the narrative if relevant.
                """
        ),
    output_key="summary"
)

Kita memerlukan cara untuk menentukan kapan loop harus berhenti (yaitu, saat semua profil yang diminta telah diringkas)

👉📝 Di ~/instavibe-bootstrap/agents/social/agent.py yang sama, ganti #REPLACE FOR check_agent dengan kode berikut:

check_agent = LlmAgent(
    name="check_agent",
    model="gemini-2.5-flash",
    description=(
        "Check if everyone's social profile are summarized and has been generated. Output 'completed' or 'pending'."
    ),
    output_key="summary_status"
)

Kita menambahkan pemeriksaan terprogram sederhana (CheckCondition) yang secara eksplisit melihat summary_status yang disimpan di State, yang ditampilkan oleh check_agent dan memberi tahu Loop Agent apakah akan melanjutkan (escalate=False) atau berhenti (escalate=True).

👉📝 Di ~/instavibe-bootstrap/agents/social/agent.py yang sama, ganti #REPLACE FOR CheckCondition yang ada di bagian atas file dengan kode berikut:

class CheckCondition(BaseAgent):
    async def _run_async_impl(self, ctx: InvocationContext) -> AsyncGenerator[Event, None]:
        #log.info(f"Checking status: {ctx.session.state.get("summary_status", "fail")}")
        log.info(f"Summary: {ctx.session.state.get("summary")}")

        status = ctx.session.state.get("summary_status", "fail").strip()
        is_done = (status == "completed")

        yield Event(author=self.name, actions=EventActions(escalate=is_done))

Status dan Callback untuk Hasil Loop

Di ADK Google, State adalah konsep penting yang merepresentasikan memori atau data kerja agen selama eksekusinya. Pada dasarnya, ini adalah konteks persisten yang menyimpan informasi yang perlu dipertahankan oleh agen di berbagai langkah, panggilan alat, atau interaksi. Status ini dapat menyimpan hasil sementara, informasi pengguna, parameter untuk tindakan berikutnya, atau data lain yang perlu diingat oleh agen saat memproses tugas.

Dalam skenario kita, saat Loop Agent melakukan iterasi, summary_agent dan check_agent menyimpan outputnya (summary dan summary_status) di State agent. Hal ini memungkinkan informasi tetap ada di seluruh iterasi. Namun, Loop Agent itu sendiri tidak otomatis menampilkan ringkasan akhir dari status saat selesai.

Agen Pemrofilan Sosial

Callback di ADK memungkinkan kami menyuntikkan logika kustom untuk dieksekusi pada titik tertentu selama siklus proses agen atau sebagai respons terhadap peristiwa tertentu, seperti penyelesaian panggilan alat atau sebelum agen menyelesaikan eksekusinya. Alat ini menyediakan cara untuk menyesuaikan perilaku agen dan memproses hasil secara dinamis.

Kita akan menggunakan after_agent_callback yang berjalan saat loop selesai (karena CheckCondition ditingkatkan). Callback modify_output_after_agent ini mengambil ringkasan akhir dari status dan memformatnya sebagai pesan output akhir agen.

Telepon balik

👉📝 Di ~/instavibe-bootstrap/agents/social/agent.py yang sama, ganti #REPLACE FOR modify_output_after_agent dengan kode berikut:

def modify_output_after_agent(callback_context: CallbackContext) -> Optional[types.Content]:

    agent_name = callback_context.agent_name
    invocation_id = callback_context.invocation_id
    current_state = callback_context.state.to_dict()
    current_user_content = callback_context.user_content
    print(f"[Callback] Exiting agent: {agent_name} (Inv: {invocation_id})")
    print(f"[Callback] Current summary_status: {current_state.get("summary_status")}")
    print(f"[Callback] Current Content: {current_user_content}")

    status = current_state.get("summary_status").strip()
    is_done = (status == "completed")
    # Retrieve the final summary from the state

    final_summary = current_state.get("summary")
    print(f"[Callback] final_summary: {final_summary}")
    if final_summary and is_done and isinstance(final_summary, str):
        log.info(f"[Callback] Found final summary, constructing output Content.")
        # Construct the final output Content object to be sent back
        return types.Content(role="model", parts=[types.Part(text=final_summary.strip())])
    else:
        log.warning("[Callback] No final summary found in state or it's not a string.")
        # Optionally return a default message or None if no summary was generated
        return None

Menentukan Agen Root Loop

Terakhir, kita akan menentukan LoopAgent utama. Agen ini mengatur sub-agen secara berurutan dalam setiap iterasi loop (profile_agent -> summary_agent -> check_agent -> CheckCondition). Proses ini akan mengulangi urutan ini hingga max_iterations kali atau hingga CheckCondition menandakan penyelesaian. after_agent_callback memastikan ringkasan akhir ditampilkan.

👉📝 Di ~/instavibe-bootstrap/agents/social/agent.py yang sama, ganti #REPLACE FOR root_agent dengan kode berikut:

root_agent = LoopAgent(
    name="InteractivePipeline",
    sub_agents=[
        profile_agent,
        summary_agent,
        check_agent,
        CheckCondition(name="Checker")
    ],
    description="Find everyone's social profile on events, post and friends",
    max_iterations=10,
    after_agent_callback=modify_output_after_agent
)

Mari kita uji alur kerja multi-agen ini menggunakan UI Dev ADK.

👉💻 Luncurkan server web ADK:

. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
cd  ~/instavibe-bootstrap/agents
sed -i "s|^\(O\?GOOGLE_CLOUD_PROJECT\)=.*|GOOGLE_CLOUD_PROJECT=${PROJECT_ID}|" ~/instavibe-bootstrap/agents/social/.env
adk web

Buka UI Dev ADK (port 8000 melalui Pratinjau Web). Di menu dropdown agen (kanan atas), pilih Agen Sosial.

👉 Sekarang, berikan tugas untuk membuat profil beberapa orang. Di dialog chat, masukkan:

Tell me about Mike and Bob

Setelah agen merespons (yang mungkin memerlukan waktu lebih lama karena perulangan dan beberapa panggilan LLM), jangan hanya melihat output chat akhir. Buka tab Events di panel sebelah kiri UI Dev ADK.

👉 Langkah Verifikasi: Di tab Events, Anda akan melihat rekaman aktivitas eksekusi langkah demi langkah yang mendetail. 09-01-adk-dev-ui.png

Setelah mengamati cara agen memanggil setiap sub-agen, tempat Anda mengharapkan alur berjalan dari profile_agent -> summary_agent -> check_agent, Checker dalam setiap iterasi. Namun, dalam praktiknya, kita melihat ‘pengoptimalan mandiri' agen yang canggih sedang beraksi.

Karena model yang mendasarinya melihat seluruh permintaan (misalnya, 'profil Mike dan Bob'), model ini sering kali memilih jalur yang paling efisien, mengumpulkan semua data yang diperlukan dalam satu giliran yang digabungkan, bukan melakukan iterasi beberapa kali. Anda dapat melihat input, output, dan status untuk setiap langkah, termasuk panggilan alat yang dilakukan oleh profile_agent

09-02-ui-graph.png

dan pembaruan status dari check_agent dan CheckCondition. 09-03-ui-state.png

Rekaman aktivitas visual ini sangat berharga untuk memahami dan men-debug cara kerja alur kerja multi-agen hingga ringkasan akhir dibuat dan ditampilkan oleh callback.

Setelah Anda menjelajahi respons chat dan rekaman aktivitas peristiwa, kembali ke terminal Cloud Shell dan tekan Ctrl+C untuk menghentikan UI Dev ADK.

10. Komunikasi Antar-Agen (A2A)

Sejauh ini, kita telah membuat agen khusus, tetapi agen tersebut beroperasi secara terpisah atau dalam alur kerja yang telah ditentukan sebelumnya di mesin yang sama. Untuk membangun sistem multi-agen yang benar-benar terdistribusi dan kolaboratif, kita memerlukan cara agar agen, yang berpotensi berjalan sebagai layanan terpisah, dapat saling menemukan dan berkomunikasi secara efektif. Di sinilah protokol Agent-to-Agent (A2A) berperan.

Protokol A2A adalah standar terbuka yang dirancang khusus untuk komunikasi yang dapat dioperasikan antara agen AI. Meskipun MCP berfokus pada interaksi agen-ke-alat, A2A berfokus pada interaksi agen-ke-agen. Hal ini memungkinkan agen untuk:

  • Temukan: Temukan agen lain dan pelajari kemampuannya melalui Kartu Agen standar.
  • Berkomunikasi: Bertukar pesan dan data dengan aman.
  • Berkolaborasi: Mendelegasikan tugas dan mengoordinasikan tindakan untuk mencapai sasaran yang kompleks.

Protokol A2A memfasilitasi komunikasi ini melalui mekanisme seperti "Kartu Agen", yang dapat digunakan agen untuk mengiklankan kemampuan dan informasi koneksi mereka.

10-05-agent-card

A2A menggunakan standar web yang sudah dikenal (HTTP, SSE, JSON-RPC) dan sering kali menggunakan model client-server di mana satu agen (klien) mengirimkan tugas ke agen lain (agen/server jarak jauh). Standardisasi ini adalah kunci untuk membangun sistem modular dan skalabel tempat agen yang dikembangkan secara independen dapat bekerja sama.

Mengaktifkan A2A untuk Agen InstaVibe

Agar agen Planner, Interaksi Platform, dan Sosial yang ada dapat diakses oleh agen lain melalui A2A, kita perlu membungkus setiap agen dengan komponen Server A2A. Server ini akan:

  • Mengekspos Kartu Agen: Menayangkan deskripsi standar kemampuan agen melalui endpoint HTTP.
  • Mendengarkan Tugas(Pesan Permintaan): Menerima permintaan tugas masuk dari agen lain (klien A2A) sesuai dengan protokol A2A.
  • Mengelola Eksekusi Tugas(Pesan Permintaan): Menyerahkan tugas yang diterima ke logika agen ADK yang mendasarinya untuk diproses.

Planner Agent (A2A Enabled)

all-agent-planner

Mari kita mulai dengan menambahkan lapisan server A2A ke Agen Perencana kita.

Tentukan logika startup server A2A. Kode ini menentukan AgentCard (deskripsi publik agen), mengonfigurasi A2AServer, dan memulainya, dengan menautkannya ke PlatformAgentExecutor.

👉📝 Tambahkan kode berikut ke akhir ~/instavibe-bootstrap/agents/planner/a2a_server.py:

class PlannerAgent:
    """An agent to help user planning a event with its desire location."""
    SUPPORTED_CONTENT_TYPES = ["text", "text/plain"]

    def __init__(self):
        self._agent = self._build_agent()
        self.runner = Runner(
            app_name=self._agent.name,
            agent=self._agent,
            artifact_service=InMemoryArtifactService(),
            session_service=InMemorySessionService(),
            memory_service=InMemoryMemoryService(),
        )
        capabilities = AgentCapabilities(streaming=True)
        skill = AgentSkill(
            id="event_planner",
            name="Event planner",
            description="""
            This agent generates multiple fun plan suggestions tailored to your specified location, dates, and interests,
            all designed for a moderate budget. It delivers detailed itineraries,
            including precise venue information (name, latitude, longitude, and description), in a structured JSON format.
            """,
            tags=["instavibe"],
            examples=["What about Bostona MA this weekend?"],
        )
        self.agent_card = AgentCard(
            name="Event Planner Agent",
            description="""
            This agent generates multiple fun plan suggestions tailored to your specified location, dates, and interests,
            all designed for a moderate budget. It delivers detailed itineraries,
            including precise venue information (name, latitude, longitude, and description), in a structured JSON format.
            """,
            url=f"{PUBLIC_URL}",
            version="1.0.0",
            defaultInputModes=PlannerAgent.SUPPORTED_CONTENT_TYPES,
            defaultOutputModes=PlannerAgent.SUPPORTED_CONTENT_TYPES,
            capabilities=capabilities,
            skills=[skill],
        )

    def get_processing_message(self) -> str:
        return "Processing the planning request..."

    def _build_agent(self) -> LlmAgent:
        """Builds the LLM agent for the night out planning agent."""
        return agent.root_agent


if __name__ == '__main__':
    try:
        plannerAgent = PlannerAgent()

        request_handler = DefaultRequestHandler(
            agent_executor=PlannerAgentExecutor(plannerAgent.runner,plannerAgent.agent_card),
            task_store=InMemoryTaskStore(),
        )

        server = A2AStarletteApplication(
            agent_card=plannerAgent.agent_card,
            http_handler=request_handler,
        )
        logger.info(f"Attempting to start server with Agent Card: {plannerAgent.agent_card.name}")
        logger.info(f"Server object created: {server}")

        uvicorn.run(server.build(), host='0.0.0.0', port=port)
    except Exception as e:
        logger.error(f"An error occurred during server startup: {e}")
        exit(1)

👉💻 Mari kita uji dengan cepat apakah server A2A dimulai dengan benar secara lokal dan menayangkan Kartu Agennya. Jalankan perintah berikut di terminal pertama Anda:

. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
cd ~/instavibe-bootstrap/agents/
python -m planner.a2a_server

👉 Sekarang, buka jendela terminal lain. (Klik tanda + di panel terminal) dua terminal

👉💻 Gunakan curl untuk meminta Kartu Agen dari server yang berjalan secara lokal:

curl http://localhost:10003/.well-known/agent.json | jq

Anda akan melihat representasi JSON AgentCard yang kita tentukan, yang mengonfirmasi bahwa server berjalan dan mengiklankan agen Planner.

10-02-planner-a2a.png

Kembali ke terminal pertama (tempat server berjalan) dan tekan Ctrl+C untuk menghentikannya.

👉💻 Setelah logika server A2A ditambahkan, kita dapat membangun image container.

Membangun dan Men-deploy Agen Perencana

. ~/instavibe-bootstrap/set_env.sh

cd ~/instavibe-bootstrap/agents

# Set variables specific to the PLANNER agent
export IMAGE_TAG="latest"
export AGENT_NAME="planner"
export IMAGE_NAME="planner-agent"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="planner-agent"
export PUBLIC_URL="https://planner-agent-${PROJECT_NUMBER}.${REGION}.run.app"

echo "Building ${AGENT_NAME} agent..."
gcloud builds submit . \
  --config=cloudbuild-build.yaml \
  --project=${PROJECT_ID} \
  --region=${REGION} \
  --substitutions=_AGENT_NAME=${AGENT_NAME},_IMAGE_PATH=${IMAGE_PATH}

echo "Image built and pushed to: ${IMAGE_PATH}"

👉💻 Deploy Planner Agent kita di Cloud Run.

. ~/instavibe-bootstrap/set_env.sh

cd ~/instavibe-bootstrap/agents

# Set variables specific to the PLANNER agent
export IMAGE_TAG="latest"
export AGENT_NAME="planner"
export IMAGE_NAME="planner-agent"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="planner-agent"
export PUBLIC_URL="https://planner-agent-${PROJECT_NUMBER}.${REGION}.run.app"


gcloud run deploy ${SERVICE_NAME} \
  --image=${IMAGE_PATH} \
  --platform=managed \
  --region=${REGION} \
  --set-env-vars="A2A_HOST=0.0.0.0" \
  --set-env-vars="A2A_PORT=8080" \
  --set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=TRUE" \
  --set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}" \
  --set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
  --set-env-vars="PUBLIC_URL=${PUBLIC_URL}" \
  --allow-unauthenticated \
  --project=${PROJECT_ID} \
  --min-instances=1

Mari kita verifikasi bahwa layanan yang di-deploy berjalan dan menayangkan Kartu Agennya dengan benar dari cloud menggunakan A2A Inspector.

👉 Dari ikon Pratinjau web di toolbar Cloud Shell, pilih Ubah port. Tetapkan port ke 8081, lalu klik "Change and Preview". Tab browser baru akan terbuka dengan antarmuka A2A Inspector.

10-08-web-preview.png

👉💻 Di terminal, dapatkan URL agen perencana yang di-deploy:

export PLANNER_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep planner-agent)
echo ${PLANNER_AGENT_URL}

👉💻 Salin URL output.

👉 Di UI A2A Inspector, tempelkan URL ke kolom Agent URL, lalu klik Connect.

👀 Detail kartu dan JSON agen akan muncul di tab Kartu Agen, yang mengonfirmasi bahwa koneksi berhasil.

10-03-planner-a2a.png

👉 Klik tab Chat di A2A Inspector. Di sini Anda dapat berinteraksi langsung dengan agen yang di-deploy. Kirim pesan untuk menguji kemampuan perencanaannya. Contoh:

Plan something for me in Boston MA this weekend, and I enjoy classical music

👀 Untuk memeriksa komunikasi mentah, klik balon pesan Anda, lalu klik balon respons agen di jendela chat. Saat Anda mengklik setiap pesan, pesan JSON-RPC 2.0 lengkap yang dikirim atau diterima akan ditampilkan, yang sangat berharga untuk proses debug.

Biarkan tab A2A Inspector tetap terbuka. JANGAN ditutup! Kita akan menggunakannya lagi sebentar lagi untuk menguji dua agen lainnya.

10-06-a2a-inspector.png

Agen Interaksi Platform (Diaktifkan untuk A2A)

all-agent-platform

Selanjutnya, kita akan mengulangi proses untuk Platform Interaction Agent (yang menggunakan MCP).

👉📝 Tentukan penyiapan server A2A, termasuk AgentCard uniknya, di akhir ~/instavibe-bootstrap/agents/platform_mcp_client/a2a_server.py:

class PlatformAgent:
  """An agent that post event and post to instavibe."""

  SUPPORTED_CONTENT_TYPES = ["text", "text/plain"]

  def __init__(self):
    self._agent = self._build_agent()
    self.runner = Runner(
        app_name=self._agent.name,
        agent=self._agent,
        artifact_service=InMemoryArtifactService(),
        session_service=InMemorySessionService(),
        memory_service=InMemoryMemoryService(),
    )
    capabilities = AgentCapabilities(streaming=True)
    skill = AgentSkill(
            id="instavibe_posting",
            name="Post social post and events on instavibe",
            description="""
            This "Instavibe" agent helps you create posts (identifying author, text, and sentiment – inferred if unspecified) and register
            for events (gathering name, date, attendee). It efficiently collects required information and utilizes dedicated tools
            to perform these actions on your behalf, ensuring a smooth sharing experience.
            """,
            tags=["instavibe"],
            examples=["Create a post for me, the post is about my cute cat and make it positive, and I'm Alice"],
        )
    self.agent_card = AgentCard(
            name="Instavibe Posting Agent",
            description="""
            This "Instavibe" agent helps you create posts (identifying author, text, and sentiment – inferred if unspecified) and register
            for events (gathering name, date, attendee). It efficiently collects required information and utilizes dedicated tools
            to perform these actions on your behalf, ensuring a smooth sharing experience.
            """,
            url=f"{PUBLIC_URL}",
            version="1.0.0",
            defaultInputModes=PlatformAgent.SUPPORTED_CONTENT_TYPES,
            defaultOutputModes=PlatformAgent.SUPPORTED_CONTENT_TYPES,
            capabilities=capabilities,
            skills=[skill],
        )


  def get_processing_message(self) -> str:
      return "Processing the social post and event request..."

  def _build_agent(self) -> LlmAgent:
    """Builds the LLM agent for the Processing the social post and event request."""
    return agent.root_agent


if __name__ == '__main__':
    try:
        platformAgent = PlatformAgent()

        request_handler = DefaultRequestHandler(
            agent_executor=PlatformAgentExecutor(platformAgent.runner,platformAgent.agent_card),
            task_store=InMemoryTaskStore(),
        )

        server = A2AStarletteApplication(
            agent_card=platformAgent.agent_card,
            http_handler=request_handler,
        )

        uvicorn.run(server.build(), host='0.0.0.0', port=port)
    except Exception as e:
        logger.error(f"An error occurred during server startup: {e}")
        exit(1)

Agen Sosial (A2A Diaktifkan)

all-agent-social

Terakhir, aktifkan A2A untuk Agen Pemrofilan Sosial kita.

👉📝 Tentukan penyiapan server A2A dan AgentCard di akhir ~/instavibe-bootstrap/agents/social/a2a_server.py:

class SocialAgent:
  """An agent that handles social profile analysis."""

  SUPPORTED_CONTENT_TYPES = ["text", "text/plain"]

  def __init__(self):
    self._agent = self._build_agent()
    self.runner = Runner(
        app_name=self._agent.name,
        agent=self._agent,
        artifact_service=InMemoryArtifactService(),
        session_service=InMemorySessionService(),
        memory_service=InMemoryMemoryService(),
    )
    capabilities = AgentCapabilities(streaming=True)
    skill = AgentSkill(
                id="social_profile_analysis",
                name="Analyze Instavibe social profile",
                description="""
                Using a provided list of names, this agent synthesizes Instavibe social profile information by analyzing posts, friends, and events.
                It delivers a comprehensive single-paragraph summary for individuals, and for groups, identifies commonalities in their social activities
                and connections based on profile data.
                """,
                tags=["instavibe"],
                examples=["Can you tell me about Bob and Alice?"],
    )
    self.agent_card = AgentCard(
                name="Social Profile Agent",
                description="""
                Using a provided list of names, this agent synthesizes Instavibe social profile information by analyzing posts, friends, and events.
                It delivers a comprehensive single-paragraph summary for individuals, and for groups, identifies commonalities in their social activities
                and connections based on profile data.
                """,
                url=f"{PUBLIC_URL}",
                version="1.0.0",
                defaultInputModes=self.SUPPORTED_CONTENT_TYPES,
                defaultOutputModes=self.SUPPORTED_CONTENT_TYPES,
                capabilities=capabilities,
                skills=[skill],
    )

  def get_processing_message(self) -> str:
      return "Processing the social profile analysis request..."

  def _build_agent(self) -> LoopAgent:
    """Builds the LLM agent for the social profile analysis agent."""
    return agent.root_agent

if __name__ == '__main__':
    try:
        socialAgent = SocialAgent()

        request_handler = DefaultRequestHandler(
            agent_executor=SocialAgentExecutor(socialAgent.runner,socialAgent.agent_card),
            task_store=InMemoryTaskStore(),
        )

        server = A2AStarletteApplication(
            agent_card=socialAgent.agent_card,
            http_handler=request_handler,
        )

        uvicorn.run(server.build(), host='0.0.0.0', port=port)
    except Exception as e:
        logger.error(f"An error occurred during server startup: {e}")
        exit(1)

Membangun dan Men-deploy agen Interaksi Platform dan Sosial

Agen ini memerlukan akses ke Spanner, jadi pastikan variabel lingkungan SPANNER_INSTANCE_ID, SPANNER_DATABASE_ID, dan MCP_SERVER_URL diteruskan dengan benar selama deployment.

👉💻 Bangun dan deploy ke Cloud Run dengan Cloud Build:

. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/agents
export MCP_SERVER_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep mcp-tool-server)/sse


gcloud builds submit . \
  --config=cloudbuild.yaml \
  --project="${PROJECT_ID}" \
  --region="${REGION}" \
  --substitutions=\
_PROJECT_ID="${PROJECT_ID}",\
_PROJECT_NUMBER="${PROJECT_NUMBER}",\
_REGION="${REGION}",\
_REPO_NAME="${REPO_NAME}",\
_SPANNER_INSTANCE_ID="${SPANNER_INSTANCE_ID}",\
_SPANNER_DATABASE_ID="${SPANNER_DATABASE_ID}",\
_MCP_SERVER_URL="${MCP_SERVER_URL}"

👉💻 Di terminal, dapatkan URL agen platform yang di-deploy:

export PLATFORM_MPC_CLIENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep platform-mcp-client)
echo $PLATFORM_MPC_CLIENT_URL

👉💻 Salin URL output.

👉 Di UI A2A Inspector, tempelkan URL ke kolom Agent URL, lalu klik Connect.

👀 Detail kartu dan JSON agen akan muncul di tab Kartu Agen, yang mengonfirmasi bahwa koneksi berhasil.

10-05-platform-a2a.png

👉 Klik tab Chat di A2A Inspector. Di sinilah Anda dapat berinteraksi langsung dengan agen yang di-deploy. Kirim pesan untuk menguji kemampuan agen dalam membuat postingan:

Create a post for me, the post says 'Paws, purrs, and ocean views 🐾☕🌊. Spent my morning at the Morning Seaside Cat Café, where every sip comes with a side of snuggles and sea breeze.' and make it positive, and I'm Oscar.

👀 Untuk memeriksa komunikasi mentah, klik balon pesan Anda, lalu klik balon respons agen di jendela chat. Saat Anda mengklik setiap pesan, pesan JSON-RPC 2.0 lengkap yang dikirim atau diterima akan ditampilkan, yang sangat berharga untuk proses debug.

👉💻 Di terminal, dapatkan URL agen Sosial yang di-deploy:

export SOCIAL_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep social-agent)
echo $SOCIAL_AGENT_URL

👉💻 Salin URL output.

👉 Di UI A2A Inspector, tempelkan URL ke kolom Agent URL, lalu klik Connect.

👀 Detail kartu dan JSON agen akan muncul di tab Kartu Agen, yang mengonfirmasi bahwa koneksi berhasil.

10-04-social-a2a.png

👉 Klik tab Chat di A2A Inspector. Di sini Anda dapat berinteraksi langsung dengan agen yang di-deploy, Kirimkan pesan untuk menganalisis profil pengguna dari database Anda:

Can you tell me about both Ian and Kevin's profile, what are their common interests?

👀 Untuk memeriksa komunikasi mentah, klik balon pesan Anda, lalu klik balon respons agen di jendela chat. Saat Anda mengklik setiap pesan, pesan JSON-RPC 2.0 lengkap yang dikirim atau diterima akan ditampilkan, yang sangat berharga untuk proses debug.

👉 Bagus, kita telah selesai memeriksa semua agen kita. Sekarang Anda dapat menutup tab A2A Inspector.

11. Agen Orchestrator (Klien A2A)

Sekarang kita memiliki tiga agen khusus (Planner, Platform, Social) yang berjalan sebagai layanan independen yang mendukung A2A di Cloud Run. Bagian terakhir adalah Agen Orchestrator. Agen ini akan bertindak sebagai koordinator pusat atau Klien A2A. Aplikasi ini akan menerima permintaan pengguna, menentukan agen jarak jauh mana yang diperlukan untuk memenuhi permintaan (berpotensi secara berurutan), lalu menggunakan protokol A2A untuk mendelegasikan tugas ke agen jarak jauh tersebut. Untuk workshop ini, kita akan menjalankan agen Orchestrator secara lokal menggunakan UI Dev ADK.

all-agent-orchestrator

Pertama, mari kita tingkatkan logika Orchestrator untuk menangani pendaftaran agen jarak jauh yang ditemukannya. Menyimpan detail koneksi dari Kartu Agen yang diambil selama inisialisasi.

👉📝 Di ~/instavibe-bootstrap/agents/orchestrate/agent.py, ganti #REPLACE ME REG AGENT CARD dengan:

async with httpx.AsyncClient(timeout=30) as client:
            for i, address in enumerate(REMOTE_AGENT_ADDRESSES):
                log.info(f"--- STEP 3.{i}: Attempting connection to: {address} ---")
                try:
                    card_resolver = A2ACardResolver(client, address)
                    card = await card_resolver.get_agent_card()
                    
                    remote_connection = RemoteAgentConnections(agent_card=card, agent_url=address)
                    self.remote_agent_connections[card.name] = remote_connection
                    self.cards[card.name] = card
                    log.info(f"--- STEP 5.{i}: Successfully stored connection for {card.name} ---")

                except Exception as e:
                    log.error(f"--- CRITICAL FAILURE at STEP 4.{i} for address: {address} ---")
                    log.error(f"--- The hidden exception type is: {type(e).__name__} ---")
                    log.error(f"--- Full exception details and traceback: ---", exc_info=True)

Selanjutnya, tentukan alat untuk agen Orchestrator itu sendiri dalam ADK.

  • send_message (fungsi A2A untuk mendelegasikan pekerjaan).

👉📝 Ganti #REPLACE ME CREATE AGENT di ~/instavibe-bootstrap/agents/orchestrate/agent.py dengan:

def create_agent(self) -> Agent:
        """Synchronously creates the ADK Agent object."""
        return Agent(
            model="gemini-2.5-flash",
            name="orchestrate_agent",
            instruction=self.root_instruction,
            before_agent_callback=self.before_agent_callback,
            description=("Orchestrates tasks for child agents."),
            tools=[self.send_message], 
        )

Logika inti Orchestrator terletak pada instruksinya, yang memberi tahu cara menggunakan A2A.

👉📝 Ganti #REPLACE ME INSTRUCTIONS di ~/instavibe-bootstrap/agents/orchestrate/agent.py dengan metode pembuatan petunjuk ini:

def root_instruction(self, context: ReadonlyContext) -> str:
        current_agent = self.check_active_agent(context)
        return f"""
                You are an expert AI Orchestrator. Your primary responsibility is to intelligently interpret user requests, break them down into a logical plan of discrete actions, and delegate each action to the most appropriate specialized remote agent using the send_message function. You do not perform the tasks yourself but manage their assignment, sequence, and critically, their outcomes.
                    **Core Directives & Decision Making:**

                    *   **Understand User Intent & Complexity:**
                        *   Carefully analyze the user's request to determine the core task(s) they want to achieve. Pay close attention to keywords and the overall goal.
                        *   Identify if the request requires a single agent or a sequence of actions from multiple agents. For example, "Analyze John Doe's profile and then create a positive post about his recent event attendance" would require two agents in sequence.

                    *   **Task Planning & Sequencing (for Multi-Step Requests):**
                        *   Before delegating, outline the clear sequence of agent tasks.
                        *   Identify dependencies. If Task B requires output from Task A, execute them sequentially. If tasks are independent (like creating a post and then creating an event), execute them one after the other as separate delegations.
                        *   Agent Reusability: An agent's completion of one task does not make it unavailable. If a user's plan involves multiple, distinct actions that fall under the same agent's expertise (e.g., create a post, then create an event), you must call that same agent again for the subsequent task.

                    *   **Task Delegation & Management (using `send_message`):**
                        *   **Delegation:** Use `send_message` to assign actionable tasks to the selected remote agent. Your `send_message` call MUST include:
                            *   The `remote_agent_name` you've selected.
                            *   The `user_request` or all necessary parameters extracted from the user's input, formatted in a way the target agent will understand.
                        *   **Contextual Awareness for Remote Agents:** If a remote agent repeatedly requests user confirmation or seems to lack context, assume it lacks access to the full conversation history. In such cases, enrich your `send_message` with all necessary contextual information relevant to that specific agent from the conversation history.
                        *   **Sequential Task Execution:**
                            *   After a preceding task completes (indicated by the agent's response or a success signal), gather any necessary output from it.
                            *   Then, use `send_message` for the next agent in the sequence, providing it with the user's original relevant intent and any necessary data obtained from the previous agent's task.
                        *   **Active Agent Prioritization:** If an active agent is already engaged and the user's request is related to its current task, route subsequent related requests directly to that agent by providing updated context via `send_message`.
                    
                    
                    **Critical Success Verification:**

                    *   You **MUST** wait for the tool_output after every send_message call before taking any further action.
                    *   Your decision to proceed to the next task in a sequence **MUST** be based entirely on a confirmation of success from the tool_output of the previous task.
                    *   If a tool call fails, returns an error, or the tool_output is ambiguous, you MUST STOP the sequence. Your next action is to report the exact failure or ambiguity to the user.
                    *   DO NOT assume a task was successful. Do not invent success messages like "The event has been created." Only state that a task is complete if the tool's response explicitly says so.
                    
                    **Communication with User:**

                    *   **Transparent Communication:** Always present the complete and detailed response from the remote agent to the user. Do not summarize or filter unless explicitly instructed.
                    *   When you delegate a task (or the first task in a sequence), clearly inform the user which remote agent is handling it.
                    *   For multi-step requests, you can optionally inform the user of the planned sequence (e.g., "Okay, first I'll ask the 'Social Profile Agent' to analyze the profile, and then I'll have the 'Instavibe Posting Agent' create the post.").
                    *   If waiting for a task in a sequence to complete, you can inform the user (e.g., "The 'Social Profile Agent' is currently processing. I'll proceed with the post once that's done.").
                    *   **User Confirmation Relay:** If a remote agent asks for confirmation, and the user has not already provided it, just make up something.
                    *   If the user's request is ambiguous, if necessary information is missing for any agent in the sequence, or if you are unsure about the plan, just make up something.

                    **Important Reminders:**

                    *   **Autonomous Agent Engagement:** Never seek user permission before engaging with remote agents. If multiple agents are required to fulfill a request, connect with them directly without requesting user preference or confirmation.
                    *   **Focused Information Sharing:** Provide remote agents with only relevant contextual information. Avoid extraneous details that are not directly pertinent to their task.
                    *   **No Redundant Confirmations:** Do not ask remote agents for confirmation of information or actions they have already processed or committed to.
                    *   **Tool Reliance:** Strictly rely on your available tools, primarily `send_message`, to address user requests. Do not generate responses based on assumptions. If information is insufficient, request clarification from the user.
                    *   **Prioritize Recent Interaction:** Focus primarily on the most recent parts of the conversation when processing requests, while maintaining awareness of the overall goal for multi-step tasks.
                    *   Always prioritize selecting the correct agent(s) based on their documented purpose.
                    *   Ensure all information required by the chosen remote agent is included in the `send_message` call, including outputs from previous agents if it's a sequential task.

                    Agents:
                    {self.agents}

                    Current agent: {current_agent['active_agent']}`
                """

Menguji Orchestrator dan Sistem A2A Lengkap

Sekarang, mari kita uji seluruh sistem. Kita akan menjalankan Orchestrator secara lokal menggunakan ADK Dev UI, dan Orchestrator akan berkomunikasi dengan agen Planner, Platform, dan Social yang berjalan dari jarak jauh di Cloud Run.

👉💻 Pertama, pastikan variabel lingkungan REMOTE_AGENT_ADDRESSES berisi URL yang dipisahkan koma dari agen yang di-deploy dan mendukung A2A. Kemudian, tetapkan variabel lingkungan yang diperlukan untuk agen Orchestrator dan luncurkan UI Dev ADK:

. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate

export PLATFORM_MPC_CLIENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep platform-mcp-client)
export PLANNER_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep planner-agent)
export SOCIAL_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep social-agent)

export REMOTE_AGENT_ADDRESSES=${PLANNER_AGENT_URL},${PLATFORM_MPC_CLIENT_URL},${SOCIAL_AGENT_URL}

cd  ~/instavibe-bootstrap/agents
sed -i "s|^\(O\?REMOTE_AGENT_ADDRESSES\)=.*|REMOTE_AGENT_ADDRESSES=${REMOTE_AGENT_ADDRESSES}|" ~/instavibe-bootstrap/agents/orchestrate/.env
adk web

👉 Buka UI Dev ADK (Ubah port kembali ke 8000 melalui Pratinjau Web).

10-08-web-preview.png

👉 Di dropdown agen, pilih agen orchestrate.

👉 Sekarang, berikan tugas kompleks yang memerlukan koordinasi beberapa agen jarak jauh. Coba contoh pertama ini, yang akan melibatkan Agen Sosial, lalu Agen Perencana:

You are an expert event planner for a user named  Diana.
    Your task is to design a fun and personalized event.

    Here are the details for the plan:
    - Friends to invite: Ian, Nora
    - Desired date: "2025-10-15"
    - Location idea or general preference: "Chicago"

    Your process should be:
    1. Analyze the provided friend names. If you have access to a tool to get their InstaVibe profiles or summarized interests, please use it.
    2. Based on their potential interests (or general good taste if profiles are unavailable), create a tailored plan for the outing, check if you have access to any event planner tools.
    3. Ensure the plan includes the original `planned_date`.

    The user wants a comprehensive plan that includes:
    - The list of invited friends.
    - A catchy and descriptive name for the event.
    - The exact planned date for the event.
    - A summary of what the group will do.
    - Specific recommended spots (e.g., restaurants, bars, activity venues) with their names, (if possible, approximate latitude/longitude for mapping, and address), and a brief description of why it fits the plan.
    - A short, exciting message that {Diana} can send to {Ian, Nora} to get them excited about the event.

Orkestrasi

Amati interaksi di jendela chat UI Dev ADK. Perhatikan respons Orchestrator dengan cermat – Orchestrator harus menyatakan agen jarak jauh mana yang didelegasikan tugasnya (misalnya, "Oke, saya akan bertanya kepada Agen Profil Sosial tentang Ian dan Nora terlebih dahulu...").

Selain itu, periksa tab Peristiwa di UI untuk melihat panggilan alat pokok (send_message) yang dilakukan ke URL agen jarak jauh.

Mengirim Tugas

👉 Sekarang, coba contoh kedua yang harus melibatkan Agen Integrasi Platform secara langsung:

Hey, can you register an event on Instavibe for Laura and Charlie? Let's call it 'Vienna Concert & Castles Day'.
here are more info
"event_name": "Vienna Concert & Castles Day",
  "description": "A refined and unforgettable day in Vienna with Laura and Charlie. The day begins with a guided tour of the magnificent Schönbrunn Palace, showcasing imperial architecture and history. In the evening, enjoy a classical music concert in one of Vienna's most iconic concert halls.",
  "event_date": "2025-10-14T10:00:00+02:00",
  "locations": [
    {
      "name": "Schönbrunn Palace",
      "description": "A UNESCO World Heritage Site and former imperial summer residence, Schönbrunn Palace offers opulent rooms, beautiful baroque gardens, and a glimpse into the life of the Habsburg monarchy. Visitors can stroll the grounds or take a guided historical tour.",
      "latitude": 48.184516,
      "longitude": 16.312222,
      "address": "Schönbrunner Schloßstraße 47, 1130 Wien, Austria"
    },
    {
      "name": "Musikverein Vienna",
      "description": "Home to the world-renowned Vienna Philharmonic, the Musikverein is one of the finest concert halls in the world. Its 'Golden Hall' is famous for its acoustics and ornate design. Attendees can enjoy a powerful classical concert in an unforgettable setting.",
      "latitude": 48.200132,
      "longitude": 16.373777,
      "address": "Musikvereinsplatz 1, 1010 Wien, Austria"
    }
  ],
  "attendee_names": ["Laura", "Charlie", "Oscar"] And I am Oscar

Sekali lagi, pantau chat dan tab Peristiwa. Orchestrator harus mengidentifikasi kebutuhan untuk membuat acara dan mendelegasikan tugas (dengan semua detail yang diberikan) kepada "Platform Integration Agent". Anda juga dapat mengklik tombol Trace untuk melihat rekaman aktivitas guna menganalisis waktu respons kueri dan operasi yang dijalankan. Mengirim Peristiwa

Kemudian, Anda dapat memverifikasi bahwa peristiwa muncul di aplikasi web InstaVibe. Acara InstaVibe

Hal ini menunjukkan keberhasilan penerapan sistem multi-agen menggunakan ADK dan protokol A2A, di mana orkestrator pusat mendelegasikan tugas ke agen jarak jauh khusus.

Jangan lupa untuk menghentikan ADK Dev UI (Ctrl+C di terminal) setelah Anda selesai menguji.

12. Agent Engine dan Panggilan Jarak Jauh dari InstaVibe

Sejauh ini, kita telah menjalankan agen khusus di Cloud Run dan menguji Orchestrator secara lokal menggunakan UI Dev ADK. Untuk skenario produksi, kita memerlukan lingkungan yang andal, skalabel, dan terkelola untuk menghosting agen. Di sinilah peran Google Vertex AI Agent Engine.

Agent Engine adalah layanan terkelola sepenuhnya di Vertex AI yang dirancang khusus untuk men-deploy dan menskalakan agen AI. Platform ini memisahkan pengelolaan infrastruktur, keamanan, dan overhead operasional, sehingga developer (terutama yang kurang memahami lingkungan cloud yang kompleks) dapat berfokus pada logika dan kemampuan agen, bukan mengelola server. Layanan ini menyediakan runtime khusus yang dioptimalkan untuk workload agentic.

Sekarang kita akan men-deploy agen Orchestrator ke Agent Engine. (Catatan: Mekanisme deployment yang ditunjukkan di bawah menggunakan skrip kustom (agent_engine_app.py) yang disediakan dalam materi workshop, karena alat deployment langsung ADK-ke-Agent-Engine resmi mungkin masih dalam tahap pengembangan. Skrip ini menangani pengemasan dan men-deploy agen Orchestrator, yang dikonfigurasi dengan alamat agen jarak jauh yang diperlukan.)

Jalankan perintah berikut untuk men-deploy agen Orchestrator ke Agent Engine. Pastikan variabel lingkungan REMOTE_AGENT_ADDRESSES (yang berisi URL agen Planner, Platform, dan Social Anda di Cloud Run) masih disetel dengan benar dari bagian sebelumnya.

👉💻 Kita akan men-deploy agen Orchestrate ke Agent Engine (Catatan: ini adalah penerapan deployment saya sendiri, ADK memiliki CLI untuk membantu deployment, saya akan memperbarui ini setelah BYO-SA diterapkan.)

cd ~/instavibe-bootstrap/agents/
. ~/instavibe-bootstrap/set_env.sh

gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member="serviceAccount:service-$PROJECT_NUMBER@gcp-sa-aiplatform-re.iam.gserviceaccount.com" \
    --role="roles/viewer"


source ~/instavibe-bootstrap/env/bin/activate
export PLATFORM_MPC_CLIENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep platform-mcp-client)
export PLANNER_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep planner-agent)
export SOCIAL_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep social-agent)

export REMOTE_AGENT_ADDRESSES=${PLANNER_AGENT_URL},${PLATFORM_MPC_CLIENT_URL},${SOCIAL_AGENT_URL}
sed -i "s|^\(O\?REMOTE_AGENT_ADDRESSES\)=.*|REMOTE_AGENT_ADDRESSES=${REMOTE_AGENT_ADDRESSES}|" ~/instavibe-bootstrap/agents/orchestrate/.env

adk deploy agent_engine \
--display_name "orchestrate-agent" \
--project $GOOGLE_CLOUD_PROJECT \
--region $GOOGLE_CLOUD_LOCATION \
--staging_bucket gs://$GOOGLE_CLOUD_PROJECT-agent-engine \
--trace_to_cloud \
--requirements_file orchestrate/requirements.txt \
orchestrate

Sekarang setelah Orchestrator dihosting di platform Agent Engine terkelola, aplikasi web InstaVibe kita perlu berkomunikasi dengannya. Daripada berinteraksi melalui UI Dev ADK, aplikasi web akan melakukan panggilan jarak jauh ke endpoint Agent Engine.

10-agent-remote.png

Pertama, kita perlu mengubah kode aplikasi InstaVibe untuk melakukan inisialisasi klien Agent Engine menggunakan ID unik agen Orchestrator yang di-deploy. ID ini diperlukan untuk menargetkan instance agen yang benar di platform.

👉📝 Buka ~/instavibe-bootstrap/instavibe/introvertally.py dan ganti #REPLACE ME initiate agent_engine dengan kode berikut. Kode ini mengambil ID Agent Engine dari variabel lingkungan (yang akan kita tetapkan sebentar lagi) dan mendapatkan objek klien:

ORCHESTRATE_AGENT_ID = os.environ.get('ORCHESTRATE_AGENT_ID')
agent_engine = agent_engines.get(ORCHESTRATE_AGENT_ID)

Alur pengguna yang kami rencanakan di InstaVibe melibatkan dua interaksi dengan agen: pertama, membuat rencana yang direkomendasikan, dan kedua, meminta pengguna untuk mengonfirmasi sebelum agen benar-benar memposting acara ke platform.

Karena aplikasi web InstaVibe (berjalan di Cloud Run) dan agen Orchestrator (berjalan di Agent Engine) kini merupakan layanan terpisah, aplikasi web perlu melakukan panggilan jarak jauh ke endpoint Agent Engine untuk berinteraksi dengan agen.

👉📝 Mari kita perbarui kode yang melakukan panggilan awal untuk membuat rekomendasi rencana. Di file introvertally.py yang sama, ganti #REPLACE ME Query remote agent get plan dengan cuplikan berikut, yang menggunakan klien agent_engine untuk mengirim permintaan pengguna:

agent_engine.stream_query(
                user_id=user_id,
                message=prompt_message,
            )

👉📝 Selanjutnya, perbarui kode yang menangani konfirmasi pengguna (misalnya, saat pengguna mengklik "Konfirmasi Paket"). Tindakan ini akan mengirimkan pesan lanjutan ke percakapan yang sama di Agent Engine, yang menginstruksikan Orchestrator untuk melanjutkan memposting acara (yang akan didelegasikan ke agen Integrasi Platform). Ganti #REPLACE ME Query remote agent for confirmation untuk konfirmasi di introvertally.py dengan:

agent_engine.stream_query(
            user_id=agent_session_user_id,
            message=prompt_message,
        )

Rute aplikasi web memerlukan akses ke fungsi ini. Pastikan fungsi yang diperlukan dari introvertally.py diimpor dalam file rute Flask.

👉📝 Di cd ~/instavibe-bootstrap/instavibe/ally_routes.py, kita akan terlebih dahulu mengarahkan ke penggantian instance # REPLACE ME TO ADD IMPORT dengan berikut:

from introvertally import call_agent_for_plan, post_plan_event

👉📝 Tambahkan fitur prototipe ke InstaVibe, di ~/instavibe-bootstrap/instavibe/templates/base.html, ganti <!–REPLACE_ME_LINK_TO_INTROVERT_ALLY–> dengan berikut ini:

            <li class="nav-item">
              <a class="nav-link" href="{{ url_for('ally.introvert_ally_page') }}">Introvert Ally</a>
            </li>

Sebelum dapat men-deploy ulang aplikasi InstaVibe, kita memerlukan Resource ID spesifik agen Orchestrator yang kita deploy ke Agent Engine.

Saat ini, pengambilan secara terprogram melalui gcloud mungkin terbatas, jadi kita akan menggunakan skrip Python pembantu (temp-endpoint.py yang disediakan di workshop) untuk mengambil ID dan menyimpannya dalam variabel lingkungan.

👉💻 Jalankan perintah berikut untuk mengeksekusi skrip. Skrip akan mengambil ID Endpoint Agent Engine dan memberikan izin yang diperlukan ke akun layanan default agent engine (Catatan: Skrip dikonfigurasi untuk menggunakan akun layanan default karena saat ini tidak dapat diubah oleh pengguna).

. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/instavibe/
source ~/instavibe-bootstrap/env/bin/activate
python temp-endpoint.py
export ORCHESTRATE_AGENT_ID=$(cat temp_endpoint.txt)
echo "ORCHESTRATE_AGENT_ID set to: ${ORCHESTRATE_AGENT_ID}"

ID Endpoint Agent Engine

Terakhir, kita perlu men-deploy ulang aplikasi web InstaVibe dengan kode yang telah diupdate dan variabel lingkungan ORCHESTRATE_AGENT_ID yang baru agar aplikasi tersebut mengetahui cara terhubung ke agen yang berjalan di Agent Engine.

👉💻 Perintah berikut akan membangun ulang image aplikasi InstaVibe dan men-deploy versi baru ke Cloud Run:

. ~/instavibe-bootstrap/set_env.sh

cd ~/instavibe-bootstrap/instavibe/

export IMAGE_TAG="latest"
export APP_FOLDER_NAME="instavibe"
export IMAGE_NAME="instavibe-webapp"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="instavibe"

echo "Building ${APP_FOLDER_NAME} webapp image..."
gcloud builds submit . \
  --tag=${IMAGE_PATH} \
  --project=${PROJECT_ID}

echo "Deploying ${SERVICE_NAME} to Cloud Run..."

gcloud run deploy ${SERVICE_NAME} \
  --image=${IMAGE_PATH} \
  --platform=managed \
  --region=${REGION} \
  --allow-unauthenticated \
  --set-env-vars="SPANNER_INSTANCE_ID=${SPANNER_INSTANCE_ID}" \
  --set-env-vars="SPANNER_DATABASE_ID=${SPANNER_DATABASE_ID}" \
  --set-env-vars="APP_HOST=0.0.0.0" \
  --set-env-vars="APP_PORT=8080" \
  --set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}" \
  --set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
  --set-env-vars="GOOGLE_MAPS_API_KEY=${GOOGLE_MAPS_API_KEY}" \
  --set-env-vars="ORCHESTRATE_AGENT_ID=${ORCHESTRATE_AGENT_ID}" \
  --project=${PROJECT_ID} \
  --min-instances=1 \
  --cpu=2 \
  --memory=2Gi

Setelah deployment akhir selesai, buka URL aplikasi InstaVibe Anda di tab browser yang berbeda.

Menguji Pengalaman InstaVibe Lengkap yang Didukung AI

Fitur "InstaVibe Ally" kini sudah aktif, didukung oleh sistem multi-agen kami yang diatur melalui Vertex AI Agent Engine dan berkomunikasi melalui A2A.

12-02-new.png

Klik "InstaVibe Ally" dan minta untuk merencanakan acara.

12-03-introvertally.png

Amati log aktivitas di sebelah kanan saat agen bekerja (mungkin perlu waktu 90-120 detik). Setelah rencana muncul, tinjau rencana tersebut, lalu klik "Konfirmasi Rencana Ini" untuk melanjutkan postingan.

12-04-confirm.png

Orchestrator kini akan menginstruksikan agen Platform untuk membuat postingan dan acara dalam InstaVibe. 12-05-posting.png

Periksa halaman beranda InstaVibe untuk melihat postingan dan acara baru. 12-06-instavibe.png

Halaman acara akan mencerminkan detail yang dihasilkan oleh agen.

12-07-event.png

Menganalisis Performa dengan Cloud Trace

Anda mungkin melihat bahwa proses ini memerlukan waktu. Vertex AI Agent Engine terintegrasi dengan Cloud Trace, sehingga kami dapat menganalisis latensi sistem multi-agen kami.

Buka Traces di konsol Google Cloud, pilih agent_run[orchestrate_agent] di Span, Anda akan melihat beberapa Span, klik Span tersebut

12-08-trace.png

Dalam detail rekaman aktivitas, Anda dapat mengidentifikasi bagian mana yang membutuhkan waktu lebih lama. Misalnya, panggilan ke agen Planner mungkin menunjukkan latensi yang lebih tinggi karena perujukan penelusuran dan pembuatan yang kompleks. 12-09-plan.png

Demikian pula, saat membuat postingan dan acara, Anda mungkin melihat waktu yang dihabiskan oleh Orchestrator untuk memproses data dan menyiapkan panggilan alat untuk agen Platform. 12-10-post.png

Mempelajari rekaman aktivitas ini akan membantu memahami dan mengoptimalkan performa sistem agen Anda.

celebrate.png

Selamat! Anda telah berhasil membangun, men-deploy, dan menguji sistem AI multi-agen yang canggih menggunakan ADK, A2A, MCP, dan layanan Google Cloud. Anda telah menangani orkestrasi agen, penggunaan alat, pengelolaan status, dan deployment cloud, sehingga membuat fitur berteknologi AI yang berfungsi untuk InstaVibe. Selamat, Anda telah menyelesaikan workshop ini.

13. Pembersihan

Agar tidak menimbulkan biaya berkelanjutan pada akun Google Cloud Anda, penting untuk menghapus resource yang kita buat selama workshop ini. Perintah berikut akan membantu Anda menghapus instance Spanner, layanan Cloud Run, repositori Artifact Registry, Kunci API, Vertex AI Agent Engine, dan izin IAM terkait.

Penting:

  • Pastikan Anda menjalankan perintah ini di project Google Cloud yang sama dengan yang digunakan untuk workshop.
  • Jika Anda telah menutup terminal Cloud Shell, beberapa variabel lingkungan seperti $PROJECT_ID, $SPANNER_INSTANCE_ID, dll., mungkin belum ditetapkan. Anda harus mengekspor ulang seperti yang Anda lakukan selama penyiapan workshop atau mengganti variabel dalam perintah di bawah dengan nilai sebenarnya.
  • Perintah ini akan menghapus resource Anda secara permanen. Periksa kembali sebelum menjalankan jika Anda memiliki data penting lainnya dalam project ini.

👉💻 Jalankan skrip berikut untuk membersihkan.

Mereset variabel lingkungan

. ~/instavibe-bootstrap/set_env.sh

Menghapus Mesin Agen:

cd ~/instavibe-bootstrap/utils
source ~/instavibe-bootstrap/env/bin/activate
export ORCHESTRATE_AGENT_ID=$(cat ~/instavibe-bootstrap/instavibe/temp_endpoint.txt)
echo "ORCHESTRATE_AGENT_ID set to: ${ORCHESTRATE_AGENT_ID}"
python remote_delete.py
deactivate
echo "Vertex AI Agent Engine deletion initiated."

Hapus Layanan Cloud Run:

# InstaVibe Web Application
gcloud run services delete instavibe --platform=managed --region=${REGION} --project=${PROJECT_ID} --quiet

# MCP Tool Server
gcloud run services delete mcp-tool-server --platform=managed --region=${REGION} --project=${PROJECT_ID} --quiet

# Planner Agent (A2A Server)
gcloud run services delete planner-agent --platform=managed --region=${REGION} --project=${PROJECT_ID} --quiet

# Platform MCP Client Agent (A2A Server)
gcloud run services delete platform-mcp-client --platform=managed --region=${REGION} --project=${PROJECT_ID} --quiet

# Social Agent (A2A Server)
gcloud run services delete social-agent --platform=managed --region=${REGION} --project=${PROJECT_ID} --quiet

echo "Cloud Run services deletion initiated."

Hentikan dan Hapus Container Docker A2A Inspector

docker rm --force a2a-inspector

Menghapus Instance Spanner:

echo "Deleting Spanner instance: ${SPANNER_INSTANCE_ID}..."
gcloud spanner instances delete ${SPANNER_INSTANCE_ID} --project=${PROJECT_ID} --quiet
echo "Spanner instance deletion initiated."

Menghapus Repositori Artifact Registry:

echo "Deleting Artifact Registry repository: ${REPO_NAME}..."
gcloud artifacts repositories delete ${REPO_NAME} --location=${REGION} --project=${PROJECT_ID} --quiet
echo "Artifact Registry repository deletion initiated."

Menghapus Peran dari Akun Layanan:

echo "Removing roles from service account: $SERVICE_ACCOUNT_NAME in project $PROJECT_ID"

# Remove Project-level roles for default service account
gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/spanner.admin"

gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/spanner.databaseUser"

gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/artifactregistry.admin"

gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/cloudbuild.builds.editor"

gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/run.admin"

gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/iam.serviceAccountUser"

gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/aiplatform.user"

gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/logging.logWriter"

gcloud projects remove-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/logging.viewer"


echo "All specified roles have been removed."

Menghapus File Workshop Lokal:

echo "Removing local workshop directory ~/instavibe-bootstrap..."
rm -rf ~/instavibe-bootstrap
rm -rf ~/a2a-inspector
rm -f ~/mapkey.txt
rm -f ~/project_id.txt
echo "Local directory removed."

Pembersihan