この Codelab について
1. 概要
さまざまな業界において、コンテキスト検索はアプリケーションの中核をなす重要な機能です。検索拡張生成は、生成 AI を活用した検索メカニズムによって、この重要な技術革新の重要な推進力となってきました。生成モデルは、広範なコンテキスト ウィンドウと優れた出力品質を備え、AI を変革しています。RAG は、AI アプリケーションとエージェントにコンテキストを挿入するための体系的な方法を提供し、さまざまなメディアの構造化データや情報に基づいて AI アプリケーションとエージェントを構築します。このコンテキスト データは、真実の明確さと出力の精度にとって重要ですが、結果の精度はどの程度でしょうか。ビジネスは、こうしたコンテキスト マッチと関連性の精度に大きく依存していますか?このプロジェクトは、そんなあなたにぴったりです。
ベクトル検索の秘密は、ベクトルを構築するだけでなく、ベクトルの一致が実際に適切かどうかを把握することです。検索結果のリストに目を向け、「この機能は動作しているのか?」と疑問に思ったことがある人は多いはずです。ベクトル マッチの品質を実際に評価する方法について説明します。「RAG で何が変わったの?」と思われた方もいるかもしれません。なんでもよ!長年、検索拡張生成(RAG)は有望な目標ではあるものの、達成は困難と思われていました。これで、ミッション クリティカルなタスクに必要なパフォーマンスと信頼性を備えた RAG アプリケーションを構築するためのツールが完成しました。
ここまでで、次の 3 つの基本事項を理解しました。
- エージェントにとってのコンテキスト検索の意味と、ベクトル検索を使用してコンテキスト検索を実現する方法。
- また、データの範囲内(つまりデータベース内)でベクトル検索を実現する方法についても詳しく説明しました(ご存じない方のために、すべての Google Cloud データベースがこれをサポートしています)。
- Google は、ScaNN インデックスを活用した AlloyDB ベクトル検索機能により、軽量なベクトル検索 RAG 機能を高パフォーマンスかつ高品質で実現する方法について、他社よりも一歩進んだ方法を説明しました。
基本、中級、上級の RAG テストをまだ実施していない場合は、こちら、こちら、こちらの 3 つのテストを、記載されている順番で実施することをおすすめします。
特許検索は、検索テキストにコンテキスト的に関連する特許を見つける際にユーザーを支援する機能です。この機能はすでに過去に構築されています。次に、そのアプリケーションの品質管理されたコンテキスト検索を可能にする、新しい高度な RAG 機能を使用して、アプリケーションを構築します。それでは詳しく見ていきましょう。
以下の図は、このアプリで発生する処理の全体的な流れを示しています。~
目標
ユーザーがテキスト記述に基づいて特許を検索できるようにし、パフォーマンスと品質を向上させます。また、AlloyDB の最新の RAG 機能を使用して、生成された一致の品質を評価できるようにします。
作成するアプリの概要
このラボでは、次の作業を行います。
- AlloyDB インスタンスを作成して Patents Public Dataset を読み込む
- メタデータ インデックスと ScaNN インデックスを作成する
- ScaNN のインライン フィルタリング方法を使用して AlloyDB に高度なベクトル検索を実装する
- 想起評価機能を実装する
- クエリのレスポンスを評価する
要件
2. 始める前に
プロジェクトを作成する
- Google Cloud コンソールのプロジェクト選択ページで、Google Cloud プロジェクトを選択または作成します。
- Cloud プロジェクトに対して課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。
- Google Cloud 上で動作するコマンドライン環境の Cloud Shell を使用します。Google Cloud コンソールの上部にある [Cloud Shell をアクティブにする] をクリックします。
- Cloud Shell に接続したら、次のコマンドを使用して、認証が完了していることと、プロジェクトがプロジェクト ID に設定されていることを確認します。
gcloud auth list
- Cloud Shell で次のコマンドを実行して、gcloud コマンドがプロジェクトを認識していることを確認します。
gcloud config list project
- プロジェクトが設定されていない場合は、次のコマンドを使用して設定します。
gcloud config set project <YOUR_PROJECT_ID>
- 必要な API を有効にします。Cloud Shell ターミナルで gcloud コマンドを使用できます。
gcloud services enable alloydb.googleapis.com compute.googleapis.com cloudresourcemanager.googleapis.com servicenetworking.googleapis.com run.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com aiplatform.googleapis.com
gcloud コマンドの代わりに、コンソールで各プロダクトを検索するか、このリンクを使用します。
gcloud コマンドとその使用方法については、ドキュメントをご覧ください。
3. データベースの設定
このラボでは、特許データのデータベースとして AlloyDB を使用します。クラスタを使用して、データベースやログなどのすべてのリソースを保持します。各クラスタには、データへのアクセス ポイントを提供するプライマリ インスタンスがあります。テーブルには実際のデータが保持されます。
特許データセットを読み込む AlloyDB クラスタ、インスタンス、テーブルを作成しましょう。
クラスタとインスタンスを作成する
- Cloud コンソールの AlloyDB ページに移動します。Cloud コンソールのほとんどのページは、コンソールの検索バーを使用して簡単に見つけることができます。
- そのページで [クラスタを作成] を選択します。
- 次のような画面が表示されます。次の値を使用してクラスタとインスタンスを作成します(リポジトリからアプリケーション コードをクローンする場合は、値が一致していることを確認してください)。
- クラスタ ID: "
vector-cluster
" - password: "
alloydb
" - PostgreSQL 15 / 最新バージョンを推奨
- Region: "
us-central1
" - ネットワーキング: 「
default
」
- デフォルトのネットワークを選択すると、次のような画面が表示されます。
[接続の設定] を選択します。
- [自動的に割り振られた IP 範囲を使用する] を選択し、[続行] をクリックします。情報を確認したら、[CREATE CONNECTION] を選択します。
- ネットワークが設定されたら、クラスタの作成を続行できます。[CREATE CLUSTER] をクリックして、クラスタの設定を完了します。
インスタンス ID(クラスタまたはインスタンスの構成時に確認できます)を
vector-instance
。変更できない場合は、今後のすべての参照でインスタンス ID を使用してください。
クラスタの作成には 10 分ほどかかります。正常に完了すると、作成したクラスタの概要を示す画面が表示されます。
4. データの取り込み
次は、店舗に関するデータを含むテーブルを追加します。AlloyDB に移動し、プライマリ クラスタと AlloyDB Studio を選択します。
インスタンスの作成が完了するまで待つ必要があります。完了したら、クラスタの作成時に作成した認証情報を使用して AlloyDB にログインします。PostgreSQL の認証には、次のデータを使用します。
- ユーザー名: 「
postgres
」 - データベース: 「
postgres
」 - パスワード: 「
alloydb
」
AlloyDB Studio で認証が正常に完了すると、エディタに SQL コマンドが入力されます。最後のウィンドウの右側にあるプラス記号を使用して、複数のエディタ ウィンドウを追加できます。
必要に応じて、実行、フォーマット、クリアのオプションを使用して、エディタ ウィンドウに AlloyDB のコマンドを入力します。
拡張機能を有効にする
このアプリの作成では、拡張機能 pgvector
と google_ml_integration
を使用します。pgvector 拡張機能を使用すると、ベクトル エンベディングを保存して検索できます。google_ml_integration 拡張機能は、Vertex AI 予測エンドポイントにアクセスして SQL で予測を取得するために使用する関数を提供します。次の DDL を実行して、これらの拡張機能を有効にします。
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
データベースで有効になっている拡張機能を確認するには、次の SQL コマンドを実行します。
select extname, extversion from pg_extension;
テーブルを作成する
AlloyDB Studio で次の DDL ステートメントを使用してテーブルを作成できます。
CREATE TABLE patents_data ( id VARCHAR(25), type VARCHAR(25), number VARCHAR(20), country VARCHAR(2), date VARCHAR(20), abstract VARCHAR(300000), title VARCHAR(100000), kind VARCHAR(5), num_claims BIGINT, filename VARCHAR(100), withdrawn BIGINT, abstract_embeddings vector(768)) ;
abstract_embeddings 列には、テキストのベクトル値を保存できます。
権限を付与
次のステートメントを実行して、「embedding」関数に対する実行権限を付与します。
GRANT EXECUTE ON FUNCTION embedding TO postgres;
AlloyDB サービス アカウントに Vertex AI ユーザーロールを付与する
Google Cloud IAM コンソールで、AlloyDB サービス アカウント(service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com の形式)に「Vertex AI ユーザー」ロールへのアクセス権を付与します。PROJECT_NUMBER にはプロジェクト番号を指定します。
または、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"
特許データをデータベースに読み込む
データセットとして、BigQuery の Google Patents Public Datasets を使用します。AlloyDB Studio を使用してクエリを実行します。データは、この insert_scripts.sql
ファイルにソースされます。このファイルを実行して、特許データを読み込みます。
- Google Cloud コンソールで、AlloyDB ページを開きます。
- 新しく作成したクラスタを選択し、インスタンスをクリックします。
- AlloyDB ナビゲーション メニューで [AlloyDB Studio] をクリックします。自分の認証情報でログインします。
- 右側の [新しいタブ] アイコンをクリックして、新しいタブを開きます。
- 上記の
insert_scripts.sql
スクリプトからinsert
クエリ ステートメントをエディタにコピーします。このユースケースのクイックデモでは、10 ~ 50 個の挿入ステートメントをコピーします。 - [実行] をクリックします。クエリの結果が [結果] テーブルに表示されます。
注: 挿入スクリプトには大量のデータが含まれています。これは、挿入スクリプトにエンベディングが含まれているためです。GitHub でファイルを読み込めない場合は、[生データを表示] をクリックします。これは、Google Cloud のトライアル クレジット請求先アカウントを使用している場合に、数個以上のエンベディング(最大 20 ~ 25 個)を生成する必要がないようにするためです。
5. 特許データのエンベディングを作成する
まず、次のサンプルクエリを実行して、エンベディング関数をテストします。
SELECT embedding('text-embedding-005', 'AlloyDB is a managed, cloud-hosted SQL database service.');
これにより、クエリのサンプルテキストのエンベディング ベクトルが返されます。これは浮動小数点数の配列のように見えます。次のように表示されます。
abstract_embeddings ベクトル フィールドを更新する
挿入スクリプトの一部として abstract_embeddings データを挿入していない場合にのみ、次の DML を実行して、テーブル内の特許要約を対応するエンベディングで更新します。
UPDATE patents_data set abstract_embeddings = embedding( 'text-embedding-005', abstract);
Google Cloud のトライアル クレジット請求先アカウントを使用している場合、数個を超えるエンベディング(最大 20 ~ 25 個)を生成できないことがあります。そのため、エンベディングは挿入スクリプトにすでに含まれています。また、「特許データをデータベースに読み込む」手順を完了していれば、テーブルに読み込まれているはずです。
6. AlloyDB の新機能を使用して高度な RAG を実行する
テーブル、データ、エンベディングがすべて準備できたので、ユーザーの検索テキストに対してリアルタイム ベクトル検索を実行します。これをテストするには、次のクエリを実行します。
SELECT id || ' - ' || title as title FROM patents_data ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
このクエリでは、
- ユーザーが検索したテキストは「Sentiment Analysis」です。
- モデル text-embedding-005 を使用して、embedding() メソッドでエンベディングに変換しています。
- "<=>" は、COSINE SIMILARITY 距離メソッドの使用を表します。
- エンベディング方法の結果をベクトル型に変換し、データベースに保存されているベクトルと互換性を持たせています。
- LIMIT 10 は、検索テキストに最も近い 10 件の一致を選択することを表します。
AlloyDB は、ベクトル検索 RAG を次のレベルに引き上げます。
新機能は多数あります。デベロッパー向けの機能には次の 2 つがあります。
- インライン フィルタリング
- 再現率評価ツール
インライン フィルタリング
以前は、デベロッパーはベクトル検索クエリを実行し、フィルタリングと再現率を処理する必要がありました。AlloyDB クエリ オプティマイザーは、フィルタ付きクエリの実行方法を最適化します。インライン フィルタリングは新しいクエリ最適化手法であり、これにより AlloyDB クエリ オプティマイザーは、ベクトル インデックスとメタデータ列のインデックスの両方を活用して、メタデータのフィルタ条件とベクトル検索の両方を同時に評価できます。これにより、リコール パフォーマンスが向上し、デベロッパーは AlloyDB の機能をすぐに利用できるようになります。
インライン フィルタリングは、選択性が中程度の場合に最適です。AlloyDB はベクトル インデックスを検索する際に、メタデータのフィルタ条件(通常は WHERE 句で処理されるクエリの関数フィルタ)に一致するベクトルの距離のみを計算します。これにより、ポストフィルタやプレフィルタの利点を補完し、クエリのパフォーマンスを大幅に向上させます。
- pgvector 拡張機能をインストールまたは更新する
CREATE EXTENSION IF NOT EXISTS vector WITH VERSION '0.8.0.google-3';
pgvector 拡張機能がすでにインストールされている場合は、ベクトル拡張機能をバージョン 0.8.0.google-3 以降にアップグレードして、再現率評価ツールを利用できるようにします。
ALTER EXTENSION vector UPDATE TO '0.8.0.google-3';
この手順は、ベクトル拡張機能が <0.8.0.google-3> の場合にのみ実行する必要があります。
重要な注意事項: 行数が 100 未満の場合は、ScaNN インデックスは適用されないため、最初から作成する必要はありません。その場合は、次の手順をスキップしてください。
- ScaNN インデックスを作成するには、alloydb_scann 拡張機能をインストールします。
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- まず、インデックスを使用せず、インライン フィルタを有効にせずにベクトル検索クエリを実行します。
SELECT id || ' - ' || title as title FROM patents_data
WHERE num_claims >= 15
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
結果は次のようになります。
- Explain Analyze を実行します(インデックスとインライン フィルタなし)。
実行時間は 2.4 ms
- num_claims フィールドに通常のインデックスを作成して、このフィールドでフィルタできるようにしましょう。
CREATE INDEX idx_patents_data_num_claims ON patents_data (num_claims);
- 特許検索アプリの ScaNN インデックスを作成しましょう。AlloyDB Studio から次のコマンドを実行します。
CREATE INDEX patent_index ON patents_data
USING scann (abstract_embeddings cosine)
WITH (num_leaves=32);
重要な注意事項: (num_leaves=32)
は、1,000 行を超える合計データセットに適用されます。行数が 100 未満の場合は、インデックスは適用されないため、インデックスを作成する必要はありません。
- ScaNN インデックスでインライン フィルタリングを有効にします。
SET scann.enable_inline_filtering = on
- 次に、フィルタとベクトル検索を含む同じクエリを実行します。
SELECT id || ' - ' || title as title FROM patents_data
WHERE num_claims >= 15
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
ご覧のとおり、同じベクトル検索で実行時間が大幅に短縮されています。ベクトル検索にインライン フィルタリングを組み込んだ ScaNN インデックスによって、これが可能になりました。
次に、この ScaNN 対応ベクトル検索の再現率を評価しましょう。
再現率評価ツール
類似検索における再現率は、検索から取得された関連インスタンスの割合(真陽性のインスタンスの数)です。これは、検索品質の測定に使用される最も一般的な指標です。再現率低下の一因は、近似最近傍検索(aNN)と K 最近傍検索(kNN)の違いにあります。AlloyDB の ScaNN のようなベクトル インデックスは aNN アルゴリズムを実装しており、再現率のわずかなトレードオフと引き換えに、大規模データセットでのベクトル検索を高速化できます。AlloyDB では、個々のクエリのトレードオフをデータベース内で直接測定し、経時的な安定性を確認できるようになりました。この情報に応じてクエリやインデックスのパラメータを更新すれば、より良い検索結果とパフォーマンスを実現できます。
検索結果のリコールのロジックは何ですか?
ベクトル検索のコンテキストにおける「再現率」とは、インデックスから返されたベクトルのうち、真の最近傍であるものの割合を指します。たとえば、20 個の最近傍に対する最近傍のクエリで、グラウンド トゥルースの最近傍が 19 個返された場合、再現率は 19÷20×100 = 95% となります。再現率は検索品質に使用される指標で、クエリベクトルに客観的に最も近い結果が返された割合として定義されます。
特定の構成のベクトル インデックスに対するベクトルクエリの再現率は、evaluate_query_recall 関数で確認できます。この関数を使用すると、目的のベクトルクエリの再現率を達成するようにパラメータをチューニングできます。
注意事項:
次の手順で HNSW インデックスで権限拒否エラーが発生した場合は、この再現率評価セクション全体をスキップしてください。この Codelab のドキュメント作成時点でリリースされたばかりであるため、この時点ではアクセス制限が関係している可能性があります。
- ScaNN インデックスと HNSW インデックスで、インデックス スキャンの有効化フラグを設定します。
SET scann.enable_indexscan = on
SET hnsw.enable_index_scan = on
- AlloyDB Studio で次のクエリを実行します。
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <=> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 25 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
evaluate_query_recall 関数は、クエリをパラメータとして受け取り、その再現率を返します。関数の入力クエリとして、パフォーマンスの確認に使用したクエリを使用しています。インデックス メソッドとして SCaNN を追加しました。その他のパラメータ オプションについては、ドキュメントをご覧ください。
これまで使用してきたこのベクトル検索クエリの再現率は次のとおりです。
リコール率は 70% ですね。この情報を使用して、インデックス パラメータ、メソッド、クエリ パラメータを変更し、このベクトル検索のレコード数を増やすことができます。
7. 変更したクエリとインデックス パラメータでテストする
次に、受信したリコールに基づいてクエリ パラメータを変更して、クエリをテストします。
- 結果セット内の行数を 7 に変更しました(以前は 25 でした)。これにより、RECALL が 86% に改善されました。
つまり、ユーザーに表示する一致数をリアルタイムで変更し、ユーザーの検索コンテキストに応じて一致の関連性を高めることができます。
- インデックス パラメータを変更して、もう一度試してみましょう。
このテストでは、類似度距離関数として 「Cosine」 ではなく 「L2 Distance」 を使用します。また、検索結果セットの数が増えていても検索結果の品質が向上するかどうかを確認するため、クエリの上限を 10 に変更します。
[前] コサイン類似性距離関数を使用するクエリ:
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <=> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 10 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
非常に重要な注意事項: 「このクエリが COSINE 類似性を使用していることは、どうやってわかるのですか?」という質問が寄せられることがあります。距離関数は、<=> を使用してコサイン距離を表すことで識別できます。
ベクトル検索距離関数のドキュメントへのリンク。
上記のクエリの結果は次のとおりです。
ご覧のとおり、インデックス ロジックを変更しなくても、RECALL は 70% です。インライン フィルタリングのセクションのステップ 6 で作成した ScaNN インデックス「patent_index
」を覚えていますか?上記のクエリの実行中も、同じインデックスが有効です。
次に、別の距離関数クエリ(L2 距離: <->)を使用してインデックスを作成します。
drop index patent_index;
CREATE INDEX patent_index_L2 ON patents_data
USING scann (abstract_embeddings L2)
WITH (num_leaves=32);
drop index ステートメントは、テーブルに不要なインデックスがないことを確認するためのものです。
これで、次のクエリを実行して、ベクトル検索機能の距離関数を変更した後の RECALL を評価できます。
[AFTER] コサイン類似性距離関数を使用するクエリ:
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <-> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 10 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
上記のクエリの結果は次のとおりです。
90% という驚異的な再現率
インデックスでは、目的の再現率とアプリケーションで使用するデータセットに基づいて、num_leaves など、他のパラメータも変更できます。
8. クリーンアップ
この投稿で使用したリソースについて、Google Cloud アカウントに課金されないようにするには、次の操作を行います。
- Google Cloud コンソールで、[リソース マネージャー] ページに移動します。
- プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
- ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。
- または、このプロジェクト用に作成した AlloyDB クラスタを削除することもできます(構成時にクラスタに us-central1 を選択しなかった場合は、このハイパーリンクのロケーションを変更してください)。[クラスタを削除] ボタンをクリックします。
9. 完了
これで、これで、AlloyDB の高度なベクトル検索を使用して、高パフォーマンスで真に意味に基づくコンテキスト ベースの Patent Search クエリを作成できました。ここで説明した ADK と AlloyDB のすべての機能を使用して、品質管理されたマルチツール エージェント アプリケーションを作成しました。高性能で高品質の特許ベクトル検索と分析エージェントが作成されます。こちらをご覧ください。https://youtu.be/Y9fvVY0yZTY
このエージェントの構築方法については、こちらの codelab をご覧ください。