自然言語を使用してデータベースにクエリを実行する

このページでは、AlloyDB Omni で利用可能なプレビューについて説明します。このプレビューでは、自然言語を使用してデータベースのクエリを試すことができます。

概要

AlloyDB Omni を使用すると、一連の試験運用版機能をプレビューできます。これにより、データベース ドリブンのアプリケーションで、アプリケーションのユーザーからの自然言語クエリ(「荷物はどこですか?」や「各部門のトップ収益者は誰ですか?」など)をより安全に実行できます。AlloyDB Omni は、自然言語入力をデータベース固有の SQL クエリに変換し、結果をアプリケーションのユーザーが表示できるものに限定します。

自然言語クエリの利点とリスク

Gemini Pro などの大規模言語モデルを使用すると、アプリケーションのエンドユーザーが作成した自然言語クエリに基づいて、アプリケーションでデータベース クエリを実行できます。たとえば、アプリケーションのデータベース スキーマにアクセスできるモデルは、次のようにエンドユーザーの入力を受け取ることができます。

What are the cheapest direct flights from Boston to Denver in July?

次のような SQL クエリに変換します。

SELECT flight.id, flight.price, carrier.name, [...]
FROM [...]
WHERE [...]
ORDER BY flight.price ASC 
LIMIT 10

自然言語クエリは、ユーザーにサービスを提供する強力なツールとしてアプリケーションに提供できます。ただし、このテクノロジーは明確なセキュリティ リスクも伴います。エンドユーザーがデータベース テーブルに対して任意のクエリを実行できるようにする前に、考慮すべき点があります。アクセス制限のある読み取り専用のデータベース ユーザーとしてデータベースに接続するようにアプリを構成している場合でも、自然言語クエリを許可するアプリは、次のような攻撃に対して脆弱になる可能性があります。

  • 悪意のあるユーザーは、プロンプト挿入攻撃を送信して、基盤となるモデルを操作し、アプリがアクセスできるすべてのデータを公開しようとする可能性があります。
  • モデル自体が、適切な範囲よりも広範な SQL クエリを生成し、善意のユーザー クエリに応答して機密データを漏洩する可能性があります。

パラメータ化された安全なビューでクエリをサニタイズする

前のセクションで説明したリスクを軽減するために、Google はパラメータ化されたセキュア ビューを開発しました。この試験運用版機能は、このページで説明する手法を使用してプレビューできます。

パラメータ化されたセキュアビューを使用すると、自然言語クエリがデータを取得できるテーブルと列を明示的に定義し、個々のアプリケーション ユーザーが使用できる行の範囲に追加の制限を追加できます。これらの制限により、ユーザーがどのようなフレーズでクエリを実行しても、アプリケーションのユーザーが自然言語クエリで表示できるデータを厳密に制御できます。

このプレビューを有効にすると、Google が開発した alloydb_ai_nlparameterized_views という試験運用版の拡張機能にアクセスできます。

parameterized_views 拡張機能には、次の機能があります。

  • パラメータ化されたセキュアビュー。クエリがアクセスできるデータ範囲を制限するための SQL ビューのバリエーションです。
  • execute_parameterized_views() 関数。パラメータ化された安全なビューをクエリできます。

alloydb_ai_nl 拡張機能には次の機能があります。

  • google_get_sql_current_schema() 関数。自然言語クエリを現在のスキーマ内のテーブルとビューの SQL クエリに変換します。

以降のセクションでは、これらの機能の使用方法と、それらの連携方法について説明します。

始める前に

AI モデルの統合を含む AlloyDB Omni バージョン 15.5.1 以降をインストールします。詳細については、AlloyDB for PostgreSQL AI を使用して AlloyDB Omni をインストールするをご覧ください。

パラメータ化された安全なビュー用にデータベースを設定する

  1. psql を使用して AlloyDB Omni クラスタに接続します。

  2. shared_preload_libraries ディレクティブの値に alloydb_ai_nlparameterized_views が含まれるように、/var/alloydb/config/postgresql.conf の内容を編集します。編集したディレクティブは次のようになります。

    shared_preload_libraries='g_stats,google_job_scheduler,google_insights,pg_stat_statements,google_db_advisor,google_columnar_engine,alloydb_ai_nl,parameterized_views'
    
  3. AlloyDB Omni を停止します。

  4. AlloyDB Omni を起動します

  5. alloydb_ai_nl 拡張機能と parameterized_views 拡張機能を有効にします。

    CREATE EXTENSION google_ml_integration;
    ALTER SYSTEM SET google_ml_integration.enable_model_support=on;
    ALTER SYSTEM SET alloydb_ai_nl.enabled=on;
    ALTER SYSTEM SET parameterized_views.enabled=on;
    SELECT pg_reload_conf();
    CREATE EXTENSION alloydb_ai_nl CASCADE;
    CREATE EXTENSION parameterized_views;
    
  6. Model エンドポイント管理を使用して、Gemini Pro API に基づいて新しい言語モデルを登録します。

    CALL google_ml.create_model(
        model_id => 'MODEL_ID',
        model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/us-central1/publishers/google/models/gemini-pro:streamGenerateContent',
        model_provider => 'google',
        model_auth_type => 'alloydb_service_agent_iam');
    

    次のように置き換えます。

  7. 新しいデータベース ユーザーを作成します。まだ権限やロールを付与しないでください。この手順の後のステップで、ユーザーに必要な権限が付与されます。

パラメータ化された安全なビュー

パラメータ化されたセキュア ビューは、通常の PostgreSQL セキュア ビュー(基本的には保存された SELECT ステートメント)とよく似ています。パラメータ化された安全なビューでは、通常のデータベース クエリのバインディング変数と同様に、クエリ時にビューに渡される 1 つ以上の名前付きパラメータ値を指定することもできます。

たとえば、顧客への商品の配送状況を追跡するデータベースを持つアプリケーションを実行しているとします。ユーザーがクエリ Where is my package?12345 タイプの ID を使用してこのアプリケーションにログインしました。パラメータ化された安全なビューを使用すると、AlloyDB for PostgreSQL がこのクエリを実行する方法に次の要件が適用されるようにできます。

  • このクエリでは、データベースのパラメータ化された安全なビューに明示的にリストされているデータベース列のみを読み取ることができます。この場合、itemsusersshipments テーブルの特定の列が該当します。
  • このクエリは、クエリを実行したユーザーに関連付けられているデータベース行のみを読み取ることができます。この場合、返される行が、id 列の値が 12345 である users テーブルの行とデータ関係を持つ必要があります。

パラメータ化された安全なビューを作成する

パラメータ化された安全なビューを作成するには、次の属性を使用して PostgreSQL CREATE VIEW DDL コマンドを使用します。

  • security_barrier オプションを使用してビューを作成します。
  • アプリケーション ユーザーが表示できる行のみを表示するように制限するには、WHERE 句で $@PARAMETER_NAME 構文を使用して必要なパラメータを追加します。一般的なケースは、WHERE COLUMN = $@PARAMETER_NAME を使用して列の値を確認することです。

次の例のパラメータ化された安全なビューでは、users という名前のテーブルの 3 つの列にアクセスできます。また、users.id が必須パラメータと一致する行にのみ結果を制限します。

CREATE VIEW user_psv WITH (security_barrier) AS 
SELECT 
  username,
  full_name,
  birthday
FROM 
  users
WHERE 
  users.id = $@user_id; 

パラメータ化された安全なビューの中核となる SELECT ステートメントは、通常の PostgreSQL ビューで許可されるステートメントと同じくらい複雑にできます。

ビューを作成したら、先ほど作成したユーザーに、ビューに対して SELECT クエリを実行する権限を付与する必要があります。

GRANT SELECT ON VIEW_NAME TO NL_DB_USER;

次のように置き換えます。

  • VIEW_NAME: 前の手順で作成したビューの名前。
  • NL_DB_USER: 自然言語クエリの実行に指定したデータベース ユーザーの名前。

パラメータ化された安全なビューに対してクエリを実行する

通常の PostgreSQL ビューと類似していますが、パラメータ化された安全なビューを直接クエリすることはできません。代わりに、parameterized_views 拡張機能で提供される execute_parameterized_query() 関数を使用します。この関数の構文は次のとおりです。

SELECT * FROM
parameterized_views.execute_parameterized_query(
    query => SQL_QUERY
    param_names => ARRAY [PARAMETER_NAMES],
    param_values => ARRAY [PARAMETER_VALUES]
)

次のように置き換えます。

  • SQL_QUERY: FROM 句が 1 つ以上のパラメータ化された安全なビューを参照する SQL クエリ。
  • PARAMETER_NAMES: 渡すパラメータ名のリスト(文字列)。
  • PARAMETER_VALUES: 渡すパラメータ値のリスト。このリストは param_names リストと同じサイズにする必要があります。値の順序は名前の順序と一致します。

この関数は、JSON オブジェクトのテーブルを返します。テーブルの各行は、元のクエリ結果の行の row_to_json() 値と同等です。

通常の使用では、query 引数の値は独自のコードではなく、AlloyDB for PostgreSQL データベースと統合した AI モデルによって生成されます。

次の例は、Python でパラメータ化されたセキュア ビューをクエリして結果を表示する方法を示しています。これは、前のセクションの user_psv の例のビューを基にしています。

# Assume a get_user_id() function that returns the ID of the current
# application user.
app_user_id = get_user_id()

pool = await asyncpg.create_pool(
    host=INSTANCE_IP
    user=NL_DB_USER
    password=NL_DB_PASSWORD
    database=DB_NAME
)

table_name = "user_psv"

query = f"""
    SELECT 
      full_name,
      birthday
    FROM 
      {table_name} 
"""
params = {
    "user_id": app_user_id
}

param_query = f"""
SELECT * FROM parameterized_views.execute_parameterized_query(
  query => '{query}',
  param_names => $1,
  param_values => $2
);
"""

sql_results = await pool.execute(
    param_query, 
    params.keys(), 
    params.values()
)

for row in sql_results:
    print(json.loads(row))

自然言語クエリを実行する

パラメータ化された安全なビューを使用して自然言語クエリを実行するプロセスは 2 段階です。

  1. 適切なパラメータ化された安全なビューへの SELECT アクセス権のみを持つデータベース ユーザーとして、大規模言語モデルを使用して自然言語クエリを SQL に変換します。
  2. execute_parameterized_query() 関数を使用して SQL を処理し、現在のユーザー セッションに適したパラメータ値にバインドします。

以降のセクションでは、これらのステップについて詳しく説明します。

自然言語から SQL に変換する

自然言語入力を SQL に変換するには、パラメータ化された安全なビュー テクノロジー プレビューに含まれている google_get_sql_current_schema() 関数を使用します。

SELECT alloydb_ai_nl.google_get_sql_current_schema(
  sql_text => 'NL_TEXT',
  model_id => 'MODEL_ID',
  prompt_text => 'HINT_TEXT'
);

次のように置き換えます。

  • NL_TEXT: SQL クエリに変換する自然言語テキスト。
  • MODEL_ID: パラメータ化された安全なビュー用にデータベースを設定するときにモデル カタログに登録したモデルの ID。
  • HINT_TEXT: データベース スキーマに関する追加情報(自然言語で表現)。これにより、テーブル、列、関係の構造を分析するだけでは抽出できない、スキーマの重要な側面についてモデルに追加のヒントを提供できます。例: When joining flights and seats, be sure to join on flights.id = seats.flight_id.

この関数の出力は、SQL クエリを含む文字列です。

パラメータを使用して変換された SQL を実行する

自然言語クエリを SQL に変換したら、このページで説明したように execute_parameterized_views() を呼び出し、パラメータ化された安全なビューに必要なパラメータを渡します。

この関数は、特定のクエリで必要なパラメータよりも多くのパラメータを渡すと機能するため、アプリケーションに値が設定されているパラメータ化されたすべてのセキュア ビューで使用されるすべてのパラメータを使用して呼び出すことができます。未定義のパラメータが必要なクエリを実行しようとすると、関数は例外をスローします。

自然言語クエリの実行例

このセクションでは、自然言語入力から SQL 結果セットまでの完全なフローを示します。コードサンプルは、アプリケーションが実行する基盤となる SQL クエリと関数を示しています。

このサンプル フローでは、アプリケーションについて次のことを前提としています。

  • データベース ドリブンのアプリケーションで、顧客への商品の発送を追跡します。
  • Model Catalog に my-gemini-model という名前の Gemini Pro ベースのモデルを登録しました。
  • データベースに shipment_view という名前のパラメータ化された安全なビューを定義しています。
    • このビューは、お客様への配送に関連する複数のテーブルからデータを選択します。
    • このビューには user_id パラメータが必要です。このパラメータの値は、アプリケーションのエンドユーザーの ID です。
  1. アプリケーション ユーザー ID が 12345 のエンドユーザーが、ウェブ アプリケーションに「パッケージはどこですか?」と入力します。
  2. アプリケーションは google_get_sql_current_schema() を呼び出して入力を SQL に変換します。

    SELECT alloydb_ai_nl.google_get_sql_current_schema(
      sql_text => 'Where is my package?'
      model_id => 'my-gemini-model'
    );
    

    この呼び出しは、単一の SQL SELECT クエリを含む文字列を返します。クエリは、パラメータ化されたセキュアビューを操作するために作成したデータベース ユーザーに表示されるパラメータ化されたセキュアビューに限定されます。

    Where is my package? から生成された SQL は次のようになります。

    SELECT current_location, ship_date, ship_eta FROM shipment_view;
    

    shipment_view はパラメータ化された安全なビューであり、通常の PostgreSQL ビューではないため、次のステップで説明するように、アプリケーションは execute_parameterized_views() を使用して、必要な user_id パラメータでクエリを安全に実行する必要があります。

  3. アプリは、出力を制約するパラメータとともに SQL を execute_parameterized_views() に渡します。この例では、入力を提供したアプリケーション エンドユーザーの ID です。

    SELECT * FROM
    parameterized_views.execute_parameterized_views(
        query => 'SELECT current_location, ship_date, ship_eta FROM shipment_view',
        param_names => ['user_id'],
        param_values => ['12345']
    );
    
    

    出力は、JSON データとして表現された SQL 結果セットです。

  4. アプリケーションは必要に応じて JSON データを処理します。

自然言語処理用のデータベース設計

このテクノロジー プレビューで提供される google_get_sql_current_schema() 関数は、主にパラメータ化された安全なビューの機能を示すために使用され、この開発中のテクノロジーを早期にテストできます。他のプレビュー版と同様に、この関数は本番環境のアプリケーションには適用しないでください。

これを念頭に置いて、このセクションのアドバイスを適用すると、google_get_sql_current_schema() のテスト中に google_get_sql_current_schema() の出力の品質を向上させることができます。

人間が理解できるようにスキーマを設計する

一般に、データベース構造には、一般的な人間のデベロッパーがテーブル、列、リレーションシップの目的を推測できるほど明確な名前とコメントを付けます。このように明確にすることで、大規模言語モデルがスキーマに基づいてより正確な SQL クエリを生成できるようになります。

わかりやすい名前を使用する

テーブル、列、リレーションシップにはわかりやすい名前を付けます。略語や頭字語は使用しないでください。たとえば、モデルは u という名前のテーブルよりも users という名前のテーブルで適切に動作します。

既存のデータ構造の名前を変更できない場合は、google_get_sql_current_schema() を呼び出すときに prompt_text 引数を使用してモデルにヒントを提供します。

特定のデータ型を使用する

列により具体的なデータ型を使用すると、モデルはデータに関するより正確な推論を行うことができます。たとえば、列を真偽値の格納専用に使用する場合は、10integer ではなく、truefalseboolean データ型を使用します。

プレビューを有効にした後に慎重にロールバックする

データベースでパラメータ化されたセキュアビューのテクノロジー プレビューを有効にした後、AlloyDB Omni を 15.5.0 より前のバージョンにロールバックする場合は、ダウングレードする前にいくつかの手動クリーンアップ手順を行う必要があります。

これらの手順を実行しないと、パラメータ化された安全なビューのクエリ、変更、削除を試みると SQL エラーが発生します。これには、結果にパラメータ化された安全なビュー(SELECT * FROM pg_views など)が含まれる可能性があるデータベースのビューカタログに対するクエリが含まれます。

AlloyDB Omni のロールバック前に、このテクノロジー プレビューをデータベースから完全に削除する手順は次のとおりです。

  1. psql で、DROP VIEW コマンドを使用して、データベース内のすべてのパラメータ化された安全なビューを削除します。

  2. psqlDROP EXTENSION コマンドを使用して、データベースで alloydb_ai_nl 拡張機能と parameterized_views 拡張機能を無効にします。

  3. postgresql.conf ファイルで、shared_preload_libraries ディレクティブから alloydb_ai_nlparameterized_views への参照を削除します。

AlloyDB Omni のインストールのロールバックの詳細については、アップグレードをロールバックするをご覧ください。