Membangun dan Men-deploy Agen Pet Passport di Cloud Run

1. Ringkasan

Dalam lab kode ini, Anda akan mempelajari cara men-deploy aplikasi Pet Passport, sebuah agen AI yang menggunakan Model Context Protocol (MCP) untuk menggabungkan analisis data dan layanan lokasi.

Aplikasi ini membantu pengguna merencanakan hari yang sempurna bersama mereka berdasarkan popularitas ras di New York City. Agen menggunakan rantai penalaran "Makro ke Mikro":

  1. Penemuan Strategis (BigQuery): Mengidentifikasi Kode Pos NYC dengan populasi tertinggi untuk ras tertentu.
  2. Eksekusi Lokal (Maps): Menggunakan Kode Pos tersebut sebagai bias lokasi untuk menemukan "kafe yang ramah hewan peliharaan" dan "taman".
  3. Pembuatan Itinerari: Menggabungkan data untuk membuat itinerari "Paspor Hewan Peliharaan" dengan link dan gambar yang dapat diklik.

Agen ini dibangun menggunakan framework google-adk dan didukung oleh Gemini.

Catatan: Kode project lengkap, termasuk UI frontend, tersedia di GitHub. Dalam codelab ini, kita akan berfokus pada logika agen inti dan penyiapan infrastruktur.

2. Penyiapan dan persyaratan

Pertama, pastikan lingkungan pengembangan Anda telah disiapkan dengan benar.

1. Melakukan autentikasi dengan Google Cloud

Tetapkan project Google Cloud aktif Anda dan lakukan autentikasi. Hal ini diperlukan agar agen dapat mengakses BigQuery dan layanan lainnya.

gcloud config set project [YOUR-PROJECT-ID]
gcloud auth application-default login --project [YOUR-PROJECT-ID]

Catatan: Jika Anda mengalami error tentang project lain selama autentikasi, Anda dapat melewatinya dengan menonaktifkan project kuota dan menyetelnya secara manual:

gcloud auth application-default login --disable-quota-project
gcloud auth application-default set-quota-project [YOUR-PROJECT-ID]

2. Persyaratan Software

Anda harus menginstal software berikut di komputer lokal Anda:

  • Python (diperlukan versi 3.13 atau yang lebih tinggi)
  • Git (untuk mendownload repositori)

Mendownload Repositori

Kode untuk project ini tersedia di repositori MCP Google. Clone repositori dan buka folder project:

git clone https://github.com/google/mcp.git
cd examples/petpassport

3. Penginstalan

Setelah Anda memiliki file, mari siapkan lingkungan Python.

  1. Buat lingkungan virtual: Tindakan ini akan menjaga dependensi Anda tetap terisolasi.
    python3 -m venv .venv
    
  2. Aktifkan lingkungan virtual:
    • Di Linux/macOS:
      source .venv/bin/activate
      
    • Di Windows:
      .venv\Scripts\activate
      
  3. Instal dependensi:
    pip install google-adk==1.28.0 python-dotenv google-genai pillow uvicorn
    

Aktifkan Cloud API

Aktifkan API berikut di project Anda:

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

Pilih wilayah

Tetapkan region sebagai variabel lingkungan di shell Anda:

export REGION=us-central1

4. Mendapatkan Kunci API

Untuk menggunakan layanan Maps dan Gemini, Anda harus mendapatkan kunci API dan menyimpannya dalam file .env di root project.

1. Kunci Google Maps API

  1. Buka Google Cloud Console.
  2. Buka APIs & Services > Credentials.
  3. Klik Create Credentials > API key.
  4. Salin kunci yang dihasilkan dan tambahkan ke file .env Anda sebagai MAPS_API_KEY=[YOUR_KEY].
  5. (Direkomendasikan) Batasi kunci agar hanya mengizinkan Maps API yang digunakan oleh server MCP.

2. Kunci Gemini API (AI Studio)

  1. Buka Google AI Studio.
  2. Klik Dapatkan kunci API atau buka bagian kunci API.
  3. Klik Buat kunci API.
  4. Salin kunci dan tambahkan ke file .env Anda sebagai GEMINI_API_KEY=[YOUR_KEY].

5. Menginstal Dependensi

Buat file requirements.txt di folder petpassport/:

google-adk==1.28.0
python-dotenv
google-genai
pillow

6. Mengautentikasi Server MCP

Aplikasi ini mengandalkan server Model Context Protocol (MCP) untuk berinteraksi dengan Google Maps dan BigQuery. Untuk mengautentikasi server ini, Anda perlu mengonfigurasi variabel lingkungan dan header yang sesuai.

  1. MCP Google Maps: Memerlukan kunci Maps API yang valid yang diteruskan di header X-Goog-Api-Key.
  2. BigQuery MCP: Memerlukan kredensial OAuth dengan akses ke layanan BigQuery. Agen menggunakan akun layanan komputasi default saat berjalan di Cloud Run, atau kredensial lokal Anda saat berjalan secara lokal.

Kami menyediakan skrip penyiapan setup/setup_env.sh di repositori yang membantu mengonfigurasi variabel ini dalam file .env Anda.

7. Membuat Tabel BigQuery

Sebelum agen dapat mengkueri data izin, kita perlu membuat set data dan tabel di BigQuery serta memuat datanya.

Kami menyediakan skrip penyiapan setup/setup_bigquery.sh yang melakukan langkah-langkah berikut:

  1. Membuat bucket Cloud Storage bernama pet-passport-data-[PROJECT_ID] untuk menyimpan data mentah.
  2. Mendownload set data (CSV) Pendaftaran NYC publik.
  3. Mengupload CSV ke bucket.
  4. Membuat set data BigQuery bernama nyc_dogs.
  5. Memuat data dari bucket ke dalam tabel bernama licenses di set data.

Untuk menjalankan skrip penyiapan, jalankan perintah berikut di terminal Anda:

bash setup/setup_bigquery.sh

8. Menghubungkan ke Server MCP

Bagian penting dari aplikasi ini adalah menggunakan MCP untuk terhubung ke data dan layanan. Di bagian ini, Anda akan mengonfigurasi toolset MCP untuk BigQuery dan Google Maps dalam file bernama petpassport/tools.py.

Selesaikan tools.py Kode

Berikut adalah penerapan lengkap untuk tools.py, termasuk set alat MCP dan alat kustom untuk persistensi gambar dan data. Kami telah mengoptimalkan kode ini untuk mengurangi redundansi dengan memindahkan resolusi bucket ke tingkat modul:

import os
import dotenv
import google.auth
import time
import datetime
from google.cloud import storage
from PIL import Image
from google import genai
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams 

MAPS_MCP_URL = "https://mapstools.googleapis.com/mcp" 
BIGQUERY_MCP_URL = "https://bigquery.googleapis.com/mcp" 

PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT', 'project_not_set')
BUCKET_NAME = f"pet-passport-data-{PROJECT_ID}" 

def get_maps_mcp_toolset():
    dotenv.load_dotenv()
    maps_api_key = os.getenv('MAPS_API_KEY', 'no_api_found')
    
    tools = MCPToolset(
        connection_params=StreamableHTTPConnectionParams(
            url=MAPS_MCP_URL,
            headers={    
                "X-Goog-Api-Key": maps_api_key
            },
            timeout=30.0,          
            sse_read_timeout=300.0
        )
    )
    print("Maps MCP Toolset configured.")
    return tools


def get_bigquery_mcp_toolset():   
    credentials, project_id = google.auth.default(
            scopes=["https://www.googleapis.com/auth/bigquery"]
    )

    credentials.refresh(google.auth.transport.requests.Request())
    oauth_token = credentials.token
        
    HEADERS_WITH_OAUTH = {
        "Authorization": f"Bearer {oauth_token}",
        "x-goog-user-project": project_id
    }

    tools = MCPToolset(
        connection_params=StreamableHTTPConnectionParams(
            url=BIGQUERY_MCP_URL,
            headers=HEADERS_WITH_OAUTH,
            timeout=30.0,          
            sse_read_timeout=300.0
        )
    )
    print("BigQuery MCP Toolset configured.")
    return tools

def generate_pet_passport_photo(prompt: str, image_path: str = None) -> str:
    """Generates an image using gemini-3.1-flash-image-preview based on a prompt and a reference image."""
    client = genai.Client()
    output_path = f"/tmp/pet_passport_{int(time.time())}.png"
    
    try:
        image = Image.open(image_path)
        response = client.models.generate_content(
            model="gemini-3.1-flash-image-preview",
            contents=[prompt, image],
        )
        
        for part in response.parts:
            if part.inline_data is not None:
                generated_image = part.as_image()
                generated_image.save(output_path)
                
                # Upload to GCS and generate signed URL
                try:
                    storage_client = storage.Client()
                    bucket = storage_client.bucket(BUCKET_NAME)
                    blob_name = os.path.basename(output_path)
                    blob = bucket.blob(blob_name)
                    
                    blob.upload_from_filename(output_path)
                    
                    url = blob.generate_signed_url(
                        version="v4",
                        expiration=datetime.timedelta(hours=24),
                        method="GET",
                    )
                    return url
                except Exception as e:
                    print(f"Error uploading image to GCS: {e}")
                    return output_path
                
        raise ValueError("No image was returned by the model.")
    except Exception as e:
        print(f"Error generating image: {e}")
        raise

def save_pet_passport(user_id: str, breed: str, postal_code: str, route_details: str, image_paths: list[str] = None) -> str:
    """Appends the generated itinerary to the user's history in GCS."""
    try:
        storage_client = storage.Client()
        bucket = storage_client.bucket(BUCKET_NAME)
        blob = bucket.blob(f"user-{user_id}.json")
        
        # Download existing or start fresh
        # ... (Implementation details hidden for brevity) ...
        return "Success"
    except Exception as e:
        print(f"Error saving path: {e}")
        raise

Penjelasan Kode: tools.py

  • get_maps_mcp_toolset dan get_bigquery_mcp_toolset mengonfigurasi klien MCP dengan endpoint dan header autentikasi yang benar.
  • generate_pet_passport_photo menggunakan Gemini untuk membuat adegan dan mengupload hasilnya ke Google Cloud Storage, serta menampilkan URL Bertanda Tangan ke frontend agar tetap ada saat server dimulai ulang.

9. Membuat Agen

Setelah alat Anda dikonfigurasi, saatnya membangun "otak" agen. Anda akan menggunakan Agent Development Kit (ADK) untuk membuat agen dalam file bernama petpassport/agent.py.

Selesaikan agent.py Kode

Berikut adalah implementasi lengkap untuk agent.py, tempat kita menentukan agen dan instruksinya:

import os
import dotenv
import tools
from google.adk.agents import LlmAgent

dotenv.load_dotenv()

PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT', 'project_not_set')

maps_toolset = tools.get_maps_mcp_toolset()
bigquery_toolset = tools.get_bigquery_mcp_toolset()

root_agent = LlmAgent(
    model='gemini-2.5-pro',
    name='root_agent',
    instruction=f"""
        You are the Pet Passport Agent. Your goal is to help users find a fun walking route for their dog in NYC.
        
        When given a breed and a postal code, follow this flow:
        1. **Strategic Discovery:** Use BigQuery to find the most popular neighborhood for that breed in NYC.
        2. **Local Execution:** Use Maps to build a walking route with specific places (parks, cafes) in that area.
        
        **NO DIRECTIONS LINKS:** You must NOT include a Google Maps directions link (e.g., `https://www.google.com/maps/dir/...`) in your final response. Only provide links to individual places.
        
        After generating the itinerary, you MUST call the `save_pet_passport` tool to save this path to the user's profile. Pass a clean summary of the itinerary as `route_details`. The summary should include details (like rating, description from maps).
    """,
    tools=[maps_toolset, bigquery_toolset, tools.generate_pet_passport_photo, tools.save_pet_passport]
)

Penjelasan Kode: agent.py

  • Kami mengimpor tools secara langsung (struktur yang diratakan) untuk mendukung lingkungan penampung.
  • Agen diinisialisasi dengan gemini-2.5-pro.
  • Petunjuk ini menentukan rantai pemikiran multi-langkah yang ketat (BigQuery terlebih dahulu, lalu Maps) dan melarang keras halusinasi atau rendering rute jalan kaki yang menyebabkan kekacauan.

10. Menjalankan Aplikasi Secara Lokal

Sebelum men-deploy ke Cloud Run, sebaiknya uji aplikasi secara lokal.

  1. Pastikan Anda berada di direktori project:
    cd examples/petpassport
    
  2. Mulai server FastAPI: Kita menggunakan uvicorn untuk menjalankan aplikasi. Titik entri adalah main.py di dalam folder petpassport.
    uvicorn petpassport.main:app --reload
    
  3. Buka UI: Buka http://127.0.0.1:8000/ui/ di browser Anda untuk berinteraksi dengan antarmuka Pet Passport.

11. Men-deploy ke Cloud Run

Setelah agen Anda siap, saatnya men-deploy-nya ke Cloud Run. Kami menggunakan perintah gcloud standar secara langsung untuk mempertahankan kontrol ketat atas lingkungan penampung.

Dari direktori project, jalankan perintah berikut:

gcloud run deploy petpassport \
  --source petpassport \
  --region $REGION \
  --allow-unauthenticated \
  --labels dev-tutorial=google-mcp

Mengonfigurasi Variabel Lingkungan

Setelah deployment, buka layanan Cloud Run di Konsol Google Cloud dan tetapkan variabel lingkungan berikut di tab Variables & Secrets:

  • MAPS_API_KEY: Kunci Google Maps API Anda.
  • GOOGLE_CLOUD_PROJECT: Project ID Anda.
  • PROJECT_ID: Project ID Anda (dukungan redundansi untuk modul lama).

12. Contoh Perintah

Coba berinteraksi dengan agen yang di-deploy menggunakan perintah berikut:

  1. Standar: "Saya ingin berjalan-jalan dengan Golden Retriever saya di NYC dekat 10021. Temukan rute untuk kami yang memiliki kafe."
  2. Ras Berbeda: "Saya memiliki French Bulldog dan kami berada di Upper West Side (dekat 10024). Sarankan jalan kaki singkat yang berhenti di taman populer."
  3. Dengan Gambar: (Upload foto Anda) "Ini foto Corgi saya! Kami berada di dekat 10013. Rencanakan hari yang sempurna untuk kami."

13. Pembersihan

Agar tidak menimbulkan biaya untuk resource yang digunakan dalam tutorial ini:

  • Hapus layanan Cloud Run: gcloud run services delete petpassport --region=$REGION
  • Hapus bucket GCS: gcloud storage rm -r gs://pet-passport-data-$PROJECT_ID