このチュートリアルでは、検索拡張生成(RAG)に基づく大規模言語モデル(LLM)アプリケーションと、Cloud Storage バケットにアップロードされた PDF ファイルを統合する方法について説明します。
このガイドでは、アップロードされたドキュメントの表現(エンベディング)を保持するストレージとセマンティック検索エンジンとしてデータベースを使用します。Langchain フレームワークを使用してエンベディングを操作し、Vertex AI で利用可能な Gemini モデルを使用します。
Langchain は、多くの ML タスクを簡素化し、さまざまなベクトル データベースや AI サービスと統合するためのインターフェースを備えた、よく利用されているオープンソースの Python フレームワークです。
このチュートリアルは、GKE と Cloud Storage に RAG LLM アプリケーションをデプロイすることに関心があるクラウド プラットフォームの管理者とアーキテクト、ML エンジニア、MLOps(DevOps)の専門家を対象としています。
目標
このチュートリアルでは、以下の方法について学習します。
- ドキュメント エンベディングを作成してベクトル データベースに保存するアプリケーションのビルドとデプロイを行う。
- アプリケーションを自動化し、Cloud Storage バケットへの新規ドキュメントのアップロードをトリガーする。
- セマンティック検索を利用してドキュメントのコンテンツに基づいて質問に答える chatbot アプリケーションをデプロイする。
Deployment のアーキテクチャ
このチュートリアルでは、Cloud Storage バケット、Eventarc トリガー、次の Service を作成します。
embed-docs
: ユーザーが Cloud Storage バケットに新しいドキュメントをアップロードするたびに、Eventarc はこの Service をトリガーします。この Service は Kubernetes Job を開始して、アップロードされたドキュメントのエンベディングを作成し、ベクトル データベースに格納します。chatbot
: この Service は、セマンティック検索と Gemini API を使用して、アップロードされたドキュメントに関する自然言語の質問に回答します。
次の図は、ドキュメントのアップロードとベクトル化のプロセスを示しています。
この図では、ユーザーが Cloud Storage バケットにファイルをアップロードしています。Eventarc は、バケットのオブジェクト metadataUpdated
イベントをサブスクライブしています。ユーザーが新しいドキュメントをアップロードすると、Eventarc は Eventarc のイベント フォワーダー(Kubernetes ワークロード)を使用して embed-docs
Service を呼び出します。Service が、アップロードされたドキュメントのエンベディングを作成します。embed-docs
Service は、Vertex AI エンベディング モデルを使用して、エンベディングをベクトル データベースに保存します。
次の図は、chatbot
Service を使用して、アップロードされたドキュメント コンテンツについて質問するプロセスを示しています。
ユーザーは自然言語を使用して質問できます。chatbot は、アップロードされたファイルのコンテンツのみに従って回答を生成します。chatbot は、セマンティック検索を使用してベクトル データベースからコンテキストを取得し、質問とコンテキストを Gemini に送信します。
費用
このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。
始める前に
このチュートリアルでは、Cloud Shell を使用してコマンドを実行します。Google Cloud Shell は、Google Cloud でホストされているリソースを管理するためのシェル環境です。Cloud Shell には、Google Cloud CLI、kubectl、Terraform のコマンドライン ツールがプリインストールされています。Cloud Shell を使用しない場合は、Google Cloud CLI をインストールします。
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
- Install the Google Cloud CLI.
-
To initialize the gcloud CLI, run the following command:
gcloud init
-
Create or select a Google Cloud project.
-
Create a Google Cloud project:
gcloud projects create PROJECT_ID
Replace
PROJECT_ID
with a name for the Google Cloud project you are creating. -
Select the Google Cloud project that you created:
gcloud config set project PROJECT_ID
Replace
PROJECT_ID
with your Google Cloud project name.
-
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Vertex AI, Cloud Build, Eventarc, Artifact Registry APIs:
gcloud services enable aiplatform.googleapis.com
cloudbuild.googleapis.com eventarc.googleapis.com artifactregistry.googleapis.com - Install the Google Cloud CLI.
-
To initialize the gcloud CLI, run the following command:
gcloud init
-
Create or select a Google Cloud project.
-
Create a Google Cloud project:
gcloud projects create PROJECT_ID
Replace
PROJECT_ID
with a name for the Google Cloud project you are creating. -
Select the Google Cloud project that you created:
gcloud config set project PROJECT_ID
Replace
PROJECT_ID
with your Google Cloud project name.
-
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Vertex AI, Cloud Build, Eventarc, Artifact Registry APIs:
gcloud services enable aiplatform.googleapis.com
cloudbuild.googleapis.com eventarc.googleapis.com artifactregistry.googleapis.com -
Grant roles to your user account. Run the following command once for each of the following IAM roles:
eventarc.admin
gcloud projects add-iam-policy-binding PROJECT_ID --member="USER_IDENTIFIER" --role=ROLE
- Replace
PROJECT_ID
with your project ID. -
Replace
USER_IDENTIFIER
with the identifier for your user account. For example,user:myemail@example.com
. - Replace
ROLE
with each individual role.
- Replace
クラスタを作成する
Qdrant、Elasticsearch、または Postgres クラスタを作成します。
Qdrant
GKE に Qdrant ベクトル データベースをデプロイするの手順に沿って、Autopilot モードまたは Standard モードの GKE クラスタで実行される Qdrant クラスタを作成します。
Elasticsearch
GKE に Elasticsearch ベクトル データベースをデプロイするの手順に沿って、Autopilot モードまたは Standard モードの GKE クラスタで実行される Elasticsearch クラスタを作成します。
PGVector
GKE に PostgreSQL ベクトル データベースをデプロイするの手順に沿って、Autopilot モードまたは Standard モードの GKE クラスタで PGVector を実行する Postgres クラスタを作成します。
Weaviate
GKE に Weaviate ベクトル データベースをデプロイするの手順に沿って、Autopilot モードまたは Standard モードの GKE クラスタで実行される Weaviate クラスタを作成します。
環境を設定する
Cloud Shell を使用して環境を設定します。
プロジェクトの環境変数を設定します。
Qdrant
export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=qdrant export REGION=us-central1 export DB_NAMESPACE=qdrant
PROJECT_ID
は、実際の Google Cloud プロジェクト ID に置き換えます。Elasticsearch
export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=elasticsearch export REGION=us-central1 export DB_NAMESPACE=elastic
PROJECT_ID
は、実際の Google Cloud プロジェクト ID に置き換えます。PGVector
export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=postgres export REGION=us-central1 export DB_NAMESPACE=pg-ns
PROJECT_ID
は、実際の Google Cloud プロジェクト ID に置き換えます。Weaviate
export PROJECT_ID=PROJECT_ID export KUBERNETES_CLUSTER_PREFIX=weaviate export REGION=us-central1 export DB_NAMESPACE=weaviate
PROJECT_ID
は、実際の Google Cloud プロジェクト ID に置き換えます。GKE クラスタが実行されていることを確認します。
gcloud container clusters list --project=${PROJECT_ID} --region=${REGION}
出力は次のようになります。
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS [KUBERNETES_CLUSTER_PREFIX]-cluster us-central1 1.30.1-gke.1329003 <EXTERNAL IP> e2-standard-2 1.30.1-gke.1329003 6 RUNNING
GitHub からサンプルコード リポジトリのクローンを作成します。
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
databases
ディレクトリに移動します。cd kubernetes-engine-samples/databases
インフラストラクチャを準備する
Artifact Registry リポジトリを作成し、Docker イメージをビルドして、Artifact Registry に push します。
Artifact Registry リポジトリを作成します。
gcloud artifacts repositories create ${KUBERNETES_CLUSTER_PREFIX}-images \ --repository-format=docker \ --location=${REGION} \ --description="Vector database images repository" \ --async
Cloud Build を使用して
embed-docs
Service とchatbot
Service の Docker イメージのビルドと push ができるように、Compute Engine サービス アカウントにstorage.objectAdmin
権限とartifactregistry.admin
権限を設定します。export PROJECT_NUMBER=PROJECT_NUMBER gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \ --role="roles/storage.objectAdmin" gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \ --role="roles/artifactregistry.admin"
PROJECT_NUMBER
は、実際の Google Cloud プロジェクトの番号に置き換えます。embed-docs
Service とchatbot
Service の Docker イメージをビルドします。embed-docs
イメージには、Eventarc 転送リクエストを受信するアプリケーションとエンベディング ジョブの両方の Python コードが含まれています。Qdrant
export DOCKER_REPO="${REGION}-docker.pkg.dev/${PROJECT_ID}/${KUBERNETES_CLUSTER_PREFIX}-images" gcloud builds submit qdrant/docker/chatbot --region=${REGION} \ --tag ${DOCKER_REPO}/chatbot:1.0 --async gcloud builds submit qdrant/docker/embed-docs --region=${REGION} \ --tag ${DOCKER_REPO}/embed-docs:1.0 --async
Elasticsearch
export DOCKER_REPO="${REGION}-docker.pkg.dev/${PROJECT_ID}/${KUBERNETES_CLUSTER_PREFIX}-images" gcloud builds submit elasticsearch/docker/chatbot --region=${REGION} \ --tag ${DOCKER_REPO}/chatbot:1.0 --async gcloud builds submit elasticsearch/docker/embed-docs --region=${REGION} \ --tag ${DOCKER_REPO}/embed-docs:1.0 --async
PGVector
export DOCKER_REPO="${REGION}-docker.pkg.dev/${PROJECT_ID}/${KUBERNETES_CLUSTER_PREFIX}-images" gcloud builds submit postgres-pgvector/docker/chatbot --region=${REGION} \ --tag ${DOCKER_REPO}/chatbot:1.0 --async gcloud builds submit postgres-pgvector/docker/embed-docs --region=${REGION} \ --tag ${DOCKER_REPO}/embed-docs:1.0 --async
Weaviate
export DOCKER_REPO="${REGION}-docker.pkg.dev/${PROJECT_ID}/${KUBERNETES_CLUSTER_PREFIX}-images" gcloud builds submit weaviate/docker/chatbot --region=${REGION} \ --tag ${DOCKER_REPO}/chatbot:1.0 --async gcloud builds submit weaviate/docker/embed-docs --region=${REGION} \ --tag ${DOCKER_REPO}/embed-docs:1.0 --async
イメージを確認します。
gcloud artifacts docker images list $DOCKER_REPO \ --project=$PROJECT_ID \ --format="value(IMAGE)"
出力は次のようになります。
$REGION-docker.pkg.dev/$PROJECT_ID/${KUBERNETES_CLUSTER_PREFIX}-images/chatbot $REGION-docker.pkg.dev/$PROJECT_ID/${KUBERNETES_CLUSTER_PREFIX}-images/embed-docs
Kubernetes Job の実行権限を持つ Kubernetes サービス アカウントをデプロイします。
Qdrant
sed "s/<PROJECT_ID>/$PROJECT_ID/;s/<CLUSTER_PREFIX>/$KUBERNETES_CLUSTER_PREFIX/" qdrant/manifests/05-rag/service-account.yaml | kubectl -n qdrant apply -f -
Elasticsearch
sed "s/<PROJECT_ID>/$PROJECT_ID/;s/<CLUSTER_PREFIX>/$KUBERNETES_CLUSTER_PREFIX/" elasticsearch/manifests/05-rag/service-account.yaml | kubectl -n elastic apply -f -
PGVector
sed "s/<PROJECT_ID>/$PROJECT_ID/;s/<CLUSTER_PREFIX>/$KUBERNETES_CLUSTER_PREFIX/" postgres-pgvector/manifests/03-rag/service-account.yaml | kubectl -n pg-ns apply -f -
Weaviate
sed "s/<PROJECT_ID>/$PROJECT_ID/;s/<CLUSTER_PREFIX>/$KUBERNETES_CLUSTER_PREFIX/" weaviate/manifests/04-rag/service-account.yaml | kubectl -n weaviate apply -f -
Terraform を使用して GKE クラスタを作成し、
create_service_account
を true に設定すると、別のサービス アカウントが作成され、クラスタとノードで使用されます。この Compute Engine サービス アカウントにartifactregistry.serviceAgent
ロールを付与して、ノードがembed-docs
とchatbot
用に作成された Artifact Registry からイメージを pull できるようにします。export CLUSTER_SERVICE_ACCOUNT=$(gcloud container clusters describe ${KUBERNETES_CLUSTER_PREFIX}-cluster \ --region=${REGION} \ --format="value(nodeConfig.serviceAccount)") gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="serviceAccount:${CLUSTER_SERVICE_ACCOUNT}" \ --role="roles/artifactregistry.serviceAgent"
サービス アカウントへのアクセス権を付与しないと、
embed-docs
サービスとchatbot
サービスのデプロイ時に Artifact Registry からイメージを pull しようとすると、ノードに権限の問題が発生する可能性があります。embed-docs
Service とchatbot
Service の Kubernetes Deployment をデプロイします。Qdrant
sed "s|<DOCKER_REPO>|$DOCKER_REPO|" qdrant/manifests/05-rag/chatbot.yaml | kubectl -n qdrant apply -f - sed "s|<DOCKER_REPO>|$DOCKER_REPO|" qdrant/manifests/05-rag/docs-embedder.yaml | kubectl -n qdrant apply -f -
Elasticsearch
sed "s|<DOCKER_REPO>|$DOCKER_REPO|" elasticsearch/manifests/05-rag/chatbot.yaml | kubectl -n elastic apply -f - sed "s|<DOCKER_REPO>|$DOCKER_REPO|" elasticsearch/manifests/05-rag/docs-embedder.yaml | kubectl -n elastic apply -f -
PGVector
sed "s|<DOCKER_REPO>|$DOCKER_REPO|" postgres-pgvector/manifests/03-rag/chatbot.yaml | kubectl -n pg-ns apply -f - sed "s|<DOCKER_REPO>|$DOCKER_REPO|" postgres-pgvector/manifests/03-rag/docs-embedder.yaml | kubectl -n pg-ns apply -f -
Weaviate
sed "s|<DOCKER_REPO>|$DOCKER_REPO|" weaviate/manifests/04-rag/chatbot.yaml | kubectl -n weaviate apply -f - sed "s|<DOCKER_REPO>|$DOCKER_REPO|" weaviate/manifests/04-rag/docs-embedder.yaml | kubectl -n weaviate apply -f -
GKE の Eventarc トリガーを有効にします。
gcloud eventarc gke-destinations init
プロンプトが表示されたら、「
y
」と入力します。Terraform を使用して Cloud Storage バケットをデプロイし、Eventarc トリガーを作成します。
export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token) terraform -chdir=vector-database/terraform/cloud-storage init terraform -chdir=vector-database/terraform/cloud-storage apply \ -var project_id=${PROJECT_ID} \ -var region=${REGION} \ -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX} \ -var db_namespace=${DB_NAMESPACE}
プロンプトが表示されたら、「
yes
」と入力します。コマンドが完了するまで数分かかることがあります。Terraform が次のリソースを作成します。
- ドキュメントをアップロードする Cloud Storage バケット
- Eventarc トリガー
- Eventarc の使用権限を持つ
service_account_eventarc_name
という名前の Google Cloud サービス アカウント。 - バケットの読み取りと Vertex AI モデルへのアクセス権を持つ
service_account_bucket_name
という名前の Google Cloud サービス アカウント。
出力は次のようになります。
... # Several lines of output omitted Apply complete! Resources: 15 added, 0 changed, 0 destroyed. ... # Several lines of output omitted
ドキュメントを読み込み、chatbot クエリを実行する
デモ用のドキュメントをアップロードしてクエリを実行し、chatbot を使用してデモ用ドキュメントを検索します。
サンプル ドキュメントを
carbon-free-energy.pdf
バケットにアップロードします。gsutil cp vector-database/documents/carbon-free-energy.pdf gs://${PROJECT_ID}-${KUBERNETES_CLUSTER_PREFIX}-training-docs
ドキュメント エンベディング ジョブが正常に完了したことを確認します。
kubectl get job -n ${DB_NAMESPACE}
出力は次のようになります。
NAME COMPLETIONS DURATION AGE docs-embedder1716570453361446 1/1 32s 71s
ロードバランサの外部 IP アドレスを取得します。
export EXTERNAL_IP=$(kubectl -n ${DB_NAMESPACE} get svc chatbot --output jsonpath='{.status.loadBalancer.ingress[0].ip}') echo http://${EXTERNAL_IP}:80
この外部 IP アドレスをウェブブラウザで開きます。
http://EXTERNAL_IP
chatbot から次のようなメッセージが返されます。
How can I help you?
アップロードされたドキュメントの内容について質問します。何も見つけられない場合、chatbot は「
I don't know
」と回答します。たとえば、次のような質問をします。You: Hi, what are Google plans for the future?
chatbot から次のような出力が表示されます。
Bot: Google intends to run on carbon-free energy everywhere, at all times by 2030. To achieve this, it will rely on a combination of renewable energy sources, such as wind and solar, and carbon-free technologies, such as battery storage.
アップロードされたドキュメントのコンテキストに関係のない質問を chatbot にします。たとえば、次のような質問をします。
You: What are Google plans to colonize Mars?
chatbot から次のような出力が表示されます。
Bot: I don't know. The provided context does not mention anything about Google's plans to colonize Mars.
アプリケーション コードについて
このセクションでは、アプリケーション コードの動作について説明します。Docker イメージ内には 3 つのスクリプトがあります。
endpoint.py
: ドキュメントのアップロードごとに Eventarc イベントを受信し、Kubernetes Job を開始して処理します。embedding-job.py
: バケットからドキュメントをダウンロードし、エンベディングを作成して、ベクトル データベースに格納します。chat.py
: 保存されているドキュメントのコンテンツにクエリを実行します。
次の図は、ドキュメント データに基づいて回答を生成するプロセスを示しています。
この図では、アプリケーションが PDF ファイルを読み込み、ファイルをチャンクに分割してからベクトルに分割し、そのベクトルをベクトル データベースに送信しています。その後、ユーザーが chatbot に質問します。RAG チェーンは、セマンティック検索を使用してベクトル データベースを検索し、質問と一緒にコンテキストも LLM に返します。LLM が質問に回答し、質問をチャットの履歴に保存します。
endpoint.py
について
このファイルは、Eventarc からのメッセージを処理し、ドキュメントを埋め込む Kubernetes Job を作成します。また、ポート 5001 でどこからでもリクエストを受け付けます。
Qdrant
Elasticsearch
PGVector
Weaviate
embedding-job.py
について
このファイルはドキュメントを処理し、ベクトル データベースに送信します。
Qdrant
Elasticsearch
PGVector
Weaviate
chat.py
について
このファイルは、提供されたコンテキストと以前の回答のみを使用して質問に回答するようにモデルを構成します。コンテキストまたは会話履歴がデータと一致しないと、モデルは I don't know
を返します。
Qdrant
Elasticsearch
PGVector
Weaviate
クリーンアップ
このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。
プロジェクトを削除する
課金が発生しないようにする最も簡単な方法は、このチュートリアル用に作成したプロジェクトを削除することです。
Delete a Google Cloud project:
gcloud projects delete PROJECT_ID
プロジェクトを削除すると、クリーンアップが完了します。プロジェクトを削除していない場合は、個々のリソースを削除します。
リソースを個別に削除する
Artifact Registry リポジトリを削除します。
gcloud artifacts repositories delete ${KUBERNETES_CLUSTER_PREFIX}-images \ --location=${REGION} \ --async
プロンプトが表示されたら、「
y
」と入力します。Cloud Storage バケットと Eventarc トリガーを削除します。
export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token) terraform -chdir=vector-database/terraform/cloud-storage destroy \ -var project_id=${PROJECT_ID} \ -var region=${REGION} \ -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX} \ -var db_namespace=${DB_NAMESPACE}
プロンプトが表示されたら、「
yes
」と入力します。Eventarc では、作成時と削除時の両方で有効なエンドポイント ターゲットが必要です。
次のステップ
- GKE にデータベースをデプロイするためのベスト プラクティスについて学習する。
- GKE でデータ量の多いワークロードを実行するためのソリューションを確認する。