สร้างและติดตั้งใช้งานเอเจนต์หนังสือเดินทางสัตว์เลี้ยงใน Cloud Run

1. ภาพรวม

ใน Codelab นี้ คุณจะได้เรียนรู้วิธีทำให้ใช้งานได้แอป Pet Passport ซึ่งเป็น AI Agent ที่ใช้ Model Context Protocol (MCP) เพื่อรวมการวิเคราะห์ข้อมูลและบริการตามตำแหน่ง

แอปนี้ช่วยให้ผู้ใช้วางแผนการออกไปเที่ยวกับสุนัขได้อย่างสมบูรณ์แบบ โดยอิงตามความนิยมของสายพันธุ์ในนิวยอร์กซิตี้ Agent ใช้ห่วงโซ่การให้เหตุผลแบบ "จากภาพรวมไปสู่รายละเอียด" ดังนี้

  1. การค้นพบเชิงกลยุทธ์ (BigQuery): ระบุรหัสไปรษณีย์ของนิวยอร์กซิตี้ที่มีประชากรสายพันธุ์หนึ่งๆ มากที่สุด
  2. การดำเนินการในพื้นที่ (Maps): ใช้รหัสไปรษณีย์ดังกล่าวเป็นค่าความเอนเอียงด้านสถานที่เพื่อค้นหา "คาเฟ่ที่อนุญาตให้นำสัตว์เลี้ยงเข้าได้" และ "สวนสาธารณะสำหรับสุนัข"
  3. การสร้างแผนการเดินทาง: รวมข้อมูลเพื่อสร้างแผนการเดินทาง "Pet Passport" พร้อมลิงก์และรูปภาพที่คลิกได้

Agent สร้างขึ้นโดยใช้เฟรมเวิร์ก google-adk และขับเคลื่อนโดย Gemini

หมายเหตุ: โค้ดโปรเจ็กต์ฉบับสมบูรณ์ รวมถึง UI ส่วนหน้า มีให้บริการบน GitHub ใน Codelab นี้ เราจะมุ่งเน้นที่ตรรกะหลักของ Agent และการตั้งค่าโครงสร้างพื้นฐาน

2. การตั้งค่าและข้อกำหนด

ก่อนอื่น ให้ตรวจสอบว่าได้ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์อย่างถูกต้อง

1. ตรวจสอบสิทธิ์ด้วย Google Cloud

ตั้งค่าโปรเจ็กต์ที่อยู่ในระบบคลาวด์ของ Google ที่ใช้งานอยู่และตรวจสอบสิทธิ์ Agent ต้องดำเนินการนี้เพื่อเข้าถึง 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]

2. ข้อกำหนดของซอฟต์แวร์

คุณต้องติดตั้งซอฟต์แวร์ต่อไปนี้ในเครื่อง

  • Python (ต้องใช้เวอร์ชัน 3.13 ขึ้นไป)
  • Git (เพื่อดาวน์โหลดที่เก็บ)

ดาวน์โหลดที่เก็บ

โค้ดสำหรับโปรเจ็กต์นี้มีอยู่ในที่เก็บ Google MCP โคลนที่เก็บและไปที่โฟลเดอร์โปรเจ็กต์ด้วยคำสั่งต่อไปนี้

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

3. การติดตั้ง

เมื่อมีไฟล์แล้ว ให้ตั้งค่าสภาพแวดล้อม Python ดังนี้

  1. สร้างสภาพแวดล้อมเสมือน: วิธีนี้จะช่วยแยกทรัพยากร Dependency
    python3 -m venv .venv
    
  2. เปิดใช้งานสภาพแวดล้อมเสมือน
      โดยใช้คำสั่งต่อไปนี้
    • ใน Linux/macOS:
      source .venv/bin/activate
      
    • ใน Windows:
      .venv\Scripts\activate
      
  3. ติดตั้งทรัพยากร Dependency โดยใช้คำสั่งต่อไปนี้
    pip install google-adk==1.28.0 python-dotenv google-genai pillow uvicorn
    

เปิดใช้ Cloud 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

4. รับคีย์ API

หากต้องการใช้บริการ Maps และ Gemini คุณต้องรับคีย์ API และจัดเก็บไว้ในไฟล์ .env ในรูทของโปรเจ็กต์

1. คีย์ API ของ Google Maps

  1. ไปที่ คอนโซล Google Cloud
  2. ไปที่ API และบริการ > ข้อมูลเข้าสู่ระบบ
  3. คลิก สร้างข้อมูลเข้าสู่ระบบ > คีย์ API
  4. คัดลอกคีย์ที่สร้างขึ้นและเพิ่มลงในไฟล์ .env เป็น MAPS_API_KEY=[YOUR_KEY]
  5. (แนะนำ) จำกัดคีย์เพื่อให้อนุญาตเฉพาะ Maps API ที่เซิร์ฟเวอร์ MCP ใช้

2. คีย์ Gemini API (AI Studio)

  1. ไปที่ Google AI Studio
  2. คลิก รับคีย์ API หรือไปที่ส่วนคีย์ API
  3. คลิก สร้างคีย์ API
  4. คัดลอกคีย์และเพิ่มลงในไฟล์ .env เป็น GEMINI_API_KEY=[YOUR_KEY]

5. ติดตั้งทรัพยากร Dependency

สร้างไฟล์ requirements.txt ในโฟลเดอร์ petpassport/ โดยใช้คำสั่งต่อไปนี้

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

6. ตรวจสอบสิทธิ์เซิร์ฟเวอร์ MCP

แอปพลิเคชันนี้ใช้เซิร์ฟเวอร์ Model Context Protocol (MCP) เพื่อโต้ตอบกับ Google Maps และ BigQuery หากต้องการตรวจสอบสิทธิ์เซิร์ฟเวอร์เหล่านี้ คุณต้องกำหนดค่าตัวแปรสภาพแวดล้อมและส่วนหัวที่เหมาะสม

  1. Google Maps MCP: ต้องใช้คีย์ Maps API ที่ถูกต้องซึ่งส่งผ่านในส่วนหัว X-Goog-Api-Key
  2. BigQuery MCP: ต้องใช้ข้อมูลเข้าสู่ระบบ OAuth ที่มีสิทธิ์เข้าถึงบริการ BigQuery Agent จะใช้บัญชีบริการเริ่มต้นของ Compute เมื่อทำงานใน Cloud Run หรือใช้ข้อมูลเข้าสู่ระบบในเครื่องเมื่อทำงานในเครื่อง

เรามีสคริปต์การตั้งค่า setup/setup_env.sh ในที่เก็บซึ่งช่วยกำหนดค่าตัวแปรเหล่านี้ในไฟล์ .env

7. การสร้างตาราง BigQuery

ก่อนที่ Agent จะค้นหาข้อมูลใบอนุญาตสุนัขได้ เราต้องสร้างชุดข้อมูลและตารางใน BigQuery แล้วโหลดข้อมูล

เรามีสคริปต์การตั้งค่า setup/setup_bigquery.sh ซึ่งดำเนินการตามขั้นตอนต่อไปนี้

  1. สร้าง Bucket ของ Cloud Storage ชื่อ pet-passport-data-[PROJECT_ID] เพื่อจัดเก็บข้อมูลดิบ
  2. ดาวน์โหลดชุดข้อมูลการออกใบอนุญาตสุนัขของนิวยอร์กซิตี้แบบสาธารณะ (CSV)
  3. อัปโหลด CSV ไปยัง Bucket
  4. สร้างชุดข้อมูล BigQuery ชื่อ nyc_dogs
  5. โหลดข้อมูลจาก Bucket ลงในตารางชื่อ licenses ในชุดข้อมูล

หากต้องการเรียกใช้สคริปต์การตั้งค่า ให้เรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล

bash setup/setup_bigquery.sh

8. เชื่อมต่อกับเซิร์ฟเวอร์ MCP

ส่วนสำคัญของแอปนี้คือการใช้ MCP เพื่อเชื่อมต่อกับข้อมูลและบริการ ในส่วนนี้ คุณจะได้กำหนดค่าชุดเครื่องมือ MCP สำหรับ BigQuery และ Google Maps ในไฟล์ชื่อ petpassport/tools.py

โค้ด tools.py ฉบับสมบูรณ์

นี่คือการใช้งาน tools.py ฉบับสมบูรณ์ ซึ่งรวมถึงชุดเครื่องมือ MCP และเครื่องมือที่กำหนดเองสำหรับการคงอยู่ของรูปภาพและข้อมูล เราได้เพิ่มประสิทธิภาพโค้ดนี้เพื่อลดความซ้ำซ้อนด้วยการย้ายการแก้ปัญหา Bucket ไปไว้ที่ระดับโมดูล

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 ที่ลงชื่อแล้วไปยังฟรอนท์เอนด์เพื่อให้คงอยู่ได้แม้จะมีการรีสตาร์ทเซิร์ฟเวอร์

9. การสร้าง Agent

เมื่อกำหนดค่าเครื่องมือแล้ว ก็ถึงเวลาสร้าง "สมอง" ของ Agent คุณจะใช้ Agent Development Kit (ADK) เพื่อสร้าง Agent ในไฟล์ชื่อ petpassport/agent.py

โค้ด agent.py ฉบับสมบูรณ์

นี่คือการใช้งาน agent.py ฉบับสมบูรณ์ ซึ่งเรากำหนด Agent และคำแนะนำสำหรับ Agent

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 โดยตรง (โครงสร้างแบบแบน) เพื่อรองรับสภาพแวดล้อมคอนเทนเนอร์
  • Agent ได้รับการเริ่มต้นด้วย gemini-2.5-pro
  • คำแนะนำกำหนดห่วงโซ่ความคิดแบบหลายขั้นตอนที่เข้มงวด (BigQuery ก่อน แล้วจึง Maps) และห้ามไม่ให้เกิดการหลอนหรือการแสดงเส้นทางการเดินที่ทำให้เกิดความยุ่งเหยิง

10. การเรียกใช้แอปพลิเคชันในเครื่อง

ก่อนที่จะติดตั้งใช้งานใน Cloud Run คุณควรทดสอบแอปพลิเคชันในเครื่อง

  1. ตรวจสอบว่าคุณอยู่ในไดเรกทอรีโปรเจ็กต์ โดยใช้คำสั่งต่อไปนี้
    cd examples/petpassport
    
  2. เริ่มเซิร์ฟเวอร์ FastAPI โดยใช้ uvicorn เพื่อเรียกใช้แอป จุดแรกเข้าคือ main.py ภายในโฟลเดอร์ petpassport
    uvicorn petpassport.main:app --reload
    
  3. เปิด UI โดยไปที่ http://127.0.0.1:8000/ui/ ในเบราว์เซอร์เพื่อโต้ตอบกับอินเทอร์เฟซ Pet Passport

11. กำลังทำให้ใช้งานได้กับ Cloud Run

เมื่อ Agent พร้อมแล้ว ก็ถึงเวลาติดตั้งใช้งานใน 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 Maps
  • GOOGLE_CLOUD_PROJECT: รหัสโปรเจ็กต์
  • PROJECT_ID: รหัสโปรเจ็กต์ (รองรับความซ้ำซ้อนสำหรับโมดูลเดิม)

12. ตัวอย่างพรอมต์

ลองโต้ตอบกับ Agent ที่ติดตั้งใช้งานแล้วโดยใช้พรอมต์ต่อไปนี้

  1. มาตรฐาน: "ฉันอยากไปเดินเล่นกับโกลเด้นรีทรีฟเวอร์ในนิวยอร์กซิตี้แถวๆ 10021 ช่วยหาเส้นทางที่มีคาเฟ่ให้เราหน่อย"
  2. สายพันธุ์อื่น: "ฉันมีสุนัขเฟรนช์บูลด็อกและเราอยู่ใน Upper West Side (แถวๆ 10024) ช่วยแนะนำการเดินเล่นสั้นๆ ที่แวะสวนสาธารณะสำหรับสุนัขยอดนิยมหน่อย"
  3. พร้อมรูปภาพ: (อัปโหลดรูปภาพสุนัข) "นี่คือรูปภาพสุนัขคอร์กี้ของฉัน เราอยู่แถวๆ 10013 ช่วยวางแผนการออกไปเที่ยวที่สมบูรณ์แบบให้เราหน่อย"

13. ล้างข้อมูล

วิธีหลีกเลี่ยงการเรียกเก็บเงินสำหรับทรัพยากรที่ใช้ในบทแนะนำนี้

  • ลบบริการ Cloud Run โดยใช้คำสั่ง gcloud run services delete petpassport --region=$REGION
  • ลบ Bucket ของ GCS โดยใช้คำสั่ง gcloud storage rm -r gs://pet-passport-data-$PROJECT_ID