ساخت و استقرار یک نماینده گذرنامه حیوانات خانگی در Cloud Run

۱. مرور کلی

در این آزمایشگاه کد، یاد خواهید گرفت که چگونه برنامه Pet Passport را مستقر کنید، یک عامل هوش مصنوعی که از پروتکل Model Context (MCP) برای ترکیب تجزیه و تحلیل داده‌ها و سرویس‌های موقعیت مکانی استفاده می‌کند.

این اپلیکیشن به کاربران کمک می‌کند تا بر اساس محبوبیت نژاد سگ در شهر نیویورک، یک روز عالی را با سگ خود برنامه‌ریزی کنند. این عامل از یک زنجیره استدلال «کلان به خرد» استفاده می‌کند:

  1. کشف استراتژیک (BigQuery): کد پستی نیویورک را با بیشترین جمعیت برای یک نژاد خاص شناسایی می‌کند.
  2. اجرای محلی (نقشه‌ها): از آن کد پستی به عنوان یک بایاس مکانی برای یافتن «کافه‌های مناسب حیوانات خانگی» و «پارک‌های سگ» استفاده می‌کند.
  3. تولید برنامه سفر: داده‌ها را برای ایجاد یک برنامه سفر «گذرنامه حیوانات خانگی» با لینک‌ها و تصاویر قابل کلیک ترکیب می‌کند.

این عامل با استفاده از چارچوب google-adk ساخته شده و توسط Gemini پشتیبانی می‌شود.

توجه: کد کامل پروژه، شامل رابط کاربری frontend، در GitHub موجود است. در این آزمایشگاه کد، ما بر منطق عامل اصلی و راه‌اندازی زیرساخت تمرکز خواهیم کرد.

۲. تنظیمات و الزامات

ابتدا، بیایید مطمئن شویم که محیط توسعه شما به درستی تنظیم شده است.

۱. احراز هویت با گوگل کلود

پروژه فعال Google Cloud خود را تنظیم کرده و احراز هویت کنید. این برای دسترسی نماینده به BigQuery و سایر سرویس‌ها ضروری است.

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

توجه: اگر هنگام احراز هویت با خطاهایی در مورد یک پروژه متفاوت مواجه شدید، می‌توانید با غیرفعال کردن پروژه سهمیه‌بندی و تنظیم دستی آن، از این مشکل عبور کنید:

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

۲. الزامات نرم‌افزاری

شما باید نرم‌افزارهای زیر را روی دستگاه محلی خود نصب داشته باشید:

  • پایتون (نسخه ۳.۱۳ یا بالاتر مورد نیاز است)
  • گیت (برای دانلود مخزن)

مخزن را دانلود کنید

کد این پروژه در مخزن Google MCP موجود است. مخزن را کپی کنید و به پوشه پروژه بروید:

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

۳. نصب

حالا که فایل‌ها را دارید، بیایید محیط پایتون را راه‌اندازی کنیم.

  1. ایجاد یک محیط مجازی: این کار وابستگی‌های شما را ایزوله نگه می‌دارد.
    python3 -m venv .venv
    
  2. فعال کردن محیط مجازی:
    • در لینوکس/مک او اس:
      source .venv/bin/activate
      
    • در ویندوز:
      .venv\Scripts\activate
      
  3. نصب وابستگی‌ها:
    pip install google-adk==1.28.0 python-dotenv google-genai pillow uvicorn
    

فعال کردن APIهای ابری

API های زیر را در پروژه خود فعال کنید:

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

یک منطقه را انتخاب کنید

منطقه را به عنوان یک متغیر محیطی در پوسته خود تنظیم کنید:

export REGION=us-central1

۴. دریافت کلیدهای API

برای استفاده از سرویس‌های Maps و Gemini، باید کلیدهای API را دریافت کرده و آنها را در یک فایل .env در ریشه پروژه ذخیره کنید.

۱. کلید API نقشه‌های گوگل

  1. به کنسول ابری گوگل بروید.
  2. به APIها و خدمات > اعتبارنامه‌ها بروید.
  3. روی ایجاد اعتبارنامه‌ها > کلید API کلیک کنید.
  4. کلید تولید شده را کپی کرده و آن را به فایل .env خود با نام MAPS_API_KEY=[YOUR_KEY] اضافه کنید.
  5. (توصیه می‌شود) کلید را محدود کنید تا فقط APIهای نقشه‌ای که توسط سرور MCP استفاده می‌شوند، مجاز باشند.

۲. کلید API جمینی (استودیوی هوش مصنوعی)

  1. به استودیوی هوش مصنوعی گوگل بروید.
  2. روی دریافت کلید API کلیک کنید یا به بخش کلیدهای API بروید.
  3. روی ایجاد کلید API کلیک کنید.
  4. کلید را کپی کرده و آن را با نام GEMINI_API_KEY=[YOUR_KEY] به فایل .env خود اضافه کنید.

۵. نصب وابستگی‌ها

یک فایل requirements.txt در پوشه petpassport/ ایجاد کنید:

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

6. احراز هویت سرورهای MCP

این برنامه برای تعامل با Google Maps و BigQuery به سرورهای Model Context Protocol (MCP) متکی است. برای تأیید اعتبار این سرورها، باید متغیرهای محیطی و هدرهای مناسب را پیکربندی کنید.

  1. Google Maps MCP: به یک کلید معتبر Maps API که در هدر X-Goog-Api-Key ارسال شده است، نیاز دارد.
  2. BigQuery MCP: به اعتبارنامه‌های OAuth با دسترسی به سرویس BigQuery نیاز دارد. این عامل هنگام اجرا روی Cloud Run از حساب کاربری سرویس محاسباتی پیش‌فرض یا هنگام اجرای محلی از اعتبارنامه‌های محلی شما استفاده می‌کند.

ما یک اسکریپت راه‌اندازی به setup/setup_env.sh در مخزن ارائه می‌دهیم که به پیکربندی این متغیرها در فایل .env شما کمک می‌کند.

۷. ایجاد جدول BigQuery

قبل از اینکه عامل بتواند داده‌های مجوز سگ را جستجو کند، باید مجموعه داده‌ها و جدول را در BigQuery ایجاد کنیم و داده‌ها را بارگذاری کنیم.

ما یک اسکریپت راه‌اندازی setup/setup_bigquery.sh ارائه می‌دهیم که مراحل زیر را انجام می‌دهد:

  1. یک سطل ذخیره‌سازی ابری به نام pet-passport-data-[PROJECT_ID] برای ذخیره داده‌های خام ایجاد می‌کند.
  2. مجموعه داده‌های عمومی صدور مجوز سگ نیویورک (CSV) را دانلود می‌کند.
  3. CSV را در سطل بارگذاری می‌کند.
  4. یک مجموعه داده BigQuery با نام nyc_dogs ایجاد می‌کند.
  5. داده‌ها را از سطل داده در جدولی به نام licenses در مجموعه داده‌ها بارگذاری می‌کند.

برای اجرای اسکریپت راه‌اندازی، دستور زیر را در ترمینال خود اجرا کنید:

bash setup/setup_bigquery.sh

۸. به سرورهای MCP متصل شوید

بخش کلیدی این برنامه استفاده از MCP برای اتصال به داده‌ها و سرویس‌ها است. در این بخش، مجموعه ابزارهای MCP را برای BigQuery و Google Maps در فایلی به نام petpassport/tools.py پیکربندی خواهید کرد.

کد کامل tools.py

در اینجا پیاده‌سازی کامل tools.py ، شامل مجموعه ابزارهای MCP و ابزارهای سفارشی برای ماندگاری تصویر و داده‌ها، ارائه شده است. ما این کد را برای کاهش افزونگی با انتقال وضوح سطل به سطح ماژول بهینه کرده‌ایم:

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

توضیح کد: tools.py

  • get_maps_mcp_toolset و get_bigquery_mcp_toolset کلاینت‌های MCP را با نقاط پایانی و هدرهای احراز هویت صحیح پیکربندی می‌کنند.
  • generate_pet_passport_photo از Gemini برای ایجاد یک صحنه استفاده می‌کند و نتیجه را در Google Cloud Storage آپلود می‌کند و یک URL امضا شده را به frontend برمی‌گرداند تا از راه‌اندازی مجدد سرور در امان بماند.

۹. ایجاد عامل

با پیکربندی ابزارهایتان، زمان آن رسیده است که «مغز» عامل را بسازید. شما از کیت توسعه عامل (ADK) برای ایجاد یک عامل در فایلی به نام petpassport/agent.py استفاده خواهید کرد.

کد کامل agent.py

در اینجا پیاده‌سازی کامل agent.py آمده است، که در آن عامل و دستورالعمل‌های آن را تعریف می‌کنیم:

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

توضیح کد: agent.py

  • ما tools مستقیماً (ساختار مسطح) وارد می‌کنیم تا از محیط کانتینر پشتیبانی کنیم.
  • این عامل با gemini-2.5-pro مقداردهی اولیه شده است.
  • این دستورالعمل‌ها یک زنجیره فکری چند مرحله‌ای دقیق (ابتدا BigQuery، سپس Maps) را تعریف می‌کنند و به شدت از توهم یا رندر مسیرهای پیاده‌روی که منجر به بی‌نظمی می‌شوند، جلوگیری می‌کنند.

۱۰. اجرای برنامه به صورت محلی

قبل از استقرار در Cloud Run، بهتر است برنامه را به صورت محلی آزمایش کنید.

  1. مطمئن شوید که در دایرکتوری پروژه هستید:
    cd examples/petpassport
    
  2. شروع سرور FastAPI: ما uvicorn برای اجرای برنامه استفاده می‌کنیم. نقطه ورود main.py در پوشه petpassport است.
    uvicorn petpassport.main:app --reload
    
  3. رابط کاربری را باز کنید: برای تعامل با رابط کاربری Pet Passport، در مرورگر خود به http://127.0.0.1:8000/ui/ بروید.

۱۱. استقرار در Cloud Run

با آماده شدن عامل شما، زمان آن رسیده است که آن را در Cloud Run مستقر کنید. ما مستقیماً از دستور استاندارد gcloud برای حفظ کنترل دقیق بر محیط کانتینر استفاده می‌کنیم.

از دایرکتوری پروژه، دستور زیر را اجرا کنید:

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

پیکربندی متغیرهای محیطی

پس از استقرار، به سرویس Cloud Run در کنسول Google Cloud بروید و متغیرهای محیطی زیر را در برگه متغیرها و اسرار تنظیم کنید:

  • MAPS_API_KEY : کلید API نقشه‌های گوگل شما.
  • GOOGLE_CLOUD_PROJECT : شناسه پروژه شما.
  • PROJECT_ID : شناسه پروژه شما (افزونگی برای ماژول‌های قدیمی پشتیبانی می‌شود).

۱۲. نمونه سوالات

با استفاده از این دستورالعمل‌ها، سعی کنید با عامل مستقر شده تعامل داشته باشید:

  1. استاندارد: «می‌خواهم با سگ گلدن رتریورم در نیویورک، نزدیک ۱۰۰۲۱، پیاده‌روی کنم. مسیری را برای ما پیدا کنید که کافه داشته باشد.»
  2. نژاد متفاوت: «من یک بولداگ فرانسوی دارم و ما در محله‌ی آپر وست ساید (نزدیک ۱۰۰۲۴) هستیم. یک پیاده‌روی کوتاه که در یک پارک سگ محبوب توقف داشته باشد را پیشنهاد دهید.»
  3. با تصویر: (عکسی از سگ خود آپلود کنید) "این عکسی از سگ کورگی من است! ما نزدیک به ۱۰۰۱۳ هستیم. یک روز عالی برای ما برنامه‌ریزی کنید."

۱۳. تمیز کردن

برای جلوگیری از پرداخت هزینه برای منابع استفاده شده در این آموزش:

  • سرویس Cloud Run را حذف کنید: gcloud run services delete petpassport --region=$REGION
  • سطل GCS را حذف کنید: gcloud storage rm -r gs://pet-passport-data-$PROJECT_ID