Kompilowanie i wdrażanie agenta paszportu dla zwierząt w Cloud Run

1. Przegląd

W tym ćwiczeniu dowiesz się, jak wdrożyć aplikację Pet Passport, czyli agenta AI, który korzysta z protokołu Model Context Protocol (MCP) do łączenia analizy danych i usług lokalizacyjnych.

Aplikacja pomaga użytkownikom zaplanować idealny dzień z psem na podstawie popularności rasy w Nowym Jorku. Agent używa łańcucha rozumowania „od makro do mikro”:

  1. Strategic Discovery (BigQuery): określa kod pocztowy w Nowym Jorku, w którym mieszka najwięcej osób danej rasy.
  2. Wykonywanie lokalne (Mapy): używa kodu pocztowego jako odchylenia lokalizacji do wyszukiwania „kawiarni przyjaznych zwierzętom” i „wybiegów dla psów”.
  3. Generowanie planu podróży: łączy dane, aby utworzyć plan podróży „Paszport dla zwierząt” z klikalnymi linkami i obrazami.

Agent został utworzony z użyciem platformy google-adk i korzysta z technologii Gemini.

Uwaga: pełny kod projektu, w tym interfejs użytkownika, jest dostępny na GitHubie. W tym laboratorium skupimy się na podstawowej logice agenta i konfiguracji infrastruktury.

2. Konfiguracja i wymagania

Najpierw upewnijmy się, że środowisko programistyczne jest prawidłowo skonfigurowane.

1. Uwierzytelnianie w Google Cloud

Ustaw aktywny projekt Google Cloud i uwierzytelnij się. Jest to wymagane, aby agent mógł uzyskać dostęp do BigQuery i innych usług.

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

Uwaga: jeśli podczas uwierzytelniania napotkasz błędy dotyczące innego projektu, możesz je pominąć, wyłączając projekt limitu i ustawiając go ręcznie:

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

2. Wymagania dotyczące oprogramowania

Na komputerze lokalnym musisz mieć zainstalowane to oprogramowanie:

  • Python (wymagana jest wersja 3.13 lub nowsza)
  • Git (do pobrania repozytorium)

Pobieranie repozytorium

Kod tego projektu jest dostępny w repozytorium Google MCP. Sklonuj repozytorium i przejdź do folderu projektu:

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

3. Instalacja

Skoro masz już pliki, skonfigurujmy środowisko Pythona.

  1. Utwórz środowisko wirtualne: dzięki temu zależności będą odseparowane.
    python3 -m venv .venv
    
  2. Aktywuj środowisko wirtualne:
    • W systemie Linux/macOS:
      source .venv/bin/activate
      
    • W systemie Windows:
      .venv\Scripts\activate
      
  3. Zainstaluj zależności:
    pip install google-adk==1.28.0 python-dotenv google-genai pillow uvicorn
    

Włączanie interfejsów Cloud API

Włącz w projekcie te interfejsy API:

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

Wybierz region

Ustaw region jako zmienną środowiskową w powłoce:

export REGION=us-central1

4. Uzyskiwanie kluczy interfejsu API

Aby korzystać z usług Mapy i Gemini, musisz uzyskać klucze interfejsu API i zapisać je w pliku .env w katalogu głównym projektu.

1. Klucz interfejsu API Map Google

  1. Otwórz konsolę Google Cloud.
  2. Otwórz Interfejsy API i usługi > Dane logowania.
  3. Kliknij Utwórz dane logowania > Klucz interfejsu API.
  4. Skopiuj wygenerowany klucz i dodaj go do pliku .env jako MAPS_API_KEY=[YOUR_KEY].
  5. (Zalecane) Ogranicz klucz, aby zezwalał tylko na interfejsy API Map Google używane przez serwer MCP.

2. Klucz interfejsu Gemini API (AI Studio)

  1. Otwórz Google AI Studio.
  2. Kliknij Uzyskaj klucz interfejsu API lub otwórz sekcję kluczy interfejsów API.
  3. Kliknij Utwórz klucz interfejsu API.
  4. Skopiuj klucz i dodaj go do pliku .env jako GEMINI_API_KEY=[YOUR_KEY].

5. Instalowanie zależności

Utwórz plik requirements.txt w folderze petpassport/:

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

6. Uwierzytelnianie serwerów MCP

Ta aplikacja korzysta z serwerów Model Context Protocol (MCP) do interakcji z Mapami Google i BigQuery. Aby uwierzytelnić te serwery, musisz skonfigurować odpowiednie zmienne środowiskowe i nagłówki.

  1. Google Maps MCP: wymaga prawidłowego klucza interfejsu API Map Google przekazanego w nagłówku X-Goog-Api-Key.
  2. BigQuery MCP: wymaga danych logowania OAuth z dostępem do usługi BigQuery. Gdy agent działa w Cloud Run, korzysta z domyślnego konta usługi Compute, a gdy działa lokalnie, korzysta z lokalnych danych logowania.

W repozytorium udostępniamy skrypt konfiguracji setup/setup_env.sh, który pomaga skonfigurować te zmienne w pliku .env.

7. Tworzenie tabeli BigQuery

Zanim agent będzie mógł wysyłać zapytania o dane dotyczące licencji na psy, musimy utworzyć zbiór danych i tabelę w BigQuery oraz wczytać dane.

Udostępniamy skrypt konfiguracjisetup/setup_bigquery.sh, który wykonuje te czynności:

  1. Tworzy zasobnik Cloud Storage o nazwie pet-passport-data-[PROJECT_ID] do przechowywania nieprzetworzonych danych.
  2. Pobiera publiczny zbiór danych NYC Dog Licensing (CSV).
  3. Przesyła plik CSV do zasobnika.
  4. Tworzy zbiór danych BigQuery o nazwie nyc_dogs.
  5. Wczytuje dane z zasobnika do tabeli o nazwie licenses w zbiorze danych.

Aby uruchomić skrypt konfiguracji, wykonaj w terminalu to polecenie:

bash setup/setup_bigquery.sh

8. Łączenie z serwerami MCP

Kluczowym elementem tej aplikacji jest korzystanie z MCP do łączenia się z danymi i usługami. W tej sekcji skonfigurujesz zestawy narzędzi MCP dla BigQuery i Map Google w pliku o nazwie petpassport/tools.py.

Dokończ kod tools.py

Oto pełna implementacja tools.py, w tym zestawy narzędzi MCP i niestandardowe narzędzia do utrwalania obrazów i danych. Zoptymalizowaliśmy ten kod, aby zmniejszyć nadmiarowość, przenosząc rozdzielczość koszyka na poziom modułu:

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

Wyjaśnienie kodu: tools.py

  • get_maps_mcp_toolsetget_bigquery_mcp_toolset konfigurują klientów MCP z prawidłowymi punktami końcowymi i nagłówkami uwierzytelniania.
  • generate_pet_passport_photo używa Gemini do utworzenia sceny i przesyła wynik do Google Cloud Storage, zwracając podpisany adres URL do frontendu, aby przetrwać ponowne uruchomienia serwera.

9. Tworzenie agenta

Po skonfigurowaniu narzędzi możesz zacząć budować „mózg” agenta. Za pomocą pakietu Agent Development Kit (ADK) utworzysz agenta w pliku o nazwie petpassport/agent.py.

Dokończ kod agent.py

Oto pełna implementacja agent.py, w której definiujemy agenta i jego instrukcje:

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

Wyjaśnienie kodu: agent.py

  • Importujemy tools bezpośrednio (spłaszczona struktura), aby obsługiwać środowisko kontenera.
  • Agent został zainicjowany z wartością gemini-2.5-pro.
  • Instrukcje określają ścisły wieloetapowy proces myślowy (najpierw BigQuery, potem Mapy) i surowo zabraniają halucynacji lub renderowania tras pieszych, które prowadzą do bałaganu.

10. Lokalne uruchamianie aplikacji

Przed wdrożeniem aplikacji w Cloud Run warto ją przetestować lokalnie.

  1. Sprawdź, czy jesteś w katalogu projektu:
    cd examples/petpassport
    
  2. Uruchom serwer FastAPI: do uruchomienia aplikacji używamy polecenia uvicorn. Punktem wejścia jest plik main.py w folderze petpassport.
    uvicorn petpassport.main:app --reload
    
  3. Otwórz interfejs: w przeglądarce otwórz stronę http://127.0.0.1:8000/ui/, aby korzystać z interfejsu paszportu dla zwierząt.

11. Wdrażanie w Cloud Run

Gdy agent będzie gotowy, możesz go wdrożyć w Cloud Run. Używamy standardowego polecenia gcloud, aby zachować ścisłą kontrolę nad środowiskiem kontenera.

W katalogu projektu uruchom to polecenie:

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

Konfigurowanie zmiennych środowiskowych

Po wdrożeniu otwórz usługę Cloud Run w konsoli Google Cloud i na karcie Zmienne i obiekty tajne ustaw te zmienne środowiskowe:

  • MAPS_API_KEY: klucz interfejsu API Map Google.
  • GOOGLE_CLOUD_PROJECT: identyfikator projektu.
  • PROJECT_ID: identyfikator projektu (w przypadku starszych modułów obsługiwana jest redundancja).

12. Przykładowe prompty

Spróbuj wejść w interakcję z wdrożonym agentem, używając tych promptów:

  1. Standard: „Chcę iść na spacer z golden retrieverem w Nowym Jorku w pobliżu kodu pocztowego 10021”. Znajdź dla nas trasę, na której jest kawiarnia”.
  2. Inna rasa: „Mam buldoga francuskiego i mieszkam w Upper West Side (w pobliżu kodu pocztowego 10024). Zaproponuj krótki spacer z przystankiem w popularnym parku dla psów”.
  3. Z obrazem: (prześlij zdjęcie psa) „Oto zdjęcie mojego corgi. Jesteśmy w pobliżu kodu 10013. Zaplanuj dla nas idealny dzień”.

13. Czyszczenie danych

Aby uniknąć obciążenia konta opłatami za zasoby użyte w tym samouczku:

  • Usuń usługę Cloud Run: gcloud run services delete petpassport --region=$REGION
  • Usuń zasobnik GCS: gcloud storage rm -r gs://pet-passport-data-$PROJECT_ID