🤖 Membangun Agen AI Multimodal dengan Graph RAG, ADK & Memory Bank

1. Pengantar

cover

1. Tantangan

Dalam skenario respons bencana, mengoordinasikan korban selamat dengan berbagai keterampilan, sumber daya, dan kebutuhan di beberapa lokasi memerlukan kemampuan penelusuran dan pengelolaan data yang cerdas. Workshop ini mengajarkan cara membangun sistem AI produksi yang menggabungkan:

  1. 🗄️ Database Grafik (Spanner): Menyimpan hubungan kompleks antara penyintas, keterampilan, dan sumber daya
  2. 🔍 Penelusuran yang Didukung AI: Penelusuran campuran semantik + kata kunci menggunakan embedding
  3. 📸 Pemrosesan Multimodal: Mengekstrak data terstruktur dari gambar, teks, dan video
  4. 🤖 Orkestrasi Multi-Agen: Mengoordinasikan agen khusus untuk alur kerja yang kompleks
  5. 🧠 Memori Jangka Panjang: Personalisasi dengan Vertex AI Memory Bank

percakapan

2. Yang Akan Anda Buat

Database Grafik Jaringan Korban dengan:

  • 🗺️ Visualisasi Grafik Interaktif 3D hubungan antar-korban
  • 🔍 Penelusuran Cerdas (kata kunci, semantik, dan campuran)
  • 📸 Pipeline Upload Multimodal (mengekstraksi entitas dari gambar/video)
  • 🤖 Sistem Multi-Agen untuk orkestrasi tugas yang kompleks
  • 🧠 Integrasi Bank Memori untuk interaksi yang dipersonalisasi

3. Teknologi Inti

Komponen

Teknologi

Tujuan

Database

Grafik Cloud Spanner

Menyimpan node (penyintas, keterampilan) dan edge (hubungan)

AI Search

Gemini + Embeddings

Pemahaman semantik + penelusuran kemiripan

Framework Agen

ADK (Agent Development Kit)

Mengorkestrasi alur kerja AI

Memori

Vertex AI Memory Bank

Penyimpanan preferensi pengguna jangka panjang

Frontend

React + Three.js

Visualisasi grafik 3D interaktif

2. Persiapan Lingkungan (Lewati jika Anda berada di Workshop)

Bagian Satu: Aktifkan Akun Penagihan

  • Mengklaim akun penagihan dengan kredit 5 dolar, Anda akan memerlukannya untuk deployment. Pastikan Anda login ke akun Gmail Anda.

Bagian Dua: Lingkungan Terbuka

  1. 👉 Klik link ini untuk langsung membuka Cloud Shell Editor
  2. 👉 Jika diminta untuk memberikan otorisasi kapan saja hari ini, klik Authorize untuk melanjutkan. Klik untuk memberikan otorisasi pada Cloud Shell
  3. 👉 Jika terminal tidak muncul di bagian bawah layar, buka terminal:
    • Klik Lihat
    • Klik TerminalMembuka terminal baru di Cloud Shell Editor
  4. 👉💻 Di terminal, verifikasi bahwa Anda sudah diautentikasi dan project disetel ke project ID Anda menggunakan perintah berikut:
    gcloud auth list
    
  5. 👉💻 Clone project bootstrap dari GitHub:
    git clone https://github.com/google-americas/way-back-home.git
    

3. Penyiapan Lingkungan

1. Lakukan inisialisasi

Di terminal Cloud Shell Editor, jika terminal tidak muncul di bagian bawah layar, buka terminal:

  • Klik Lihat
  • Klik Terminal

Membuka terminal baru di Cloud Shell Editor

👉💻 Di terminal, Jadikan skrip init dapat dieksekusi dan jalankan:

cd ~/way-back-home/level_2
./init.sh

2. Konfigurasi Project

👉💻 Tetapkan project ID Anda:

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

👉💻 Aktifkan API yang diperlukan (proses ini memerlukan waktu sekitar 2-3 menit):

gcloud services enable compute.googleapis.com \
                       aiplatform.googleapis.com \
                       run.googleapis.com \
                       cloudbuild.googleapis.com \
                       artifactregistry.googleapis.com \
                       spanner.googleapis.com \
                       storage.googleapis.com

3. Jalankan Skrip Penyiapan

👉💻 Jalankan skrip penyiapan:

cd ~/way-back-home/level_2
./setup.sh

Tindakan ini akan membuat .env untuk Anda. Di cloudshell, buka way_back_homeproject. Di folder level_2, Anda dapat melihat file .env yang dibuat untuk Anda. Jika tidak dapat menemukannya, Anda dapat mengklik View -> Toggle Hidden File untuk melihatnya. open_project

4. Memuat Data Sampel

👉💻 Buka backend dan instal dependensi:

cd ~/way-back-home/level_2/backend
uv sync

👉💻 Muat data awal penyintas:

uv run python ~/way-back-home/level_2/backend/setup_data.py

Tindakan ini akan membuat:

  • Instance Spanner (survivor-network)
  • Database (graph-db)
  • Semua tabel node dan edge
  • Grafik properti untuk membuat kueri Hasil yang diharapkan:
============================================================
SUCCESS! Database setup complete.
============================================================

Instance:  survivor-network
Database:  graph-db
Graph:     SurvivorGraph

Access your database at:
https://console.cloud.google.com/spanner/instances/survivor-network/databases/graph-db?project=waybackhome

Jika mengklik link setelah Access your database at di output, Anda dapat membuka Spanner di Konsol Google Cloud.

open_spanner

Anda akan melihat Spanner di Konsol Google Cloud.

spanner

4. Memvisualisasikan Data Grafik di Spanner Studio

Panduan ini membantu Anda memvisualisasikan dan berinteraksi dengan data grafik Survivor Network secara langsung di Konsol Google Cloud menggunakan Spanner Studio. Cara ini adalah cara yang bagus untuk memverifikasi data Anda dan memahami struktur grafik sebelum membangun agen AI.

1. Mengakses Spanner Studio

  1. Pada langkah terakhir, pastikan Anda mengklik link dan membuka Spanner Studio.

spanner_studio

2. Memahami Struktur Grafik ("Gambaran Besar")

Anggap set data Survivor Network sebagai teka-teki logika atau Status Game:

Entitas

Peran dalam Sistem

Analogi

Pemberlakuan

Agen/pemain

Pemain

Bioma

Lokasi mereka

Zona Peta

Keahlian

Yang dapat mereka lakukan

Kemampuan

Kebutuhan

Apa yang kurang (Krisis)

Misi/Quest

Referensi

Item yang ditemukan di dunia

Loot

Tujuan: Tugas agen AI adalah menghubungkan Keterampilan (Solusi) dengan Kebutuhan (Masalah), dengan mempertimbangkan Bioma (Batasan lokasi).

🔗 Tepi (Hubungan):

  • SurvivorInBiome: Pelacakan lokasi
  • SurvivorHasSkill: Inventaris kemampuan
  • SurvivorHasNeed: Daftar masalah aktif
  • SurvivorFoundResource: Inventaris item
  • SurvivorCanHelp: Hubungan yang disimpulkan (AI menghitungnya!)

3. Membuat Kueri Grafik

Mari kita jalankan beberapa kueri untuk melihat "Kisah" dalam data.

Spanner Graph menggunakan GQL (Graph Query Language). Untuk menjalankan kueri, gunakan GRAPH SurvivorNetwork yang diikuti dengan pola kecocokan Anda.

👉 Kueri 1: Daftar Global (Siapa di mana?) Ini adalah fondasi Anda - memahami lokasi sangat penting untuk operasi penyelamatan.

GRAPH SurvivorNetwork
MATCH result = (s:Survivors)-[:SurvivorInBiome]->(b:Biomes)
RETURN TO_JSON(result) AS json_result

Anda akan melihat hasil seperti di bawah ini: query1

👉 Pertanyaan 2: Matriks Keterampilan (Kemampuan) Setelah mengetahui lokasi semua orang, cari tahu apa yang dapat mereka lakukan.

GRAPH SurvivorNetwork
MATCH result = (s:Survivors)-[h:SurvivorHasSkill]->(k:Skills)
RETURN TO_JSON(result) AS json_result

Anda akan melihat hasil seperti di bawah ini: query2

👉 Kueri 3: Siapa yang sedang dalam Krisis? (Papan Misi) Lihat para penyintas yang membutuhkan bantuan dan apa yang mereka butuhkan.

GRAPH SurvivorNetwork
MATCH result = (s:Survivors)-[h:SurvivorHasNeed]->(n:Needs)
RETURN TO_JSON(result) AS json_result

Anda akan melihat hasil seperti di bawah ini: query3

🔎 Tingkat Lanjut: Matchmaking - Siapa yang Dapat Membantu Siapa?

Di sinilah grafik menjadi sangat berguna. Kueri ini menemukan penyintas yang memiliki keterampilan yang dapat memenuhi kebutuhan penyintas lain.

GRAPH SurvivorNetwork
MATCH result = (helper:Survivors)-[:SurvivorHasSkill]->(skill:Skills)-[:SkillTreatsNeed]->(need:Needs)<-[:SurvivorHasNeed]-(helpee:Survivors)
RETURN TO_JSON(result) AS json_result

Anda akan melihat hasil seperti di bawah ini: query4

selain positif Fungsi Kueri Ini:

Daripada hanya menampilkan "Pertolongan Pertama mengobati luka bakar" (yang jelas dari skema), kueri ini menemukan:

  • Dr. Elena Frost (yang memiliki Pelatihan Medis) → dapat mengobati → Kapten Tanaka (yang mengalami luka bakar)
  • David Chen (yang memiliki pengetahuan P3K) → dapat mengobati → Letnan Park (yang mengalami keseleo pada pergelangan kaki)

Alasan Hal Ini Efektif:

Yang Akan Dilakukan Agen AI Anda:

Saat pengguna bertanya "Siapa yang bisa mengobati luka bakar?", agen akan:

  1. Menjalankan kueri grafik serupa
  2. Hasil: "Dr. Frost memiliki Pelatihan Medis dan dapat membantu Kapten Tanaka"
  3. Pengguna tidak perlu mengetahui tabel atau hubungan perantara.

5. Embedding yang Didukung AI di Spanner

1. Mengapa Embedding? (Tidak ada tindakan, hanya baca)

Dalam skenario bertahan hidup, waktu sangat penting. Saat korban melaporkan keadaan darurat, seperti I need someone who can treat burns atau Looking for a medic, mereka tidak dapat membuang waktu untuk menebak nama skill yang tepat dalam database.

Skenario Nyata: Survivor: Captain Tanaka has burns—we need medical help NOW!

Penelusuran kata kunci tradisional untuk "tenaga medis" → 0 hasil ❌

Penelusuran semantik dengan embedding → Menemukan "Pelatihan Medis", "Pertolongan Pertama" ✅

Inilah yang dibutuhkan agen: penelusuran cerdas seperti manusia yang memahami maksud, bukan hanya kata kunci.

2. Membuat Model Embedding

spanner_embedding

Sekarang, mari kita buat model yang mengonversi teks menjadi embedding menggunakan text-embedding-004 Google.

👉 Di Spanner Studio, jalankan SQL ini (ganti $YOUR_PROJECT_ID dengan project ID Anda):

‼️ Di editor Cloud Shell, buka File -> Open Folder -> way-back-home/level_2 untuk melihat seluruh project.

project_id

👉 Jalankan kueri ini di Spanner Studio dengan menyalin dan menempelkan kueri di bawah, lalu klik tombol Jalankan:

CREATE MODEL TextEmbeddings
INPUT(content STRING(MAX))
OUTPUT(embeddings STRUCT<values ARRAY<FLOAT32>>)
REMOTE OPTIONS (
    endpoint = '//aiplatform.googleapis.com/projects/$YOUR_PROJECT_ID/locations/us-central1/publishers/google/models/text-embedding-004'
);

Fungsi Fitur Ini:

  • Membuat model virtual di Spanner (tanpa bobot model yang disimpan secara lokal)
  • Menunjuk ke text-embedding-004 Google di Vertex AI
  • Menentukan kontrak: Input adalah teks, output adalah array float 768 dimensi

Mengapa "REMOTE OPTIONS"?

  • Spanner tidak menjalankan model itu sendiri
  • Vertex AI akan dipanggil melalui API saat Anda menggunakan ML.PREDICT
  • Zero-ETL: Tidak perlu mengekspor data ke Python, memproses, dan mengimpor ulang

Klik tombol Run, setelah berhasil, Anda dapat melihat hasilnya seperti di bawah ini:

spanner_result

3. Menambahkan Kolom Embedding

👉 Tambahkan kolom untuk menyimpan embedding:

ALTER TABLE Skills ADD COLUMN skill_embedding ARRAY<FLOAT32>;

Klik tombol Run, setelah berhasil, Anda dapat melihat hasilnya seperti di bawah ini:

embedding_result

4. Membuat Embedding

👉 Menggunakan AI untuk membuat penyematan vektor untuk setiap keterampilan:

UPDATE Skills
SET skill_embedding = (
    SELECT embeddings.values
    FROM ML.PREDICT(
        MODEL TextEmbeddings,
        (SELECT name AS content)
    )
)
WHERE skill_embedding IS NULL;

Klik tombol Run, setelah berhasil, Anda dapat melihat hasilnya seperti di bawah ini:

skills_result

Apa yang terjadi: Setiap nama kemampuan (misalnya, "pertolongan pertama") dikonversi menjadi vektor 768 dimensi yang merepresentasikan makna semantiknya.

5. Memverifikasi Embedding

👉 Periksa apakah embedding telah dibuat:

SELECT 
    skill_id,
    name,
    ARRAY_LENGTH(skill_embedding) AS embedding_dimensions
FROM Skills
LIMIT 5;

Output yang diinginkan:

spanner_result

Sekarang kita menguji kasus penggunaan yang sama persis dari skenario kita: menemukan keterampilan medis menggunakan istilah "paramedis".

👉 Temukan keterampilan yang mirip dengan "tenaga medis":

WITH query_embedding AS (
    SELECT embeddings.values AS val
    FROM ML.PREDICT(MODEL TextEmbeddings, (SELECT "medic" AS content))
)
SELECT
    s.name AS skill_name,
    s.category,
    COSINE_DISTANCE(s.skill_embedding, (SELECT val FROM query_embedding)) AS distance
FROM Skills AS s
WHERE s.skill_embedding IS NOT NULL
ORDER BY distance ASC
LIMIT 10;
  • Mengonversi istilah penelusuran pengguna "medic" menjadi embedding
  • Menyimpannya dalam tabel sementara query_embedding

Hasil yang diharapkan (jarak yang lebih rendah = lebih mirip):

spanner_result

7. Membuat Model Gemini untuk Analisis

spanner_gemini

👉 Buat referensi model AI generatif (ganti $YOUR_PROJECT_ID dengan project ID Anda):

CREATE MODEL GeminiPro
INPUT(prompt STRING(MAX))
OUTPUT(content STRING(MAX))
REMOTE OPTIONS (
    endpoint = '//aiplatform.googleapis.com/projects/$YOUR_PROJECT_ID/locations/us-central1/publishers/google/models/gemini-2.5-pro',
    default_batch_size = 1
);

Perbedaan dari Model Embedding:

  • Embedding: Teks → Vektor (untuk penelusuran kemiripan)
  • Gemini: Teks → Teks yang Dihasilkan (untuk penalaran/analisis)

spanner_result

8. Menggunakan Gemini untuk Analisis Kompatibilitas

👉 Menganalisis pasangan penyintas untuk kompatibilitas misi:

WITH PairData AS (
    SELECT
        s1.name AS Name_A,
        s2.name AS Name_B,
        CONCAT(
            "Assess compatibility of these two survivors for a resource-gathering mission. ",
            "Survivor 1: ", s1.name, ". ",
            "Survivor 2: ", s2.name, ". ",
            "Give a score from 1-10 and a 1-sentence reason."
        ) AS prompt
    FROM Survivors s1
    JOIN Survivors s2 ON s1.survivor_id < s2.survivor_id
    LIMIT 1
)
SELECT
    Name_A,
    Name_B,
    content AS ai_assessment
FROM ML.PREDICT(
    MODEL GeminiPro,
    (SELECT Name_A, Name_B, prompt FROM PairData)
);

Output yang diinginkan:

Name_A          | Name_B            | ai_assessment
----------------|-------------------|----------------
"David Chen"    | "Dr. Elena Frost" | "**Score: 9/10** Their compatibility is extremely high as David's practical, hands-on scavenging skills are perfectly complemented by Dr. Frost's specialized knowledge to identify critical medical supplies and avoid biological hazards."

6. Membangun Agen RAG Grafik dengan Penelusuran Hybrid

1. Ringkasan Arsitektur Sistem

Bagian ini membangun sistem penelusuran multi-metode yang memberikan fleksibilitas pada agen Anda untuk menangani berbagai jenis kueri. Sistem ini memiliki tiga lapisan: Agent Layer, Tool Layer, Service Layer.

architecture_hybrid_search

Mengapa Tiga Lapisan?

  • Pemisahan tugas: Agen berfokus pada maksud, alat berfokus pada antarmuka, layanan berfokus pada penerapan
  • Fleksibilitas: Agen dapat memaksakan metode tertentu atau membiarkan perutean otomatis AI
  • Pengoptimalan: Dapat melewati analisis AI yang mahal jika metode diketahui

Di bagian ini, Anda terutama akan menerapkan penelusuran semantik (RAG) - menemukan hasil berdasarkan makna, bukan hanya kata kunci. Selanjutnya, kami akan menjelaskan cara penelusuran hibrida menggabungkan beberapa metode.

2. Implementasi Layanan RAG

👉💻 Di terminal, buka file di Cloud Shell Editor dengan menjalankan:

cloudshell edit ~/way-back-home/level_2/backend/services/hybrid_search_service.py

Cari komentar # TODO: REPLACE_SQL

Ganti seluruh baris ini dengan kode berikut:

        # This is your working query from the successful run!
        sql = """
            WITH query_embedding AS (
                SELECT embeddings.values AS val
                FROM ML.PREDICT(
                    MODEL TextEmbeddings,
                    (SELECT @query AS content)
                )
            )
            SELECT
                s.survivor_id,
                s.name AS survivor_name,
                s.biome,
                sk.skill_id,
                sk.name AS skill_name,
                sk.category,
                COSINE_DISTANCE(
                    sk.skill_embedding, 
                    (SELECT val FROM query_embedding)
                ) AS distance
            FROM Survivors s
            JOIN SurvivorHasSkill shs ON s.survivor_id = shs.survivor_id
            JOIN Skills sk ON shs.skill_id = sk.skill_id
            WHERE sk.skill_embedding IS NOT NULL
            ORDER BY distance ASC
            LIMIT @limit
        """

3. Definisi Alat Penelusuran Semantik

👉💻 Di terminal, buka file di Cloud Shell Editor dengan menjalankan:

cloudshell edit ~/way-back-home/level_2/backend/agent/tools/hybrid_search_tools.py

Di hybrid_search_tools.py, temukan komentar # TODO: REPLACE_SEMANTIC_SEARCH_TOOL

👉Ganti seluruh baris ini dengan kode berikut:

async def semantic_search(query: str, limit: int = 10) -> str:
    """
    Force semantic (RAG) search using embeddings.
    
    Use this when you specifically want to find things by MEANING,
    not just matching keywords. Great for:
    - Finding conceptually similar items
    - Handling vague or abstract queries
    - When exact terms are unknown
    
    Example: "healing abilities" will find "first aid", "surgery", 
    "herbalism" even though no keywords match exactly.
    
    Args:
        query: What you're looking for (describe the concept)
        limit: Maximum results
        
    Returns:
        Semantically similar results ranked by relevance
    """
    try:
        service = _get_service()
        result = service.smart_search(
            query, 
            force_method=SearchMethod.RAG,
            limit=limit
        )
        
        return _format_results(
            result["results"],
            result["analysis"],
            show_analysis=True
        )
        
    except Exception as e:
        return f"Error in semantic search: {str(e)}"

Saat Agen Menggunakan:

  • Kueri yang meminta kemiripan ("temukan yang mirip dengan X")
  • Kueri konseptual ("kemampuan penyembuhan")
  • Saat pemahaman makna sangat penting

4. Panduan Keputusan Agen (Petunjuk)

Dalam definisi agen, salin dan tempel bagian terkait penelusuran semantik ke petunjuk.

👉💻 Di terminal, buka file di Cloud Shell Editor dengan menjalankan:

cloudshell edit ~/way-back-home/level_2/backend/agent/agent.py

Agen menggunakan petunjuk ini untuk memilih alat yang tepat:

👉Di file agent.py, cari komentar # TODO: REPLACE_SEARCH_LOGIC, Replace this whole line dengan kode berikut:

- `semantic_search`: Force RAG/embedding search
  Use for: "Find similar to X", conceptual queries, unknown terminology
  Example: "Find skills related to healing"

👉Cari komentar # TODO: ADD_SEARCH_TOOLReplace this whole line dengan kode berikut:

    semantic_search,         # Force RAG

5. Memahami Cara Kerja Penelusuran Hybrid (Hanya Baca, Tidak Perlu Tindakan)

Pada langkah 2-4, Anda menerapkan penelusuran semantik (RAG), metode penelusuran inti yang menemukan hasil berdasarkan makna. Namun, Anda mungkin melihat bahwa sistem ini disebut "Penelusuran Hybrid". Berikut cara semuanya terhubung:

Cara Kerja Penggabungan Hybrid:

Dalam file way-back-home/level_2/backend/services/hybrid_search_service.py, saat hybrid_search() dipanggil, layanan menjalankan KEDUA penelusuran dan menggabungkan hasilnya:

# Location: backend/services/hybrid_search_service.py

    rank_kw = keyword_ranks.get(surv_id, float('inf'))
    rank_rag = rag_ranks.get(surv_id, float('inf'))

    rrf_score = 0.0
    if rank_kw != float('inf'):
        rrf_score += 1.0 / (K + rank_kw)
    if rank_rag != float('inf'):
        rrf_score += 1.0 / (K + rank_rag)

    combined_score = rrf_score

Untuk codelab ini, Anda menerapkan komponen penelusuran semantik (RAG), yang merupakan dasarnya. Metode kata kunci dan hibrida sudah diterapkan dalam layanan - agen Anda dapat menggunakan ketiganya.

Selamat! Anda telah berhasil menyelesaikan Agen RAG Grafik dengan penelusuran hibrida.

7. Menguji Agen Anda dengan Web ADK

Cara termudah untuk menguji agen Anda adalah dengan menggunakan perintah adk web, yang meluncurkan agen Anda dengan antarmuka chat bawaan.

1. Menjalankan Agen

👉💻 Buka direktori backend (tempat agen Anda ditentukan) dan luncurkan Antarmuka Web::

cd ~/way-back-home/level_2/backend
uv run adk web

Perintah ini memulai agen yang ditentukan dalam

agent/agent.py

dan membuka antarmuka web untuk pengujian.

👉 Buka URL:

Perintah ini akan menampilkan URL lokal (biasanya http://127.0.0.1:8000 atau yang serupa). Buka link ini di browser Anda.

adk web

Setelah mengklik URL, Anda akan melihat UI Web ADK. Pastikan Anda memilih "agen" dari pojok kiri atas.

adk_ui

2. Menguji Kemampuan Penelusuran

Agen ini dirancang untuk merutekan kueri Anda secara cerdas. Coba input berikut di jendela chat untuk melihat berbagai metode penelusuran berfungsi.

Menemukan item berdasarkan makna dan konsep, meskipun kata kuncinya tidak cocok.

Kueri Pengujian: (Pilih salah satu di bawah)

Who can help with injuries?
What abilities are related to survival?

Yang harus diperhatikan:

  • Alasannya harus menyebutkan penelusuran Semantik atau RAG.
  • Anda akan melihat hasil yang terkait secara konseptual (misalnya, "Operasi" saat meminta "Pertolongan Pertama").
  • Hasil akan memiliki ikon 🧬.

Menggabungkan filter kata kunci dengan pemahaman semantik untuk kueri yang kompleks.

Kueri Pengujian:(Pilih salah satu di bawah)

Find someone who can ply a plane in the volcanic area
Who has healing abilities in the FOSSILIZED?
Who has healing abilities in the mountains?

Yang harus diperhatikan:

  • Alasannya harus menyebutkan penelusuran Hybrid.
  • Hasil harus cocok dengan KEDUA kriteria (konsep + lokasi/kategori).
  • Hasil yang ditemukan oleh kedua metode akan memiliki ikon 🔀 dan diberi peringkat tertinggi.

👉💻 Setelah selesai menguji, akhiri proses dengan menekan Ctrl+C di command line.

8. Menjalankan Aplikasi Lengkap

Ringkasan Arsitektur Full Stack

architecture_fullstack

Tambahkan SessionService & Runner

👉💻 Di terminal, buka file chat.py di Cloud Shell Editor dengan menjalankan (pastikan Anda menekan "ctrl+C" untuk mengakhiri proses sebelumnya sebelum melanjutkan):

cloudshell edit ~/way-back-home/level_2/backend/api/routes/chat.py

👉Di file chat.py, cari komentar # TODO: REPLACE_INMEMORY_SERVICES, Ganti seluruh baris ini dengan kode berikut:

    session_service = InMemorySessionService()
    memory_service = InMemoryMemoryService()

👉Di file chat.py, cari komentar # TODO: REPLACE_RUNNER, Ganti seluruh baris ini dengan kode berikut:

runner = Runner(
    agent=root_agent, 
    session_service=session_service,
    memory_service=memory_service,
    app_name="survivor-network"
)

1. Mulai Permohonan

Jika terminal sebelumnya masih berjalan, akhiri dengan menekan Ctrl+C.

👉💻 Mulai Aplikasi:

cd ~/way-back-home/level_2/
./start_app.sh

Jika backend berhasil dimulai, Anda akan melihat Local: http://localhost:5173/" seperti di bawah: ditampilkan

👉 Klik Local: http://localhost:5173/ dari terminal.

percakapan

Kueri:

Find skills similar to healing

chat

Yang terjadi:

  • Agen mengenali permintaan kesamaan
  • Membuat embedding untuk "penyembuhan"
  • Menggunakan jarak kosinus untuk menemukan keterampilan yang mirip secara semantik
  • Menampilkan: pertolongan pertama (meskipun namanya tidak cocok dengan "penyembuhan")

Kueri:

Find medical skills in the mountains

Yang terjadi:

  1. Komponen kata kunci: Filter untuk category='medical'
  2. Komponen semantik: Sematkan "medical" dan urutkan berdasarkan kemiripan
  3. Gabungkan: Menggabungkan hasil, memprioritaskan hasil yang ditemukan oleh kedua metode 🔀

Kueri(opsional):

Who is good at survival and in the forest?

Yang terjadi:

  • Temuan kata kunci: biome='forest'
  • Temuan semantik: keterampilan yang mirip dengan "bertahan hidup"
  • Hybrid menggabungkan keduanya untuk mendapatkan hasil terbaik

👉💻 Setelah selesai menguji, di terminal, akhiri pengujian dengan menekan Ctrl+C.

9. Pipeline Multimodal — Lapisan Alat

Mengapa Kita Memerlukan Pipeline Multimodal?

Jaringan penyelamat bukan hanya teks. Korban di lapangan mengirimkan data tidak terstruktur langsung melalui chat:

  • 📸 Gambar: Foto sumber daya, bahaya, atau peralatan
  • 🎥 Video: Laporan status atau siaran SOS
  • 📄 Teks: Catatan atau log lapangan

File Apa yang Kami Proses?

Berbeda dengan langkah sebelumnya saat kita menelusuri data yang ada, di sini kita memproses File yang Diupload Pengguna. Antarmuka chat.py menangani lampiran file secara dinamis:

Sumber

Konten

Sasaran

Lampiran Pengguna

Gambar/Video/Teks

Informasi yang akan ditambahkan ke grafik

Konteks Chat

"Berikut foto perlengkapannya"

Maksud dan detail tambahan

Pendekatan yang Direncanakan: Pipeline Agen Berurutan

Kami menggunakan Sequential Agent (multimedia_agent.py) yang menggabungkan agen khusus:

architecture_uploading

Hal ini ditentukan dalam backend/agent/multimedia_agent.py sebagai SequentialAgent.

Lapisan alat menyediakan kemampuan yang dapat dipanggil oleh agen. Alat menangani "bagaimana" — mengupload file, mengekstrak entitas, dan menyimpan ke database.

1. Membuka File Alat

👉💻 Buka terminal baru. Di terminal, buka file di Cloud Shell Editor:

cloudshell edit ~/way-back-home/level_2/backend/agent/tools/extraction_tools.py

2. Menerapkan Alat upload_media

Alat ini mengupload file lokal ke Google Cloud Storage.

👉 Di extraction_tools.py, temukan komentar pass # TODO: REPLACE_UPLOAD_MEDIA_FUNCTION.

Ganti seluruh baris ini dengan kode berikut:

    """
    Upload media file to GCS and detect its type.
    
    Args:
        file_path: Path to the local file
        survivor_id: Optional survivor ID to associate with upload
        
    Returns:
        Dict with gcs_uri, media_type, and status
    """
    try:
        if not file_path:
            return {"status": "error", "error": "No file path provided"}
        
        # Strip quotes if present
        file_path = file_path.strip().strip("'").strip('"')
        
        if not os.path.exists(file_path):
            return {"status": "error", "error": f"File not found: {file_path}"}
        
        gcs_uri, media_type, signed_url = gcs_service.upload_file(file_path, survivor_id)
        
        return {
            "status": "success",
            "gcs_uri": gcs_uri,
            "signed_url": signed_url,
            "media_type": media_type.value,
            "file_name": os.path.basename(file_path),
            "survivor_id": survivor_id
        }
    except Exception as e:
        logger.error(f"Upload failed: {e}")
        return {"status": "error", "error": str(e)}

3. Menerapkan Alat extract_from_media

Alat ini adalah router — alat ini memeriksa media_type dan mengirim ke ekstraktor yang benar (teks, gambar, atau video).

👉Di extraction_tools.py, temukan komentar pass # TODO: REPLACE_EXTRACT_FROM_MEDIA.

Ganti seluruh baris ini dengan kode berikut:

    """
    Extract entities and relationships from uploaded media.
    
    Args:
        gcs_uri: GCS URI of the uploaded file
        media_type: Type of media (text/image/video)
        signed_url: Optional signed URL for public/temporary access
        
    Returns:
        Dict with extraction results
    """
    try:
        if not gcs_uri:
             return {"status": "error", "error": "No GCS URI provided"}

        # Select appropriate extractor
        if media_type == MediaType.TEXT.value or media_type == "text":
            result = await text_extractor.extract(gcs_uri)
        elif media_type == MediaType.IMAGE.value or media_type == "image":
            result = await image_extractor.extract(gcs_uri)
        elif media_type == MediaType.VIDEO.value or media_type == "video":
            result = await video_extractor.extract(gcs_uri)
        else:
            return {"status": "error", "error": f"Unsupported media type: {media_type}"}
            
        # Inject signed URL into broadcast info if present
        if signed_url:
            if not result.broadcast_info:
                result.broadcast_info = {}
            result.broadcast_info['thumbnail_url'] = signed_url
        
        return {
            "status": "success",
            "extraction_result": result.to_dict(), # Return valid JSON dict instead of object
            "summary": result.summary,
            "entities_count": len(result.entities),
            "relationships_count": len(result.relationships),
            "entities": [e.to_dict() for e in result.entities],
            "relationships": [r.to_dict() for r in result.relationships]
        }
    except Exception as e:
        logger.error(f"Extraction failed: {e}")
        return {"status": "error", "error": str(e)}

Detail Penerapan Utama:

  • Input Multimodal: Kita meneruskan perintah teks (_get_extraction_prompt()) dan objek gambar ke generate_content.
  • Structured Output: response_mime_type="application/json" memastikan LLM menampilkan JSON yang valid, yang sangat penting untuk pipeline.
  • Penautan Entitas Visual: Perintah menyertakan entitas yang diketahui sehingga Gemini dapat mengenali karakter tertentu.

4. Menerapkan Alat save_to_spanner

Alat ini mempertahankan entity dan hubungan yang diekstrak ke DB Spanner Graph.

👉Di extraction_tools.py, temukan komentar pass # TODO: REPLACE_SPANNER_AGENT.

Ganti seluruh baris ini dengan kode berikut:

    """
    Save extracted entities and relationships to Spanner Graph DB.
    
    Args:
        extraction_result: ExtractionResult object (or dict from previous step if passed as dict)
        survivor_id: Optional survivor ID to associate with the broadcast
        
    Returns:
        Dict with save statistics
    """
    try:
        # Handle if extraction_result is passed as the wrapper dict from extract_from_media
        result_obj = extraction_result
        if isinstance(extraction_result, dict) and 'extraction_result' in extraction_result:
             result_obj = extraction_result['extraction_result']
        
        # If result_obj is a dict (from to_dict()), reconstruct it
        if isinstance(result_obj, dict):
            from extractors.base_extractor import ExtractionResult
            result_obj = ExtractionResult.from_dict(result_obj)
        
        if not result_obj:
            return {"status": "error", "error": "No extraction result provided"}
            
        stats = spanner_service.save_extraction_result(result_obj, survivor_id)
        
        return {
            "status": "success",
            "entities_created": stats['entities_created'],
            "entities_existing": stats['entities_found_existing'],
            "relationships_created": stats['relationships_created'],
            "broadcast_id": stats['broadcast_id'],
            "errors": stats['errors'] if stats['errors'] else None
        }
    except Exception as e:
        logger.error(f"Spanner save failed: {e}")
        return {"status": "error", "error": str(e)}

Dengan memberikan alat tingkat tinggi kepada agen, kami memastikan integritas data sekaligus memanfaatkan kemampuan penalaran agen.

5. Layanan Update GCS

GCSService menangani upload file sebenarnya ke Google Cloud Storage.

👉💻 Di terminal, buka file di Cloud Shell Editor:

cloudshell edit ~/way-back-home/level_2/backend/services/gcs_service.py

👉 Dalam file gcs_service.py, temukan komentar # TODO: REPLACE_SAVE_TO_GCS di dalam fungsi upload_file.

Ganti seluruh baris ini dengan kode berikut:

        blob = self.bucket.blob(blob_name)
        blob.upload_from_filename(file_path)

Dengan mengabstraksi ini ke dalam layanan, Agen tidak perlu mengetahui bucket GCS, nama blob, atau pembuatan URL yang ditandatangani. Hanya meminta untuk "mengupload".

6. (Hanya Baca) Mengapa Alur Kerja Agentik > Pendekatan Tradisional?

Keunggulan Agentic:

Fitur

Pipeline Batch

Berdasarkan Peristiwa

Alur Kerja Agentik

Kompleksitas

Rendah (1 skrip)

Tinggi (5+ layanan)

Rendah (1 file Python: multimedia_agent.py)

Pengelolaan Status

Variabel global

Hard (terpisah)

Terpadu (Status agen)

Penanganan Error

Error

Log senyap

Interaktif ("Saya tidak dapat membaca file itu")

Masukan Pengguna

Cetakan konsol

Perlu polling

Segera (Bagian dari percakapan)

Kemampuan adaptasi

Logika tetap

Fungsi kaku

Cerdas (LLM memutuskan langkah berikutnya)

Kesadaran Konteks

Tidak ada

Tidak ada

Penuh (Mengetahui maksud pengguna)

Mengapa Hal Ini Penting: Dengan menggunakan multimedia_agent.py (SequentialAgent dengan 4 sub-agen: Upload → Ekstrak → Simpan → Ringkasan), kita mengganti infrastruktur yang kompleks DAN skrip yang rentan dengan logika aplikasi percakapan yang cerdas.

10. Pipeline Multimodal — Lapisan Agen

Lapisan agen menentukan kecerdasan — agen yang menggunakan alat untuk menyelesaikan tugas. Setiap agen memiliki peran tertentu dan meneruskan konteks ke agen berikutnya. Berikut adalah diagram arsitektur untuk sistem multi-agen.

agent_diagram

1. Buka File Agen

👉💻 Di terminal, buka file di Cloud Shell Editor:

cloudshell edit ~/way-back-home/level_2/backend/agent/multimedia_agent.py

2. Menentukan Agen Upload

Agen ini mengekstrak jalur file dari pesan pengguna dan menguploadnya ke GCS.

👉Di file multimedia_agent.py, temukan komentar # TODO: REPLACE_UPLOAD_AGENT.

Ganti seluruh baris ini dengan kode berikut:

upload_agent = LlmAgent(
    name="UploadAgent",
    model="gemini-2.5-flash",
    instruction="""Extract the file path from the user's message and upload it.

Use `upload_media(file_path, survivor_id)` to upload the file.
The survivor_id is optional - include it if the user mentions a specific survivor (e.g., "survivor Sarah" -> "Sarah").
If the user provides a path like "/path/to/file", use that.

Return the upload result with gcs_uri and media_type.""",
    tools=[upload_media],
    output_key="upload_result"
)

3. Menentukan Agen Ekstraksi

Agen ini "melihat" media yang diupload dan mengekstrak data terstruktur menggunakan Gemini Vision.

👉Di file multimedia_agent.py, temukan komentar # TODO: REPLACE_EXTRACT_AGENT.

Ganti seluruh baris ini dengan kode berikut:

extraction_agent = LlmAgent(
    name="ExtractionAgent", 
    model="gemini-2.5-flash",
    instruction="""Extract information from the uploaded media.

Previous step result: {upload_result}

Use `extract_from_media(gcs_uri, media_type, signed_url)` with the values from the upload result.
The gcs_uri is in upload_result['gcs_uri'], media_type in upload_result['media_type'], and signed_url in upload_result['signed_url'].

Return the extraction results including entities and relationships found.""",
    tools=[extract_from_media],
    output_key="extraction_result"
)

Perhatikan cara instruction mereferensikan {upload_result} — ini adalah cara status diteruskan antar-agen di ADK.

4. Menentukan Agen Spanner

Agen ini menyimpan entity dan hubungan yang diekstrak ke database grafik.

👉Di file multimedia_agent.py, temukan komentar # TODO: REPLACE_SPANNER_AGENT.

Ganti seluruh baris ini dengan kode berikut:

spanner_agent = LlmAgent(
    name="SpannerAgent",
    model="gemini-2.5-flash", 
    instruction="""Save the extracted information to the database.

Upload result: {upload_result}
Extraction result: {extraction_result}

Use `save_to_spanner(extraction_result, survivor_id)` to save to Spanner.
Pass the WHOLE `extraction_result` object/dict from the previous step.
Include survivor_id if it was provided in the upload step.

Return the save statistics.""",
    tools=[save_to_spanner],
    output_key="spanner_result"
)

Agen ini menerima konteks dari kedua langkah sebelumnya (upload_result dan extraction_result).

5. Menentukan Agen Ringkasan

Agen ini menyintesis hasil dari semua langkah sebelumnya menjadi respons yang mudah dipahami pengguna.

👉Di file multimedia_agent.py, temukan komentar summary_instruction="" # TODO: REPLACE_SUMMARY_AGENT_PROMPT.

Ganti seluruh baris ini dengan kode berikut:

USE_MEMORY_BANK = os.getenv("USE_MEMORY_BANK", "false").lower() == "true"
save_msg = "6. Mention that the data is also being synced to the memory bank." if USE_MEMORY_BANK else ""

summary_instruction = f"""Provide a user-friendly summary of the media processing.

Upload: {{upload_result}}
Extraction: {{extraction_result}}
Database: {{spanner_result}}

Summarize:
1. What file was processed (name and type)
2. Key information extracted (survivors, skills, needs, resources found) - list names and counts
3. Relationships identified
4. What was saved to the database (broadcast ID, number of entities)
5. Any issues encountered
{save_msg}

Be concise but informative."""

Agen ini tidak memerlukan alat — agen ini hanya membaca konteks yang dibagikan dan membuat ringkasan yang jelas untuk pengguna.

🧠 Ringkasan Arsitektur

Lapisan

File

Tanggung jawab

Alat

extraction_tools.py + gcs_service.py

Cara — Upload, ekstrak, simpan

Agent

multimedia_agent.py

Apa — Mengorkestrasikan pipeline

11. Pipeline Data Multimodal — Orkestrasi

Inti dari sistem baru kami adalah MultimediaExtractionPipeline yang ditentukan dalam backend/agent/multimedia_agent.py. Agen ini menggunakan pola Sequential Agent dari ADK (Agent Development Kit).

1. Mengapa Berurutan?

Memproses upload adalah rantai dependensi linear:

  1. Anda tidak dapat mengekstrak data hingga Anda memiliki file (Upload).
  2. Anda tidak dapat menyimpan data hingga Anda mengekstraknya (Ekstraksi).
  3. Anda tidak dapat membuat ringkasan sebelum mendapatkan hasilnya (Simpan).

SequentialAgent sangat cocok untuk hal ini. Output satu agen diteruskan sebagai konteks/input ke agen berikutnya.

2. Definisi Agen

Mari kita lihat cara merakit pipeline di bagian bawah multimedia_agent.py: 👉💻 Di terminal, buka file di Cloud Shell Editor dengan menjalankan:

cloudshell edit ~/way-back-home/level_2/backend/agent/multimedia_agent.py

Langkah ini menerima input dari kedua langkah sebelumnya. Cari komentar # TODO: REPLACE_ORCHESTRATION. Ganti seluruh baris ini dengan kode berikut:

    sub_agents=[upload_agent, extraction_agent, spanner_agent, summary_agent]

3. Terhubung dengan Agen Root

👉💻 Di terminal, buka file di Cloud Shell Editor dengan menjalankan:

cloudshell edit ~/way-back-home/level_2/backend/agent/agent.py

Cari komentar # TODO: REPLACE_ADD_SUBAGENT. Ganti seluruh baris ini dengan kode berikut:

    sub_agents=[multimedia_agent],

Satu objek ini secara efektif menggabungkan empat "pakar" menjadi satu entitas yang dapat dipanggil.

4. Aliran Data Antar-Agen

Setiap agen menyimpan outputnya dalam konteks bersama yang dapat diakses oleh agen berikutnya:

architecture_uploading

5. Buka aplikasi (lewati jika aplikasi masih berjalan)

👉💻 Mulai Aplikasi:

cd ~/way-back-home/level_2/
./start_app.sh

👉 Klik Local: http://localhost:5173/ dari terminal.

6. Pengujian Upload Gambar

👉 Di antarmuka chat, pilih salah satu foto di sini dan upload ke UI:

Di antarmuka chat, beri tahu agen tentang konteks spesifik Anda:

Here is the survivor note

Kemudian, lampirkan gambar di sini.

upload_input

upload_result

👉💻 Di terminal, setelah Anda selesai menguji, tekan "Ctrl+C" untuk mengakhiri proses.

6. Memverifikasi Upload Multimodal di Bucket GCS

gcs

  • Pilih bucket Anda, lalu klik media.

media

  • Lihat gambar yang Anda upload di sini. uploaded_img

7. Memverifikasi Upload Multimodal di Spanner (Opsional)

Di bawah ini adalah contoh output di UI untuk test_photo1.

  • Buka Google Cloud Console Spanner.
  • Pilih instance Anda: Survivor Network
  • Pilih database Anda: graph-db
  • Di sidebar kiri, klik Spanner Studio

👉 Di Spanner Studio, buat kueri data baru:

SELECT 
  s.name AS Survivor,
  s.role AS Role,
  b.name AS Biome,
  r.name AS FoundResource,
  s.created_at
FROM Survivors s
LEFT JOIN SurvivorInBiome sib ON s.survivor_id = sib.survivor_id
LEFT JOIN Biomes b ON sib.biome_id = b.biome_id
LEFT JOIN SurvivorFoundResource sfr ON s.survivor_id = sfr.survivor_id
LEFT JOIN Resources r ON sfr.resource_id = r.resource_id
ORDER BY s.created_at DESC;

Kita dapat memverifikasinya dengan melihat hasil di bawah:

spanner_verify

12. Memory Bank dengan Agent Engine

1. Cara Kerja Memori

Sistem ini menggunakan pendekatan memori ganda untuk menangani konteks langsung dan pembelajaran jangka panjang.

memory_bank

2. Apa yang dimaksud dengan Topik Memori?

Topik Memori menentukan kategori informasi yang harus diingat agen di seluruh percakapan. Anggap saja seperti lemari arsip untuk berbagai jenis preferensi pengguna.

2 Topik Kami:

  1. search_preferences: Cara pengguna melakukan penelusuran
    • Apakah mereka lebih memilih penelusuran kata kunci atau semantik?
    • Keterampilan/bioma apa yang sering mereka cari?
    • Contoh memori: "Pengguna lebih memilih penelusuran semantik untuk keterampilan medis"
  2. urgent_needs_context: Krisis yang mereka pantau
    • Resource apa yang mereka pantau?
    • Korban selamat mana yang mereka khawatirkan?
    • Contoh memori: "Pengguna melacak kekurangan obat di Northern Camp"

3. Menyiapkan Topik Kenangan

Topik memori kustom menentukan apa yang harus diingat oleh agen. Setelan ini dikonfigurasi saat men-deploy Agent Engine.

👉💻 Di terminal, buka file di Cloud Shell Editor dengan menjalankan:

cloudshell edit ~/way-back-home/level_2/backend/deploy_agent.py

Tindakan ini akan membuka ~/way-back-home/level_2/backend/deploy_agent.py di editor Anda.

Kita menentukan objek struktur MemoryTopic untuk memandu LLM tentang informasi yang akan diekstrak dan disimpan.

👉Di file deploy_agent.py, ganti # TODO: SET_UP_TOPIC dengan kode berikut:

# backend/deploy_agent.py

    custom_topics = [
        # Topic 1: Survivor Search Preferences
        MemoryTopic(
            custom_memory_topic=CustomMemoryTopic(
                label="search_preferences",
                description="""Extract the user's preferences for how they search for survivors. Include:
                - Preferred search methods (keyword, semantic, direct lookup)
                - Common filters used (biome, role, status)
                - Specific skills they value or frequently look for
                - Geographic areas of interest (e.g., "forest biome", "mountain outpost")
                
                Example: "User prefers semantic search for finding similar skills."
                Example: "User frequently checks for survivors in the Swamp Biome."
                """,
            )
        ),
        # Topic 2: Urgent Needs Context
        MemoryTopic(
            custom_memory_topic=CustomMemoryTopic(
                label="urgent_needs_context",
                description="""Track the user's focus on urgent needs and resource shortages. Include:
                - Specific resources they are monitoring (food, medicine, ammo)
                - Critical situations they are tracking
                - Survivors they are particularly concerned about
                
                Example: "User is monitoring the medicine shortage in the Northern Camp."
                Example: "User is looking for a doctor for the injured survivors."
                """,
            )
        )
    ]

4. Integrasi Agen

Kode agen harus mengetahui Bank Memori untuk menyimpan dan mengambil informasi.

👉💻 Di terminal, buka file di Cloud Shell Editor dengan menjalankan:

cloudshell edit ~/way-back-home/level_2/backend/agent/agent.py

Tindakan ini akan membuka ~/way-back-home/level_2/backend/agent/agent.py di editor Anda.

Pembuatan Agen

Saat membuat agen, kita meneruskan after_agent_callback untuk memastikan sesi disimpan ke memori setelah interaksi. Fungsi add_session_to_memory berjalan secara asinkron untuk menghindari perlambatan respons chat.

👉Di file agent.py, cari komentar # TODO: REPLACE_ADD_SESSION_MEMORY, Replace this whole line dengan kode berikut:

async def add_session_to_memory(
        callback_context: CallbackContext
) -> Optional[types.Content]:
    """Automatically save completed sessions to memory bank in the background"""
    if hasattr(callback_context, "_invocation_context"):
        invocation_context = callback_context._invocation_context
        if invocation_context.memory_service:
            # Use create_task to run this in the background without blocking the response
            asyncio.create_task(
                invocation_context.memory_service.add_session_to_memory(
                    invocation_context.session
                )
            )
            logger.info("Scheduled session save to memory bank in background")

Penyimpanan Latar Belakang

👉Di file agent.py, cari komentar # TODO: REPLACE_ADD_MEMORY_BANK_TOOL, Replace this whole line dengan kode berikut:

if USE_MEMORY_BANK:
    agent_tools.append(PreloadMemoryTool())

👉Di file agent.py, cari komentar # TODO: REPLACE_ADD_CALLBACK, Replace this whole line dengan kode berikut:

    after_agent_callback=add_session_to_memory if USE_MEMORY_BANK else None

Menyiapkan Layanan Sesi Vertex AI

👉💻 Di terminal, buka file chat.py di Cloud Shell Editor dengan menjalankan:

cloudshell edit ~/way-back-home/level_2/backend/api/routes/chat.py

👉Di file chat.py, cari komentar # TODO: REPLACE_VERTEXAI_SERVICES, Ganti seluruh baris ini dengan kode berikut:

    session_service = VertexAiSessionService(
        project=project_id,
        location=location,
        agent_engine_id=agent_engine_id
    )
    memory_service = VertexAiMemoryBankService(
        project=project_id,
        location=location,
        agent_engine_id=agent_engine_id
    )

4. Penyiapan & Penerapan

Sebelum menguji fitur memori, Anda perlu men-deploy agen dengan topik memori baru dan memastikan lingkungan Anda dikonfigurasi dengan benar.

Kami telah menyediakan skrip praktis untuk menangani proses ini.

Menjalankan Skrip Deployment

👉💻 Di terminal, jalankan skrip deployment:

cd ~/way-back-home/level_2
./deploy_and_update_env.sh

Skrip ini melakukan tindakan berikut:

  • Menjalankan backend/deploy_agent.py untuk mendaftarkan topik agen dan memori dengan Vertex AI.
  • Mencatat ID Agent Engine baru.
  • Secara otomatis memperbarui file .env Anda dengan AGENT_ENGINE_ID.
  • Memastikan USE_MEMORY_BANK=TRUE ditetapkan di file .env Anda.

[!IMPORTANT] Jika Anda melakukan perubahan pada custom_topics di deploy_agent.py, Anda harus menjalankan kembali skrip ini untuk memperbarui Agent Engine.

13. Memverifikasi Bank Memori dengan Data Multimodal

Anda dapat memverifikasi bahwa bank memori berfungsi dengan mengajari agen preferensi dan memeriksa apakah preferensi tersebut tetap ada di seluruh sesi.

1. Buka aplikasi (Lewati langkah ini jika aplikasi Anda sudah berjalan)

Buka kembali Aplikasi dengan mengikuti petunjuk di bawah: Jika terminal sebelumnya masih berjalan, akhiri dengan menekan Ctrls+C.

👉💻 Mulai Aplikasi:

cd ~/way-back-home/level_2/
./start_app.sh

👉 Klik Local: http://localhost:5173/ dari terminal.

2. Menguji Bank Memori dengan Teks

Di antarmuka chat, beri tahu agen tentang konteks spesifik Anda:

"I'm planning a medical rescue mission in the mountains. I need survivors with first aid and climbing skills."

👉 Tunggu ~30 detik agar memori diproses di latar belakang.

2. Mulai Sesi Baru

Muat ulang halaman untuk menghapus histori percakapan saat ini (memori jangka pendek).

Ajukan pertanyaan yang mengandalkan konteks yang Anda berikan sebelumnya:

"What kind of missions am I interested in?"

Respons yang Diharapkan:

"Berdasarkan percakapan Anda sebelumnya, Anda tertarik dengan:

  • Misi penyelamatan medis
  • Operasi di pegunungan/ketinggian
  • Keterampilan yang diperlukan: pertolongan pertama, panjat tebing

Apakah Anda ingin saya menemukan korban selamat yang cocok dengan kriteria ini?"

3. Menguji dengan Upload Gambar

Upload gambar, lalu tanyakan:

remember this

Anda dapat memilih salah satu foto di sini atau foto Anda sendiri dan menguploadnya ke UI:

4. Verifikasi di Vertex AI Agent Engine

Buka Google Cloud Console Agent Engine

  1. Pastikan Anda memilih project dari pemilih project di kiri atas:pemilih project
  2. Verifikasi mesin agen yang baru saja Anda deploy dari perintah sebelumnya use_memory_bank.sh:agent engineKlik mesin agen yang baru saja Anda buat.
  3. Klik Tab Memories di agen yang di-deploy ini, Anda dapat melihat semua memori di sini.melihat kenangan

👉💻 Setelah Anda selesai menguji, di terminal, klik "Ctrl + C" untuk mengakhiri proses.

🎉 Selamat! Anda baru saja melampirkan bank memori ke agen Anda.

14. Men-deploy ke Cloud Run

1. Jalankan Skrip Deployment

👉💻 Jalankan skrip deployment:

cd ~/way-back-home/level_2
./deploy_cloud_run.sh

Setelah berhasil di-deploy, Anda akan memiliki URL, ini adalah URL yang di-deploy untuk Anda. di-deploy

👉💻 Sebelum Anda menyalin URL, berikan izin dengan menjalankan:

source .env && gcloud run services add-iam-policy-binding survivor-frontend --region $REGION --member=allUsers --role=roles/run.invoker && gcloud run services add-iam-policy-binding survivor-backend --region $REGION --member=allUsers --role=roles/run.invoker

Buka URL yang di-deploy, dan Anda akan melihat aplikasi Anda aktif di sana.

2. Memahami Pipeline Build

File cloudbuild.yaml menentukan langkah-langkah berurutan berikut:

  1. Backend Build: Membangun image Docker dari backend/Dockerfile.
  2. Backend Deploy: Men-deploy container backend ke Cloud Run.
  3. Capture URL: Mendapatkan URL Backend baru.
  4. Frontend Build:
    • Menginstal dependensi.
    • Membangun aplikasi React, menyuntikkan VITE_API_URL=.
  5. Frontend Image: Membangun image Docker dari frontend/Dockerfile (mengemas aset statis).
  6. Frontend Deploy: Men-deploy container frontend.

3. Memverifikasi Deployment

Setelah build selesai (periksa link log yang disediakan oleh skrip), Anda dapat memverifikasi:

  1. Buka Konsol Cloud Run.
  2. Temukan layanan survivor-frontend.
  3. Klik URL untuk membuka aplikasi.
  4. Lakukan kueri penelusuran untuk memastikan frontend dapat berkomunikasi dengan backend.

4. (!KHUSUS PESERTA WORKSHOP) Memperbarui lokasi Anda

👉💻 Jalankan skrip penyelesaian:

cd ~/way-back-home/level_2
./set_level_2.sh

Sekarang buka waybackhome.dev, dan Anda akan melihat lokasi Anda telah diperbarui. Selamat Anda telah menyelesaikan level 2!

hasil akhir

(OPSIONAL) 5. Deployment Manual

Jika Anda lebih suka menjalankan perintah secara manual atau memahami prosesnya dengan lebih baik, berikut cara menggunakan cloudbuild.yaml secara langsung.

Menulis cloudbuild.yaml

File cloudbuild.yaml memberi tahu Google Cloud Build langkah-langkah yang harus dijalankan.

  • langkah: Daftar tindakan berurutan. Setiap langkah berjalan dalam container (misalnya, docker, gcloud, node, bash).
  • substitusi: Variabel yang dapat diteruskan pada waktu build (misalnya, $_REGION).
  • workspace: Direktori bersama tempat langkah-langkah dapat berbagi file (seperti cara kita berbagi backend_url.txt).

Menjalankan Deployment

Untuk men-deploy secara manual tanpa skrip, gunakan perintah gcloud builds submit. Anda HARUS meneruskan variabel substitusi yang diperlukan.

# Load your env vars first or replace these values manually
export PROJECT_ID=your-project-id
export REGION=us-central1

gcloud builds submit --config cloudbuild.yaml \
    --project "$PROJECT_ID" \
    --substitutions _REGION="us-central1",_GOOGLE_API_KEY="",_AGENT_ENGINE_ID="your-agent-id",_USE_MEMORY_BANK="TRUE",_GOOGLE_GENAI_USE_VERTEXAI="TRUE"

15. Kesimpulan

1. Yang Telah Anda Buat

Graph Database: Spanner dengan node (survivor, keterampilan) dan edge (hubungan)
AI Search: Penelusuran kata kunci, semantik, dan hybrid dengan penyematan
Multimodal Pipeline: Mengekstrak entitas dari gambar/video dengan Gemini
Multi-Agent System: Alur kerja terkoordinasi dengan ADK
Memory Bank: Personalisasi jangka panjang dengan Vertex AI
Production Deployment: Cloud Run + Agent Engine

2. Ringkasan Arsitektur

architecture_fullstack

3. Pelajaran Penting

  1. Graph RAG: Menggabungkan struktur database grafik dengan embedding semantik untuk penelusuran cerdas
  2. Pola Multi-Agen: Pipeline berurutan untuk alur kerja multilangkah yang kompleks
  3. AI Multimodal: Mengekstrak data terstruktur dari media tidak terstruktur (gambar/video)
  4. Agen Stateful: Bank Memori memungkinkan personalisasi di seluruh sesi

4. Konten Workshop

5. Resource