1. はじめに
この Codelab では、QueryData API を使用して最適な結果を取得する方法について説明します。データベースに自然言語リクエストを行う際に、正確で再現可能な結果を生成する方法について説明します。このガイドでは、自然言語から SQL(NL2SQL)への変換とその実用的なアプリケーションのさまざまな側面を説明する 6 つのレシピを複数の章にわたって紹介します。
前提条件
- Google Cloud と Google Cloud コンソールの基本的な知識
- コマンドライン インターフェースと Cloud Shell の基本的なスキル
学習内容
- AlloyDB クラスタとプライマリ インスタンスをデプロイする方法
- QueryData、AI 関数、パラメータ化されたセキュアビューを有効にする方法
- QueryData コンテキスト セットの作成方法
- QueryData API でさまざまなテンプレートとコンテキストを使用する方法
- ファセットを使用して QueryData テンプレートの柔軟性を高める方法
- 値検索とトライグラム インデックスを使用してデータの曖昧さを解決する方法
- テンプレートでセマンティック検索に AI 関数を使用する方法
- QueryData API でパラメータ化されたセキュアビューを使用する方法
必要なもの
- Google Cloud アカウントと Google Cloud プロジェクト
- Google Cloud コンソールと Cloud Shell をサポートする Chrome などのウェブブラウザ
2. 設定と要件
プロジェクトの設定
- Google Cloud コンソールにログインします。Gmail アカウントも Google Workspace アカウントもまだお持ちでない場合は、アカウントを作成してください。
仕事用または学校用のアカウントではなく、個人用のアカウントを使用します。
- 新しいプロジェクトを作成するか、既存のプロジェクトを再利用します。Google Cloud コンソールで新しいプロジェクトを作成するには、ヘッダーで [プロジェクトを選択] ボタンをクリックします。ポップアップ ウィンドウが開きます。

[プロジェクトを選択] ウィンドウで [新しいプロジェクト] をクリックします。新しいプロジェクトのダイアログ ボックスが開きます。

ダイアログ ボックスで、プロジェクト名を入力してロケーションを選択します。

- プロジェクト名は、このプロジェクトの参加者に表示される名称です。プロジェクト名は Google API では使用されず、いつでも変更できます。
- プロジェクト ID は、すべての Google Cloud プロジェクトにおいて一意でなければならず、不変です(設定後は変更できません)。Google Cloud コンソールでは一意の ID が自動的に生成されますが、カスタマイズすることもできます。生成された ID が気に入らない場合は、別のランダムな ID を生成するか、独自の ID を指定してその ID が使用可能かどうかを確認できます。ほとんどの Codelab では、プロジェクト ID を参照する必要があります。通常、プロジェクト ID はプレースホルダ PROJECT_ID で識別されます。
- なお、3 つ目の値として、一部の API が使用するプロジェクト番号があります。これら 3 つの値について詳しくは、こちらのドキュメントをご覧ください。
課金を有効にする
個人用の請求先アカウントを設定する
Google Cloud クレジットを使用して課金を設定した場合は、この手順をスキップできます。
個人用の請求先アカウントを設定するには、Cloud コンソールでこちらに移動して課金を有効にします。
注意事項:
- このラボを完了するのにかかる Cloud リソースの費用は 5 米ドル未満です。
- このラボの最後の手順に沿ってリソースを削除すると、それ以上の料金は発生しません。
- 新規ユーザーは、300 米ドル分の無料トライアルをご利用いただけます。
Cloud Shell の起動
Google Cloud はノートパソコンからリモートで操作できますが、この Codelab では、Google Cloud Shell(Cloud 上で動作するコマンドライン環境)を使用します。
Google Cloud コンソールで、右上のツールバーにある Cloud Shell アイコンをクリックします。

または、G キーを押してから S キーを押します。このシーケンスは、Google Cloud コンソール内からアクセスした場合、またはこのリンクを使用した場合に Cloud Shell をアクティブにします。
プロビジョニングと環境への接続にはそれほど時間はかかりません。完了すると、次のように表示されます。

この仮想マシンには、必要な開発ツールがすべて用意されています。永続的なホーム ディレクトリが 5 GB 用意されており、Google Cloud で稼働します。そのため、ネットワークのパフォーマンスと認証機能が大幅に向上しています。この Codelab での作業はすべて、ブラウザ内から実行できます。インストールは不要です。
3. はじめに
API を有効にする
AlloyDB、Compute Engine、ネットワーキング サービス、Agent Platform を使用するには、Google Cloud プロジェクトでそれぞれの API を有効にします。
Cloud Shell ターミナルで、プロジェクト ID が設定されていることを確認します。
gcloud config get-value project
このコマンドは、Google Cloud プロジェクト ID を返します。
PROJECT_ID 環境変数を設定します。
PROJECT_ID=$(gcloud config get-value project)
必要な API を有効にします。
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
予想される出力:
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.
有効になっている各 API については、ドキュメントをご覧ください。
4. AlloyDB をデプロイする
AlloyDB クラスタとプライマリ インスタンスを作成します。必要なリソースをすべてデプロイする準備済みのスクリプトを使用してデプロイすることも、AlloyDB のドキュメントに沿って手順ごとにデプロイすることもできます。
自動スクリプトを使用して AlloyDB をデプロイする
このアプローチでは、自動化されたスクリプトを使用して AlloyDB クラスタをデプロイし、デプロイされたリソースの使用を開始するために必要な構成の詳細を提供します。
Cloud Shell ターミナルで、リポジトリからデプロイ スクリプトのクローンを作成するコマンドを実行します。
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
次のようにデプロイ スクリプトを実行します。
./deploy_alloydb.sh
スクリプトの完了には 5 ~ 7 分かかります。出力には、クラスタのデプロイの詳細が表示されます。パスワードは異なりますので、今後の使用に備えてパスワードを記録しておいてください。
... <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) ----------------------------------------
Google Cloud コンソールの AlloyDB クラスタ ページで、新しいクラスタとインスタンスを表示します。

5. データベースの準備
データベースを作成し、Gemini Enterprise Agent Platform の統合を有効にして、データベース オブジェクトを構築し、サンプルデータを追加します。
AlloyDB に必要な権限を付与する
AlloyDB サービス エージェントに必要な IAM ロールを付与します。
[追加](+)をクリックして、新しい Cloud Shell タブを開きます。

新しいタブで、次のコマンドを実行します。
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"
想定されるコンソール出力:
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 を有効にする
AlloyDB クラスタで Data Access API を有効にします。
同じターミナルタブで、次のコマンドを実行します。
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",
}'
データベース フラグを更新する
インスタンス レベルでフラグを有効にする前に、Data Access API のステップが完了するまで待ちます。次の図に示すように、インスタンスのステータスに緑色のチェックマークが表示されていることを確認します。

エージェント ツールに AI 拡張機能と IAM 認証を使用するには、インスタンスで特定のデータベース フラグを有効にして、自分自身をデータベース ユーザーとして追加する必要があります。次のフラグを有効にします。
- alloydb.iam_authentication
- password.enforce_complexity
- google_ml_integration.enable_ai_query_engine
- parameterized_views
同じターミナルタブで、次のコマンドを実行します。
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
アカウントの AlloyDB IAM ユーザーを作成します。
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
ターミナルで exit コマンドを実行して、タブを閉じます。
exit
AlloyDB Studio に接続する
以降の章では、AlloyDB Studio でデータベース接続を必要とするすべての SQL コマンドを実行できます。
AlloyDB Studio を開く手順は次のとおりです。
- Google Cloud コンソールで、AlloyDB for PostgreSQL のクラスタ ページに移動します。
- プライマリ インスタンスを選択して、ウェブ インターフェースを開きます。

- 左側の [AlloyDB Studio] をクリックします。

postgresデータベースを選択し、[IAM 認証] を選択して、[認証] をクリックします。

この操作により、AlloyDB Studio インターフェースが開きます。
- [無題のクエリ] タブを選択して、SQL エディタを開きます。

次の図に示すように、SQL コマンドを実行できるエディタが開きます。

データベースを作成
クイックスタート データベースを作成する
AlloyDB Studio エディタで次のコマンドを実行して、データベースを作成します。
CREATE DATABASE quickstart_db
予想される出力:
Statement executed successfully
quickstart_db に接続する
AlloyDB Studio で [データベース/ユーザーを変更] をクリックします。

データベース リストから quickstart_db を選択し、IAM 認証を選択して認証します。

新しい接続が開き、quickstart_db データベースのオブジェクトを操作できます。
拡張機能を有効にする
必要な拡張機能をすべて確認し、データベースで有効になっていて、最小バージョンが正しいことを確認します。
必要な拡張機能がすべてデータベースに存在することを確認します。
SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'google_ml_integration', 'parameterized_views');
予想される出力:
extname | extversion -----------------------+---------------- google_ml_integration | 1.5.9 parameterized_views | 1.0 vector | 0.8.2.google-1
上記の行がすべて返されない場合は、一部の拡張機能が有効になっていないことを意味します。
拡張機能を有効にする前に、インスタンスでデータベース フラグ google_ml_integration.enable_ai_query_engine と parameterized_views.enabled がすべて有効になっていることを確認する必要があります。
quickstart_db に接続している AlloyDB Studio で、次のコマンドを実行します。
show google_ml_integration.enable_ai_query_engine;
show parameterized_views.enabled;
いずれかが「off」になっている場合は、「データベース フラグを更新する」の手順を繰り返し、「show...」コマンドを使用してステータスを再度確認します。
必要な拡張機能を有効にします。
quickstart_db に接続している AlloyDB Studio で、次のコマンドを実行します。
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS parameterized_views;
parameterized_views と google_ml の拡張機能のバージョンを確認します。
quickstart_db に接続している AlloyDB Studio で、次のコマンドを実行します。
SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'google_ml_integration', 'parameterized_views');
予想される出力:
extname | extversion -----------------------+---------------- google_ml_integration | 1.5.9 parameterized_views | 1.0 vector | 0.8.2.google-1
バージョンが必要なバージョンよりも低い場合は、parameterized_views 拡張機能を更新してみてください。
parameterized_views の場合は、次のようにします。
ALTER EXTENSION parameterized_views UPDATE;
バージョンを再度確認します。
quickstart_db に接続している AlloyDB Studio で、次のコマンドを実行します。
SELECT extname, extversion FROM pg_extension WHERE extname IN ('vector', 'google_ml_integration', 'parameterized_views');
予想される出力:
extname | extversion -----------------------+---------------- google_ml_integration | 1.5.9 parameterized_views | 1.0 vector | 0.8.2.google-1
6. サンプルデータ
次に、データベースにオブジェクトを作成してデータを読み込む必要があります。架空の不動産会社のデータセットを使用します。不動産の販売とエージェントに関する架空のデータが含まれています。データは、クローンされたリポジトリの SQL スクリプト real_estate_data.sql で提供されています。
ストレージ バケットを作成する
Google SDK(gcloud)を使用して、クローンされたリポジトリから AlloyDB データベースにデータをインポートします。そのためには、Cloud Storage バケットを作成し、AlloyDB サービス アカウントにアクセス権を付与する必要があります。または、ドキュメントに記載されているように、ウェブ コンソールを使用して実行することもできます。
Google Cloud Shell ターミナルで、次のコマンドを実行します。
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
データの読み込み
データベースの SQL ダンプは、クローン作成されたリポジトリ フォルダにあります。次のコマンドは、AlloyDB クラスタの作成時に前の手順でリポジトリをクローンしたときに、ホーム ディレクトリを開始点として使用したことを前提としています。
データベース ダンプファイルを Cloud Storage バケットにコピーします。
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
データセットを 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
このコマンドは、サンプル データセットを quickstart_db データベースに読み込みます。
AlloyDB Studio を使用して real_estate.agents テーブルのレコード数をカウントし、インポートを確認します。
SELECT COUNT(*) FROM real_estate.agents;
7. スキーマ オントロジーを準備する
QueryData コンテキスト セットを設定し、スキーマ メタデータを提供して、ADK エージェントを実行します。
メタデータを作成する
メタデータは、データベースのテーブルと列に適用される SQL コメントで構成されます。これらのコメントは、データベース オブジェクトを選択する際に QueryData エンジンをガイドします。
提供された SQL ダンプを使用してデータスキーマをインポートした場合、すべてのメタデータはスキーマにすでに作成されています。
real_estate スキーマに適用されるメタデータのスニペットの例を次に示します。
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.'; ...
独自のデータセットを使用している場合は、スキーマのメタデータを追加する方法について、ドキュメントのガイドをご覧ください。
スキーマ オントロジー コンテキストを作成する
コンテキスト セットには、AI モデルがクエリを生成する際に役立つクエリ テンプレート、ファセット、値検索が含まれています。コンテキストが設定されていない場合、AI エージェントは、主にテーブル名、列、メタデータに基づいて public スキーマから利用可能な情報のみを使用してクエリを生成し、自然言語クエリ リクエストに回答するための適切なオブジェクトを推測しようとします。
QueryData コンテキスト セットは、クエリ テンプレート、ファセット、値検索を含む JSON ファイルです。さまざまな例については、ドキュメントをご覧ください。
Web コンソールで QueryData コンテキスト セットを読み込む
コンテキスト セットを読み込むには、AlloyDB Studio を開き、左側のパネルの下部にある Context sets と 3 つのドットをクリックします。

その他アイコンをクリックして Create context set を選択します。
開いたダイアログで、次の値を入力します。
- 名前:
sixrecipes - 説明:
Real Estate Query Data - コンテキスト ファイルをアップロードする: 空のままにする
Create ボタンを初めて押すと、コンテキスト ストレージの初期化に時間がかかることがあります。
コンテキスト セット名の右側にある 3 つのドットをもう一度クリックして Edit context set を選択し、QueryData コンテキスト セット ID を確認します。

コンテキスト セット ID は、右側の開いたタブの上部に表示されます。

後の手順で使用するため、この ID を保存します。
AI エージェントを開始する
QueryData バックエンドとやり取りしてクエリを生成して実行するには、ドキュメントで説明されているように、AlloyDB Studio インターフェースを使用します。ただし、このラボでは、データベースとの主な通信ツールとして AI エージェントを使用します。AI エージェントは、将来のワークロードのより現実的なシナリオです。Google ADK フレームワークは、モデル、API、アプリケーション間のすべてのステップとインタラクションを確認できる優れたウェブ インターフェースを提供します。
Cloud Shell でエージェント ソース構成を確認します。
REPO_NAME="codelabs"
SOURCE_DIR="alloydb-ai-nla"
cd ~/$REPO_NAME/$SOURCE_DIR/data_agent
edit 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",
]
また、QueryData API を操作するための手順 call_querydata_api と、QueryData API スキルを操作するためのツールセットもあります。
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]
)
プロンプトと利用可能なツールを含むルート エージェント自体を次に示します。
# 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],
)
data_agent/SKILL.md を確認して、エージェントのシステム指示を理解します。
REPO_NAME="codelabs"
SOURCE_DIR="alloydb-ai-nla"
cd ~/$REPO_NAME/$SOURCE_DIR/data_agent
edit SKILL.md
エージェントを開始する前に、エージェントと QueryData API リクエストのパラメータを含む .env ファイルを準備する必要があります。
コンテキスト セット ID を環境変数にエクスポートします。
export QUERYDATA_CONTEXTSET=<context set id from the Create Context Set chapter>
data_agent ディレクトリにランタイム環境構成ファイル(.env)を作成します。
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
依存関係をインストールして、エージェント ウェブサービスを開始します。
cd ~/$REPO_NAME/$SOURCE_DIR/
uv sync
エージェントを起動します。
uv run adk web --allow_origins 'regex:https://.*\.cloudshell\.dev'
エンドポイント 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)

Cloud Shell で生成されたウェブサーバーの URL(http://127.0.0.1:8000 など)をクリックして、エージェント インターフェースを起動します。機能しない場合は、Cloud Shell で [ウェブでプレビュー] -> [ポート 8000 でプレビュー] をクリックして、エージェント インターフェースを開きます。
左上のプルダウンで data_agent が選択されていることを確認します。

クエリを生成して実行する
クエリ Q1 を実行してみましょう。
エージェントのチャット インターフェースで次の自然言語プロンプトを実行して、カスタム テンプレートやファセットを使用せずに QueryData のベース パフォーマンスを評価します。
How many properties are currently for sale in San Diego?
矢印ボタンを押します。

適切なスキルを選択し、そのスキルと関数を使用して API エンドポイントにリクエストを送信し、生成されたクエリと結果を取得すると、エージェント ワークフローが開始されます。

手順にマウスカーソルを合わせると、その手順で何が行われたかを確認できます。また、ステップを選択すると、左側のパネルにそのステップの詳細などが表示されます。エージェントがスキルや API をどのように使用するかを理解するのに役立ちます。

フォローアップのクエリを送信します(Q2):
List agents who sold a property for over $1000000.
エージェントは、利用可能なスキルをすでにメモリに書き込んでいるため、検出フェーズを再度実行する必要がなく、QueryData API スキルに直接移動します。
生成された SQL は次のステートメントのようになります。
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;
別のクエリを試す(Q3):
What is the average price of a single-family home with a garage in San Diego?
QueryData は空のコンテキスト セットで標準クエリを生成しますが、ビジネス タスクでは特定のビジネス ロジックと決定論的動作が必要になることがよくあります。
8. 解釈を挿入して高い精度とビジネス関連性を実現する
解釈をプロンプトに挿入することで、生成されたクエリが特定のビジネス ロジックと一致するようになります。
ここでは、デルマーの平屋建ての家を探している顧客の例を試します。この質問には 2 つの重要な指標があり、選択の頻繁なパターンを表しています。
エージェントで次の自然言語プロンプト(Q4)を試してください。
Single level Del Mar houses
エンジンは一般的なクエリを返しますが、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;
結果として 1 行が返されます。
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.
別のプロンプトをテストします(Q5):
Del Mar houses close to good schools
proximity_miles 列と school_ranking 列を使用してプロパティを並べ替えることはできますが、各指標の重みと重要度は評価されません。
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;
クエリの例をテンプレートに一般化する
ビジネス ロジックには次のものが必要です。
- 2 マイル以内の近接
- 学校のランキングが 5 以下
- 重み付けされた順序: 学校のランキング 80% + 近さ 20%(スコア = 0.8 * school_ranking + 0.2 * proximity_miles)
加重ランキングの数式は次のとおりです。
Score = 0.8 * school_ranking + 0.2 * proximity_miles
Cloud Shell のコマンドライン インターフェースを使用して、Cloud Shell から sixrecipe_context1_1.json コンテキスト ファイルをダウンロードします。
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context1_1.json
または、Cloud Shell メニューの Download メニュー項目を使用します。

AlloyDB Studio を使用して sixrecipe_context1_1.json を sixrecipe コンテキスト セットにアップロードし、この標準構造を定義します。sixrecipes コンテキストの右にあるその他アイコンをクリックし、[コンテキスト セットを編集] を使用して新しいファイルをアップロードします。これにより、古い空のコンテキストが新しいコンテキストに置き換えられます。
このテンプレートでは、良い学校の近接性ルールに対して明示的な SQL テンプレート ルールを定義しています。
{
"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\""
}
}
]
}
プロンプトを再実行します。
Del Mar houses close to good schools
結果のクエリは、テンプレートで定義されたビジネス ロジックと一致するようになりました。
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"
生成された SQL ステートメントとともに、次のインテントが生成されます。
intentExplanation: "Houses in Del Mar close to good schools (within 2 miles of schools with a rank of at least 5)."
インテントは、ADK ウェブ インターフェースの左側のペインに表示されます。

結果には、スコアで並べ替えられた 2 つのプロパティが表示されます。
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
次の章では、テンプレートのスコープを拡大します。
複数の質問をキャプチャして解釈することで解釈を挿入する
テンプレートのスコープを拡大して、「良い学校の近くにある」だけでなく、マニフェストに他の条件を追加して、「子供のいる家庭向けの家」などにも使用できるようにすることができます。
更新されたコンテキスト ファイルをダウンロードします。
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context1_2.json
更新した sixrecipe_context1_2.json ファイルをコンテキスト セットにアップロードします。
新しいコンテキスト セット ファイルで、マニフェスト "manifest": "A given city houses close to good schools." をマニフェスト "manifest": "A given city houses close to good schools, or are great for families with kids." に置き換えます。このテンプレートのアプリケーションを拡張して、複数のケースで使用できるようにします。
次のクエリ(Q6)を送信します。
Houses in Waterloo great for families with kids.
エージェントは、更新されたテンプレート マニフェストを使用して、標準化されたクエリロジックを適用し、上記のクエリと同じクエリを返します。その目的は次のとおりです。
intentExplanation : "Houses in Waterloo close to good schools (within 2 miles of schools with a rank of at least 5)."
9. ファセット テンプレートを使用して、柔軟性を維持しながら高精度を実現する
ファセットは、テンプレートと動的に組み合わされるモジュラー SQL 条件です。これにより、すべての順列に対して個別のテンプレートを作成することなく、修飾子(「スターター ファミリー」、「オーシャン ビュー」など)を処理できます。
クエリや条件ごとにテンプレートを作成する代わりに、既存のテンプレートに適用してクエリにディメンションを追加できるフラグメントを準備できます。
次の属性を持つプロパティのファセットを定義します。
- 一戸建て住宅
- 有効なリスティングのステータス
- ベッドルーム 3 ~ 4 室、バスルーム 2 室以上
- 人口 10 万人あたりの犯罪率が 500 未満の市町村にある
ファセット コンテキスト ファイルをダウンロードします。
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context2_1.json
AlloyDB Studio の sixrecipes コンテキスト セットに sixrecipe_context2_1.json をアップロードして、ファセットを構成します。
"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)"
}
}
]
ファセット検索を使用したクエリ
次の NL クエリ(Q7)を実行します。
Del Mar houses close to good schools for a starter family.
エンジンは、ファセット条件をベースクエリに直接追加します。
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"
結果は次のとおりです。
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
ファセットを追加する
新しいパターン(プロパティのウィンドウ ビューなど)に基づいて、もう 1 つディメンションを追加したい場合はどうすればよいでしょうか?
ファセット定義内にオーシャン ビューのセマンティック マッチングを追加します。
{
"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)"
}
上記のファセット定義の 0.4 という値は、実験的に調整されたしきい値です。多面的なコンテキスト ファイルをダウンロードします。
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context2_2.json
sixrecipe_context2_2.json をコンテキスト セットにアップロードし、次のプロンプト(Q8)を実行します。
Ocean view Del Mar homes near good schools.
出力には、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";
クエリは 1 つのプロパティを返します。
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).
AlloyDB Studio でプロパティの説明を確認し、次のクエリを実行して、結果を確認します。
select description from real_estate.properties where address_postal_code='92014' and description is not null;
「壮大な海のスペクタクル」という説明が表示されます。
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. 値検索を使用してプライベート データの曖昧性除去を行う
曖昧なリクエストは、場所の名前とビジネス名を混同するなど、複数のエンティティと一致する可能性があります。値検索では、これらの参照を解決するために、用語をデータベースのコンセプトにマッピングします。
値検索では、列名と列の値の組み合わせと、コンセプト タイプ(都市、国、名前など)の関連付けが提供されます。また、メタデータだけでなく、列内のデータの代表的なサンプルもインデックスに登録されているため、自然言語リクエストで使用された値を潜在的なコンセプト タイプと、結果の SQL で使用できるテーブルと列に関連付けることができます。
クエリの曖昧さ
実際には、さまざまな名前や場所のスペルミスにより、さらに難しくなる可能性があります。入力ミスと曖昧な用語を含むこのプロンプト(Q9)を実行します。
Westwod's sold properties in the last 1 month.
ここでは、名前のスペルが間違っていることと、似たような名前の場所で販売されている物件について話しているのか、不動産会社について話しているのかが不明確であるという 2 つの問題があります。このクエリを実行すると、次のようなクエリが返されます。
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
名前が修正され、質問は物件の所在地に関するもので、Westwood 市の物件を照合しようとしていると想定されています。
AlloyDB Studio で pg_trgm 拡張機能を有効にして、ファジー文字列比較をサポートします。
CREATE EXTENSION IF NOT EXISTS pg_trgm;
その後、拡張機能を使用して、QueryData コンテキスト セットに値検索を追加できます。
使用する値検索のリストは次のとおりです。
"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"
}
]
値検索コンテキスト ファイルをダウンロードします。
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context3_1.json
sixrecipe_context3_1.json を QueryData の sixrecipes コンテキスト セットにアップロードして保存します。
プロンプトを再実行します(Q9):
Westwod's sold properties in the last 1 month.
値の検索で類似した値を持つ 3 つの異なるエンティティが見つかったため、明確化レスポンスが返されました。
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?
トレースは、その特定のパスが選択された理由の手がかりになります

全文は次のとおりです。
"[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?"
クエリの曖昧さを解消する
入力プロンプトを改良する(Q10):
Westwood city location properties sold in September 2025.
クエリと結果は次のようになります。
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. セマンティック検索と AI 関数
AlloyDB AI 関数を使用すると、非構造化データに対するセマンティック フィルタリングが可能になります。ai.if や google_ml.embedding などの関数を、標準のデータベース演算子とともに SQL クエリで直接使用します。
ILIKE 演算子を含むテンプレート
まず、ILIKE 演算子を含む新しいコンテキスト ファイルをアップロードします。
ILIKE テンプレート コンテキスト ファイルをダウンロードします。
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context4_1.json
context セットに sixrecipe_context4_1.json をアップロードして、「即入居可」の住宅の標準 ILIKE パターン マッチングを評価します。
{
"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%')"
}
}
次のクエリ(Q11)を送信します。
List move-in ready houses.
結果のクエリ:
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%')
一致するレコードが 1 つ返されます。
Query Results address_street address_postal_code 40 Main St, Unit 8 N2H 2G8
AI.IF 関数を含むテンプレート
AI.IF テンプレート コンテキスト ファイルをダウンロードします。
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context4_2.json
ai.if セマンティック フィルタリング関数を評価するために、sixrecipe_context4_2.json をコンテキスト セットにアップロードします。
{
"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\")"
}
}
プロンプトを繰り返します(Q12):
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")
結果に同じプロパティが表示されます。
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
ベクトル検索によるファセット
エンベディング検索コンテキスト ファイルをダウンロードします。
cloudshell download ~/codelabs/alloydb-ai-nla/sixrecipe_context4_3.json
sixrecipe_context4_3.json をコンテキスト セットにアップロードして、google_ml.embedding を使用したセマンティック ベクトル検索を評価し、新しいキッチン家電を備えた家を検索します。
AlloyDB ベクトル検索を使用して、追加のファセットを含む sixrecipe_context4_3.json ファイルを使用してコンテキスト セットを更新します。
{
"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)"
}
}
上記のファセット定義の 0.4 という値は、実験的に調整されたしきい値です。
次のクエリ(Q13)を実行します。
List move-in ready houses with upgraded kitchen appliances.
生成された 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))
クエリ結果と自然言語による推奨事項は次のとおりです。
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. セキュリティとプライバシー
QueryData API がクエリを生成する際は常に、生成されたクエリによって他のユーザーのデータが公開されるというプライバシー上のリスクが生じます。パラメータ化されたセキュアビュー(PSV)は、NL2SQL の生成時に行レベルのセキュリティ境界を適用します。
パラメータ化されたセキュアビューを作成する
不動産取引のすべてのオファーに関する情報を含む real_estate.offers というテーブルがあります。エージェントには、他のエージェントの商談ではなく、自分の商談のみを表示したいと考えています。agent_id に基づいて行をフィルタリングできる PSV を作成します。
AlloyDB Studio で offers テーブルのパラメータ化されたセキュアビューを作成します。
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;
パラメータ化されたセキュリティ ビューの定義を確認します。
SELECT definition
FROM parameterized_views.all_parameterized_views
WHERE schemaname = 'real_estate' AND viewname = 'secure_offers';
real_estate.offers テーブルはどうですか?
AlloyDB パラメータ化されたセキュアビューを使用して QueryData データアクセスを制限する
agent.py では、パラメータ化されたセキュリティ ビュー real_estate.secure_offers が real_estate.offers ではなく TABLE_IDS に登録されています。
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",
]
また、agent_id=1 のエージェントのセッション ランタイム コンテキストを渡します。
"parameterized_secure_view_parameters": {
"parameters": {
"key": "agent_id",
"value": "1"
}
}
},
その結果、すべての QueryData API リクエストでそのパラメータが渡され、リクエストにセキュアビューが含まれている場合は、フィルタリングが適用され、その特定のエージェントの結果のみが返されます。
次のクエリ(Q14)を実行します。
List the offer id and listing price in 2025 where the offer was within 5% of the final selling price.
生成された 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
ビューをクエリすると、アクティブなエージェント セッション パラメータで結果がフィルタされ、不正なレコードデータが保護され、2 つのレコードのみが返されます。
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
AlloyDB Studio の基本 real_estate.offers テーブルに対して次のクエリを実行すると、
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
2 つ以上のレコードが返され、すべてのエージェントのデータが表示されます。
これでラボは終了です。QueryData API、AI 関数、AlloyDB パラメータ化されたセキュアビューの使用方法について説明しました。
13. 環境をクリーンアップする
ラボの終了時に AlloyDB インスタンスとクラスタを破棄します。
AlloyDB クラスタとすべてのインスタンスを削除する
クラスタは force オプションで破棄され、クラスタに属するすべてのインスタンスも削除されます。
ターミナルが切断された場合は、再度接続して、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)
クラスタを削除します。
gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force
想定されるコンソール出力:
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 バックアップを削除する
クラスタの AlloyDB バックアップをすべて削除します。
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
想定されるコンソール出力:
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 バケットを削除する
Cloud Storage インポート バケットを削除して、ストレージ料金の継続的な発生を防ぎます。
gcloud storage rm -r gs://${PROJECT_ID}-import
14. 完了
以上で、この Codelab は完了です。
学習した内容
- AlloyDB クラスタとプライマリ インスタンスをデプロイする方法
- AlloyDB で QueryData、AI 関数、パラメータ化されたセキュアビューを有効にする方法
- QueryData コンテキスト セットの作成方法
- QueryData API でさまざまなテンプレートとコンテキストを使用する方法
- ファセットを使用して QueryData テンプレートの柔軟性を高める方法
- 値検索とトライグラム インデックスを使用してデータの曖昧さを解決する方法
- テンプレートでセマンティック検索に AI 関数を使用する方法
- QueryData API でパラメータ化されたセキュアビューを使用する方法
アンケート
出力: