1. Wprowadzenie
Agenty AI są przydatne tylko w zakresie danych, do których mają dostęp. Większość danych w świecie rzeczywistym znajduje się w bazach danych, a połączenie agentów z bazami danych zwykle wymaga napisania w kodzie agenta kodu do zarządzania połączeniami, logiki zapytań i potoków osadzania. Każdy agent, który potrzebuje dostępu do bazy danych, powtarza tę pracę, a każda zmiana zapytania wymaga ponownego wdrożenia agenta.
W tym laboratorium znajdziesz inne podejście. Narzędzia bazy danych deklarujesz w pliku YAML – standardowa wersja SQL, wyszukiwanie podobieństwa wektorowego, a nawet automatyczne generowanie wektorów dystrybucyjnych. MCP Toolbox for Databases obsługuje wszystkie operacje na bazie danych jako serwer MCP. Kod agenta pozostaje minimalny: wczytaj narzędzia i pozwól Gemini zdecydować, które z nich wywołać.
Co utworzysz
Inteligentny asystent tablicy ogłoszeń dla „TechJobs” – agent ADK oparty na Gemini, który pomaga programistom przeglądać oferty pracy w branży technicznej za pomocą standardowych filtrów (stanowisko, stos technologiczny) i odkrywać oferty pracy na podstawie opisów w języku naturalnym, np. „Chcę pracować zdalnie nad chatbotami AI”. Agent odczytuje dane z bazy danych Cloud SQL PostgreSQL i zapisuje w niej dane w całości za pomocą MCP Toolbox for Databases, które obsługuje cały dostęp do bazy danych, w tym automatyczne generowanie wektorów dystrybucyjnych na potrzeby wyszukiwania wektorowego. Na koniec zarówno Toolbox, jak i agent będą działać w Cloud Run.
Czego się nauczysz
- Jak MCP (Model Context Protocol) standaryzuje dostęp do narzędzi dla agentów AI i jak MCP Toolbox for Databases stosuje to do operacji na bazie danych
- Konfigurowanie MCP Toolbox for Databases jako oprogramowania pośredniczącego między agentem ADK a Cloud SQL PostgreSQL
- Zdefiniuj narzędzia bazy danych deklaratywnie w
tools.yaml– w agencie nie ma kodu bazy danych. - Tworzenie agenta ADK, który wczytuje narzędzia z działającego serwera zestawu narzędzi za pomocą
ToolboxToolset - Generowanie wektorów dystrybucyjnych za pomocą wbudowanej funkcji
embedding()Cloud SQL i włączanie wyszukiwania semantycznego za pomocą funkcjipgvector - Użyj funkcji
valueFromParamdo automatycznego wczytywania wektorów podczas operacji zapisu. - Wdrażanie serwera Toolbox i agenta pakietu ADK w Cloud Run
Wymagania wstępne
- Konto Google Cloud z próbnym kontem rozliczeniowym
- podstawowa znajomość Pythona i SQL,
- Przydatne będzie wcześniejsze doświadczenie z bazą danych w chmurze i pakietem ADK.
2. Konfigurowanie środowiska
Ten krok przygotowuje środowisko Cloud Shell, konfiguruje projekt Google Cloud i klonuje repozytorium referencyjne.
Otwieranie Cloud Shell
Otwórz Cloud Shell w przeglądarce. Cloud Shell zapewnia wstępnie skonfigurowane środowisko ze wszystkimi narzędziami potrzebnymi do tego ćwiczenia. Gdy pojawi się prośba o autoryzację, kliknij Autoryzuj.
Następnie kliknij „Widok” –> „Terminal”, aby otworzyć terminal.Interfejs powinien wyglądać podobnie do tego:

Będzie to nasz główny interfejs: IDE u góry, terminal u dołu.
Konfigurowanie katalogu roboczego
Utwórz katalog roboczy. Cały kod, który napiszesz w tym ćwiczeniu, będzie się znajdować tutaj:
mkdir -p ~/build-agent-adk-toolbox-cloudsql
cloudshell workspace ~/build-agent-adk-toolbox-cloudsql && cd ~/build-agent-adk-toolbox-cloudsql
Następnie przygotuj kilka katalogów do zarządzania takimi elementami jak skrypty początkowe i logi.
mkdir -p ~/build-agent-adk-toolbox-cloudsql/scripts
mkdir -p ~/build-agent-adk-toolbox-cloudsql/logs
Konfigurowanie projektu Google Cloud
Utwórz plik .env ze zmiennymi lokalizacji:
# For Vertex AI / Gemini API calls
echo "GOOGLE_CLOUD_LOCATION=global" > .env
# For Cloud SQL, Cloud Run, Artifact Registry
echo "REGION=us-central1" >> .env
Aby uprościć konfigurację projektu w terminalu, pobierz ten skrypt konfiguracji projektu do katalogu roboczego:
curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh
Uruchom skrypt. Weryfikuje ono Twoje próbne konto rozliczeniowe, tworzy nowy projekt (lub weryfikuje istniejący), zapisuje identyfikator projektu w pliku .env w bieżącym katalogu i ustawia aktywny projekt w gcloud.
bash setup_verify_trial_project.sh && source .env
Skrypt wykona te działania:
- Sprawdź, czy masz aktywne konto rozliczeniowe w wersji próbnej
- Sprawdź, czy w
.envistnieje projekt (jeśli tak) - Utwórz nowy projekt lub użyj istniejącego.
- Połącz próbne konto rozliczeniowe z projektem
- Zapisz identyfikator projektu w
.env. - Ustaw projekt jako aktywny projekt
gcloud.
Sprawdź, czy projekt jest prawidłowo ustawiony, sprawdzając żółty tekst obok katalogu roboczego w wierszu poleceń terminala Cloud Shell. Powinien wyświetlać identyfikator projektu.

Aktywowanie wymaganego interfejsu API
Następnie musimy włączyć kilka interfejsów API dla usługi, z którą będziemy wchodzić w interakcje:
gcloud services enable \
aiplatform.googleapis.com \
sqladmin.googleapis.com \
compute.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com
- Vertex AI API (
aiplatform.googleapis.com) – Twój agent korzysta z modeli Gemini, a Toolbox używa interfejsu Embedding API do wyszukiwania wektorowego. - Cloud SQL Admin API (
sqladmin.googleapis.com) – możesz udostępniać instancję PostgreSQL i nią zarządzać. - Compute Engine API (
compute.googleapis.com) – wymagany do tworzenia instancji Cloud SQL. - Cloud Run, Cloud Build, Artifact Registry – używane w kroku wdrażania w dalszej części tego laboratorium
3. Przygotowywanie skryptów do inicjowania bazy danych
Ten krok rozpoczyna tworzenie instancji Cloud SQL i uruchamia automatyczny skrypt konfiguracji, który czeka na gotowość instancji, a następnie tworzy bazę danych, wypełnia ją ofertami pracy i generuje osadzanie – wszystko w ramach jednej operacji.
Najpierw dodaj hasło do bazy danych do pliku .env i wczytaj go ponownie:
echo "DB_PASSWORD=techjobs-pwd" >> .env
echo "DB_INSTANCE=jobs-instance" >> .env
echo "DB_NAME=jobs_db" >> .env
source .env
Tworzenie skryptu Bash do utworzenia instancji i bazy danych
Następnie utwórz skrypt scripts/setup_database.sh za pomocą tego polecenia:
mkdir -p ~/build-agent-adk-toolbox-cloudsql/scripts
cloudshell edit scripts/setup_database.sh
Następnie skopiuj ten kod do pliku scripts/setup_database.sh.
#!/bin/bash
set -e
source .env
echo "================================================"
echo "Database Setup"
echo "================================================"
echo ""
# Step 1: Create Cloud SQL instance
echo "[1/5] Creating Cloud SQL instance..."
# Check if instance already exists
if gcloud sql instances describe "$DB_INSTANCE" --quiet >/dev/null 2>&1; then
echo " Instance already exists"
else
echo " Creating instance (takes 5-10 minutes)..."
gcloud sql instances create "$DB_INSTANCE" \
--database-version=POSTGRES_17 \
--tier=db-custom-1-3840 \
--edition=ENTERPRISE \
--region="$REGION" \
--root-password="$DB_PASSWORD" \
--enable-google-ml-integration \
--database-flags cloudsql.enable_google_ml_integration=on \
--quiet
fi
echo " ✓ Instance ready"
echo ""
# Step 2: Verify instance is ready
echo "[2/5] Verifying instance state..."
STATE=$(gcloud sql instances describe "$DB_INSTANCE" --format='value(state)')
if [ "$STATE" != "RUNNABLE" ]; then
echo "ERROR: Instance not ready (state: $STATE)"
exit 1
fi
echo " ✓ Instance is RUNNABLE"
echo ""
# Step 3: Grant IAM permissions
echo "[3/5] Granting Vertex AI permissions..."
SERVICE_ACCOUNT=$(gcloud sql instances describe "$DB_INSTANCE" \
--format='value(serviceAccountEmailAddress)')
if [ -z "$SERVICE_ACCOUNT" ]; then
echo "ERROR: Could not retrieve service account"
exit 1
fi
gcloud projects add-iam-policy-binding "$GOOGLE_CLOUD_PROJECT" \
--member="serviceAccount:$SERVICE_ACCOUNT" \
--role="roles/aiplatform.user" \
--quiet
echo " ✓ Permissions granted"
echo ""
# Step 4: Create database
echo "[4/5] Creating database..."
# Check if database already exists
if gcloud sql databases describe "$DB_NAME" \
--instance="$DB_INSTANCE" --quiet >/dev/null 2>&1; then
echo " Database already exists"
else
gcloud sql databases create "$DB_NAME" \
--instance="$DB_INSTANCE" \
--quiet
fi
echo " ✓ Database '$DB_NAME' ready"
echo ""
# Step 5: Seed database and generate embeddings
echo "[5/5] Seeding database and generating embeddings..."
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SETUP_SCRIPT="${SCRIPT_DIR}/setup_jobs_db.py"
if [ ! -f "$SETUP_SCRIPT" ]; then
echo "ERROR: Setup script not found: $SETUP_SCRIPT"
exit 1
fi
uv run "$SETUP_SCRIPT"
echo ""
echo "================================================"
echo "Setup complete!"
echo "================================================"
echo ""
Tworzenie skryptu w Pythonie do wypełniania danych
Następnie utwórz plik Pythona ze skryptem początkowym scripts/setup_jobs_db.py za pomocą poniższego polecenia.
cloudshell edit scripts/setup_jobs_db.py
Następnie skopiuj ten kod do pliku scripts/setup_jobs_db.py.
import os
import sys
from pathlib import Path
from dotenv import load_dotenv
from google.cloud.sql.connector import Connector
import pg8000
import time
# Load environment variables from .env file
env_path = Path(__file__).parent.parent / '.env'
load_dotenv(env_path)
EMBEDDING_MODEL='gemini-embedding-001'
# Verify required environment variables
required_vars = ['GOOGLE_CLOUD_PROJECT', 'REGION', 'DB_PASSWORD']
missing_vars = [var for var in required_vars if not os.environ.get(var)]
if missing_vars:
print(f"ERROR: Missing required environment variables: {', '.join(missing_vars)}", file=sys.stderr)
print(f"", file=sys.stderr)
print(f"Expected .env file location: {env_path}", file=sys.stderr)
if not env_path.exists():
print(f"✗ File not found at that location", file=sys.stderr)
else:
print(f"✓ File exists but is missing the variables above", file=sys.stderr)
print(f"", file=sys.stderr)
print(f"Make sure your .env file contains:", file=sys.stderr)
for var in missing_vars:
print(f" {var}=<value>", file=sys.stderr)
sys.exit(1)
# Job listings data (fictional, for tutorial purposes only)
JOBS = [
("Senior Backend Engineer", "Stripe", "Backend", "Go, PostgreSQL, gRPC, Kubernetes", "$180-250K/year", "San Francisco, Hybrid", 3,
"Design and build high-throughput microservices powering payment infrastructure for millions of businesses. Optimize Go services for sub-100ms latency at scale, work with PostgreSQL and Redis for data persistence, and deploy on Kubernetes clusters handling billions of API calls."),
("Machine Learning Engineer", "Spotify", "Data/AI", "Python, TensorFlow, BigQuery, Vertex AI", "$170-230K/year", "Stockholm, Remote", 2,
"Build and deploy ML models for music recommendation and personalization systems serving hundreds of millions of listeners. Design feature pipelines in BigQuery, train models using distributed computing, and serve predictions through real-time APIs processing thousands of requests per second."),
("Frontend Engineer", "Vercel", "Frontend", "React, TypeScript, Next.js", "$140-190K/year", "Remote", 4,
"Build developer-facing dashboard interfaces and deployment tools used by millions of developers worldwide. Create responsive, accessible React components for project management, analytics, and real-time deployment monitoring with a focus on developer experience."),
("DevOps Engineer", "Datadog", "DevOps", "Terraform, GCP, Docker, Kubernetes, ArgoCD", "$160-220K/year", "New York, Hybrid", 2,
"Manage cloud infrastructure powering an observability platform used by thousands of engineering teams. Automate deployment pipelines with ArgoCD, manage multi-cloud Kubernetes clusters, and implement infrastructure-as-code with Terraform across production environments."),
("Mobile Engineer (Android)", "Grab", "Mobile", "Kotlin, Jetpack Compose, GraphQL", "$120-170K/year", "Singapore, Hybrid", 3,
"Develop features for a super-app serving millions of users across Southeast Asia. Build modern Android UIs with Jetpack Compose, integrate GraphQL APIs, and optimize app performance for diverse device capabilities and network conditions."),
("Data Engineer", "Airbnb", "Data", "Python, Apache Spark, Airflow, BigQuery", "$160-210K/year", "San Francisco, Hybrid", 2,
"Build data pipelines that process booking, search, and pricing data for a global travel marketplace. Design ETL workflows with Apache Spark and Airflow, maintain data warehouses in BigQuery, and ensure data quality for analytics and machine learning teams."),
("Full Stack Engineer", "Revolut", "Full Stack", "TypeScript, Node.js, React, PostgreSQL", "$130-180K/year", "London, Remote", 5,
"Build the next generation of financial products making banking accessible to millions of users across 35 countries. Develop real-time trading interfaces with React and WebSockets, build Node.js APIs handling market data streams, and design PostgreSQL schemas for financial transactions."),
("Site Reliability Engineer", "Cloudflare", "SRE", "Go, Prometheus, Grafana, GCP, Terraform", "$170-230K/year", "Austin, Hybrid", 2,
"Ensure 99.99% uptime for a global network handling millions of requests per second. Define SLOs, build monitoring dashboards with Prometheus and Grafana, manage incident response, and automate infrastructure scaling across 300+ data centers worldwide."),
("Cloud Architect", "Google Cloud", "Cloud", "GCP, Terraform, Kubernetes, Python", "$200-280K/year", "Seattle, Hybrid", 1,
"Help enterprises modernize their infrastructure on Google Cloud. Design multi-region architectures, lead migration projects from on-premises to GKE, and build reference implementations using Terraform and Cloud Foundation Toolkit."),
("Backend Engineer (Payments)", "Square", "Backend", "Java, Spring Boot, PostgreSQL, Kafka", "$160-220K/year", "San Francisco, Hybrid", 3,
"Build payment processing systems handling millions of transactions for businesses of all sizes. Design event-driven architectures using Kafka, implement idempotent payment flows with Spring Boot, and ensure PCI-DSS compliance across all services."),
("AI Engineer", "Hugging Face", "Data/AI", "Python, LangChain, Vertex AI, FastAPI, PostgreSQL", "$150-210K/year", "Paris, Remote", 2,
"Build AI-powered tools for the largest open-source ML community. Develop RAG pipelines that index and search model documentation, create conversational agents using LangChain, and deploy AI services with FastAPI on cloud infrastructure."),
("Platform Engineer", "Coinbase", "Platform", "Rust, Kubernetes, AWS, Terraform", "$180-250K/year", "Remote", 0,
"Build the infrastructure platform for a leading cryptocurrency exchange. Develop high-performance matching engines in Rust, manage Kubernetes clusters for microservices, and design CI/CD pipelines that enable rapid feature deployment with zero downtime."),
("QA Automation Engineer", "Shopify", "QA", "Python, Selenium, Cypress, Jenkins", "$110-160K/year", "Toronto, Hybrid", 3,
"Design and maintain automated test suites for a commerce platform powering millions of merchants. Build end-to-end test frameworks with Cypress and Selenium, integrate tests into Jenkins CI pipelines, and establish quality gates that prevent regressions in checkout and payment flows."),
("Security Engineer", "CrowdStrike", "Security", "Python, SIEM, Kubernetes, Penetration Testing", "$170-240K/year", "Austin, On-site", 1,
"Protect enterprise customers from cyber threats on a leading endpoint security platform. Conduct penetration testing, design security monitoring with SIEM tools, implement zero-trust networking in Kubernetes environments, and lead incident response for security events."),
("Product Engineer", "GitLab", "Full Stack", "Go, React, PostgreSQL, Redis, GCP", "$140-200K/year", "Remote", 4,
"Own features end-to-end for an all-in-one DevSecOps platform used by millions of developers. Build Go microservices for CI/CD pipelines, create React frontends for code review and project management, and collaborate with product managers to iterate on user-facing features using data-driven development."),
]
def get_connection():
"""Create a connection to Cloud SQL using the connector."""
project = os.environ['GOOGLE_CLOUD_PROJECT']
region = os.environ['REGION']
password = os.environ['DB_PASSWORD']
instance = os.environ['DB_INSTANCE']
database = os.environ['DB_NAME']
connector = Connector()
conn = connector.connect(
f"{project}:{region}:{instance}",
"pg8000",
user="postgres",
password=password,
db=database
)
return conn, connector
def create_schema(cursor):
"""Create extensions and jobs table."""
cursor.execute("CREATE EXTENSION IF NOT EXISTS google_ml_integration")
cursor.execute("CREATE EXTENSION IF NOT EXISTS vector")
cursor.execute("""
CREATE TABLE IF NOT EXISTS jobs (
id SERIAL PRIMARY KEY,
title VARCHAR NOT NULL,
company VARCHAR NOT NULL,
role VARCHAR NOT NULL,
tech_stack VARCHAR NOT NULL,
salary_range VARCHAR NOT NULL,
location VARCHAR NOT NULL,
openings INTEGER NOT NULL,
description TEXT NOT NULL,
description_embedding vector(3072)
)
""")
def seed_jobs(cursor, conn):
"""Insert job listings."""
cursor.execute("SELECT COUNT(*) FROM jobs")
existing_count = cursor.fetchone()[0]
if existing_count > 0:
print(f" {existing_count} jobs already exist, skipping seed")
return 0
cursor.executemany("""
INSERT INTO jobs (title, company, role, tech_stack, salary_range, location, openings, description)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
""", JOBS)
conn.commit()
return len(JOBS)
def generate_embeddings(cursor, conn):
"""Generate embeddings using Cloud SQL's embedding() function."""
cursor.execute("SELECT COUNT(*) FROM jobs WHERE description_embedding IS NULL")
null_count = cursor.fetchone()[0]
if null_count == 0:
print(" All jobs already have embeddings")
return 0
cursor.execute(f"""
UPDATE jobs
SET description_embedding = embedding('{EMBEDDING_MODEL}', description)::vector
WHERE description_embedding IS NULL
""")
rows_updated = cursor.rowcount
conn.commit()
return rows_updated
def main():
conn, connector = get_connection()
cursor = conn.cursor()
try:
create_schema(cursor)
conn.commit()
seeded = seed_jobs(cursor, conn)
if seeded > 0:
print(f" ✓ Inserted {seeded} jobs")
# Waiting for vertex role propagation
time.sleep(60)
embedded = generate_embeddings(cursor, conn)
if embedded > 0:
print(f" ✓ Generated {embedded} embeddings")
except Exception as e:
print(f"ERROR: {e}", file=sys.stderr)
sys.exit(1)
finally:
cursor.close()
conn.close()
connector.close()
if __name__ == "__main__":
main()
Przejdźmy teraz do następnego kroku.
4. Tworzenie i inicjowanie bazy danych
Teraz nasze skrypty są gotowe do wykonania. Do wykonania przygotowanego skryptu będziemy potrzebować Pythona, więc najpierw przygotujmy go.
Konfigurowanie projektu w Pythonie
uv to szybki menedżer pakietów i projektów Pythona napisany w Rust ( dokumentacja uv). W tym samouczku używamy go ze względu na szybkość i prostotę utrzymywania projektu w Pythonie.
Zainicjuj projekt w Pythonie i dodaj wymagane zależności:
uv init
uv add cloud-sql-python-connector --extra pg8000
uv add python-dotenv
Pamiętaj, że do zainicjowania bezpiecznego połączenia z instancją bazy danych, która jest uwierzytelniana za pomocą domyślnego uwierzytelniania aplikacji, używamy tutaj cloud-sql-python-connectorpakietu SDK Pythona.
Uruchom skrypt konfiguracji
Teraz możemy uruchomić skrypt konfiguracji w tle i sprawdzić dane wyjściowe konsoli, które zostaną zapisane w pliku logs/atabase_setup.log za pomocą tego polecenia. Nie musisz czekać na zakończenie tego procesu. Możesz przejść do następnej sekcji.
mkdir -p ~/build-agent-adk-toolbox-cloudsql/logs
bash scripts/setup_database.sh > logs/database_setup.log 2>&1 &
Pobierz plik binarny Toolbox
W tym samouczku użyjemy zestawu narzędzi MCP. Na szczęście zawiera on gotowy plik binarny, który można wykorzystać w środowisku Linux. Pobierzmy go teraz w tle, ponieważ zajmie to trochę czasu. Aby pobrać plik binarny i sprawdzić dziennik danych wyjściowych na platformie logs/toolbox_dl.log, uruchom to polecenie: Nie musisz czekać na zakończenie tego procesu. Możesz przejść do następnej sekcji.
cd ~/build-agent-adk-toolbox-cloudsql
curl -O https://storage.googleapis.com/mcp-toolbox-for-databases/v1.0.0/linux/amd64/toolbox > logs/toolbox_dl.log 2>&1 &
Informacje o skrypcie konfiguracji scripts/setup_database.sh
Teraz spróbujmy zrozumieć skrypt konfiguracji, który wcześniej skonfigurowaliśmy. Wykonuje te czynności:
- Pierwsze polecenie, które tam wykonujemy, to polecenie
gcloud sql instances createz tą flagą:
db-custom-1-3840to najmniejsza warstwa Cloud SQL z dedykowanym rdzeniem (1 procesor wirtualny, 3,75 GB pamięci RAM) w wersjiENTERPRISE. Więcej informacji znajdziesz tutaj. Integracja z Vertex AI ML wymaga dedykowanego rdzenia. Nie jest obsługiwana w przypadku warstw ze współużytkowanym rdzeniem (db-f1-micro,db-g1-small).--root-passwordustawia hasło domyślnego użytkownikapostgres.--enable-google-ml-integrationwłącza wbudowaną integrację Cloud SQL z Vertex AI, która umożliwia wywoływanie modeli osadzania bezpośrednio z SQL za pomocą funkcjiembedding().
- Sprawdź, czy instancja ma już stan
RUNNABLE. - Przyznaj kontu usługi instancji Cloud SQL uprawnienia do wywoływania Vertex AI za pomocą polecenia
gcloud projects add-iam-policy-binding. Jest to wymagane w przypadku wbudowanej funkcjiembedding(), której użyjemy podczas wypełniania bazy danych. - Tworzenie bazy danych
- Uruchamianie skryptu początkowego
setup_jobs_db.pyscript
Informacje o skrypcie początkowym scripts/setup_jobs_db.py
Skrypt inicjujący wykonuje te czynności:
- Inicjowanie połączenia z instancją bazy danych
- Instaluje 2 rozszerzenia PostgreSQL:
google_ml_integration– udostępnia funkcję SQLembedding(), która wywołuje modele wektorów dystrybucyjnych Vertex AI bezpośrednio z SQL. Jest to rozszerzenie na poziomie bazy danych, które udostępnia funkcje ML wjobs_db. Flaga na poziomie instancji (--enable-google-ml-integration) ustawiona podczas tworzenia instancji umożliwia maszynie wirtualnej Cloud SQL dostęp do Vertex AI – rozszerzenie udostępnia funkcje SQL w tej konkretnej bazie danych.vector(pgvector) – dodaje typ danychvectori operatory odległości do przechowywania i wysyłania zapytań dotyczących osadzania.
- Utwórz tabelę. Zwróć uwagę, że kolumna
description_embeddingtovector(3072)– kolumnapgvector, która przechowuje wektory 3072-wymiarowe. - Wypełnianie początkowych danych zadań
- Wygeneruj dane osadzania z pola
descriptioni wypełnij poledescription_embeddingza pomocą wbudowanej integracji Vertex za pomocą funkcjiembedding().
embedding('gemini-embedding-001', description)– wywołuje model wektorów dystrybucyjnych Gemini w Vertex AI bezpośrednio z SQL, przekazując tekstdescriptionkażdego zadania. Jest to rozszerzeniegoogle_ml_integrationzainstalowane w skrypcie początkowym.::vector– rzutuje zwróconą tablicę liczb zmiennoprzecinkowych na typvectorpgvector, aby można było ją przechowywać i wykonywać na niej zapytania za pomocą operatorów odległości.- Model
UPDATEdziała na wszystkich 15 wierszach, generując 1 osadzenie o 3072 wymiarach na opis stanowiska.
Przygotuje to wstępne dane, do których dostęp będzie miał nasz pracownik obsługi klienta.
5. Konfigurowanie zestawu narzędzi MCP dla baz danych
W tym kroku przedstawiamy MCP Toolbox for Databases, konfigurujemy go tak, aby łączył się z instancją Cloud SQL, i definiujemy 2 standardowe narzędzia do wykonywania zapytań SQL.
Czym jest MCP i dlaczego warto korzystać z Toolbox?

MCP (Model Context Protocol) to otwarty protokół, który standaryzuje sposób, w jaki agenci AI wykrywają narzędzia zewnętrzne i wchodzą z nimi w interakcje. Definiuje model klient-serwer: agent hostuje klienta MCP, a narzędzia są udostępniane przez serwery MCP. Każdy klient zgodny z MCP może używać dowolnego serwera zgodnego z MCP – agent nie potrzebuje niestandardowego kodu integracji dla każdego narzędzia.

MCP Toolbox for Databases to serwer MCP typu open source stworzony specjalnie z myślą o dostępie do baz danych. Bez niego musisz pisać funkcje Pythona, które otwierają połączenia z bazą danych, zarządzają pulami połączeń, tworzą zapytania parametryzowane, aby zapobiegać wstrzyknięciu kodu SQL, obsługują błędy i osadzają cały ten kod w agencie. Każdy agent, który potrzebuje dostępu do bazy danych, powtarza tę pracę. Zmiana zapytania oznacza ponowne wdrożenie agenta.
W Toolboxie piszesz plik YAML. Każde narzędzie jest mapowane na sparametryzowaną instrukcję SQL. Zestaw narzędzi obsługuje pulę połączeń, zapytania parametryzowane, uwierzytelnianie i obserwację. Narzędzia są odłączone od agenta – możesz zaktualizować zapytanie, edytując tools.yaml i ponownie uruchamiając Toolbox, bez ingerowania w kod agenta. Te same narzędzia działają w przypadku ADK, LangGraph, LlamaIndex i każdej platformy zgodnej z MCP.
Zapisz konfigurację narzędzi
Teraz musimy utworzyć plik o nazwie tools.yaml w edytorze Cloud Shell, aby skonfigurować narzędzia.
cloudshell edit tools.yaml
Plik używa formatu YAML z wieloma dokumentami – każdy blok oddzielony znakiem --- jest samodzielnym zasobem. Każde źródło ma kind, które określa, czym jest (sources w przypadku połączeń z bazą danych, tools w przypadku działań wywoływanych przez agenta), oraz type, które określa backend (cloud-sql-postgres w przypadku źródła, postgres-sql w przypadku narzędzi opartych na SQL). Narzędzie odwołuje się do swojego źródła za pomocą znaku name, dzięki czemu Zestaw narzędzi wie, z której puli połączeń ma korzystać. Zmienne środowiskowe używają składni ${VAR_NAME} i są rozwiązywane podczas uruchamiania.
Teraz skopiuj te skrypty do pliku tools.yaml.
# tools.yaml
# --- Data Source ---
kind: source
name: jobs-db
type: cloud-sql-postgres
project: ${GOOGLE_CLOUD_PROJECT}
region: ${REGION}
instance: ${DB_INSTANCE}
database: ${DB_NAME}
user: postgres
password: ${DB_PASSWORD}
---
Ten skrypt definiuje ten zasób:
- Źródło (
jobs-db) – informuje Toolbox, jak połączyć się z instancją Cloud SQL PostgreSQL. Typcloud-sql-postgreswewnętrznie korzysta z oprogramowania sprzęgającego Cloud SQL, które automatycznie obsługuje uwierzytelnianie i bezpieczne połączenia. Obiekty zastępcze${GOOGLE_CLOUD_PROJECT},${REGION}i${DB_PASSWORD}są tłumaczone ze zmiennych środowiskowych podczas uruchamiania.
Następnie dodaj ten skrypt pod symbolem --- w pliku tools.yaml.
# --- Tool 1: Search jobs by role and/or tech stack ---
kind: tool
name: search-jobs
type: postgres-sql
source: jobs-db
description: >-
Search for job listings by role category and/or tech stack.
Use this tool when the developer wants to browse listings
by role (e.g., Backend, Frontend, Data) or find jobs
using a specific technology. Both parameters accept an
empty string to match all values.
statement: |
SELECT title, company, role, tech_stack, salary_range, location, openings
FROM jobs
WHERE ($1 = '' OR LOWER(role) = LOWER($1))
AND ($2 = '' OR LOWER(tech_stack) LIKE '%' || LOWER($2) || '%')
ORDER BY title
LIMIT 10
parameters:
- name: role
type: string
description: "The role category to filter by (e.g., 'Backend', 'Frontend', 'Data/AI', 'DevOps'). Use empty string for all roles."
- name: tech_stack
type: string
description: "A technology to search for in the tech stack (partial match, e.g., 'Python', 'Kubernetes'). Use empty string for all tech stacks."
---
# --- Tool 2: Get full details for a specific job ---
kind: tool
name: get-job-details
type: postgres-sql
source: jobs-db
description: >-
Get full details for a specific job listing including its description,
salary range, location, and number of openings. Use this tool when the
developer asks about a particular job by title or company.
statement: |
SELECT title, company, role, tech_stack, salary_range, location, openings, description
FROM jobs
WHERE LOWER(title) LIKE '%' || LOWER($1) || '%'
OR LOWER(company) LIKE '%' || LOWER($1) || '%'
parameters:
- name: search_term
type: string
description: "The job title or company name to look up (partial match supported)."
---
Ten skrypt definiuje ten zasób:
- Narzędzia 1 i 2 (
search-jobs,get-job-details) – standardowe narzędzia do zapytań SQL. Każda z nich mapuje nazwę narzędzia (widoczną dla agenta) na sparametryzowaną instrukcję SQL (wykonywaną przez bazę danych). Parametry używają obiektów zastępczych$1i$2. Narzędzia wykonują je jako przygotowane instrukcje, co zapobiega wstrzyknięciu kodu SQL.
Kontynuujmy. Dodaj ten skrypt pod symbolem --- w pliku tools.yaml.
# --- Embedding Model ---
kind: embeddingModel
name: gemini-embedding
type: gemini
model: gemini-embedding-001
project: ${GOOGLE_CLOUD_PROJECT}
location: ${GOOGLE_CLOUD_LOCATION}
dimension: 3072
---
Ten skrypt definiuje ten zasób:
- Model wektorów dystrybucyjnych (
gemini-embedding) – konfiguruje Toolbox tak, aby wywoływał modelgemini-embedding-001Gemini do generowania 3072-wymiarowych wektorów dystrybucyjnych tekstu. Toolbox używa do uwierzytelniania domyślnego uwierzytelniania aplikacji (ADC) – w Cloud Shell ani Cloud Run nie jest potrzebny klucz interfejsu API. Zwróć uwagę, żedimensionskonfigurowane tutaj musi być takie samo jak wcześniej skonfigurowane do wypełnienia bazy danych.
Kontynuujmy. Dodaj ten skrypt pod symbolem --- w pliku tools.yaml.
# --- Tool 3: Semantic search by description ---
kind: tool
name: search-jobs-by-description
type: postgres-sql
source: jobs-db
description: >-
Find jobs that match a natural language description of what the developer
is looking for. Use this tool when the developer describes their ideal job
using interests, work style, career goals, or project type rather than a
specific role or tech stack. Examples: "I want to work on AI chatbots,"
"a remote job at a fintech startup," "something involving infrastructure
and reliability."
statement: |
SELECT title, company, role, tech_stack, salary_range, location, description
FROM jobs
WHERE description_embedding IS NOT NULL
ORDER BY description_embedding <=> $1
LIMIT 5
parameters:
- name: search_query
type: string
description: "A natural language description of the kind of job the developer is looking for."
embeddedBy: gemini-embedding
---
Ten skrypt definiuje ten zasób:
- Narzędzie 3 (
search-jobs-by-description) – narzędzie do wyszukiwania wektorowego. Parametrsearch_queryma wartośćembeddedBy: gemini-embedding, która informuje Zestaw narzędzi, że ma przechwycić tekst w formie surowej, wysłać go do modelu osadzania i użyć powstałego wektora w instrukcji SQL. Operator<=>to odległość kosinusowa pgvector – mniejsze wartości oznaczają bardziej podobne opisy.
Na koniec dodaj ostatnie narzędzie pod symbolem --- w pliku tools.yaml.
# --- Tool 4: Add a new job listing with automatic embedding ---
kind: tool
name: add-job
type: postgres-sql
source: jobs-db
description: >-
Add a new job listing to the platform. Use this tool when a user asks
to post a job that is not currently listed.
statement: |
INSERT INTO jobs (title, company, role, tech_stack, salary_range, location, openings, description, description_embedding)
VALUES ($1, $2, $3, $4, $5, $6, CAST($7 AS INTEGER), $8, $9)
RETURNING title, company
parameters:
- name: title
type: string
description: "The job title (e.g., 'Senior Backend Engineer')."
- name: company
type: string
description: "The company name (e.g., 'Stripe', 'Spotify')."
- name: role
type: string
description: "The role category (e.g., 'Backend', 'Frontend', 'Data/AI', 'DevOps')."
- name: tech_stack
type: string
description: "Comma-separated list of technologies (e.g., 'Python, FastAPI, GCP')."
- name: salary_range
type: string
description: "The salary range (e.g., '$150-200K/year')."
- name: location
type: string
description: "Work location and arrangement (e.g., 'Remote')."
- name: openings
type: string
description: "The number of open positions."
- name: description
type: string
description: "A short description of the job (2-3 sentences)."
- name: description_vector
type: string
description: "Auto-generated embedding vector for the job description."
valueFromParam: description
embeddedBy: gemini-embedding
Ten skrypt definiuje ten zasób:
- Narzędzie 4 (
add-job) – pokazuje wczytywanie wektorów. Parametrdescription_vectorma 2 pola specjalne: valueFromParam: description– Toolbox kopiuje wartość z parametrudescriptiondo tego parametru. LLM nigdy nie widzi tego parametru.embeddedBy: gemini-embedding– Toolbox osadza skopiowany tekst w wektorze przed przekazaniem go do SQL.
W rezultacie jedno wywołanie narzędzia przechowuje zarówno tekst opisu w formie surowej, jak i jego wektor dystrybucyjny, a agent nie ma żadnych informacji o wektorach dystrybucyjnych.
Format YAML z wieloma dokumentami rozdziela poszczególne zasoby znakiem ---. Każdy dokument ma pola kind, name i type, które określają, czym jest. Podsumowując, skonfigurowaliśmy już wszystkie te elementy:
- Określ źródłową bazę danych
- Zdefiniuj narzędzia ( narzędzie 1 i 2), aby wykonywać zapytania w bazie danych za pomocą standardowego filtra.
- Definiowanie modelu wektora dystrybucyjnego
- Zdefiniuj narzędzie do wyszukiwania wektorowego ( narzędzie 3) w bazie danych.
- Zdefiniuj narzędzie do pozyskiwania danych wektorowych ( narzędzie 4) do bazy danych.
6. Uruchamianie serwera MCP Toolbox
W poprzednim kroku skonfigurowaliśmy już niezbędne ustawienia dla narzędzi MCP. Teraz możemy uruchomić serwer.
Sprawdzanie danych początkowych
Zanim uruchomisz Toolbox, sprawdź, czy konfiguracja bazy danych została zakończona. Utwórz skrypt w Pythonie scripts/verify_database.py za pomocą tego polecenia:
cloudshell edit scripts/verify_seed.py
Następnie skopiuj ten kod do pliku scripts/verify_seed.py.
#!/usr/bin/env python3
"""Verify the database has 15 jobs with embeddings."""
import os
import sys
from pathlib import Path
from dotenv import load_dotenv
from google.cloud.sql.connector import Connector
import pg8000
# Load environment variables
env_path = Path(__file__).parent.parent / '.env'
load_dotenv(env_path)
# Verify required environment variables
required_vars = ['GOOGLE_CLOUD_PROJECT', 'REGION', 'DB_PASSWORD', 'DB_INSTANCE', 'DB_NAME']
missing_vars = [var for var in required_vars if not os.environ.get(var)]
if missing_vars:
print(f"ERROR: Missing environment variables: {', '.join(missing_vars)}", file=sys.stderr)
sys.exit(1)
def verify_database():
"""Check that 15 jobs exist with embeddings."""
connector = Connector()
try:
project = os.environ['GOOGLE_CLOUD_PROJECT']
region = os.environ['REGION']
password = os.environ['DB_PASSWORD']
instance = os.environ['DB_INSTANCE']
database = os.environ['DB_NAME']
conn = connector.connect(
f"{project}:{region}:{instance}",
"pg8000",
user="postgres",
password=password,
db=database
)
cursor = conn.cursor()
# Count jobs and embeddings
cursor.execute("SELECT COUNT(*) FROM jobs")
job_count = cursor.fetchone()[0]
cursor.execute("SELECT COUNT(*) FROM jobs WHERE description_embedding IS NOT NULL")
embedding_count = cursor.fetchone()[0]
print(f"Jobs: {job_count}/15")
print(f"Embeddings: {embedding_count}/15")
cursor.close()
conn.close()
if job_count == 15 and embedding_count == 15:
print("\n✓ Database ready!")
return True
else:
print("\n✗ Database not ready")
return False
except Exception as e:
print(f"\nERROR: {e}", file=sys.stderr)
return False
finally:
connector.close()
if __name__ == "__main__":
success = verify_database()
sys.exit(0 if success else 1)
Ten skrypt sprawdzi liczbę danych dotyczących ofert pracy i ich osadzanie. Uruchom skrypt za pomocą tego polecenia:
uv run scripts/verify_seed.py
Jeśli zobaczysz w terminalu te dane wyjściowe, oznacza to, że dane są gotowe:
Jobs: 15/15 Embeddings: 15/15 ✓ Database ready!
Uruchamianie serwera Zestawu narzędzi
W poprzednim kroku konfiguracji pobraliśmy już plik wykonywalny toolbox. Sprawdź, czy ten plik binarny istnieje i czy został pobrany. Jeśli nie, pobierz go i poczekaj na zakończenie.
cd ~/build-agent-adk-toolbox-cloudsql
if [ ! -f toolbox ]; then
curl -O https://storage.googleapis.com/mcp-toolbox-for-databases/v1.0.0/linux/amd64/toolbox
fi
chmod +x toolbox
Musimy udostępnić nasze zmienne .env procesowi podrzędnemu, który jest uruchamiany przez narzędzia MCP. Uruchom to polecenie, aby uruchomić serwer zestawu narzędzi i zapisać dane wyjściowe konsoli w pliku logs/mcp_toolbox.log.
set -a; source .env; set +a
./toolbox --config tools.yaml --enable-api > logs/mcp_toolbox.log 2>&1 &
W pliku logs/mcp_toolbox.log powinny pojawić się dane wyjściowe potwierdzające, że serwer jest gotowy, jak pokazano poniżej:
... INFO "Initialized 1 sources: jobs-db" ... INFO "Initialized 0 authServices: " ... INFO "Using Vertex AI backend for Gemini embedding" ... INFO "Initialized 1 embeddingModels: gemini-embedding" ... INFO "Initialized 4 tools: add-job, search-jobs, get-job-details, search-jobs-by-description" ... ... INFO "Server ready to serve!"
Weryfikowanie narzędzi
Wyślij zapytanie do interfejsu Toolbox API, aby wyświetlić listę wszystkich zarejestrowanych narzędzi:
curl -s http://localhost:5000/api/toolset | uv run -m json.tool
Powinny się wyświetlić narzędzia wraz z opisami i parametrami. Jak pokazano poniżej
...
"search-jobs-by-description": {
"description": "Find jobs that match a natural language description of what the developer is looking for. Use this tool when the developer describes their ideal job using interests, work style, career goals, or project type rather than a specific role or tech stack. Examples: \"I want to work on AI chatbots,\" \"a remote job at a fintech startup,\" \"something involving infrastructure and reliability.\"",
"parameters": [
{
"name": "search_query",
"type": "string",
"required": true,
"description": "A natural language description of the kind of job the developer is looking for.",
"authSources": []
}
],
"authRequired": []
}
...
Przetestuj narzędzie search-jobs bezpośrednio:
curl -s -X POST http://localhost:5000/api/tool/search-jobs/invoke \
-H "Content-Type: application/json" \
-d '{"role": "Backend", "tech_stack": ""}' | jq '.result | fromjson'
Odpowiedź powinna zawierać 2 oferty pracy na stanowisko inżyniera backendu z danych początkowych.
[
{
"title": "Backend Engineer (Payments)",
"company": "Square",
"role": "Backend",
"tech_stack": "Java, Spring Boot, PostgreSQL, Kafka",
"salary_range": "$160-220K/year",
"location": "San Francisco, Hybrid",
"openings": 3
},
{
"title": "Senior Backend Engineer",
"company": "Stripe",
"role": "Backend",
"tech_stack": "Go, PostgreSQL, gRPC, Kubernetes",
"salary_range": "$180-250K/year",
"location": "San Francisco, Hybrid",
"openings": 3
}
]
7. Tworzenie agenta ADK
Teraz użyjemy w tym projekcie ADK w Pythonie. Dodajmy wymagane zależności:
uv add google-adk==1.29.0 toolbox-adk==1.0.0
google-adk– pakiet Google Agent Development Kit, w tym pakiet Gemini SDK.toolbox-adk– integracja ADK z zestawem narzędzi MCP dla baz danych.
Tworzenie struktury katalogów agenta
ADK oczekuje określonego układu folderów: katalogu o nazwie agenta zawierającego pliki __init__.py, agent.py i .env. Aby Ci w tym pomóc, ma wbudowane polecenie, które pozwala szybko utworzyć strukturę:
uv run adk create jobs_agent \
--model gemini-2.5-flash \
--project ${GOOGLE_CLOUD_PROJECT} \
--region ${GOOGLE_CLOUD_LOCATION}
Twój katalog powinien teraz wyglądać tak:
build-agent-adk-toolbox-cloudsql/ ├── jobs_agent/ │ ├── __init__.py │ ├── agent.py │ └── .env ├── logs ├── scripts └── ...
Następnie musimy zintegrować agenta ADK z działającym serwerem Toolbox i przetestować wszystkie 4 narzędzia: standardowe zapytania, wyszukiwanie semantyczne i przetwarzanie wektorowe. Kod agenta jest minimalny: cała logika bazy danych znajduje się w tools.yaml.
Konfigurowanie środowiska agenta
Pakiet ADK odczytuje wartości GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_CLOUD_PROJECT i GOOGLE_CLOUD_LOCATION ze środowiska powłoki, które zostały już ustawione w poprzednim kroku. Jedyną zmienną specyficzną dla agenta jest TOOLBOX_URL – dodaj ją do pliku .env agenta:
echo -e "\nTOOLBOX_URL=http://127.0.0.1:5000" >> jobs_agent/.env
Aktualizowanie modułu agenta
Otwórz plik jobs_agent/agent.py w edytorze Cloud Shell.
cloudshell edit jobs_agent/agent.py
i zastąp zawartość tym kodem:
# jobs_agent/agent.py
import os
from google.adk.agents import LlmAgent
from toolbox_adk import ToolboxToolset
TOOLBOX_URL = os.environ.get("TOOLBOX_URL", "http://127.0.0.1:5000")
toolbox = ToolboxToolset(TOOLBOX_URL)
root_agent = LlmAgent(
name="jobs_agent",
model="gemini-2.5-flash",
instruction="""You are a helpful assistant at "TechJobs," a tech job listing platform.
Your job:
- Help developers browse job listings by role or tech stack.
- Provide full details about specific positions, including salary range and number of openings.
- Recommend jobs based on natural language descriptions of what the developer is looking for.
- Add new job listings to the platform when asked.
When a developer asks about a specific job by title or company, use the get-job-details tool.
When a developer asks for a specific role category or tech stack, use the search-jobs tool.
When a developer describes what kind of job they want — by interest area, work style,
career goals, or project type — use the search-jobs-by-description tool for semantic search.
When in doubt between search-jobs and search-jobs-by-description, prefer
search-jobs-by-description — it searches job descriptions and finds more relevant matches.
If a position has no openings (openings is 0), let the developer know
and suggest similar alternatives from the search results.
Be conversational, knowledgeable, and concise.""",
tools=[toolbox],
)
Zwróć uwagę, że nie ma tu kodu bazy danych – ToolboxToolset łączy się z serwerem Toolbox przy uruchamianiu i wczytuje wszystkie dostępne narzędzia. Agent wywołuje narzędzia po nazwie, a Toolbox tłumaczy te wywołania na zapytania SQL dotyczące Cloud SQL.
W przypadku lokalnego środowiska programistycznego zmienna środowiskowa TOOLBOX_URL ma domyślnie wartość http://127.0.0.1:5000. Gdy później wdrożysz usługę w Cloud Run, zastąpisz ten adres URL adresem URL Cloud Run usługi Toolbox – nie musisz wprowadzać żadnych zmian w kodzie.
Instrukcja odnosi się obecnie tylko do 2 standardowych narzędzi (search-jobs i get-job-details). Rozszerzysz ją w następnym kroku, gdy dodasz narzędzia do wyszukiwania semantycznego i przetwarzania danych.
Testowanie agenta
Uruchom interfejs programisty ADK:
cd ~/build-agent-adk-toolbox-cloudsql
uv run adk web --allow_origins "regex:https://.*\.cloudshell\.dev"
Otwórz adres URL wyświetlany w terminalu (zwykle http://localhost:8000) za pomocą funkcji Podgląd w przeglądarce w Cloud Shell lub kliknij adres URL wyświetlany w terminalu, przytrzymując Ctrl. W menu agentów w lewym górnym rogu kliknij jobs_agent.
Testowanie standardowych zapytań
Aby sprawdzić narzędzia standardowej wersji SQL-a, wypróbuj te prompty:
What backend engineering jobs do you have?
Any jobs using Kubernetes?
Tell me about the Cloud Architect position

Testowanie wyszukiwania semantycznego
Wypróbuj opisy w języku naturalnym, które nie są powiązane z określoną rolą ani zestawem technologii:
I want a remote job where I can work on AI and machine learning
Find me something in fintech with good work-life balance
I'm interested in infrastructure and reliability engineering
W zależności od typu zapytania agent spróbuje wybrać odpowiednie narzędzie: zapytania z filtrami strukturalnymi są przetwarzane przez search-jobs, a opisy w języku naturalnym przez search-jobs-by-description.

Testowanie przetwarzania wektorów
Poproś agenta o dodanie nowego zadania:
Add a new job: 'Robotics Software Engineer' at Boston Dynamics, role Robotics, tech stack: Python, C++, ROS, Computer Vision, salary $160-230K/year, location Waltham MA, Hybrid, 2 openings. Description: Design and implement autonomous navigation and manipulation algorithms for next-generation robots. Work on perception pipelines using computer vision and lidar, develop motion planning software in C++ and Python, and test systems on real hardware in warehouse and logistics environments.

Teraz spróbuj wyszukać:
Find me jobs involving autonomous systems and working with physical hardware
Osadzenie zostało wygenerowane automatycznie podczas operacji INSERT – nie jest potrzebny żaden dodatkowy krok.

Masz już w pełni działającą aplikację Agentic RAG, która korzysta z ADK, MCP Toolbox i Cloud SQL. Gratulacje! Przejdźmy do wdrażania tych aplikacji w Cloud Run.
Teraz zatrzymajmy interfejs programisty, kończąc proces przez dwukrotne naciśnięcie Ctrl+C.
8. Wdrożenie w Cloud Run
Agent i Toolbox działają lokalnie. W tym kroku obie usługi są wdrażane jako usługi Cloud Run, dzięki czemu są dostępne w internecie. Usługa Toolbox działa jako serwer MCP w Cloud Run, a usługa agenta łączy się z nią.
Przygotowywanie zestawu narzędzi do wdrożenia
Utwórz katalog wdrożenia usługi Toolbox:
cd ~/build-agent-adk-toolbox-cloudsql
mkdir -p deploy-toolbox
cp toolbox tools.yaml deploy-toolbox/
Utwórz plik Dockerfile dla zestawu narzędzi. Otwórz plik deploy-toolbox/Dockerfile w edytorze Cloud Shell:
cloudshell edit deploy-toolbox/Dockerfile
i skopiuj do niego ten skrypt:
# deploy-toolbox/Dockerfile
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY toolbox tools.yaml ./
RUN chmod +x toolbox
EXPOSE 8080
CMD ["./toolbox", "--config", "tools.yaml", "--enable-api", "--address", "0.0.0.0", "--port", "8080"]
Plik binarny Narzędzia i tools.yaml są spakowane w minimalnym obrazie Debiana. Cloud Run kieruje ruch do portu 8080.
Wdrażanie usługi Zestaw narzędzi
cd ~/build-agent-adk-toolbox-cloudsql
gcloud run deploy toolbox-service \
--source deploy-toolbox/ \
--region $REGION \
--set-env-vars "DB_PASSWORD=$DB_PASSWORD,DB_INSTANCE=$DB_INSTANCE,DB_NAME=$DB_NAME,GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT,REGION=$REGION,GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION" \
--allow-unauthenticated \
--quiet > logs/deploy_toolbox.log 2>&1 &
To polecenie przesyła źródło do Cloud Build, tworzy obraz kontenera, wypycha go do Artifact Registry i wdraża w Cloud Run. Zajmie to kilka minut. Możemy sprawdzić dziennik procesu wdrażania w pliku logs/deploy_toolbox.log.
Przygotowywanie agenta do wdrożenia
Podczas tworzenia pakietu narzędzi skonfiguruj pliki wdrożenia agenta.
Utwórz plik Dockerfile w katalogu głównym projektu. Otwórz plik Dockerfile w edytorze Cloud Shell:
cloudshell edit Dockerfile
Następnie skopiuj tę treść:
# Dockerfile
FROM ghcr.io/astral-sh/uv:python3.12-trixie-slim
WORKDIR /app
COPY pyproject.toml ./
COPY uv.lock ./
RUN uv sync --no-dev
COPY jobs_agent/ jobs_agent/
EXPOSE 8080
CMD ["uv", "run", "adk", "web", "--host", "0.0.0.0", "--port", "8080"]
Ten plik Dockerfile używa obrazu bazowego ghcr.io/astral-sh/uv, który zawiera wstępnie zainstalowane Pythona i uv. Nie musisz więc instalować uv osobno za pomocą pip.
Utwórz plik .dockerignore, aby wykluczyć niepotrzebne pliki z obrazu kontenera:
cloudshell edit .dockerignore
Następnie skopiuj do niego ten skrypt:
# .dockerignore
.venv/
__pycache__/
*.pyc
.env
jobs_agent/.env
toolbox
tools.yaml
seed.sql
deploy-toolbox/
Wdróż usługę agenta
Poczekaj na zakończenie wdrażania Toolboxa. Aby sprawdzić proces wdrażania, ponownie otwórz stronę logs/deploy_toolbox.log. Następnie pobierz adres URL Cloud Run za pomocą tego polecenia:
TOOLBOX_URL=$(gcloud run services describe toolbox-service \
--region=$REGION \
--format='value(status.url)')
echo "Toolbox URL: $TOOLBOX_URL"
Zobaczysz dane wyjściowe podobne do tych:
Toolbox URL: https://toolbox-service-xxxxxx-xx.a.run.app
Następnie sprawdźmy, czy wdrożony zestaw narzędzi działa:
curl -s "$TOOLBOX_URL/api/toolset" | python3 -m json.tool | head -5
Jeśli wynik jest podobny do tego przykładu, wdrożenie zostało już zakończone.
{
"serverVersion": "1.0.0+binary.linux.amd64.c5524d3",
"tools": {
"add-job": {
"description": "Add a new job listing to the platform. Use this tool when a user asks to post a job that is not currently listed.",
Następnie wdróżmy agenta, przekazując adres URL Toolbox jako zmienną środowiskową:
cd ~/build-agent-adk-toolbox-cloudsql
gcloud run deploy jobs-agent \
--source . \
--region $REGION \
--set-env-vars "TOOLBOX_URL=$TOOLBOX_URL,GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT,GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION,GOOGLE_GENAI_USE_VERTEXAI=TRUE" \
--allow-unauthenticated \
--quiet
Kod agenta odczytuje wartość TOOLBOX_URL ze środowiska (zostało to wcześniej skonfigurowane). Lokalnie wskazuje http://127.0.0.1:5000, a w Cloud Run wskazuje adres URL usługi Toolbox. Nie wymaga to żadnych zmian w kodzie.
Testowanie wdrożonego agenta
Pobierz adres URL Cloud Run agenta:
AGENT_URL=$(gcloud run services describe jobs-agent \
--region=$REGION \
--format='value(status.url)')
echo "Agent URL: $AGENT_URL"
Otwórz adres URL w przeglądarce. Załaduje się interfejs programistyczny ADK – ten sam interfejs, którego używasz lokalnie, ale teraz działający w Cloud Run.
W menu wybierz jobs_agent i przetestuj:
What backend engineering jobs do you have?
I want a remote job working on AI and machine learning
Oba zapytania działają za pomocą wdrożonych usług: agent w Cloud Run wywołuje Toolbox w Cloud Run, który wysyła zapytanie do Cloud SQL.
9. Gratulacje / Czyszczenie
Utworzono i wdrożono inteligentnego asystenta tablicy ofert pracy, który korzysta z MCP Toolbox for Databases do łączenia agenta ADK z Cloud SQL PostgreSQL – zarówno w przypadku standardowych zapytań SQL, jak i semantycznego wyszukiwania wektorowego.
Czego się nauczysz
- Jak MCP standaryzuje dostęp do narzędzi dla agentów AI i jak MCP Toolbox for Databases stosuje to w przypadku operacji na bazach danych – zastępowanie niestandardowego kodu bazy danych deklaratywną konfiguracją YAML.
- Jak skonfigurować Cloud SQL PostgreSQL jako źródło danych w Toolbox przy użyciu typu źródła
cloud-sql-postgres - Jak zdefiniować standardowe narzędzia do zapytań SQL z instrukcjami sparametryzowanymi, które zapobiegają wstrzykiwaniu kodu SQL
- Jak włączyć wyszukiwanie wektorowe za pomocą pgvector i
gemini-embedding-001, używając parametruembeddedBydo automatycznego osadzania zapytań - Jak
valueFromParamumożliwia automatyczne wczytywanie wektorów – model LLM podaje opis tekstowy, a Toolbox w tle kopiuje, osadza i przechowuje wektor obok tekstu. - Jak
ToolboxToolsetADK wczytuje narzędzia z działającego serwera Toolbox, dzięki czemu kod agenta jest minimalny, a logika bazy danych jest w pełni odseparowana - Jak wdrożyć serwer MCP Toolbox i agenta ADK w Cloud Run jako oddzielne usługi
Czyszczenie danych
Aby uniknąć obciążenia konta Google Cloud opłatami za zasoby utworzone w tym ćwiczeniu, możesz usunąć poszczególne zasoby lub cały projekt.
Opcja 1. Usuwanie projektu (zalecane)
Najprostszym sposobem na zwolnienie miejsca jest usunięcie projektu. Spowoduje to usunięcie wszystkich zasobów powiązanych z projektem.
gcloud projects delete $GOOGLE_CLOUD_PROJECT
Opcja 2. Usuwanie poszczególnych zasobów
Jeśli chcesz zachować projekt, ale usunąć tylko zasoby utworzone w tym laboratorium:
gcloud run services delete jobs-agent --region=$REGION --quiet
gcloud run services delete toolbox-service --region=$REGION --quiet
gcloud sql instances delete jobs-instance --quiet
gcloud artifacts repositories delete cloud-run-source-deploy --location=$REGION --quiet 2>/dev/null
