Sechs Rezepte für eine nahezu 100% genaue Text-zu-SQL-Konvertierung in AlloyDB – Codelab

1. Einführung

In diesem Codelab erfahren Sie, wie Sie mit der QueryData API die besten Ergebnisse erzielen. Sie erfahren, wie Sie genaue, wiederholbare Ergebnisse erhalten, wenn Sie Anfragen in natürlicher Sprache an Ihre Datenbank stellen. Dieser Leitfaden soll Ihnen dabei helfen. Er enthält sechs Rezepte in mehreren Kapiteln, in denen verschiedene Aspekte von natürlicher Sprache in SQL (NL2SQL) und seine praktischen Anwendungen behandelt werden.

Vorbereitung

  • Grundlegende Kenntnisse von Google Cloud und der Google Cloud Console
  • Grundkenntnisse der Befehlszeilenschnittstelle und von Cloud Shell

Lerninhalte

  • AlloyDB-Cluster und primäre Instanz bereitstellen
  • QueryData, KI-Funktionen und parametrisierte sichere Ansichten aktivieren
  • QueryData-Kontextset erstellen
  • Verschiedene Vorlagen und Kontexte in der QueryData API verwenden
  • QueryData-Vorlagen mit Attributen flexibler gestalten
  • Mehrdeutigkeiten bei Daten mit der Wertsuche und der Trigram-Indexierung beheben
  • KI-Funktionen für die semantische Suche mit Vorlagen verwenden
  • Parametrisierte sichere Ansichten mit der QueryData API verwenden

Voraussetzungen

  • Ein Google Cloud-Konto und ein Google Cloud-Projekt
  • Ein Webbrowser wie Chrome, der die Google Cloud Console und die Cloud Shell unterstützt

2. Einrichtung und Anforderungen

Projekt einrichten

  1. Melden Sie sich in der Google Cloud Console an. Wenn Sie noch kein Gmail- oder Google Workspace-Konto haben, müssen Sie eines erstellen.

Verwenden Sie stattdessen ein privates Konto.

  1. Erstellen Sie ein neues Projekt oder verwenden Sie ein vorhandenes. Klicken Sie zum Erstellen eines neuen Projekts in der Google Cloud Console in der Kopfzeile auf die Schaltfläche „Projekt auswählen“, um ein Pop-up-Fenster zu öffnen.

295004821bab6a87.png

Klicken Sie im Fenster „Projekt auswählen“ auf „Neues Projekt“. Daraufhin wird ein Dialogfeld für das neue Projekt geöffnet.

37d264871000675d.png

Geben Sie im Dialogfeld einen Projektnamen ein und wählen Sie den Speicherort aus.

96d86d3d5655cdbe.png

  • Der Projektname ist der Anzeigename für die Teilnehmer dieses Projekts. Der Projektname wird von Google APIs nicht verwendet und kann jederzeit geändert werden.
  • Die Projekt-ID ist für alle Google Cloud-Projekte eindeutig und unveränderlich. Sie kann also nicht mehr geändert werden, nachdem sie festgelegt wurde. In der Google Cloud Console wird automatisch eine eindeutige ID generiert, die Sie aber anpassen können. Wenn Ihnen die generierte ID nicht gefällt, können Sie eine weitere zufällige ID generieren oder eine eigene ID angeben, um die Verfügbarkeit zu prüfen. In den meisten Codelabs müssen Sie auf Ihre Projekt-ID verweisen, die in der Regel mit dem Platzhalter PROJECT_ID angegeben wird.
  • Zur Information: Es gibt einen dritten Wert, die Projektnummer, die von einigen APIs verwendet wird. Weitere Informationen zu diesen drei Werten

Abrechnung aktivieren

Privates Rechnungskonto einrichten

Wenn Sie die Abrechnung mit Google Cloud-Guthaben einrichten, können Sie diesen Schritt überspringen.

Hier können Sie die Abrechnung in der Cloud Console aktivieren, um ein privates Rechnungskonto einzurichten.

Hinweise:

  • Die Kosten für Cloud-Ressourcen für dieses Lab sollten weniger als 5 $ betragen.
  • Sie können die Schritte am Ende dieses Labs ausführen, um Ressourcen zu löschen und so weitere Kosten zu vermeiden.
  • Neue Nutzer haben Anspruch auf den kostenlosen Testzeitraum mit einem Guthaben von 300 $.

Cloud Shell starten

Während Sie Google Cloud von Ihrem Laptop aus per Fernzugriff nutzen können, wird in diesem Codelab Google Cloud Shell verwendet, eine Befehlszeilenumgebung, die in der Cloud ausgeführt wird.

Klicken Sie in der Google Cloud Console rechts oben in der Symbolleiste auf das Cloud Shell-Symbol:

Cloud Shell aktivieren

Alternativ können Sie auch die Tasten „G“ und „S“ drücken. Mit dieser Sequenz wird Cloud Shell aktiviert, wenn Sie sich in der Google Cloud Console befinden oder diesen Link verwenden.

Die Bereitstellung und Verbindung mit der Umgebung sollte nur wenige Augenblicke dauern. Anschließend sehen Sie in etwa Folgendes:

Screenshot des Google Cloud Shell-Terminals, auf dem zu sehen ist, dass die Umgebung verbunden ist

Diese virtuelle Maschine verfügt über sämtliche Entwicklertools, die Sie benötigen. Sie bietet ein Basisverzeichnis mit 5 GB nichtflüchtigem Speicher und läuft in Google Cloud, was die Netzwerkleistung und Authentifizierung erheblich verbessert. Alle Aufgaben in diesem Codelab können in einem Browser ausgeführt werden. Sie müssen nichts installieren.

3. Hinweis

API aktivieren

Wenn Sie AlloyDB, Compute Engine, Netzwerkdienste und die Agent Platform verwenden möchten, müssen Sie die entsprechenden APIs in Ihrem Google Cloud-Projekt aktivieren.

Prüfen Sie im Cloud Shell-Terminal, ob Ihre Projekt-ID eingerichtet ist:

gcloud config get-value project

Der Befehl sollte Ihre Google Cloud-Projekt-ID zurückgeben.

Legen Sie die Umgebungsvariable PROJECT_ID fest:

PROJECT_ID=$(gcloud config get-value project)

Aktivieren Sie die erforderlichen APIs:

gcloud services enable alloydb.googleapis.com \
                       compute.googleapis.com \
                       cloudresourcemanager.googleapis.com \
                       servicenetworking.googleapis.com \
                       geminidataanalytics.googleapis.com \
                       cloudaicompanion.googleapis.com \
                       aiplatform.googleapis.com \
                       dataplex.googleapis.com

Erwartete Ausgabe:

student@cloudshell:~ (test-project-001-402417)$ gcloud config set project test-project-001-402417
Updated property [core/project].
student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=$(gcloud config get-value project)
Your active configuration is: [cloudshell-14650]
student@cloudshell:~ (test-project-001-402417)$ 
student@cloudshell:~ (test-project-001-402417)$ gcloud services enable alloydb.googleapis.com \
                       compute.googleapis.com \
                       cloudresourcemanager.googleapis.com \
                       servicenetworking.googleapis.com \
                       geminidataanalytics.googleapis.com \
                       cloudaicompanion.googleapis.com \
                       aiplatform.googleapis.com \
                       dataplex.googleapis.com
Operation "operations/acat.p2-4470404856-1f44ebd8-894e-4356-bea7-b84165a57442" finished successfully.

Informationen zu den einzelnen aktivierten APIs finden Sie in der Dokumentation.

4. AlloyDB bereitstellen

Erstellen Sie einen AlloyDB-Cluster und eine primäre Instanz. Sie können die Bereitstellung entweder mit einem vorbereiteten Skript vornehmen, mit dem alle erforderlichen Ressourcen bereitgestellt werden, oder die Bereitstellung Schritt für Schritt selbst vornehmen. Folgen Sie dazu der AlloyDB-Dokumentation.

AlloyDB mit automatisiertem Skript bereitstellen

Bei diesem Ansatz wird ein automatisiertes Script verwendet, um den AlloyDB-Cluster bereitzustellen und die erforderlichen Konfigurationsdetails anzugeben, damit Sie mit den bereitgestellten Ressourcen arbeiten können.

Führen Sie im Cloud Shell-Terminal den Befehl aus, um das Bereitstellungsscript aus dem Repository zu klonen:

REPO_NAME="codelabs"
REPO_URL="https://github.com/GoogleCloudPlatform/$REPO_NAME"
SOURCE_DIR="alloydb-ai-nla"

git clone --no-checkout --filter=blob:none --depth=1 $REPO_URL

cd $REPO_NAME
git sparse-checkout set $SOURCE_DIR
git checkout
cd $SOURCE_DIR

Führen Sie dazu das Bereitstellungsskript aus:

./deploy_alloydb.sh

Die Ausführung des Skripts dauert fünf bis sieben Minuten. Die Ausgabe enthält die Details zur Clusterbereitstellung. Ihr Passwort ist anders. Notieren Sie es sich für die spätere Verwendung.

...
<redacted>
...
Creating primary instance: alloydb-aip-01-pr (8 vCPUs for TRIAL cluster)
Operation ID: operation-1765988049916-646282264938a-bddce198-9f248715
Creating instance...done.                                                                                                                                                                                                             
----------------------------------------
Deployment Process Completed
Cluster:  alloydb-aip-01 (TRIAL)
Instance: alloydb-aip-01-pr
Region:   us-central1
Initial Password: JBBoDTgixzYwYpkF (if new cluster)
----------------------------------------
 

Rufen Sie in der Google Cloud Console die Seite „AlloyDB-Cluster“ auf, um den neuen Cluster und die neue Instanz zu sehen.

4271eb55bcc9ec84.png

5. Datenbank vorbereiten

Erstellen Sie eine Datenbank, aktivieren Sie die Gemini Enterprise Agent Platform-Integration, erstellen Sie Datenbankobjekte und fügen Sie Beispieldaten hinzu.

Erforderliche Berechtigungen für AlloyDB erteilen

Weisen Sie dem AlloyDB-Dienst-Agent die erforderlichen IAM-Rollen zu:

Öffnen Sie einen neuen Cloud Shell-Tab, indem Sie auf „Hinzufügen“ (+) klicken.

abc505ac4d41f24e.png

Führen Sie im neuen Tab Folgendes aus:

PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
  --role="roles/aiplatform.user"

Erwartete Konsolenausgabe:

student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=$(gcloud config get-value project)
Your active configuration is: [cloudshell-11039]
student@cloudshell:~ (test-project-001-402417)$ gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
  --role="roles/aiplatform.user"
Updated IAM policy for project [test-project-001-402417].
bindings:
- members:
  - serviceAccount:service-4470404856@gcp-sa-alloydb.iam.gserviceaccount.com
  role: roles/aiplatform.user
- members:
...
etag: BwYIEbe_Z3U=
version: 1
 

Data Access API aktivieren

Aktivieren Sie die Data Access API in Ihrem AlloyDB-Cluster.

Führen Sie im selben Terminaltab den folgenden Befehl aus:

PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
ADBCLUSTER=alloydb-aip-01
curl -X PATCH \
 -H "Authorization: Bearer $(gcloud auth print-access-token)" \
 -H "Content-Type: application/json" \
 https://alloydb.googleapis.com/v1alpha/projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER/instances/$ADBCLUSTER-pr?updateMask=dataApiAccess \
 -d '{
   "dataApiAccess": "ENABLED",
 }'

Datenbank-Flags aktualisieren

Warten Sie, bis der Schritt „Data Access API“ abgeschlossen ist, bevor Sie Flags auf Instanzebene aktivieren. Prüfen Sie, ob der Status Ihrer Instanz ein grünes Häkchen anzeigt, wie in der folgenden Abbildung dargestellt.

6284731b8eff74c.jpeg

Wenn Sie KI-Erweiterungen und die IAM-Authentifizierung für Agent-Tools verwenden möchten, müssen Sie bestimmte Datenbank-Flags für die Instanz aktivieren und sich selbst als Datenbanknutzer hinzufügen. Aktivieren Sie die folgenden Flags:

  • alloydb.iam_authentication
  • password.enforce_complexity
  • google_ml_integration.enable_ai_query_engine
  • parameterized_views

Führen Sie auf demselben Terminaltab die folgenden Befehle aus:

PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
ADBCLUSTER=alloydb-aip-01
gcloud beta alloydb instances update $ADBCLUSTER-pr \
   --database-flags password.enforce_complexity=on,alloydb.iam_authentication=on,google_ml_integration.enable_ai_query_engine=on,parameterized_views.enabled=on \
   --region=$REGION \
   --cluster=$ADBCLUSTER \
   --project=$PROJECT_ID \
   --update-mode=FORCE_APPLY

Erstellen Sie einen AlloyDB-IAM-Nutzer für Ihr Konto:

REGION=us-central1
ADBCLUSTER=alloydb-aip-01
gcloud alloydb users create $(gcloud config get-value account) \
--cluster=$ADBCLUSTER \
--superuser=true \
--region=$REGION \
--type=IAM_BASED

Schließen Sie den Tab, indem Sie im Terminal den Befehl „exit“ ausführen:

exit

Verbindung zu AlloyDB Studio herstellen

In den folgenden Kapiteln können Sie alle SQL-Befehle ausführen, für die eine Datenbankverbindung in AlloyDB Studio erforderlich ist.

So öffnen Sie AlloyDB Studio:

  1. Rufen Sie in der Google Cloud Console die Seite „Cluster“ für AlloyDB for PostgreSQL auf.
  2. Wählen Sie Ihre primäre Instanz aus, um die zugehörige Weboberfläche zu öffnen.

1d7298e7096e7313.png

  1. Klicken Sie dann links auf AlloyDB Studio:

a33131c72ad29478.png

  1. Wählen Sie die postgres-Datenbank aus, wählen Sie die IAM-Authentifizierung aus und klicken Sie auf „Authentifizieren“.

8ddfb250344ca749.jpeg

Dadurch wird die AlloyDB Studio-Benutzeroberfläche geöffnet.

  1. Wählen Sie den Tab „Unbenannte Abfrage“ aus, um den SQL-Editor zu öffnen.

6696bc771fab9983.png

Dadurch wird ein Editor geöffnet, in dem Sie SQL-Befehle ausführen können, wie im folgenden Bild zu sehen ist:

ae34288e5bf237c7.png

Datenbank erstellen

Kurzanleitungsdatenbank erstellen

Führen Sie im AlloyDB Studio-Editor den folgenden Befehl aus, um die Datenbank zu erstellen:

CREATE DATABASE quickstart_db

Erwartete Ausgabe:

Statement executed successfully

Verbindung zu quickstart_db herstellen

Klicken Sie in AlloyDB Studio auf „Datenbank/Nutzer ändern“.

6f5c98f5d0b3d550.png

Wählen Sie „quickstart_db“ aus der Datenbankliste aus, wählen Sie „IAM Authentication“ (IAM-Authentifizierung) aus und authentifizieren Sie sich.

a1940c26c36ff840.jpeg

Dadurch wird eine neue Verbindung geöffnet, über die Sie mit Objekten aus der Datenbank „quickstart_db“ arbeiten können.

Erweiterungen aktivieren

Prüfen Sie alle erforderlichen Erweiterungen, um sicherzustellen, dass sie in Ihrer Datenbank aktiviert sind und die richtige Mindestversion haben.

Prüfen Sie, ob alle erforderlichen Erweiterungen in Ihrer Datenbank vorhanden sind:

SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'google_ml_integration', 'parameterized_views');

Erwartete Ausgabe:

        extname        |   extversion   
-----------------------+----------------
 google_ml_integration | 1.5.9
 parameterized_views   | 1.0
 vector                | 0.8.2.google-1

Wenn nicht alle oben genannten Zeilen zurückgegeben werden, sind einige der Erweiterungen nicht aktiviert.

Bevor wir die Erweiterungen aktivieren können, müssen wir sicherstellen, dass alle Datenbankflags ,"google_ml_integration.enable_ai_query_engine" und "parameterized_views.enabled" für die Instanz aktiviert sind.

Führen Sie in AlloyDB Studio, während Sie mit „quickstart_db“ verbunden sind, Folgendes aus:

show google_ml_integration.enable_ai_query_engine;
show parameterized_views.enabled;

Wenn einer dieser Werte „off“ anzeigt, wiederholen Sie den Schritt „Datenbank-Flags aktualisieren“ und prüfen Sie den Status noch einmal mit den „show…“-Befehlen.

Aktivieren Sie die erforderlichen Erweiterungen.

Führen Sie in AlloyDB Studio, während Sie mit „quickstart_db“ verbunden sind, Folgendes aus:

CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS parameterized_views;

Prüfen Sie die Versionen der Erweiterungen für parameterized_views und google_ml.

Führen Sie in AlloyDB Studio, während Sie mit „quickstart_db“ verbunden sind, Folgendes aus:

SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'google_ml_integration', 'parameterized_views');

Erwartete Ausgabe:

        extname        |   extversion   
-----------------------+----------------
 google_ml_integration | 1.5.9
 parameterized_views   | 1.0
 vector                | 0.8.2.google-1

Wenn die Version niedriger als die erforderliche ist, versuchen Sie, die Erweiterung „parameterized_views“ zu aktualisieren.

Bei „parameterized_views“ versuchen Sie Folgendes:

ALTER EXTENSION parameterized_views UPDATE;

Prüfen Sie die Version noch einmal.

Führen Sie in AlloyDB Studio, während Sie mit „quickstart_db“ verbunden sind, Folgendes aus:

SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'google_ml_integration', 'parameterized_views');

Erwartete Ausgabe:

        extname        |   extversion   
-----------------------+----------------
 google_ml_integration | 1.5.9
 parameterized_views   | 1.0
 vector                | 0.8.2.google-1

6. Beispieldaten

Jetzt müssen Sie Objekte in der Datenbank erstellen und Daten laden. Sie verwenden ein fiktives Dataset eines Immobilienunternehmens. Es enthält fiktive Daten zu Immobilienverkäufen und Maklern. Die Daten wurden im SQL-Script real_estate_data.sql im geklonten Repository bereitgestellt.

Storage-Bucket erstellen

Verwenden Sie das Google SDK (gcloud), um Daten aus Ihrem geklonten Repository in die AlloyDB-Datenbank zu importieren. Dazu müssen Sie einen Cloud Storage-Bucket erstellen und dem AlloyDB-Dienstkonto Zugriff gewähren. Alternativ können Sie es auch immer über die Webkonsole versuchen, wie in der Dokumentation beschrieben.

Führen Sie im Google Cloud Shell-Terminal folgenden Befehl aus:

PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
gcloud storage buckets create gs://$PROJECT_ID-import --project=$PROJECT_ID --location=$REGION
gcloud storage buckets add-iam-policy-binding gs://$PROJECT_ID-import --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" --role=roles/storage.objectViewer

Daten laden

Der SQL-Dump der Datenbank befindet sich im Ordner des geklonten Repositorys. Beim folgenden Befehl wird davon ausgegangen, dass Sie Ihr Basisverzeichnis als Ausgangspunkt verwendet haben, als Sie das Repository im vorherigen Schritt beim Erstellen des AlloyDB-Clusters geklont haben.

Kopieren Sie die Datenbank-Dumpdatei in Ihren Cloud Storage-Bucket:

REPO_NAME="codelabs"
SOURCE_DIR="alloydb-ai-nla"
cd ~/$REPO_NAME/$SOURCE_DIR
gcloud storage cp ~/$REPO_NAME/$SOURCE_DIR/real_estate_data.sql  gs://$PROJECT_ID-import

Importieren Sie das Dataset in „quickstart_db“:

PROJECT_ID=$(gcloud config get-value project)
CLUSTER_NAME=alloydb-aip-01
REGION=us-central1
IAM_USER=$(gcloud config get-value account)
gcloud alloydb clusters import $CLUSTER_NAME  --region=us-central1 --database=quickstart_db --gcs-uri=gs://$PROJECT_ID-import/real_estate_data.sql --project=$PROJECT_ID --sql --user=$IAM_USER

Mit dem Befehl wird das Beispieldataset in die Datenbank „quickstart_db“ geladen.

Prüfen Sie den Import, indem Sie die Datensätze in der Tabelle „real_estate.agents“ mit AlloyDB Studio zählen:

SELECT COUNT(*) FROM real_estate.agents;

7. Schema-Ontologie vorbereiten

Richten Sie den QueryData-Kontextsatz ein, geben Sie Schemametadaten an und führen Sie den ADK-Agent aus.

Metadaten erstellen

Metadaten bestehen aus SQL-Kommentaren, die auf Datenbanktabellen und ‑spalten angewendet werden. Diese Kommentare helfen der QueryData-Engine bei der Auswahl von Datenbankobjekten.

Wenn Sie Ihr Datenschema mit dem bereitgestellten SQL-Dump importiert haben, sind alle Metadaten bereits in Ihrem Schema vorhanden.

Hier ist ein Beispiel-Snippet für Metadaten, die auf das Schema „real_estate“ angewendet werden:

COMMENT ON TABLE real_estate.agents IS 'Stores profile, contact, brokerage affiliation, and active status for individual real estate agents.';

COMMENT ON COLUMN real_estate.agents.agent_id IS 'Primary key uniquely identifying each real estate agent in the database.';

...

Wenn Sie mit Ihrem eigenen Dataset arbeiten, können Sie der Dokumentation entnehmen, wie Sie die Metadaten für Ihr Schema hinzufügen.

Kontext für Schema-Ontologie erstellen

Ein Kontextset enthält Abfragevorlagen, Facetten und Wertesuchen, die das KI-Modell beim Generieren von Anfragen unterstützen. Ohne den Kontext festzulegen, versucht ein KI-Agent, eine Abfrage nur anhand der verfügbaren Informationen aus dem public-Schema zu generieren. Dabei werden in erster Linie die Tabellennamen, Spalten und Metadaten verwendet, um die richtigen Objekte für die Beantwortung einer Anfrage in natürlicher Sprache abzuleiten.

Der Kontext „QueryData“ ist eine JSON-Datei mit Abfragevorlagen, Facetten und Wertesuchen. Hier finden Sie verschiedene Beispiele.

QueryData-Kontextgruppe in der Webkonsole laden

Wenn Sie einen Kontextsatz laden möchten, öffnen Sie AlloyDB Studio. Im linken Bereich unten sehen Sie Context sets und drei Punkte.

d3578ceee65cd0dd.jpeg

Klicken Sie auf das Dreipunkt-Menü und wählen Sie Create context set aus.

Geben Sie im geöffneten Dialogfeld die folgenden Werte ein:

  • Name: sixrecipes
  • Beschreibung: Real Estate Query Data
  • Kontextdatei hochladen: leer lassen

Wenn Sie die Schaltfläche Create drücken, kann es einige Zeit dauern, bis der Kontextspeicher initialisiert ist, wenn Sie dies zum ersten Mal tun.

Prüfen Sie die ID des QueryData-Kontextsets, indem Sie noch einmal auf die drei Punkte rechts neben dem Namen des Kontextsets klicken und Edit context set auswählen.

6739fb9f54d7f79d.jpeg

Die ID des Kontextsets wird oben auf dem geöffneten Tab rechts angezeigt.

746b38c52a70bb3c.jpeg

Speichern Sie diese ID für spätere Schritte.

KI‑Agent starten

Um mit dem QueryData-Backend zu interagieren und Abfragen zu generieren und auszuführen, können Sie die AlloyDB Studio-Oberfläche verwenden, wie in der Dokumentation beschrieben. In diesem Lab verwenden Sie jedoch einen KI-Agenten als Hauptkommunikationstool mit der Datenbank. Die KI-Agenten sind ein realistischeres Szenario für zukünftige Arbeitslasten und das ADK-Framework von Google bietet eine hervorragende Weboberfläche, auf der Sie alle Schritte und Interaktionen zwischen Modellen, APIs und Anwendungen sehen können.

Sehen Sie sich die Agent-Quellkonfiguration in Cloud Shell an:

REPO_NAME="codelabs"
SOURCE_DIR="alloydb-ai-nla"
cd ~/$REPO_NAME/$SOURCE_DIR/data_agent
edit agent.py

In der Datei sehen Sie, wo wir die Liste der Tabellen in unserem Schema definieren. Darauf gehen wir in einem der nächsten Schritte ein.

# List of database tables included in QueryData API requests
TABLE_IDS = [
    "real_estate.municipalities",
    "real_estate.cities",
    "real_estate.agents",
    "real_estate.properties",
    "real_estate.schools",
    "real_estate.school_to_property",
    "real_estate.property_transactions",
    "real_estate.secure_offers",
]

Außerdem gibt es eine Vorgehensweise call_querydata_api für die Arbeit mit der QueryData API sowie eine Reihe von Tools für die Arbeit mit QueryData API-Skills.

def call_querydata_api(
    prompt: str,
    target_project_id: str = project_id,
    target_location: str = location,
    target_cluster_id: str = cluster_name,
    target_instance_id: str = instance_name,
    target_database_id: str = database_name,
    target_context_set_id: str = context_set_id,
    target_table_ids: list[str] = TABLE_IDS,
) -> dict:
    """Calls the Gemini Data Analytics QueryData API to translate natural ...
<Redacted>
...

# ADK File-Based Skill

database_query_skill = load_skill_from_dir(
    pathlib.Path(__file__).parent / "skills" / "database-query-skill"
)

skill_toolset = SkillToolset(
    skills=[database_query_skill]
)

Hier sehen Sie den Stamm-Agenten mit einem Prompt und verfügbaren Tools.

# Agent configuration

root_agent = Agent(
    model=MODEL_ID,
    name='root_agent',
    description='A helpful assistant for analyst requests.',
    instruction=f"""
    Answer user questions to the best of your knowledge using provided tools.
    Do not try to generate non-existent data but use the grounded data from the database.
    When you answer questions about database contents, real estate properties, or sales activity:
    1. Refer to database-query-skill for instructions on querying data using QueryData API.
    2. Use `call_querydata_api` to submit the natural language prompt to the QueryData API.
       CRITICAL: Call `call_querydata_api` EXACTLY ONCE per user request. Do NOT make retries, follow-up calls, or rephrased calls to `call_querydata_api`, even if the result contains zero rows or empty data.
    3. Immediately parse the JSON response from that first `call_querydata_api` call.
    4. Format your final response to the user containing:
       - The generated SQL query (formatted in a Markdown SQL code block).
       - The query results formatted as a Markdown table (constructed from `queryResult.columns` and `queryResult.rows`).
       - The natural language answer (`naturalLanguageAnswer`).
    """,
    tools=[call_querydata_api, skill_toolset],
)

Sehen Sie sich die Datei „data_agent/SKILL.md“ an, um die Systemanweisungen des Agenten zu verstehen:

REPO_NAME="codelabs"
SOURCE_DIR="alloydb-ai-nla"
cd ~/$REPO_NAME/$SOURCE_DIR/data_agent
edit SKILL.md

Bevor Sie den Agent starten, müssen Sie eine .env-Datei mit Parametern für Agent- und QueryData API-Anfragen vorbereiten.

Exportieren Sie Ihre Kontextgruppe-ID in eine Umgebungsvariable:

export QUERYDATA_CONTEXTSET=<context set id from the Create Context Set chapter>

Erstellen Sie die Konfigurationsdatei für die Laufzeitumgebung (.env) im Verzeichnis „data_agent“:

PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
REPO_NAME="codelabs"
SOURCE_DIR="alloydb-ai-nla"
cd ~/$REPO_NAME/$SOURCE_DIR/data_agent
echo "GOOGLE_GENAI_USE_ENTERPRISE=true" > .env
echo "GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project -q)" >> .env
echo "GOOGLE_CLOUD_LOCATION=global" >> .env
echo "QUERYDATA_CONTEXTSET=$QUERYDATA_CONTEXTSET" >> .env
echo "ALLOYDB_CLUSTER=alloydb-aip-01" >> .env
echo "ALLOYDB_INSTANCE=alloydb-aip-01-pr" >> .env
echo "ALLOYDB_DATABASE=quickstart_db" >> .env
echo "ALLOYDB_LOCATION=$REGION" >> .env

Installieren Sie die Abhängigkeiten und starten Sie den Agent-Webdienst:

cd ~/$REPO_NAME/$SOURCE_DIR/
uv sync

Starten Sie den Agent:

uv run adk web --allow_origins 'regex:https://.*\.cloudshell\.dev'

Die Ausgabe sollte wie unten aussehen, mit dem Endpunkt http://127.0.0.1:8000 .

INFO:     Started server process [83608]
INFO:     Waiting for application startup.

+-----------------------------------------------------------------------------+
| ADK Web Server started                                                      |
|                                                                             |
| For local testing, access at http://127.0.0.1:8000.                         |
+-----------------------------------------------------------------------------+

INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

4aa60270e31efe37.jpeg

Klicken Sie in Cloud Shell auf die generierte Webserver-URL (z.B. http://127.0.0.1:8000), um die Agent-Oberfläche zu starten. Wenn das nicht funktioniert, klicken Sie in Cloud Shell auf „Webvorschau“ –> „Vorschau auf Port 8000“, um die Agent-Oberfläche zu öffnen.

Prüfen Sie, ob im Drop-down-Menü oben links data_agent ausgewählt ist.

ad695db289666da3.jpeg

Abfragen erstellen und ausführen

Wir führen die Abfrage Q1 aus.

Führen Sie diesen Prompt in natürlicher Sprache in der Chatoberfläche des Agents aus, um die Leistung von QueryData ohne benutzerdefinierte Vorlagen oder Facetten zu bewerten:

How many properties are currently for sale in San Diego?

Drücken Sie dann die Pfeiltaste.

77773a81de6360a2.jpeg

Dadurch wird der Agent-Workflow gestartet. Der Agent wählt die entsprechende Skill aus und verwendet diese Skill und die Funktion, um die Anfrage an den API-Endpunkt zu senden und die generierte Anfrage und die Ergebnisse zurückzugeben.

de9b3e4854b9a506.jpeg

Wenn Sie den Mauszeiger auf die Schritte bewegen, sehen Sie genau, was in den einzelnen Schritten passiert ist. Außerdem können Sie das und vieles mehr im linken Bereich sehen, wenn Sie einen Schritt auswählen. So können Sie besser nachvollziehen, wie Agenten mit Skills und APIs zusammenarbeiten.

605dcf936ba38cb8.jpeg

Folgeabfrage senden (Q2):

List agents who sold a property for over $1000000.

Sie werden feststellen, dass der Agent direkt zum Skill „QueryData API“ wechselt, da er die verfügbaren Skills bereits in den Speicher geschrieben hat und die Ermittlungsphase nicht noch einmal durchlaufen muss.

Der generierte SQL-Code ähnelt dieser Anweisung:

SELECT DISTINCT "a"."agent_id", "a"."firstname", "a"."lastname", "a"."email", "a"."brokerage" 
FROM "real_estate"."agents" AS "a" 
INNER JOIN "real_estate"."property_transactions" AS "t" ON "a"."agent_id" = "t"."seller_agent_id" 
WHERE "t"."sale_price" > 1000000 AND "a"."agent_id" IS NOT NULL 
ORDER BY "a"."lastname" ASC NULLS LAST;

Versuchen Sie es mit einer anderen Anfrage (Q3):

What is the average price of a single-family home with a garage in San Diego?

Mit QueryData werden Standardabfragen mit einem leeren Kontextsatz generiert. Für geschäftliche Aufgaben sind jedoch häufig eine bestimmte Geschäftslogik und deterministisches Verhalten erforderlich.

8. Hohe Genauigkeit und geschäftliche Relevanz durch Einbeziehung von Interpretationen

Wenn Sie Interpretationen in Prompts einfügen, wird sichergestellt, dass die generierten Abfragen einer bestimmten Geschäftslogik entsprechen.

Sie probieren ein Beispiel aus, bei dem ein Kunde nach einstöckigen Häusern in Del Mar fragt. Die Frage enthält zwei wichtige Messwerte und stellt ein häufiges Muster für eine Auswahl dar.

Probieren Sie den folgenden Natural Language Prompt (Q4) im Agent aus.

Single level Del Mar houses

Die Engine gibt eine allgemeine Anfrage zurück, enthält aber möglicherweise einige zusätzliche Bedingungen wie is_single_family = TRUE:

SELECT p."property_id", p."address_street", p."price", p."bedrooms", p."bathrooms", p."listing_status", p."is_single_family", p."num_stories", c."city_name" 
FROM "real_estate"."properties" AS p 
JOIN "real_estate"."cities" AS c ON p."city_id" = c."city_id" 
WHERE c."city_name" ILIKE 'Del Mar' AND p."num_stories" = 1 AND p."is_single_family" = TRUE 
ORDER BY p."property_id" ASC NULLS LAST;

Als Ergebnis erhalten wir eine zurückgegebene Zeile:

Natural Language Answer
The database contains one single-level, single-family house in Del Mar:

Address: 999 Main Ave (Postal Code: 90024)
Price: $3,800,000.00
Bedrooms: 4
Bathrooms: 3.5
Listing Status: Active
Features: Single-family home (1 story), has a garage, and no condo fees.

Anderen Prompt testen (Q5):

Del Mar houses close to good schools

Es ist intelligent genug, um die Spalten proximity_miles und school_ranking zum Sortieren der Eigenschaften zu verwenden, aber es wird keine Gewichtung und Wichtigkeit der einzelnen Messwerte berücksichtigt.

SELECT "p"."property_id", "p"."address_street", "p"."price", "p"."bedrooms", "p"."bathrooms", "s"."school_name", "s"."school_ranking", "sp"."proximity_miles" 
FROM "real_estate"."properties" AS "p" 
INNER JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id" 
INNER JOIN "real_estate"."school_to_property" AS "sp" ON "p"."property_id" = "sp"."property_id" 
INNER JOIN "real_estate"."schools" AS "s" ON "sp"."school_id" = "s"."school_id" 
WHERE "c"."city_name" = 'Del Mar' AND "sp"."proximity_miles" IS NOT NULL AND "s"."school_ranking" IS NOT NULL 
ORDER BY "sp"."proximity_miles" ASC NULLS LAST, "s"."school_ranking" ASC NULLS LAST;

Beispielabfrage in eine Vorlage umwandeln

Für die Geschäftslogik sind folgende Angaben erforderlich:

  • In einem Umkreis von 2 Meilen
  • Ranking der Schule von 5 oder niedriger
  • Gewichtete Sortierung: 80% Schulranking + 20% Nähe (Punktzahl = 0,8 * school_ranking + 0,2 * proximity_miles)

Hier ist die Formel für das gewichtete Ranking:

‬‭‬‭‬‭‬‭‬Score = 0.8 * school_ranking + 0.2 * proximity_miles

Laden Sie die Kontextdatei „sixrecipe_context1_1.json“ aus Cloud Shell herunter. Verwenden Sie dazu die Befehlszeile in Cloud Shell:

cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context1_1.json

Oder über den Menüpunkt Download im Cloud Shell-Menü:

c0d781806d966dcb.jpeg

Laden Sie die sixrecipe_context1_1.json mit AlloyDB Studio in Ihren sixrecipe-Kontextsatz hoch, um diese Standardstruktur zu definieren. Klicken Sie rechts neben dem sixrecipes-Kontext auf die drei Punkte und verwenden Sie „Kontextgruppe bearbeiten“, um die neue Datei hochzuladen. Der alte leere Kontext wird durch den neuen ersetzt.

Die Vorlage definiert explizite SQL-Vorlagenregeln für Regeln für eine gute Schulnähe:

{
  "facets": [],
  "templates": [
    {
      "nl_query": "Riverside houses close to good schools.",
      "sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\", \"s\".\"school_name\", \"stp\".\"proximity_miles\" FROM \"real_estate\".\"properties\" AS \"p\" JOIN \"real_estate\".\"cities\" AS \"c\" ON \"p\".\"city_id\" = \"c\".\"city_id\" JOIN \"real_estate\".\"school_to_property\" AS \"stp\" ON \"p\".\"property_id\" = \"stp\".\"property_id\" JOIN \"real_estate\".\"schools\" AS \"s\" ON \"stp\".\"school_id\" = \"s\".\"school_id\" WHERE \"c\".\"city_name\" = 'Riverside' AND \"s\".\"school_ranking\" <= 5 AND \"stp\".\"proximity_miles\" <= 2 ORDER BY 0.8 * \"s\".\"school_ranking\" + 0.2 * \"stp\".\"proximity_miles\"",
      "intent": "Houses in Riverside close to good schools (within 2 miles of schools with a rank of at least 5).",
      "manifest": "A given city houses close to good schools.",
      "parameterized": {
        "parameterized_intent": "Houses in $1 close to good schools (within 2 miles of schools with a rank of at least 5).",
        "parameterized_sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\", \"s\".\"school_name\", \"stp\".\"proximity_miles\" FROM \"real_estate\".\"properties\" AS \"p\" JOIN \"real_estate\".\"cities\" AS \"c\" ON \"p\".\"city_id\" = \"c\".\"city_id\" JOIN \"real_estate\".\"school_to_property\" AS \"stp\" ON \"p\".\"property_id\" = \"stp\".\"property_id\" JOIN \"real_estate\".\"schools\" AS \"s\" ON \"stp\".\"school_id\" = \"s\".\"school_id\" WHERE \"c\".\"city_name\" = $1 AND \"s\".\"school_ranking\" <= 5 AND \"stp\".\"proximity_miles\" <= 2 ORDER BY 0.8 * \"s\".\"school_ranking\" + 0.2 * \"stp\".\"proximity_miles\""
      }
    }
  ]
}

Führen Sie den Prompt noch einmal aus:

Del Mar houses close to good schools

Die resultierende Abfrage entspricht jetzt der in der Vorlage definierten Geschäftslogik:

SELECT "p"."address_street", "p"."address_postal_code", "s"."school_name", "stp"."proximity_miles" 
FROM "real_estate"."properties" AS "p" 
JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id" 
JOIN "real_estate"."school_to_property" AS "stp" ON "p"."property_id" = "stp"."property_id" 
JOIN "real_estate"."schools" AS "s" ON "stp"."school_id" = "s"."school_id" 
WHERE "c"."city_name" = 'Del Mar' AND "s"."school_ranking" <= 5 AND "stp"."proximity_miles" <= 2 
ORDER BY 0.8 * "s"."school_ranking" + 0.2 * "stp"."proximity_miles"

Zusammen mit der generierten SQL-Anweisung wird die folgende Intention generiert:

intentExplanation: "Houses in Del Mar close to good schools (within 2 miles of schools with a rank of at least 5)."

Die Intention wird im linken Bereich der ADK-Weboberfläche angezeigt:

bfb9d6bc718f57cf.jpeg

In den Ergebnissen werden zwei Properties nach unserem Score sortiert angezeigt:

Query Results
address_street        address_postal_code        school_name        proximity_miles
200 Coast Blvd        92014        Del Mar Heights Elementary        0.50
100 Del Mar Heights Rd        92014        Del Mar Heights Elementary        1.00
Answer
Based on the data, here are the properties in Del Mar located within 2 miles of a top-rated school (ranking of 5 or better):

200 Coast Blvd (92014)

School: Del Mar Heights Elementary
Proximity: 0.50 miles
100 Del Mar Heights Rd (92014)

School: Del Mar Heights Elementary
Proximity: 1.00 miles

Im nächsten Kapitel erweitern Sie den Umfang der Vorlage.

Interpretation durch Erfassen und Interpretieren mehrerer Fragen einfügen

Sie können den Anwendungsbereich unserer Vorlage erweitern, sodass sie nicht nur für „in der Nähe von guten Schulen“ verwendet werden kann. Fügen Sie dem Manifest weitere Bedingungen hinzu, die beispielsweise für „Häuser für Familien mit Kindern“ verwendet werden können.

Laden Sie die aktualisierte Kontextdatei herunter:

cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context1_2.json

Laden Sie die aktualisierte Datei sixrecipe_context1_2.json in Ihren Kontextsatz hoch.

In der neuen Kontextset-Datei ersetzen wir das Manifest "manifest": "A given city houses close to good schools." durch das Manifest "manifest": "A given city houses close to good schools, or are great for families with kids.". Dadurch kann die Vorlage für mehr als nur einen Fall verwendet werden.

Senden Sie diese Anfrage (Q6):

Houses in Waterloo great for families with kids.

Der Agent verwendet das aktualisierte Vorlagenmanifest, um Ihre standardisierte Abfragelogik anzuwenden. Dadurch wird dieselbe Abfrage wie oben zurückgegeben, mit der Absicht:

intentExplanation
:
"Houses in Waterloo close to good schools (within 2 miles of schools with a rank of at least 5)."

9. Mit Faceted Templates hohe Genauigkeit bei gleichzeitiger Flexibilität erreichen

Facetten sind modulare SQL-Bedingungen, die dynamisch mit Vorlagen kombiniert werden, um Qualifizierer (z.B. „Starterfamilie“, „Meerblick“) zu verarbeiten, ohne für jede Permutation separate Vorlagen erstellen zu müssen.

Anstatt für jede Abfrage oder Bedingung eine Vorlage zu erstellen, können wir Fragmente vorbereiten, die auf vorhandene Vorlagen angewendet werden können, um der Abfrage weitere Dimensionen hinzuzufügen.

Definieren Sie ein Facet für Properties mit den folgenden Attributen:

  • Ein Einfamilienhaus
  • Ein aktiver Eintrag
  • Drei bis vier Schlafzimmer und mindestens zwei Badezimmer
  • Standort in einer Gemeinde mit einer Kriminalitätsrate von unter 500 Delikten pro 100.000 Einwohnern

Laden Sie die facettierte Kontextdatei herunter:

cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context2_1.json

Laden Sie „sixrecipe_context2_1.json“ in Ihren Kontextsatz „sixrecipes“ in AlloyDB Studio hoch, um die Facetten zu konfigurieren.

  "facets": [
    {
      "sql_snippet": "real_estate.properties.is_single_family = TRUE AND real_estate.properties.listing_status = 'Active' AND real_estate.properties.bedrooms BETWEEN 3 AND 4 AND real_estate.properties.bathrooms >= 2.0 AND 500 > (SELECT m.crime_rate_per_100k FROM real_estate.cities c JOIN real_estate.municipalities m ON c.municipality_id = m.municipality_id AND c.city_id = real_estate.properties.city_id)",
      "intent": "for a starter family (active single-family home listings with 3 to 4 bedrooms, 2+ bathrooms, and a crime rate under 500 per 100,000 residents)",
      "manifest": "for a starter family",
      "parameterized": {
        "parameterized_intent": "for a starter family (active single-family home listings with 3 to 4 bedrooms, 2+ bathrooms, and a crime rate under 500 per 100,000 residents)",
        "parameterized_sql_snippet": "real_estate.properties.is_single_family = TRUE AND real_estate.properties.listing_status = 'Active' AND real_estate.properties.bedrooms BETWEEN 3 AND 4 AND real_estate.properties.bathrooms >= 2.0 AND 500 > (SELECT m.crime_rate_per_100k FROM real_estate.cities c JOIN real_estate.municipalities m ON c.municipality_id = m.municipality_id AND c.city_id = real_estate.properties.city_id)"
      }
    }
  ]

Führen Sie diese NL-Abfrage aus (Q7):

Del Mar houses close to good schools for a starter family.

Die Engine hängt Ihre Facettenbedingungen direkt an die Basisabfrage an:

SELECT "p"."address_street", "p"."address_postal_code", "s"."school_name", "stp"."proximity_miles" 
FROM "real_estate"."properties" AS "p" 
JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id" 
JOIN "real_estate"."school_to_property" AS "stp" ON "p"."property_id" = "stp"."property_id" 
JOIN "real_estate"."schools" AS "s" ON "stp"."school_id" = "s"."school_id" 
WHERE "c"."city_name" = 'Del Mar' 
  AND "s"."school_ranking" <= 5 
  AND "stp"."proximity_miles" <= 2 
  AND "p"."is_single_family" = TRUE 
  AND "p"."listing_status" = 'Active' 
  AND "p"."bedrooms" BETWEEN 3 AND 4 
  AND "p"."bathrooms" >= 2.0 
  AND 500 > (
    SELECT m.crime_rate_per_100k 
    FROM real_estate.cities c 
    JOIN real_estate.municipalities m ON c.municipality_id = m.municipality_id 
    AND c.city_id = p.city_id
  ) 
ORDER BY 0.8 * "s"."school_ranking" + 0.2 * "stp"."proximity_miles"

Hier sind die Ergebnisse:

Query Results
address_street        address_postal_code        school_name        proximity_miles
200 Coast Blvd        92014        Del Mar Heights Elementary        0.50
Natural Language Answer
Based on your criteria, there is an active listing for a single-family house in Del Mar that fits your needs:

Address: 200 Coast Blvd, Del Mar, 92014
Nearby School: Del Mar Heights Elementary (ranked within the top 5)
Proximity to School: 0.50 miles

Weitere Facetten hinzufügen

Was ist, wenn wir eine weitere Dimension basierend auf dem neuen Muster hinzufügen möchten, z. B. eine Fensteransicht für die Property?

Semantisches Matching für Meerblick in einer Facettendefinition hinzufügen

    {
      "sql_snippet": "((real_estate.properties.description_embedding <=> google_ml.embedding('gemini-embedding-001', 'unobstructed, panoramic, ocean vista, vast Pacific, breathtaking, commanding view, deep blue horizon, massive, sweeping view')::vector) < 0.4)",
      "intent": "with ocean view",
      "manifest": "with ocean view",
      "parameterized": {
        "parameterized_intent": "with ocean view",
        "parameterized_sql_snippet": "((real_estate.properties.description_embedding <=> google_ml.embedding('gemini-embedding-001', 'unobstructed, panoramic, ocean vista, vast Pacific, breathtaking, commanding view, deep blue horizon, massive, sweeping view')::vector) < 0.4)"
      }

Der Wert 0,4 in der obigen Facettendefinition ist ein experimentell kalibrierter Grenzwert. Laden Sie die vielseitige Kontextdatei herunter:

cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context2_2.json

Laden Sie sixrecipe_context2_2.json in Ihren Kontextsatz hoch und führen Sie diesen Prompt aus (Q8):

Ocean view Del Mar homes near good schools.

Die Ausgabe enthält Standardbedingungen in Kombination mit dem Abgleich der Vektorähnlichkeit über google_ml.embedding:

SELECT "p"."address_street", "p"."address_postal_code", "s"."school_name", "stp"."proximity_miles" 
FROM "real_estate"."properties" AS "p" 
JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id" 
JOIN "real_estate"."school_to_property" AS "stp" ON "p"."property_id" = "stp"."property_id" 
JOIN "real_estate"."schools" AS "s" ON "stp"."school_id" = "s"."school_id" 
WHERE "c"."city_name" = 'Del Mar' AND "s"."school_ranking" <= 5 AND "stp"."proximity_miles" <= 2 
AND (((p.description_embedding <=> google_ml.embedding('gemini-embedding-001', 'unobstructed, panoramic, ocean vista, vast Pacific, breathtaking, commanding view, deep blue horizon, massive, sweeping view')::vector) <= 0.4)) 
ORDER BY 0.8 * "s"."school_ranking" + 0.2 * "stp"."proximity_miles";

Die Abfrage gibt eine Property zurück:

Query Results
address_street        address_postal_code        school_name        proximity_miles
100 Del Mar Heights Rd        92014        Del Mar Heights Elementary        1.00
Answer
The ocean-view home in Del Mar near a top-ranked school is located at 100 Del Mar Heights Rd (92014).

It is situated just 1.00 mile away from Del Mar Heights Elementary, which is one of the area's highly-ranked schools (ranking of 5 or better).

Prüfen Sie die Ergebnisse, indem Sie die Beschreibung des Attributs in AlloyDB Studio aufrufen und die folgende Abfrage ausführen:

select description from real_estate.properties where address_postal_code='92014' and description is not null;

Dort wird die Beschreibung mit „magnificent marine spectacle“ angezeigt.

Well-located 2-bedroom condo with excellent proximity to coastal shopping and dining. The balcony provides a magnificent marine spectacle against an azure backdrop. Under contract, high monthly HOA fee.

10. Eindeutige Zuordnung Ihrer privaten Daten mithilfe von Wertesuchen

Mehrdeutige Anfragen können mehreren Entitäten entsprechen, z. B. wenn ein Ortsname mit einem Unternehmensnamen verwechselt wird. Bei der Wertsuche werden Begriffe Datenbankkonzepten zugeordnet, um diese Referenzen aufzulösen.

Die Wertsuche stellt Verbindungen zwischen dem Spaltennamen und den Werten in der Spalte sowie einem Konzepttyp her, z. B. Stadt, Land oder Name. Da nicht nur Metadaten, sondern auch repräsentative Stichproben der Daten in einer Spalte indexiert wurden, kann ein in der Anfrage in natürlicher Sprache verwendeter Wert einem potenziellen Konzepttyp zugeordnet werden. Außerdem kann ermittelt werden, welche Tabelle und Spalte im resultierenden SQL verwendet werden können.

Mehrdeutigkeit in einer Abfrage

In der Realität kann es noch schwieriger sein, da Namen und Orte oft falsch geschrieben werden. Führen Sie diesen Prompt (Q9) mit einem Tippfehler und einem mehrdeutigen Begriff aus:

Westwod's sold properties in the last 1 month.

Hier gibt es zwei Probleme: Der Name ist falsch geschrieben und es ist nicht klar, ob es sich um Immobilien handelt, die an einem Ort mit ähnlichen Namen verkauft werden, oder um eine Immobilienagentur. Wenn wir die Abfrage ausführen, wird eine Abfrage wie die folgende zurückgegeben.

SELECT "p"."property_id", "p"."address_street", "p"."address_postal_code", "p"."price" AS "listing_price", "p"."bedrooms", "p"."bathrooms", "p"."listing_status", "pt"."sale_date", "pt"."sale_price", "c"."city_name" FROM "real_estate"."properties" AS "p" INNER JOIN "real_estate"."property_transactions" AS "pt" ON "p"."property_id" = "pt"."property_id" INNER JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id" WHERE ("c"."city_name" ILIKE '%Westwood%' OR "c"."city_name" ILIKE '%Westwod%') AND "pt"."sale_date" >= '2025-09-01'::date AND "pt"."sale_date" <= '2025-09-30'::date ORDER BY "pt"."sale_date" DESC NULLS LAST, "pt"."sale_price" DESC NULLS LAST

Der Name wurde korrigiert und es wurde davon ausgegangen, dass sich die Frage auf den Standort der Immobilie bezieht. Es wurde versucht, Immobilien in der Stadt Westwood zu finden.

Aktivieren Sie die Erweiterung „pg_trgm“ in AlloyDB Studio, um ungenaue Stringvergleiche zu unterstützen:

CREATE EXTENSION IF NOT EXISTS pg_trgm;

Danach können wir die Erweiterung verwenden, um dem QueryData-Kontextset Wertesuchen hinzuzufügen.

Hier ist die Liste der Wertesuchen, die wir verwenden möchten:

"value_searches": [
    {
      "conceptType": "Municipality name",
      "query": "/* Requires extension: pg_trgm */ WITH TrigramMetrics AS (SELECT T.municipality_name AS original_value, (T.municipality_name % $value::text) AS normalized_dist FROM real_estate.municipalities T WHERE T.municipality_name % $value::text) SELECT original_value AS value, 'real_estate.municipalities.municipality_name' AS columns, 'Name of the municipality' AS concept_type, normalized_dist AS distance, ''::text AS context FROM TrigramMetrics",
      "description": "Trigram match for municipality name"
    },
    {
      "conceptType": "City name",
      "query": "/* Requires extension: pg_trgm */ WITH TrigramMetrics AS (SELECT T.city_name AS original_value, (T.city_name % $value::text) AS normalized_dist FROM real_estate.cities T WHERE T.city_name % $value::text) SELECT original_value AS value, 'real_estate.cities.city_name' AS columns, 'Name of the city' AS concept_type, normalized_dist AS distance, ''::text AS context FROM TrigramMetrics",
      "description": "Trigram match for city name"
    },
    {
      "conceptType": "Brokerage name",
      "query": "/* Requires extension: pg_trgm */ WITH TrigramMetrics AS (SELECT T.brokerage AS original_value, (T.brokerage % $value::text) AS normalized_dist FROM real_estate.agents T WHERE T.brokerage % $value::text) SELECT original_value AS value, 'real_estate.agents.brokerage' AS columns, 'Name of the brokerage' AS concept_type, normalized_dist AS distance, ''::text AS context FROM TrigramMetrics",
      "description": "Trigram match for brokerage name"
    }
  ]

Laden Sie die Kontextdatei für die Wertsuche herunter:

cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context3_1.json

Laden Sie „sixrecipe_context3_1.json“ in das QueryData-Kontextset „sixrecipes“ hoch und speichern Sie es.

Führen Sie den Prompt noch einmal aus (Q9):

Westwod's sold properties in the last 1 month.

Es wurde eine Antwort zur Klarstellung zurückgegeben, da bei der Wertsuche drei verschiedene Einheiten mit ähnlichen Werten gefunden wurden:

The database requires some clarification to provide the exact information you need:

The search term 'Westwod' (Westwood) is ambiguous because it can refer to:

A municipality name (e.g., the municipality of Westwood)
A city name (e.g., the city of Westwood)
A brokerage name (e.g., properties sold by agents affiliated with the Westwood brokerage)
Could you please clarify which of these you are referring to?

Der Trace gibt uns einen Hinweis darauf, warum dieser bestimmte Pfad ausgewählt wurde.

88c52932dcbef8f9.jpeg

Hier der vollständige Text:

"[NOT_ENOUGH_INFO] The search term 'Westwod' is ambiguous because it can refer to a municipality name, a city name, or a brokerage name. Could you please clarify if you are referring to properties sold within the municipality of Westwood, the city of Westwood, or properties sold by agents affiliated with the Westwood brokerage?"

Mehrdeutigkeiten aus der Anfrage entfernen

Eingabeaufforderung optimieren (Q10):

Westwood city location properties sold in September 2025.

Jetzt haben wir die Abfrage und die Ergebnisse:

Generated SQL
SELECT "p"."property_id", "p"."address_street", "p"."address_postal_code", "p"."price", "pt"."sale_date", "pt"."sale_price" 
FROM "real_estate"."properties" AS "p" 
INNER JOIN "real_estate"."cities" AS "c" ON "p"."city_id" = "c"."city_id" 
INNER JOIN "real_estate"."property_transactions" AS "pt" ON "p"."property_id" = "pt"."property_id" 
WHERE "c"."city_name" = 'Westwood' 
  AND "pt"."sale_date" >= '2025-09-01'::date 
  AND "pt"."sale_date" <= '2025-09-30'::date 
ORDER BY "pt"."sale_date" ASC NULLS LAST

Query Results
property_id        address_street        address_postal_code        price        sale_date        sale_price
32        999 Main St        99999        3800000.00        2025-09-12        1000000.00

11. Semantische Suche und KI-Funktionen

AlloyDB AI-Funktionen ermöglichen das semantische Filtern unstrukturierter Daten. Funktionen wie ai.if und google_ml.embedding können direkt in SQL-Abfragen zusammen mit Standarddatenbankoperatoren verwendet werden.

Vorlage mit ILIKE-Operatoren

Laden Sie als Erstes die neue Kontextdatei mit ILIKE-Operatoren hoch.

Laden Sie die Kontextdatei für die ILIKE-Vorlage herunter:

cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context4_1.json

Laden Sie „sixrecipe_context4_1.json“ in Ihr Kontextset hoch, um das standardmäßige ILIKE-Mustervergleich für bezugsfertige Häuser zu bewerten.

    {
      "nl_query": "Move-in ready houses",
      "sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\" FROM \"real_estate\".\"properties\" AS \"p\" WHERE \"p\".listing_status = 'Active' AND \"p\".\"description\" IS NOT NULL AND (\"p\".description ILIKE '%turnkey%' OR \"p\".description ILIKE '%move-in%')",
      "intent": "Move-in ready houses",
      "manifest": "Move-in ready houses",
      "parameterized": {
        "parameterized_intent": "Move-in ready houses",
        "parameterized_sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\" FROM \"real_estate\".\"properties\" AS \"p\" WHERE \"p\".listing_status = 'Active' AND \"p\".\"description\" IS NOT NULL AND (\"p\".description ILIKE '%turnkey%' OR \"p\".description ILIKE '%move-in%')"
      }
    }

Senden Sie diese Anfrage (Q11):

List move-in ready houses.

Resultierende Anfrage:

SELECT "p"."address_street", "p"."address_postal_code" 
FROM "real_estate"."properties" AS "p" 
WHERE "p".listing_status = 'Active' 
  AND "p"."description" IS NOT NULL 
  AND ("p".description ILIKE '%turnkey%' OR "p".description ILIKE '%move-in%')

Es wird ein übereinstimmender Datensatz zurückgegeben.

Query Results
address_street        address_postal_code
40 Main St, Unit 8        N2H 2G8

Vorlage mit der Funktion AI.IF

Laden Sie die Kontextdatei für die AI.IF-Vorlage herunter:

cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context4_2.json

Laden Sie „sixrecipe_context4_2.json“ in Ihren Kontextsatz hoch, um die semantische Filterfunktion „ai.if“ zu testen.

    {
      "nl_query": "List Move-in ready houses",
      "sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\" FROM \"real_estate\".\"properties\" AS \"p\" WHERE \"p\".listing_status = 'Active' AND \"p\".\"description\" IS NOT NULL AND ai.if('Does this description represent a move-in ready house? Description: ' || \"p\".\"description\")",
      "intent": "List Move-in ready houses",
      "manifest": "List Move-in ready houses",
      "parameterized": {
        "parameterized_intent": "List Move-in ready houses",
        "parameterized_sql": "SELECT \"p\".\"address_street\", \"p\".\"address_postal_code\" FROM \"real_estate\".\"properties\" AS \"p\" WHERE \"p\".listing_status = 'Active' AND \"p\".\"description\" IS NOT NULL AND ai.if('Does this description represent a move-in ready house? Description: ' || \"p\".\"description\")"
      }
    }

Wiederholen Sie den Prompt (Q12):

List move-in ready houses.

Generiertes SQL:

SELECT "p"."address_street", "p"."address_postal_code" 
FROM "real_estate"."properties" AS "p" 
WHERE "p".listing_status = 'Active' 
  AND "p"."description" IS NOT NULL 
  AND ai.if('Does this description represent a move-in ready house? Description: ' || "p"."description")

Das Ergebnis enthält dieselbe Eigenschaft:

Query Results
Address Street        Address Postal Code
40 Main St, Unit 8        N2H 2G8
Natural Language Answer
The move-in ready home currently available is located at:

Address: 40 Main St, Unit 8
Postal Code: N2H 2G8

Laden Sie die Kontextdatei für die Einbettungssuche herunter:

cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context4_3.json

Laden Sie „sixrecipe_context4_3.json“ in Ihr Kontextset hoch, um die semantische Vektorsuche mit „google_ml.embedding“ zu testen und Häuser mit neuen Küchengeräten zu suchen.

Aktualisieren Sie den Kontextsatz mit der Datei sixrecipe_context4_3.json mit einer zusätzlichen Facette mithilfe der AlloyDB-Vektorsuche.

    {
      "sql_snippet": "((real_estate.properties.description_embedding <=> google_ml.embedding('gemini-embedding-001', 'Upgraded kitchen appliances')::vector) < 0.4)",
      "intent": "with upgraded kitchen appliances",
      "manifest": "with upgraded kitchen appliances",
      "parameterized": {
        "parameterized_intent": "with upgraded kitchen appliances",
        "parameterized_sql_snippet": "((real_estate.properties.description_embedding <=> google_ml.embedding('gemini-embedding-001', 'Upgraded kitchen appliances')::vector) < 0.4)"
      }
    }

Der Wert 0,4 in der obigen Facettendefinition ist ein experimentell kalibrierter Grenzwert.

Führen Sie diese Abfrage (Q13) aus:

List move-in ready houses with upgraded kitchen appliances.

Generiertes SQL:

SELECT "p"."address_street", "p"."address_postal_code" FROM "real_estate"."properties" AS "p" WHERE "p"."listing_status" = 'Active' AND "p"."description" IS NOT NULL AND ai.if('Does this description represent a Move-in ready house? Description: ' || "p"."description") AND ((("p"."description_embedding" <=> google_ml.embedding('gemini-embedding-001', 'Upgraded kitchen appliances')::vector) < 0.4))

Hier sind die Abfrageergebnisse und die Empfehlung in natürlicher Sprache:

Query Results
Address        Postal Code
40 Main St, Unit 8        N2H 2G8
Natural Language Answer
The move-in ready house with upgraded kitchen appliances is located at:

Address: 40 Main St, Unit 8
Postal Code: N2H 2G8

12. Sicherheit und Datenschutz

Wenn die QueryData API Abfragen generiert, besteht das Risiko, dass durch die generierten Abfragen Daten anderer Nutzer offengelegt werden. Mit Parameterized Secure Views (PSVs) werden Sicherheitsgrenzen auf Zeilenebene während der NL2SQL-Generierung erzwungen.

Parametrisierte sichere Ansicht erstellen

Wir haben eine Tabelle „real_estate.offers“ mit Informationen zu Angeboten für alle unsere Immobilienangebote. Unsere Kundenservicemitarbeiter sollen nur ihre eigenen Angebote sehen, nicht die anderer Kundenservicemitarbeiter. Wir erstellen eine PSV mit der Möglichkeit, Zeilen basierend auf der agent_id zu filtern.

Erstellen Sie eine parametrisierte sichere Ansicht für die Tabelle „offers“ in AlloyDB Studio:

CREATE VIEW real_estate.secure_offers
  WITH (security_barrier) AS
SELECT offer_id, property_id, buyer_agent_id,
    seller_agent_id, offer_amount, offer_date,
    offer_status, offer_expiration_date,
    contingencies
FROM real_estate.offers
WHERE buyer_agent_id = $@agent_id;

Überprüfen Sie die Definition der parametrisierten sicheren Ansicht:

SELECT definition
FROM parameterized_views.all_parameterized_views
WHERE schemaname = 'real_estate' AND viewname = 'secure_offers';

Was ist mit der Tabelle „real_estate.offers“?

Datenzugriff auf QueryData mit parametrisierten sicheren Ansichten in AlloyDB einschränken

In der Datei „agent.py“ wird die parametrisierte Sicherheitsansicht „real_estate.secure_offers“ anstelle von „real_estate.offers“ in TABLE_IDS registriert:

Der Quellcode von „agent.py“:

 List of database tables included in QueryData API requests
TABLE_IDS = [
    "real_estate.municipalities",
    "real_estate.cities",
    "real_estate.agents",
    "real_estate.properties",
    "real_estate.schools",
    "real_estate.school_to_property",
    "real_estate.property_transactions",
    "real_estate.secure_offers",
]

Und übergibt den Sitzungslaufzeitkontext für einen Agenten mit agent_id=1:

            "parameterized_secure_view_parameters": {
                "parameters": {
                    "key": "agent_id",
                    "value": "1"
                }
            }
        },

Daher wird bei jeder QueryData API-Anfrage dieser Parameter übergeben. Wenn die sichere Ansicht in die Anfrage aufgenommen wird, wird sie gefiltert und es werden nur Ergebnisse für diesen bestimmten Kundenservicemitarbeiter zurückgegeben.

Führen Sie diese Abfrage aus (Q14):

List the offer id and listing price in 2025 where the offer was within 5% of the final selling price.

Generiertes SQL:

SELECT "o"."offer_id", "p"."price" AS "listing_price" 
FROM "real_estate"."secure_offers" AS "o" 
INNER JOIN "real_estate"."properties" AS "p" ON "o"."property_id" = "p"."property_id" 
INNER JOIN "real_estate"."property_transactions" AS "t" ON "o"."property_id" = "t"."property_id" 
WHERE "o"."offer_date" >= '2025-01-01' 
  AND "o"."offer_date" <= '2025-12-31' 
  AND "o"."offer_amount" IS NOT NULL 
  AND "t"."sale_price" IS NOT NULL 
  AND "p"."price" IS NOT NULL 
  AND ABS("o"."offer_amount" - "t"."sale_price") <= (0.05 * "t"."sale_price") 
ORDER BY "o"."offer_id" ASC NULLS LAST

Wenn Sie die Ansicht abfragen, werden die Ergebnisse nach dem Parameter für die aktive Agentsitzung gefiltert. So werden unbefugte Datensätze geschützt und nur zwei Datensätze zurückgegeben.

Query Results
Offer ID        Listing Price
7        $750,000.00
8        $510,000.00
Natural Language Answer
Here are the offers from 2025 where the offer amount was within 5% of the final selling price:

Offer ID 7: Listing Price of $750,000.00
Offer ID 8: Listing Price of $510,000.00

Wenn Sie die folgende Abfrage für die Basistabelle „real_estate.offers“ in AlloyDB Studio ausführen:

SELECT "o"."offer_id", "p"."price" AS "listing_price" 
FROM "real_estate"."offers" AS "o" 
INNER JOIN "real_estate"."properties" AS "p" ON "o"."property_id" = "p"."property_id" 
INNER JOIN "real_estate"."property_transactions" AS "t" ON "o"."property_id" = "t"."property_id" 
WHERE "o"."offer_date" >= '2025-01-01' 
  AND "o"."offer_date" <= '2025-12-31' 
  AND "o"."offer_amount" IS NOT NULL 
  AND "t"."sale_price" IS NOT NULL 
  AND "p"."price" IS NOT NULL 
  AND ABS("o"."offer_amount" - "t"."sale_price") <= (0.05 * "t"."sale_price") 
ORDER BY "o"."offer_id" ASC NULLS LAST

Es werden mehr als zwei Datensätze zurückgegeben, die Daten für alle Kundenservicemitarbeiter enthalten.

Damit ist das Lab abgeschlossen. Sie haben gelernt, wie Sie die QueryData API, KI-Funktionen und parametrisierte sichere Ansichten in AlloyDB verwenden.

13. Umgebung bereinigen

Löschen Sie die AlloyDB-Instanzen und den Cluster, wenn Sie das Lab abgeschlossen haben.

AlloyDB-Cluster und alle Instanzen löschen

Der Cluster wird mit der Option force zerstört. Dadurch werden auch alle Instanzen gelöscht, die zum Cluster gehören.

Wenn die Verbindung zu Ihrem Terminal getrennt wurde, stellen Sie die Verbindung wieder her und definieren Sie das Projekt und die Umgebungsvariablen in Cloud Shell:

gcloud config set project <YOUR_PROJECT_ID>
export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
export PROJECT_ID=$(gcloud config get-value project)

Löschen Sie den Cluster:

gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force

Erwartete Konsolenausgabe:

student@cloudshell:~ (test-project-001-402417)$ gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force
All of the cluster data will be lost when the cluster is deleted.

Do you want to continue (Y/n)?  Y

Operation ID: operation-1697820178429-6082890a0b570-4a72f7e4-4c5df36f
Deleting cluster...done.   

AlloyDB-Sicherungen löschen

Löschen Sie alle AlloyDB-Sicherungen für den Cluster:

for i in $(gcloud alloydb backups list \
  --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" \
  --format="value(name)" \
  --sort-by=~createTime) ; do \
  gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done

Erwartete Konsolenausgabe:

student@cloudshell:~ (test-project-001-402417)$ for i in $(gcloud alloydb backups list --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" --format="value(name)" --sort-by=~createTime) ; do gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done
Operation ID: operation-1697826266108-60829fb7b5258-7f99dc0b-99f3c35f
Deleting backup...done.                                                                                                                                                                                                                                                            

Cloud Storage-Bucket löschen

Löschen Sie den Cloud Storage-Import-Bucket, um laufende Speichergebühren zu vermeiden:

gcloud storage rm -r gs://${PROJECT_ID}-import 

14. Glückwunsch

Herzlichen Glückwunsch zum Abschluss des Codelabs!

Behandelte Themen

  • AlloyDB-Cluster und primäre Instanz bereitstellen
  • QueryData, KI-Funktionen und parametrisierte sichere Ansichten für AlloyDB aktivieren
  • QueryData-Kontextset erstellen
  • Verschiedene Vorlagen und Kontexte in der QueryData API verwenden
  • QueryData-Vorlagen mit Attributen flexibler gestalten
  • Mehrdeutigkeiten bei Daten mit der Wertsuche und der Trigram-Indexierung beheben
  • KI-Funktionen für die semantische Suche mit Vorlagen verwenden
  • Parametrisierte sichere Ansichten mit der QueryData API verwenden

Umfrage

Ausgabe:

Wie werden Sie diese Anleitung verwenden?

Nur durchlesen Lesen und Übungen machen