Way Back Home - Sistem Multi-Agen Dua Arah Live

1. Misi

Story

Anda terombang-ambing di hamparan ruang angkasa yang sunyi dan belum dipetakan. Pulsa Solar yang sangat besar telah merobek kapal Anda melalui celah dimensi, membuat Anda terdampar di saku alam semesta tanpa peta bintang.

Setelah berhari-hari melakukan perbaikan yang melelahkan, deru mesin yang sudah tidak asing akhirnya kembali terdengar. Roket Anda sudah siap digunakan. Anda bahkan berhasil membuat uplink jarak jauh ke Mothership. Keberangkatan sudah dekat. Anda siap pulang.

Namun, saat Anda bersiap untuk menggunakan flash drive, sinyal bahaya menembus suara statis. Sensor Anda mendeteksi permintaan bantuan dari planet yang ditetapkan sebagai "Ozymandias". Para penyintas terperangkap di dunia yang sekarat ini, dan kapal mereka terdampar. Misi Anda sangat penting: selamatkan mereka sebelum atmosfer planet runtuh.

Satu-satunya cara mereka untuk melarikan diri adalah dengan roket kuno yang sudah rusak dan dibangun dengan Teknologi Alien. Meskipun berfungsi, Warp Drive-nya hancur. Untuk menyelamatkan para penyintas, Anda harus terhubung dari jarak jauh ke Volatile Workbench mereka dan merakit drive pengganti secara manual.

Tantangan

Anda tidak memiliki pengalaman dengan teknologi alien ini, yang terkenal rapuh. Komponen yang tidak stabil dapat menjadi bahaya radioaktif dalam hitungan detik. Anda memiliki satu kesempatan untuk mengoperasikan Volatile Workbench. Asisten AI Anda saat ini kesulitan memproses data visual dan manual teknis secara bersamaan, sehingga menghasilkan petunjuk yang tidak akurat dan peringatan bahaya yang terlewat.

Agar berhasil, Anda harus mengupgrade AI dari entitas monolitik menjadi Sistem multi-agen kolaboratif.

Tujuan Misi Anda:

Rakit Warp Drive dengan mengikuti petunjuk real-time khusus dari sistem multi-agen baru Anda.

Mission Alpha

Yang akan Anda bangun

Ringkasan

  • Sistem AI multi-agen dua arah real-time yang menampilkan Agen Pengiriman pusat yang mengelola interaksi pengguna dan berkoordinasi dengan agen khusus.
  • Agen Arsitek yang terhubung ke database Redis untuk mengambil dan menyajikan data skematik.
  • Monitor Keselamatan proaktif yang menggunakan alat streaming untuk menganalisis feed video live guna mendeteksi bahaya visual dan memicu pemberitahuan real-time.
  • Frontend berbasis React yang menyediakan antarmuka pengguna untuk berinteraksi dengan sistem, melakukan streaming video dan audio ke agen backend.

Yang akan Anda pelajari

Teknologi / Konsep

Deskripsi

Google Agent Development Kit (ADK)

Anda akan menggunakan ADK untuk membangun, menguji, dan mengelola agen, dengan memanfaatkan framework-nya untuk menangani komunikasi real-time, integrasi alat, dan siklus proses agen.

Streaming Bidireksional (Bidi)

Anda akan menerapkan agen streaming dua arah yang memungkinkan komunikasi dua arah yang natural dan berlatensi rendah, sehingga manusia dan AI dapat menyela dan merespons secara real-time.

Sistem Multiagen

Anda akan mempelajari cara mendesain sistem AI terdistribusi di mana agen utama mendelegasikan tugas ke agen khusus, sehingga memungkinkan pemisahan masalah dan arsitektur yang lebih skalabel.

Protokol Agent-to-Agent (A2A)

Anda akan menggunakan protokol A2A untuk mengaktifkan komunikasi antara Agen Pengiriman dan Agen Arsitek, sehingga mereka dapat menemukan kemampuan masing-masing dan bertukar data.

Alat Streaming

Anda akan menerapkan alat streaming yang bertindak sebagai proses latar belakang, yang terus-menerus menganalisis feed video untuk memantau perubahan status (bahaya) dan secara proaktif memberikan hasil.

Google Cloud Run & Memorystore

Anda akan men-deploy seluruh aplikasi multi-agen ke lingkungan produksi, menggunakan Cloud Run untuk menghosting layanan agen dan Memorystore (Redis) sebagai database persisten.

FastAPI & WebSockets

Backend dibangun menggunakan FastAPI dan WebSockets untuk menangani komunikasi real-time berperforma tinggi yang diperlukan untuk streaming audio, video, dan respons agen.

Frontend React

Anda akan bekerja dengan frontend berbasis React yang merekam dan melakukan streaming media pengguna (audio/video) serta menampilkan respons real-time dari agen AI.

2. Menyiapkan Lingkungan Anda

Mengakses Cloud Shell

👉Klik Activate Cloud Shell di bagian atas konsol Google Cloud (Ikon berbentuk terminal di bagian atas panel Cloud Shell), cloud-shell.png

👉Klik tombol "Open 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. open-editor.png

👉Buka terminal di IDE cloud,

03-05-new-terminal.png

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

gcloud auth list

Anda akan melihat akun Anda tercantum sebagai (ACTIVE).

Prasyarat

ℹ️ Level 0 bersifat Opsional (Tetapi Direkomendasikan)

Anda dapat menyelesaikan misi ini tanpa Level 0, tetapi menyelesaikannya terlebih dahulu akan memberikan pengalaman yang lebih imersif, sehingga Anda dapat melihat suar Anda menyala di peta global saat Anda maju.

Menyiapkan Lingkungan Project

Kembali di terminal, selesaikan konfigurasi dengan menetapkan project aktif dan mengaktifkan layanan Google Cloud yang diperlukan (Cloud Run, Vertex AI, dll.).

👉💻 Di terminal Anda, tetapkan Project ID:

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

👉💻 Aktifkan Layanan yang Diperlukan:

gcloud services enable  compute.googleapis.com \
                        artifactregistry.googleapis.com \
                        run.googleapis.com \
                        cloudbuild.googleapis.com \
                        iam.googleapis.com \
                        aiplatform.googleapis.com \
                        cloudresourcemanager.googleapis.com \
                        redis.googleapis.com \
                        vpcaccess.googleapis.com

Instal Dependensi

👉💻 Buka Level 4 dan instal paket Python yang diperlukan:

cd $HOME/way-back-home/level_4
uv sync

Ketergantungan utamanya adalah:

Paket

Tujuan

fastapi

Framework web berperforma tinggi untuk streaming SSE dan Stasiun Satelit

uvicorn

Server ASGI diperlukan untuk menjalankan aplikasi FastAPI

google-adk

Agent Development Kit yang digunakan untuk membangun Agen Formasi

a2a-sdk

Library protokol Agent-to-Agent untuk komunikasi standar

google-genai

Klien native untuk mengakses model Gemini

redis

Klien Python untuk terhubung ke Schematic Vault (Memorystore)

websockets

Dukungan untuk komunikasi dua arah real-time

python-dotenv

Mengelola variabel lingkungan dan secret konfigurasi

pydantic

Validasi data dan pengelolaan setelan

Verifikasi Penyiapan

Sebelum kita membahas kode, pastikan semua sistem berfungsi dengan baik. Jalankan skrip verifikasi untuk mengaudit Project Google Cloud, API, dan dependensi Python Anda.

👉💻 Jalankan Skrip Verifikasi:

cd $HOME/way-back-home/level_4/scripts
chmod +x verify_setup.sh
. verify_setup.sh

👀 Anda akan melihat serangkaian Centang Hijau (✅).

  • Jika Anda melihat Cross Merah (❌), ikuti perintah perbaikan yang disarankan dalam output (misalnya, gcloud services enable ... atau pip install ...).
  • Catatan: Peringatan kuning untuk .env dapat diterima untuk saat ini; kita akan membuat file tersebut di langkah berikutnya.
🚀 Verifying Mission Bravo (Level 4) Infrastructure...

✅ Google Cloud Project: xxxxxxx
✅ Cloud APIs: Active
✅ Python Environment: Ready

🎉 SYSTEMS ONLINE. READY FOR MISSION.

3. Membangun Schematic Vault di Redis dan Agen BiDireksional dengan ADK

Anda telah menemukan repositori skema planet yang berisi cetak biru roket terlantar. Untuk mengambil data ini secara akurat, Anda harus berinteraksi dengan antarmuka pengelolaan khusus repositori: agen Architect.

Ringkasan

Menyediakan Vault Skema (Redis)

Sebelum Arsitek dapat membantu kami, kami harus memastikan data dihosting di lingkungan yang aman dan memiliki ketersediaan tinggi. Kita akan menggunakan Redis sebagai penyimpanan data cepat untuk skema alien kita. Untuk kemudahan pengembangan, kita akan menjalankan instance Redis lokal, tetapi petunjuk tentang cara men-deploy ke lingkungan produksi dengan Google Cloud Memorystore akan diberikan nanti.

👉💻 Jalankan perintah berikut di terminal Anda untuk menyediakan instance Redis (Proses ini dapat memakan waktu 2-3 menit):

docker run -d --name ozymandias-vault -p 6379:6379 redis:8.6-rc1-alpine

👉💻 Untuk memuat data awal, jalankan perintah berikut untuk masuk ke Redis Shell:

docker exec -it ozymandias-vault redis-cli

(Perintah Anda akan berubah menjadi 127.0.0.1:6379)

👉💻 Tempelkan perintah ini di dalamnya:

RPUSH "HYPERION-X" "Warp Core" "Flux Pipe" "Ion Thruster"
RPUSH "NOVA-V" "Ion Thruster" "Warp Core" "Flux Pipe"
RPUSH "OMEGA-9" "Flux Pipe" "Ion Thruster" "Warp Core"
RPUSH "GEMINI-MK1" "Coolant Tank" "Servo" "Fuel Cell"
RPUSH "APOLLO-13" "Warp Core" "Coolant Tank" "Ion Thruster"
RPUSH "VORTEX-7" "Quantum Cell" "Graviton Coil" "Plasma Injector"
RPUSH "CHRONOS-ALPHA" "Shield Emitter" "Data Crystal" "Quantum Cell"
RPUSH "NEBULA-Z" "Plasma Injector" "Flux Pipe" "Graviton Coil"
RPUSH "PULSAR-B" "Data Crystal" "Servo" "Shield Emitter"
RPUSH "TITAN-PRIME" "Ion Thruster" "Quantum Cell" "Warp Core"

👉💻 Ketik exit untuk kembali ke shell normal Anda.

👉💻 Untuk memeriksa apakah data ada dengan mengkueri kapal tertentu langsung dari terminal, jalankan:

# Check 'TITAN-PRIME'
docker exec ozymandias-vault redis-cli LRANGE "TITAN-PRIME" 0 -1

👀 Berikut adalah output yang diharapkan:

1) "Ion Thruster"
2) "Quantum Cell"
3) "Warp Core"

Mengimplementasikan Architect Agent

Architect Agent adalah agen khusus yang bertanggung jawab untuk mengambil cetak biru skematik dari vault Redis kami. API ini bertindak sebagai antarmuka data khusus, yang memastikan bahwa Agen Pengiriman utama menerima informasi yang akurat dan terstruktur tanpa perlu mengetahui logika database yang mendasarinya.

Ringkasan

Google Agent Development Kit (ADK) adalah framework modular yang memungkinkan penyiapan multi-agen ini. Platform ini menangani dua lapisan penting:

  1. Siklus Proses Koneksi & Sesi: Berinteraksi dengan API real-time memerlukan pengelolaan protokol yang kompleks—menangani handshake, autentikasi, dan sinyal tetap aktif.
  2. Panggilan Fungsi: Ini adalah "Perjalanan Pulang Pergi Model-Kode-Model". Saat LLM memutuskan bahwa ia memerlukan data, LLM akan menghasilkan panggilan fungsi terstruktur. ADK mencegat hal ini, menjalankan kode Python Anda (lookup_schematic_tool), dan memasukkan kembali hasilnya ke dalam konteks model dalam milidetik.

Sekarang kita akan membangun Architect. Agen ini tidak memiliki akses kamera. Fungsi ini hanya ada untuk menerima "Nama Drive" dan menampilkan "Daftar Komponen" dari database.

👉💻 Kita akan menggunakan perintah adk create. Ini adalah alat dari Agent Development Kit (ADK) yang otomatis membuat kode boilerplate dan struktur file untuk agen baru, sehingga menghemat waktu penyiapan.

cd $HOME/way-back-home/level_4/backend/
uv run adk create architect_agent

Mengonfigurasi Agen

CLI akan meluncurkan wizard penyiapan interaktif. Gunakan respons berikut untuk mengonfigurasi agen Anda:

  1. Pilih model: Pilih Opsi 1 (Gemini Flash).
    • Catatan: Versi tertentu (misalnya, 2.5, 3.0) dapat bervariasi berdasarkan ketersediaan. Selalu pilih varian "Flash" untuk kecepatan.
  2. Pilih backend: Pilih Opsi 2 (Vertex AI).
  3. Masukkan Project ID Google Cloud: Tekan Enter untuk menerima default (terdeteksi dari lingkungan Anda).
  4. Enter Google Cloud Region: Tekan Enter untuk menerima default (us-central1).

👀 Interaksi terminal Anda akan terlihat seperti ini:

(way-back-home) user@cloudshell:~/way-back-home/level_4/agent$ adk create architect_agent

Choose a model for the root agent:
1. gemini-2.5-flash
2. Other models (fill later)
Choose model (1, 2): 1

1. Google AI
2. Vertex AI
Choose a backend (1, 2): 2

You need an existing Google Cloud account and project...
Enter Google Cloud project ID [your-project-id]: <PRESS ENTER>
Enter Google Cloud region [us-central1]: <PRESS ENTER>

Agent created in /home/user/way-back-home/level_4/agent/architect_agent:
- .env
- __init__.py
- agent.py

Sekarang Anda akan melihat pesan keberhasilan Agent created. Tindakan ini akan menghasilkan kode kerangka yang akan kita ubah pada langkah berikutnya.

👉✏️ Buka dan buka file $HOME/way-back-home/level_4/backend/architect_agent/agent.py yang baru dibuat di editor Anda. Tambahkan cuplikan alat ke file setelah baris impor pertama:

import os
import redis

REDIS_IP = os.environ.get('REDIS_HOST', 'localhost')
r = redis.Redis(host=REDIS_IP, port=6379, decode_responses=True)

def lookup_schematic_tool(drive_name: str) -> list[str]:
    """Returns the ordered list of parts for a drive from local Redis."""
    
    # Logic to clean input like "TARGET: X" -> "X"
    clean_name = drive_name.replace("TARGET:", "").replace("TARGET", "").strip()
    clean_name = clean_name.replace(":", "").strip()
    
    # LRANGE gets all items in the list (index 0 to -1)
    result = r.lrange(clean_name, 0, -1)
    
    if not result:
        print(f"[ARCHITECT] Error: Drive ID '{clean_name}' not found in Redis.")
        return ["ERROR: Drive ID not found."]
    
    print(f"[ARCHITECT] Returning schematic for {clean_name}: {result}")
    return result

👉✏️ Ganti seluruh baris instruction dalam definisi root_agent dengan kode berikut dan tambahkan juga alat yang telah kita tentukan sebelumnya:

    instruction='''SYSTEM ROLE: Database API.
    INPUT: Text string (Drive Name).
    TASK: Run `lookup_schematic_tool`.
    OUTPUT: Return ONLY the raw list from the tool.
    CONSTRAINT: Do NOT add conversational text.
    ''',
    tools=[lookup_schematic_tool],

Keunggulan ADK

Dengan tersedianya Architect secara online, kita kini memiliki sumber tepercaya. Sebelum kita menghubungkannya ke agen utama,Agent Development Kit (ADK) memberikan keuntungan yang signifikan dengan menyederhanakan kompleksitas pembangunan dan pengujian agen AI. Dengan konsol developer adk web bawaannya, kita dapat mengisolasi dan memverifikasi fungsi Architect Agent, khususnya kemampuan pemanggilan alatnya, sebelum mengintegrasikannya ke dalam sistem multi-agen yang lebih besar. Pendekatan modular untuk pengembangan dan pengujian ini sangat penting untuk membangun aplikasi AI yang tangguh dan andal.

👉💻 Di terminal Anda, jalankan:

cd $HOME/way-back-home/level_4/
. scripts/check_redis.sh
cd $HOME/way-back-home/level_4/backend/
uv run adk web

👀 Tunggu hingga Anda melihat:

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

INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
  • Klik ikon Web preview di toolbar Cloud Shell. Pilih Ubah port, tetapkan ke 8000, lalu klik Ubah dan Pratinjau. *Pratinjau Web
  • Pilih architect_agent.
  • Memicu Alat: Di antarmuka chat, ketik: CHRONOS-ALPHA (atau ID Drive apa pun dari database skema).
  • Mengamati Perilaku:
    • Arsitek harus segera memicu lookup_schematic_tool.
    • Karena petunjuk sistem kami yang ketat, model ini hanya akan menampilkan daftar suku cadang (misalnya, ['Shield Emitter', 'Data Crystal', 'Quantum Cell']) tanpa kata pengisi percakapan.
  • Verifikasi Log: Lihat jendela terminal Anda. Anda akan melihat log eksekusi yang berhasil: [ARCHITECT] Returning schematic for CHRONOS-ALPHA: ['Shield Emitter', 'Data Crystal', 'Quantum Cell'] !(architect_agent adk)[img/03-02-adkweb.png]

Jika Anda melihat log eksekusi alat dan respons data bersih, agen spesialis Anda berfungsi sebagaimana mestinya. Layanan ini dapat memproses permintaan, membuat kueri vault, dan menampilkan data terstruktur.

👉💻 Tekan Ctrl+C untuk keluar.

Melakukan inisialisasi Server A2A

Untuk menghubungkan Agen Pengiriman ke Architect, kita menggunakan Protokol Agent-to-Agent (A2A).

Meskipun protokol seperti MCP (Model Context Protocol) berfokus pada menghubungkan agen ke alat, A2A berfokus pada menghubungkan agen ke agen lain. Ini adalah standar yang memungkinkan Dispatcher kami "menemukan" Architect dan memahami kemampuannya untuk mencari skema.

A2A

Alur A2A: Dalam misi ini, kita menggunakan model klien-server:

  1. Server (Arsitek): Menghosting alat database dan "mengiklankan" kemampuannya melalui Kartu Agen.
  2. Klien (Pengiriman): Membaca kartu Arsitek, memahami API-nya, dan mengirim permintaan skema.

Apa yang dimaksud dengan Kartu Agen?

Anggap Kartu Agen sebagai kartu nama digital atau "Surat Izin Mengemudi" untuk AI. Saat server A2A dimulai, server tersebut akan memublikasikan objek JSON ini yang berisi:

  • Identitas: Nama (architect_agent) dan ID agen.
  • Deskripsi: Ringkasan yang dapat dibaca manusia dan mesin tentang fungsinya ("Peran Sistem: Database API...").
  • Antarmuka: Kunci input (drive_name) dan format output tertentu yang diharapkan.

Tanpa kartu ini, agen Dispatch akan beroperasi tanpa mengetahui apa pun, menebak cara berkomunikasi dengan Architect.

Buat Kode Server

👉✏️ Di editor Anda, di direktori $HOME/way-back-home/level_4/backend/architect_agent, buat file bernama server.py, lalu tempelkan kode berikut:

from google.adk.a2a.utils.agent_to_a2a import to_a2a
from agent import root_agent
import os
import logging
import json
from dotenv import load_dotenv

load_dotenv()

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("architect_server")
HOST= os.environ.get("HOST_URL","localhost")
PROTOCOL= os.environ.get("PROTOCOL","http")
PORT= os.environ.get("A2A_PORT",8081)

# 1. Create the A2A App (Handles Agent Card & HTTP)
# This middleware automatically sets up the /a2a/v1/... endpoints
app = to_a2a(root_agent, host=HOST, port=PORT, protocol=PROTOCOL)

if __name__ == "__main__":
    import uvicorn
    # Use 0.0.0.0 to allow external access if needed, port 8080 as standard
    uvicorn.run(app, host='0.0.0.0', port=8081)

👉💻 Kembali di terminal Anda, buka folder dan mulai server:

cd $HOME/way-back-home/level_4/
. scripts/check_redis.sh
cd $HOME/way-back-home/level_4/backend/architect_agent
uv run server.py

👀 Konfirmasi apakah server A2A dimulai:

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

Memverifikasi Kartu Agen

Buka tab terminal baru (klik ikon +). Kita akan memverifikasi bahwa Architect menyiarkan identitasnya dengan benar dengan mengambil Kartu Agennya secara manual.

👉💻 Jalankan perintah berikut:

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

👀 Anda akan melihat respons JSON. Cari kolom description di output. Respons ini harus sesuai dengan petunjuk yang Anda berikan kepada agen sebelumnya ("SYSTEM ROLE: Database API...").

{
  "capabilities": {},
  "defaultInputModes": [
    "text/plain"
  ],
  "defaultOutputModes": [
    "text/plain"
  ],
  "description": "A helpful assistant for user questions.",
  "name": "root_agent",
  "preferredTransport": "JSONRPC",
  "protocolVersion": "0.3.0",
  "skills": [
    {
      "description": "A helpful assistant for user questions. SYSTEM ROLE: Database API.\n    INPUT: Text string (Drive Name).\n    TASK: Run `lookup_schematic_tool`.\n    OUTPUT: Return ONLY the raw list from the tool.\n    CONSTRAINT: Do NOT add conversational text.\n    ",
      "examples": [],
      "id": "root_agent",
      "name": "model",
      "tags": [
        "llm"
      ]
    },
    {
      "description": "Returns the ordered list of parts for a drive from local Redis.",
      "id": "root_agent-lookup_schematic_tool",
      "name": "lookup_schematic_tool",
      "tags": [
        "llm",
        "tools"
      ]
    }
  ],
  "supportsAuthenticatedExtendedCard": false,
  "url": "http://localhost:8081",
  "version": "0.0.1"
}

Jika Anda melihat JSON ini, berarti Architect sudah aktif, protokol A2A sudah aktif, dan Kartu Agen siap ditemukan oleh Dispatcher.

Setelah Architect siap digunakan sebagai resource jarak jauh, kita dapat melanjutkan untuk menghubungkannya ke Agen Pengiriman.

👉💻 Tekan Ctrl+C untuk keluar dari server A2A.

4. Menghubungkan Agen BIDI-Streams ke Agen Jarak Jauh dan Alat Streaming

Sekarang Anda akan mengonfigurasi hub komunikasi utama untuk menjembatani kesenjangan antara data langsung dan Arsitek jarak jauh. Koneksi ini memerlukan pipeline latensi rendah dan bandwidth tinggi untuk memastikan meja perakitan tetap stabil selama pengoperasian.

Memahami Agen Streaming Dua Arah (Live)

Streaming dua arah (Bidi) di ADK menambahkan kemampuan interaksi suara dan video dua arah latensi rendah dari Gemini Live API ke agen AI. Hal ini merepresentasikan perubahan mendasar dari interaksi AI tradisional. Alih-alih pola "tanya-dan-tunggu" yang kaku, pola ini memungkinkan komunikasi dua arah secara real-time di mana manusia dan AI dapat berbicara, mendengar, dan merespons secara bersamaan.

Pikirkan perbedaan antara mengirim email dan melakukan percakapan melalui telepon. Interaksi Agen Tradisional seperti email: Anda mengirim pesan lengkap, menunggu respons lengkap, lalu mengirim pesan lain. Streaming dua arah seperti percakapan telepon: lancar, alami, dengan kemampuan untuk menyela, mengklarifikasi, dan merespons secara real-time.

Karakteristik Utama:

  • Komunikasi Dua Arah: Pertukaran data berkelanjutan tanpa menunggu respons lengkap. AI akan merespons segera setelah mendeteksi bahwa pengguna telah selesai berbicara.
  • Interupsi Responsif: Pengguna dapat menginterupsi agen di tengah respons dengan input baru, seperti dalam percakapan manusia. Jika AI sedang menjelaskan langkah yang rumit dan Anda berkata, "Tunggu, ulangi," AI akan segera berhenti dan menanggapi interupsi Anda.
  • Dioptimalkan untuk Multimodalitas: Bidi-streaming unggul dalam memproses berbagai jenis input secara bersamaan. Anda dapat berbicara dengan agen sambil menunjukkan bagian alien melalui video, dan agen akan memproses kedua aliran dalam satu koneksi terpadu.

Lifecycle

👀 Sebelum menerapkan logika klien, mari kita periksa kerangka yang telah dibuat sebelumnya untuk Agen Pengiriman. Agen ini akan berkomunikasi dengan pengguna melalui suara dan video serta mendelegasikan kueri ke Architect Agent.

__init__.py
agent.py
hazard_db.py
  • agent.py: Ini adalah "Otak". Saat ini berisi penyiapan streaming Bidi dasar. Kita akan mengubah file ini untuk menambahkan logika A2A Client sehingga dapat berkomunikasi dengan Architect.
  • hazard_db.py: Ini adalah alat lokal khusus untuk Agen Pengiriman, yang berisi protokol keamanan. Database ini terpisah dari database skematik Arsitek.

Mengimplementasikan Klien A2A

Untuk mengizinkan Agen Pengiriman berkomunikasi dengan Arsitek jarak jauh kami, kita harus menentukan Agen A2A Jarak Jauh. Tindakan ini memberi tahu agen Dispatch tempat menemukan Architect dan tampilan "Kartu Agen"-nya.

Klien A2A

👉✏️ Ganti #REPLACE-REMOTEA2AAGENT di $HOME/way-back-home/level_4/backend/dispatch_agent/agent.py dengan kode berikut:

architect_agent = RemoteA2aAgent(
    name="execute_architect",
    description="[SILENT ACTION]: Retrieves the REQUIRED SUBSET of parts. The screen shows a full inventory; this tool filters out the wrong parts. Must be called INSTANTLY when a Target Name is found. Input: Target Name.",
    agent_card=(f"{ARCHITECT_URL}{AGENT_CARD_WELL_KNOWN_PATH}"),
    httpx_client=insecure_client,
)

Cara Kerja Alat Streaming

Dengan agen sebelumnya, alat mengikuti pola "Permintaan-Respons" standar, agen mengajukan pertanyaan, alat memberikan jawaban, dan interaksi berakhir. Namun, di Ozymandias, bahaya tidak menunggu Anda bertanya apakah ada bahaya atau tidak. Untuk melakukannya, Anda memerlukan Alat Streaming.

Alur Alat Streaming

Alat streaming memungkinkan fungsi untuk melakukan streaming hasil sementara kembali ke agen secara real-time, sehingga agen dapat bereaksi terhadap perubahan saat terjadi. Kasus penggunaan umum mencakup memantau fluktuasi harga saham atau, dalam kasus ini, memantau streaming video live untuk perubahan status.

Tidak seperti alat standar, alat streaming adalah Fungsi Asinkron yang bertindak sebagai AsyncGenerator. Artinya, bukan return-ing satu nilai, yield-ing beberapa pembaruan dari waktu ke waktu.

Untuk menentukan alat streaming di ADK, Anda harus mematuhi persyaratan teknis berikut:

  1. Fungsi Asinkron: Alat harus ditentukan dengan async def.
  2. Jenis Nilai yang Ditampilkan AsyncGenerator: Fungsi harus diketik untuk menampilkan AsyncGenerator. Parameter pertama adalah jenis data yang dihasilkan (misalnya, str), dan yang kedua biasanya None.
  3. Input Stream: Kami menggunakan Alat Streaming Video. Dalam mode ini, streaming video/audio sebenarnya (LiveRequestQueue) diteruskan langsung ke dalam fungsi, sehingga alat dapat "melihat" frame yang sama dengan yang dilihat agen.

Anggap alat streaming sebagai Sentinel. Saat Anda dan agen Dispatch sedang membahas cetak biru, sentinel berjalan di latar belakang, memproses setiap frame video secara diam-diam untuk memastikan keselamatan Anda.

Alat Streaming

Menerapkan Alat Pemantauan Latar Belakang

Sekarang kita akan menerapkan alat monitor_for_hazard. Alat ini akan memproses input_stream (frame video), menganalisisnya menggunakan panggilan visi ringan yang terpisah, dan yield peringatan hanya jika bahaya terdeteksi.

👉✏️ Di $HOME/way-back-home/level_4/backend/dispatch_agent/agent.py, ganti #REPLACE_MONITOR_HAZARD dengan logika berikut:

async def monitor_for_hazard(
    input_stream: LiveRequestQueue,
):
  """Monitor if any part is glowing"""
  print("start monitor_video_stream!")
  client = Client()
  prompt_text = (
      "Monitor the left menu if you see any glowing part, detect it's name"
  )
  last_count = None

  while True:
    last_valid_req = None
    print("Monitoring loop cycle")
    
    # use this loop to pull the latest images and discard the old ones
    # Process only the current batch of events
    while input_stream._queue.qsize() != 0:
      live_req = await input_stream.get()

      if live_req.blob is not None and live_req.blob.mime_type == "image/jpeg":
        # Consumed by Monitor (Eyes)
        # Deepcopy to ensure we detach from any referenced object before potential reuse/gc
        # last_valid_req = deepcopy(live_req)
        last_valid_req = live_req

    # If we found a valid image, process it
    if last_valid_req is not None:
      print("Processing the most recent frame from the queue")

      # Create an image part using the blob's data and mime type
      image_part = genai_types.Part.from_bytes(
          data=last_valid_req.blob.data, mime_type=last_valid_req.blob.mime_type
      )

      contents = genai_types.Content(
          role="user",
          parts=[image_part, genai_types.Part.from_text(text=prompt_text)],
      )


      # Call the model to generate content based on the provided image and prompt
      try:
          response = await client.aio.models.generate_content(
              model="gemini-2.5-flash",
              contents=contents,
              config=genai_types.GenerateContentConfig(
                  system_instruction=(
                      "Focus strictly on the far-left vertical column under the heading 'PARTS REPLICATOR.' "
                      "Ignore the center of the screen and the 'BLUEPRINT' area entirely. "
                      "Look only at the list containing"
                      "Identify if any item in this specific left-side list has a bright white border glow and the text 'HAZARD DETECTED' overlaying it. "
                      "If found, return ONLY the part name in ALL CAPS. If no part in that leftmost list is glowing, return nothing."
                  )
              ),
          )
      except Exception as e:
          print(f"Error calling Gemini: {e}")
          await asyncio.sleep(1)
          continue
      print("Gemini response received.response:", response.candidates[0].content.parts[0].text)

      current_text = response.candidates[0].content.parts[0].text.strip()
      
      # If we have a logical change (and it's not just empty)
      if current_text and current_text != last_count:
        # Ignore "Nothing." response from model
        if current_text == "Nothing." or "I cannot fulfill" in current_text:
            print(f"Model sees nothing or refused. Skipping alert.")
            last_count = current_text
            continue

        print(f"New hazard detected: {current_text} (was: {last_count})")
        last_count = current_text
        
        part_name = current_text
        color = lookup_part_safety(part_name)
        yield f"Hazard detected place {part_name} to the {color} bin"
      
      # Update last_count even if it's empty, so we can detect when it reappears? 
      # Actually if it goes from "DATA CRYSTAL" to "" (nothing), we probably just silence.
      # But if we don't update last_count on empty, we won't re-trigger if "DATA CRYSTAL" stays "DATA CRYSTAL".
      # The user wants to detect hazards. 
      # If current_text is empty, we should probably update last_count to empty so next valid one triggers.
      if not current_text:
          last_count = None
        
    else:
        print("No valid frame found, skipping processing.")
        
    await asyncio.sleep(5)

Mengimplementasikan Agen Pengiriman

Dispatch Agent adalah antarmuka utama dan pengelola Anda. Karena mengelola link streaming dua arah (suara dan video live Anda), aplikasi ini harus mempertahankan kontrol percakapan setiap saat. Untuk melakukannya, kita akan menggunakan fitur ADK tertentu: Agent-as-a-Tool.

Konsep: Agent-as-a-Tool vs. Sub-Agent

Saat membangun sistem multi-agen, Anda harus memutuskan cara berbagi tanggung jawab. Dalam misi penyelamatan kami, perbedaan ini sangat penting:

  • Agent-as-a-Tool: Ini adalah pendekatan yang direkomendasikan untuk hub streaming dua arah kami. Saat agen Pengiriman (Agen A) memanggil agen Arsitek (Agen B) sebagai alat, data Arsitek akan diteruskan kembali ke Pengiriman. Kemudian, Dispatch akan menafsirkan data tersebut dan membuat respons untuk Anda. Pengiriman tetap terkendali dan terus menangani semua input pengguna berikutnya.
  • Sub-Agen: Dalam hubungan sub-agen, tanggung jawab sepenuhnya dialihkan. Jika Dispatch mengalihkan Anda ke Architect sebagai sub-agen, Anda akan berbicara langsung dengan API database yang tidak memiliki "visi" dan tidak memiliki keterampilan percakapan. Agen utama (Pengiriman) tidak akan terlibat.

Kontrol

Dengan menggunakan Agent-as-a-Tool, kami memanfaatkan pengetahuan khusus Arsitek sekaligus mempertahankan interaksi yang lancar dan mirip manusia dari agen streaming dua arah.

Mengodekan Logika Pemilihan Rute

Sekarang kita akan menggabungkan architect_agent dalam AgentTool dan memberikan "Peta Logika" kepada agen Dispatch. Peta ini memberi tahu agen secara tepat kapan harus mengambil data dari brankas dan kapan harus melaporkan temuan dari sentinel latar belakang.

Untuk memberi Dispatch "mata" yang tidak pernah berkedip, kita harus memberinya akses ke Streaming Tool yang kita buat pada langkah sebelumnya.

Di ADK, saat Anda menambahkan fungsi AsyncGenerator (seperti monitor_for_hazard) ke daftar tools, agen akan memperlakukannya sebagai proses latar belakang yang persisten. Alih-alih eksekusi satu kali, agen "berlangganan" ke output alat. Hal ini memungkinkan Dispatch melanjutkan percakapan utamanya sementara Sentinel secara diam-diam memberikan peringatan bahaya di latar belakang.

👉✏️ Ganti #REPLACE_AGENT_TOOLS di $HOME/way-back-home/level_4/backend/dispatch_agent/agent.py dengan kode berikut:

tools=[AgentTool(agent=architect_agent), monitor_for_hazard],    

Verifikasi

👉💻 Setelah kedua agen dikonfigurasi, kita dapat menguji interaksi multi-agen langsung.

  • Di terminal A, mulai Architect Agent:
cd $HOME/way-back-home/level_4/
. scripts/check_redis.sh
cd $HOME/way-back-home/level_4/backend/architect_agent
uv run server.py
  • Di terminal baru (terminal B), jalankan Agen Pengiriman:
cd $HOME/way-back-home/level_4/backend/
cp architect_agent/.env .env
uv run adk web

Menguji sistem multi-agen yang menggunakan model multimodal real-time seperti gemini-live dalam simulator adk web melibatkan alur kerja tertentu. Simulator sangat baik untuk memeriksa panggilan alat, tetapi memiliki ketidakcocokan yang diketahui saat pertama kali memproses gambar dengan jenis model ini.

  • Klik ikon Web preview di toolbar Cloud Shell. Pilih Ubah port, tetapkan ke 8000, lalu klik Ubah dan Pratinjau.

👉Pilih dispatch_agent, lalu upload Blueprint dan Tangani Error yang Diharapkan

Ini adalah langkah yang paling penting. Kita perlu memberikan konteks gambar kepada agen.

  • Saat antarmuka dimuat, izinkan aplikasi mengakses mikrofon Anda saat diminta.
  • Download gambar cetak biru ini ke komputer Anda: Contoh Blueprint
  • Di antarmuka adk web, klik ikon klip kertas dan upload gambar cetak biru yang baru saja Anda download. Tambahkan file

⚠️⚠️Anda akan melihat error 400 INVALID_ARGUMENT. Hal ini sudah diperkirakan.⚠️⚠️

Pesan Error yang Diharapkan

Error ini terjadi karena handler gambar adk web tidak sepenuhnya kompatibel dengan API model gemini-live untuk upload satu kali. Namun, gambar telah berhasil ditambahkan ke konteks sesi.

  • 👉 Untuk menghapus error, cukup muat ulang halaman browser.

Memicu Proses Assembly

👉 Setelah dimuat ulang, error akan hilang, dan Anda akan melihat gambar cetak biru dalam histori chat. Sekarang agen memiliki konteks visual yang dibutuhkan.

  • Klik ikon mikrofon untuk mengaktifkannya. Antarmuka akan menampilkan "Mendengarkan...".
  • Ucapkan perintah suara: "mulai merakit".
  • Agen akan memproses permintaan Anda, dan UI akan berubah menjadi "Sedang berbicara...". Anda akan mendengar respons khusus audio yang mencantumkan bagian yang diperlukan.

Respons Lisan Agen

4. Memverifikasi Panggilan Alat Agen-ke-Agen

👉 Respons audio awal mengonfirmasi bahwa sistem berfungsi, tetapi keajaiban sebenarnya ada di rekaman aktivitas komunikasi multi-agen.

  • Nonaktifkan mikrofon.
  • Muat ulang halaman sekali lagi.

Panel "Trace" di sebelah kiri akan diisi. Anda dapat melihat alur eksekusi yang berhasil dan lengkap:

  • dispatch_agent pertama memanggil monitor_for_hazard.
  • Kemudian, aplikasi membuat beberapa panggilan execute_architect ke architect_agent untuk mengambil data skematik.

Verifikasi Panggilan Alat

Urutan ini mengonfirmasi bahwa seluruh alur kerja multi-agen berfungsi dengan benar: dispatch_agent menerima permintaan, mendelegasikan tugas pengambilan data ke architect_agent melalui panggilan alat, dan menerima kembali data untuk memenuhi perintah pengguna.

Link streaming dua arah Anda kini dapat melakukan pemantauan di latar belakang dan kolaborasi multi-agen. Selanjutnya, kita akan mempelajari cara menguraikan respons kompleks ini di frontend.

👉💻 Tekan Ctrl+c di kedua terminal untuk keluar.

5. Pembahasan Mendalam tentang Aliran Peristiwa Multimodal Langsung

Pada langkah sebelumnya, kita berhasil memverifikasi sistem multiagen menggunakan server pengembangan bawaan, adk web. Utilitas ini menggunakan peluncur ADK default untuk mengelola sesi, streaming, dan siklus proses agen secara otomatis. Namun, untuk membuat aplikasi mandiri yang siap produksi seperti layanan FastAPI kami (main.py), kita memerlukan kontrol eksplisit. Kita harus membuat dan mengelola ADK Runner secara manual untuk menangani sesi pengguna aktif, karena merupakan komponen inti yang memproses streaming dua arah untuk audio, video, dan teks.

Loop Model-Code-Model

Untuk memahami cara kerja sistem secara real-time, mari kita ikuti siklus proses satu sesi misi. Loop ini merepresentasikan pertukaran objek LlmRequest dan LlmResponse yang berkelanjutan.

  1. Link Visual: Anda memulai koneksi dan membagikan webcam/Layar Anda. Frame JPEG fidelitas tinggi mulai mengalir Upstream melalui realtimeInput (menggunakan LiveRequestQueue).
  2. Aktivasi Sentinel: Sistem mengirimkan stimulus "Halo" awal. Sesuai petunjuknya, Agen Pengiriman akan segera memicu monitor_for_hazard Alat Streaming. Tindakan ini akan memulai loop latar belakang yang secara diam-diam mengamati setiap frame yang masuk.
  3. Perintah Pilot: Anda berbicara ke dalam komunikasi: "Mulai merakit".
  4. Vocal Upstream: Suara Anda direkam sebagai audio 16 kHz dan dikirim Upstream bersama frame video.
  5. Delegasi (A2A): Dispatch "mendengar" maksud Anda. Agen menyadari bahwa ia tidak memiliki diagram, sehingga ia memanggil Architect Agent menggunakan protokol AgentTool (Agent-as-a-Tool).
  6. Pengambilan Fakta: Architect membuat kueri database Redis dan menampilkan daftar komponen ke Dispatch. Dispatch tetap menjadi "Master Sesi", yang menerima data tanpa mengalihkan Anda.
  7. Downstream Informasi: Dispatch mengirim modelTurn (Downstream) yang berisi teks dan audio native: "Arsitek Dikonfirmasi. Subkumpulan yang diperlukan adalah: Warp Core, Flux Pipe, Ion Thruster."
  8. Krisis: Tiba-tiba, komponen di meja kerja menjadi tidak stabil dan mulai Bersinar Putih.
  9. Deteksi Mandiri: Loop monitor_for_hazard di latar belakang (Sentinel) mengambil frame JPEG tertentu yang berisi cahaya. Aplikasi ini memproses frame dengan memanggil Gemini dan mengidentifikasi bahaya.
  10. Keamanan Hilir: Alat streaming yields hasil. Karena ini adalah agen Bidi-Streaming, Dispatch dapat mengganggu statusnya saat ini untuk segera mengirimkan peringatan keselamatan penting Downstream: "Bahaya terdeteksi! Menetralkan Kristal Data sekarang. Pindahkan ke tempat sampah MERAH."

Flow

Menetapkan konfigurasi Runtime Agen

RunConfig di ADK memungkinkan konfigurasi mendetail perilaku agen, termasuk cara menangani data streaming dan berinteraksi dengan berbagai modalitas.

streaming_mode disetel ke BIDI untuk komunikasi dua arah secara real-time, sehingga pengguna dan agen dapat berbicara dan mendengarkan secara bersamaan. Parameter response_modalities menentukan jenis output yang dapat dihasilkan agen, seperti suara dan teks. input_audio_transcription mengonfigurasi cara agen memproses dan mentranskripsikan ucapan masuk pengguna. Untuk menciptakan pengalaman yang lebih andal, session_resumption memungkinkan agen mengingat konteks percakapan dan melanjutkannya jika koneksi terputus. Terakhir, proactivity memungkinkan agen memulai tindakan atau ucapan tanpa perintah langsung dari pengguna, seperti mengeluarkan peringatan bahaya secara spontan, sementara enable_affective_dialog memungkinkan agen menghasilkan respons yang lebih alami dan empatik. Anda dapat mempelajari lebih lanjut RunConfig ADK di sini.

👉✏️ Temukan placeholder #REPLACE_RUN_CONFIG di file $HOME/way-back-home/level_4/backend/main.py Anda dan ganti dengan logika penguraian berikut:

run_config = RunConfig(
            streaming_mode=StreamingMode.BIDI,
            response_modalities=response_modalities,
            input_audio_transcription=types.AudioTranscriptionConfig(),
            output_audio_transcription=types.AudioTranscriptionConfig(),
            session_resumption=types.SessionResumptionConfig(),
            proactivity=(
                types.ProactivityConfig(proactive_audio=True) if proactivity else None
            ),
            enable_affective_dialog=affective_dialog if affective_dialog else None,
        )

Menerapkan Permintaan ke Agen

Selanjutnya, kita akan menerapkan uplink komunikasi inti yang melakukan streaming data multimodal secara real-time dari Volatile Workbench pengguna ke Dispatch Agent melalui WebSocket. Agen akan terus "melihat" (frame video) dan "mendengar" (perintah suara). Logika ini terus menerima aliran data, membedakan antara potongan audio biner yang masuk dan paket teks/gambar yang di-JSON, serta mengenkapsulasinya ke dalam objek Blob (untuk multimedia) atau Content (untuk teks), lalu mengirimkannya ke LiveRequestQueue untuk mendukung sesi agen dua arah.

BIDI

Cari placeholder #PROCESS_AGENT_REQUEST di file $HOME/way-back-home/level_4/backend/main.py Anda dan ganti dengan logika penguraian berikut:

# Start the loop
        try:
            while True:
                # Receive message from WebSocket (text or binary)
                message = await websocket.receive()

                # Handle binary frames (audio data)
                if "bytes" in message:
                    audio_data = message["bytes"]
                    audio_blob = types.Blob(
                        mime_type="audio/pcm;rate=16000", data=audio_data
                    )
                    live_request_queue.send_realtime(audio_blob)

                # Handle text frames (JSON messages)
                elif "text" in message:
                    text_data = message["text"]
                    json_message = json.loads(text_data)

                    # Extract text from JSON and send to LiveRequestQueue
                    if json_message.get("type") == "text":
                        logger.info(f"User says: {json_message['text']}")
                        content = types.Content(
                            parts=[types.Part(text=json_message["text"])]
                        )
                        live_request_queue.send_content(content)

                    # Handle audio data (microphone)
                    elif json_message.get("type") == "audio":
                        # logger.info("Received AUDIO packet") # Uncomment for verbose debugging
                        import base64
                        # Decode base64 audio data
                        audio_data = base64.b64decode(json_message.get("data", ""))
                        
                        # logger.info(f"Received Audio Chunk: {len(audio_data)} bytes")
                        
                        import math
                        import struct
                        # Calculate RMS to debug silence
                        count = len(audio_data) // 2
                        shorts = struct.unpack(f"<{count}h", audio_data)
                        sum_squares = sum(s*s for s in shorts)
                        rms = math.sqrt(sum_squares / count) if count > 0 else 0
                        
                        # logger.info(f"RMS: {rms:.2f} | Bytes: {len(audio_data)}")

                        # Send to Live API as PCM 16kHz
                        audio_blob = types.Blob(
                            mime_type="audio/pcm;rate=16000", 
                            data=audio_data
                        )
                        live_request_queue.send_realtime(audio_blob)

                    # Handle image data
                    elif json_message.get("type") == "image":
                        import base64
                        
                        # Decode base64 image data
                        image_data = base64.b64decode(json_message["data"])
                        # logger.info(f"Received Image Frame: {len(image_data)} bytes")
                        
                        mime_type = json_message.get("mimeType", "image/jpeg")

                        # Send image as blob
                        image_blob = types.Blob(mime_type=mime_type, data=image_data)
                        live_request_queue.send_realtime(image_blob)
                        
                        frame_count += 1
                        
        finally:
             pass                   

Data multimodal kini dikirim ke agen.

Menerapkan Respons: Struktur Data Peristiwa Hilir

Saat Anda menjalankan agen dua arah (live) dengan ADK, data yang kembali dari agen dikemas ke dalam jenis Peristiwa tertentu yang diwarisi dari struktur GenAI SDK inti. Objek Event yang Anda terima dalam loop async for event in runner.run_live(...) adalah satu objek yang berisi beberapa kolom opsional, masing-masing untuk jenis informasi yang berbeda:

Acara

Cara konten disusun:

  • Saat Agen Berbicara (melalui .server_content): Kolom ini bukan hanya teks biasa. Objek ini berisi daftar Parts. Setiap Part adalah penampung untuk satu jenis data—baik string teks (seperti "The part is stable.") atau blob audio mentah (suara).
  • Saat Agen Bertindak (melalui .tool_call): Kolom ini berisi daftar objek FunctionCall. Setiap FunctionCall adalah objek terstruktur sederhana yang menentukan nama alat dan argumen input dalam format bersih yang dapat dibaca dan dieksekusi dengan mudah oleh kode backend Anda.

👀 Jika Anda melihat satu Event yang dihasilkan oleh loop run_live, JSON (yang dihasilkan oleh event.model_dump(by_alias=True)) akan terlihat seperti ini, dengan mengikuti bentuk GenAI SDK secara ketat:

{
  "serverContent": {  // <-- LiveServerMessageServerContent
    "modelTurn": {    // <-- ModelTurn
      "parts": [      // <-- list[Part]
        {
          "text": "Architect Confirmed."
        },
        {
          "inlineData": { // <-- Blob (Audio Bytes)
            "mimeType": "audio/pcm;rate=24000",
            "data": "BASE64_AUDIO_DATA..."
          }
        }
      ]
    }
  },
  "toolCall": {       // <-- LiveServerMessageToolCall
    "functionCalls": [ // <-- list[FunctionCall]
      {
        "name": "neutralize_hazard",
        "args": { "color": "RED" }
      }
    ]
  }
}

👉✏️ Sekarang kita akan memperbarui downstream_task di main.py untuk meneruskan data peristiwa lengkap. Logika ini memastikan bahwa setiap "pemikiran" AI dicatat di terminal diagnostik kapal dan dikirim sebagai satu objek JSON ke UI frontend.

Cari placeholder #PROCESS_AGENT_RESPONSE di file $HOME/way-back-home/level_4/backend/main.py Anda dan ganti dengan logika penguraian berikut:

            # Suppress raw event logging
            event_json = event.model_dump_json(exclude_none=True, by_alias=True)
            # logger.info(f"raw_event: {event_json[:200]}...") 
            await websocket.send_text(event_json)

Eksekusi Misi

Setelah brankas backend terhubung dan kedua agen dikonfigurasi, semua sistem kini siap digunakan. Langkah-langkah berikut akan meluncurkan aplikasi lengkap, sehingga Anda dapat berinteraksi dengan sistem dua agen yang baru saja Anda buat.

Tujuan: Merakit mesin warp yang ditugaskan secara acak yang muncul di meja kerja Anda. Protokol: Anda harus mengikuti panduan lisan dari Agen Pengiriman, terutama peringatan bahaya untuk komponen tertentu.

Mengaktifkan Spesialis (Arsitek)

👉💻 Di jendela terminal pertama, luncurkan agen Architect. Layanan backend ini akan terhubung ke vault Redis dan menunggu permintaan skema dari Dispatcher.

# Ensure you are in the backend directory
cd $HOME/way-back-home/level_4/
. scripts/check_redis.sh
cd $HOME/way-back-home/level_4/backend
# Start the A2A Server on Port 8081
uv run architect_agent/server.py

(Biarkan terminal ini tetap berjalan. Sekarang, agen tersebut adalah "agen database" aktif Anda.)

Meluncurkan Cockpit (Dispatcher)

👉💻 Di jendela terminal baru (Terminal B), kita akan membuat UI frontend dan memulai agen Dispatch utama, yang menyajikan antarmuka pengguna dan menangani semua komunikasi langsung.

# 1. Build the Frontend Assets
cd $HOME/way-back-home/level_4/frontend
npm install
npm run build

# 2. Launch the Main Application Server
cd $HOME/way-back-home/level_4/backend
cp architect_agent/.env .env
uv run main.py

(Tindakan ini akan memulai server utama di Port 8080.)

Menjalankan Skenario Pengujian

Sistem ini kini sudah aktif. Tujuan Anda adalah mengikuti petunjuk agen untuk menyelesaikan perakitan.

  1. 👉 Akses Workbench:
    • Klik ikon Web preview di toolbar Cloud Shell.
    • Pilih Ubah port, tetapkan ke 8080, lalu klik Ubah dan Pratinjau.
  2. 👉 Mulai Misi:
    • Saat antarmuka dimuat, pastikan Anda mengizinkannya mengakses layar dan mikrofon Anda. Jendela
    • Anda akan diminta untuk memilih tab atau jendela yang akan dibagikan. Jika Anda membagikan jendela, untuk menghindari masalah, pastikan ini adalah SATU-SATUNYA tab di jendela.
    • Drive dengan nama acak (misalnya, "NOVA-V", "OMEGA-9") akan ditugaskan kepada Anda.
  3. 👉 Assembly Loop:
    • Permintaan: Untuk mulai merakit drive, ucapkan: "Mulai merakit".Merakit
    • Respons Arsitek: Agen akan memberikan komponen yang benar untuk merakit drive.
    • Pemeriksaan Bahaya: Jika komponen tampak berbahaya di meja kerja:
      • Alat monitor_for_hazard agen Dispatch akan mengidentifikasinya secara visual.
      • Hal ini akan menghasilkan "PERINGATAN BAHAYA VISUAL". (Proses ini akan memakan waktu sekitar 30 detik)
      • Fitur ini akan memeriksa bin mana yang akan digunakan untuk menonaktifkan bahaya. Hazard
    • Tindakan: Agen Pengiriman akan memberi Anda perintah langsung: "Bahaya Dikonfirmasi. Segera masukkan XXX ke dalam tempat sampah Merah." Anda harus mengikuti petunjuk ini untuk melanjutkan.

Misi Selesai. Anda telah berhasil membuat sistem multi-agen interaktif. Para survivor aman, roket telah keluar dari atmosfer, dan "Way Back Home" Anda berlanjut.

👉💻 Tekan Ctrl+c di kedua terminal untuk keluar.

6. Men-deploy ke Produksi (Opsional)

Anda telah berhasil menguji agen secara lokal. Sekarang, kita harus mengupload inti neural Arsitek ke mainframe kapal (Cloud Run). Hal ini akan memungkinkannya beroperasi sebagai layanan permanen dan independen yang dapat dikueri oleh agen Dispatch dari mana saja.

Ringkasan

Menyediakan Secure Vault (Infrastruktur)

Sebelum men-deploy agen, kita harus membuat memori persistennya (Memorystore) dan saluran aman untuk mengaksesnya (Konektor VPC).

👉💻 Buat Instance Memorystore (Redis Vault):

export REGION="us-central1"
gcloud redis instances create ozymandias-vault-prod --size=1 --tier=basic --region=${REGION}

👉💻 Ambil Alamat Jaringan Vault: Jalankan perintah ini dan salin alamat IP host. Ini adalah alamat pribadi instance Redis baru Anda.

gcloud redis instances describe ozymandias-vault-prod --region=us-central1

👉💻 Buat Konektor Akses VPC (Secure Bridge): Konektor ini berfungsi sebagai jembatan pribadi, yang memungkinkan Cloud Run mengakses instance Redis di dalam VPC Anda.

export REGION="us-central1"
export SUBNET_NAME="vpc-connector-subnet"
export PROJECT_ID=$(gcloud config get-value project)
# Create the Dedicated Subnet ---

gcloud compute networks subnets create ${SUBNET_NAME} \
    --network=default \
    --region=${REGION} \
    --range=192.168.1.0/28


gcloud compute networks vpc-access connectors create architect-connector \
 --region ${REGION} \
 --subnet ${SUBNET_NAME} \
 --subnet-project ${PROJECT_ID} \
 --min-instances 2 \
 --max-instances 3 \
 --machine-type f1-micro

👉💻 Muat data:

export REGION="us-central1"
export ZONE="us-central1-a"
export VM_NAME="redis-seeder-$(date +%s)"
export REDIS_IP=$(gcloud redis instances describe ozymandias-vault-prod --region=${REGION} | grep 'host:' | awk '{print $2}')

gcloud compute instances create ${VM_NAME} \
    --zone=${ZONE} \
    --machine-type=e2-micro \
    --image-family=debian-11 \
    --image-project=debian-cloud \
    --quiet \
    --metadata=startup-script='#! /bin/bash
        # Install tools quietly
        apt-get update > /dev/null
        apt-get install -y redis-tools > /dev/null

        # Run each command individually
        redis-cli -h '"${REDIS_IP}"' DEL "HYPERION-X"
        redis-cli -h '"${REDIS_IP}"' RPUSH "HYPERION-X" "Warp Core" "Flux Pipe" "Ion Thruster"
        redis-cli -h '"${REDIS_IP}"' DEL "NOVA-V"
        redis-cli -h '"${REDIS_IP}"' RPUSH "NOVA-V" "Ion Thruster" "Warp Core" "Flux Pipe"
        redis-cli -h '"${REDIS_IP}"' DEL "OMEGA-9"
        redis-cli -h '"${REDIS_IP}"' RPUSH "OMEGA-9" "Flux Pipe" "Ion Thruster" "Warp Core"
        redis-cli -h '"${REDIS_IP}"' DEL "GEMINI-MK1"
        redis-cli -h '"${REDIS_IP}"' RPUSH "GEMINI-MK1" "Coolant Tank" "Servo" "Fuel Cell"
        redis-cli -h '"${REDIS_IP}"' DEL "APOLLO-13"
        redis-cli -h '"${REDIS_IP}"' RPUSH "APOLLO-13" "Warp Core" "Coolant Tank" "Ion Thruster"
        redis-cli -h '"${REDIS_IP}"' DEL "VORTEX-7"
        redis-cli -h '"${REDIS_IP}"' RPUSH "VORTEX-7" "Quantum Cell" "Graviton Coil" "Plasma Injector"
        redis-cli -h '"${REDIS_IP}"' DEL "CHRONOS-ALPHA"
        redis-cli -h '"${REDIS_IP}"' RPUSH "CHRONOS-ALPHA" "Shield Emitter" "Data Crystal" "Quantum Cell"
        redis-cli -h '"${REDIS_IP}"' DEL "NEBULA-Z"
        redis-cli -h '"${REDIS_IP}"' RPUSH "NEBULA-Z" "Plasma Injector" "Flux Pipe" "Graviton Coil"
        redis-cli -h '"${REDIS_IP}"' DEL "PULSAR-B"
        redis-cli -h '"${REDIS_IP}"' RPUSH "PULSAR-B" "Data Crystal" "Servo" "Shield Emitter"
        redis-cli -h '"${REDIS_IP}"' DEL "TITAN-PRIME"
        redis-cli -h '"${REDIS_IP}"' RPUSH "TITAN-PRIME" "Ion Thruster" "Quantum Cell" "Warp Core"

        # Signal that the script has finished
        echo "SEEDING_COMPLETE"
    '
# This command streams the logs and waits until grep finds our completion message.
# The -m 1 flag tells grep to exit after the first match.
gcloud compute instances tail-serial-port-output ${VM_NAME} --zone=${ZONE} | grep -m 1 "SEEDING_COMPLETE"

gcloud compute instances delete ${VM_NAME} --zone=${ZONE} --quiet

Men-deploy Aplikasi Agen

Mengompilasi dan Membangun Image Agen

👉💻 Buka direktori backend dan buat dockerfile.

export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=architect-agent
export IMAGE_PATH=gcr.io/${PROJECT_ID}/${SERVICE_NAME}
export VPC_CONNECTOR_NAME=architect-connector
export REDIS_IP=$(gcloud redis instances describe ozymandias-vault-prod --region=${REGION} | grep 'host:' | awk '{print $2}')

cd $HOME/way-back-home/level_4/backend/architect_agent
cp $HOME/way-back-home/level_4/requirements.txt requirements.txt
cat <<EOF > Dockerfile
# Use an official Python runtime as a parent image
FROM python:3.13-slim

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file and install dependencies for THIS agent
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

# Copy the rest of the architect's code (server.py, agent.py, etc.)
COPY . .

# Expose the port the architect server runs on
EXPOSE 8081

# Command to run the application
# This assumes your server file is named server.py and the FastAPI object is 'app'
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8081"]
EOF

👉💻 Kemas aplikasi ke dalam image container.

cd $HOME/way-back-home/level_4/backend/architect_agent

export PROJECT_ID=$(gcloud config get-value project)
export SERVICE_NAME=architect-agent
export IMAGE_PATH=gcr.io/${PROJECT_ID}/${SERVICE_NAME}
export REGION=us-central1


# This should now print the full, correct path
echo "Verifying build path: ${IMAGE_PATH}"

gcloud builds submit . --tag ${IMAGE_PATH}

Men-deploy ke Cloud Run

👉💻 Deploy agen ke Cloud Run. Kita akan menyuntikkan IP Redis dan menautkan Konektor VPC langsung ke perintah peluncuran. Hal ini memastikan agen memulai dengan koneksi pribadi yang aman ke databasenya.

cd $HOME/way-back-home/level_4/backend/architect_agent

export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=architect-agent
export IMAGE_PATH=gcr.io/${PROJECT_ID}/${SERVICE_NAME}
export VPC_CONNECTOR_NAME=architect-connector
export REDIS_IP=$(gcloud redis instances describe ozymandias-vault-prod --region=${REGION} | grep 'host:' | awk '{print $2}')
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
export PREDICTED_HOST="${SERVICE_NAME}-${PROJECT_NUMBER}.${REGION}.run.app"
export PROTOCOL=https

gcloud run deploy ${SERVICE_NAME} \
  --image=${IMAGE_PATH} \
  --platform=managed \
  --region=${REGION} \
  --port=8081 \
  --allow-unauthenticated \
  --labels=dev-tutorial=multi-modal \
  --vpc-connector=${VPC_CONNECTOR_NAME} \
  --vpc-egress=private-ranges-only \
  --set-env-vars="REDIS_HOST=${REDIS_IP}" \
  --set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=True" \
  --set-env-vars="MODEL_ID=gemini-2.5-flash" \
  --set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
  --set-env-vars="HOST_URL=${PREDICTED_HOST}" \
  --set-env-vars="PROTOCOL=${PROTOCOL}" \
  --set-env-vars="A2A_PORT=443"

👉💻 Verifikasi apakah server A2A sedang berjalan.

export REGION=us-central1
export ARCHITECT_AGENT_URL=$(gcloud run services describe architect-agent --platform managed --region ${REGION} --format 'value(status.url)')
curl -s  ${ARCHITECT_AGENT_URL}/.well-known/agent.json | jq 

Setelah perintah selesai, Anda akan melihat Service URL. Agen Arsitek kini aktif di cloud, terhubung secara permanen ke brankasnya, dan siap menyajikan data skematik ke agen lain.

Men-deploy Dispatch Hub ke Mainframe Produksi

Setelah Architect Agent beroperasi di cloud, kita harus men-deploy Dispatch Hub. Agen ini akan berfungsi sebagai antarmuka pengguna utama, menangani streaming suara/video live dan mendelegasikan kueri database ke endpoint aman Architect.

👉💻 Jalankan perintah berikut di terminal Cloud Shell. Perintah ini akan membuat Dockerfile multi-tahap yang lengkap di direktori backend Anda.

cd $HOME/way-back-home/level_4

cat <<EOF > Dockerfile
# STAGE 1: Build the React Frontend
# This stage uses a Node.js container to build the static frontend assets.
FROM node:20-slim as builder

# Set the working directory for our build process
WORKDIR /app

# Copy the frontend's package files first to leverage Docker's layer caching.
COPY frontend/package*.json ./frontend/
# Run 'npm install' from the context of the 'frontend' subdirectory
RUN npm --prefix frontend install

# Copy the rest of the frontend source code
COPY frontend/ ./frontend/
# Run the build script, which will create the 'frontend/dist' directory
RUN npm --prefix frontend run build


# STAGE 2: Build the Python Production Image
# This stage creates the final, lean container with our Python app and the built frontend.
FROM python:3.13-slim

# Set the final working directory
WORKDIR /app

# Install uv, our fast package manager
RUN pip install uv

# Copy the requirements.txt from the root of our build context
COPY requirements.txt .
# Install the Python dependencies
RUN uv pip install --no-cache-dir --system -r requirements.txt

# Copy the entire backend directory into the container
COPY backend/ ./backend/

# CRITICAL STEP: Copy the built frontend assets from the 'builder' stage.
# The source is the '/app/frontend/dist' directory from Stage 1.
# The destination is './frontend/dist', which matches the exact relative path
# your backend/main.py script expects to find.
COPY --from=builder /app/frontend/dist ./frontend/dist/

# Cloud Run injects a PORT environment variable, which your main.py already uses.
# We expose 8000 as a standard practice.
EXPOSE 8000

# Set the command to run the application.
# We specify the full path to the Python script.
CMD ["python", "backend/main.py"]
EOF

Mengompilasi dan Membangun Image Agen/Frontend

👉💻 Buka direktori backend yang berisi kode agen Dispatch (main.py) dan kemas ke dalam image container.

cd $HOME/way-back-home/level_4
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=mission-bravo
export IMAGE_PATH=gcr.io/${PROJECT_ID}/${SERVICE_NAME}
# This assumes your dispatch agent server (main.py) is in the backend folder

gcloud builds submit . --tag ${IMAGE_PATH}

Men-deploy ke Cloud Run

👉💻 Deploy Dispatch Hub ke Cloud Run. Kita akan menyuntikkan URL Arsitek sebagai variabel lingkungan, sehingga membuat link penting antara dua agen cloud-native kita.

export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=mission-bravo
export AGENT_SERVICE_NAME=architect-agent
export IMAGE_PATH=gcr.io/${PROJECT_ID}/${SERVICE_NAME}
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
export ARCHITECT_AGENT_URL="https://${AGENT_SERVICE_NAME}-${PROJECT_NUMBER}.${REGION}.run.app"
gcloud run deploy ${SERVICE_NAME} \
  --image=${IMAGE_PATH} \
  --platform=managed \
  --region=${REGION} \
  --port=8080 \
  --labels=dev-tutorial=multi-modal \
  --allow-unauthenticated \
  --set-env-vars="ARCHITECT_URL=${ARCHITECT_AGENT_URL}" \
  --set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=True" \
  --set-env-vars="MODEL_ID=gemini-live-2.5-flash-preview-native-audio-09-2025" \
  --set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
  --set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}"

Setelah perintah selesai, Anda akan melihat URL Layanan (misalnya, https://mission-bravo-...run.app). Aplikasi kini aktif di cloud.

👉 Buka halaman Google Cloud Run dan pilih layanan biometric-scout dari daftar. CloudRun

👉 Cari URL Publik yang ditampilkan di bagian atas halaman Detail layanan. CloudRun

Pemeriksaan Sistem Akhir (Pengujian Menyeluruh)

👉 Sekarang Anda akan berinteraksi dengan sistem aktif.

  1. Dapatkan URL: Salin Service URL dari output perintah deployment terakhir (URL ini harus diakhiri dengan run.app).
  2. Buka Cockpit: Tempelkan URL ke browser web Anda.
  3. Mulai Kontak: Saat antarmuka dimuat, pastikan Anda mengizinkannya mengakses layar dan mikrofon Anda.
  4. Minta Data: Saat perjalanan ditetapkan, minta untuk mulai merakit. Misalnya: "Mulai merakit"

CloudRun

Sekarang Anda berinteraksi dengan sistem multi-agen yang di-deploy sepenuhnya dan berjalan sepenuhnya di Google Cloud.

Sistem Multi-agen mengunci cincin penampungan terakhir di tempatnya, dan radiasi yang tidak menentu menjadi stabil.

"Warp Drive: STABIL. Rescue Craft: ENGINES IGNITED."

Berakhir

Di monitor Anda, pesawat alien melesat ke atas, nyaris lolos dari permukaan Ozymandias yang hancur saat atmosfer runtuh. Pesawat itu mendarat di orbit yang aman di samping pesawat Anda, dan komunikasi dipenuhi dengan suara para survivor—terguncang, tetapi masih hidup. Setelah penyelamatan selesai dan rute menuju rumah Anda aman, link jarak jauh akan terputus.

Berkat Anda, para penyintas berhasil diselamatkan.

Jika Anda berpartisipasi dalam Level 0, jangan lupa untuk memeriksa progres Anda dalam misi kembali ke rumah.

FINAL