このチュートリアルでは、検索拡張生成(RAG)に基づく大規模言語モデル(LLM)アプリケーションと、Cloud Storage バケットにアップロードされた PDF ファイルを統合する方法について説明します。
このガイドでは、アップロードされたドキュメントの表現(エンベディング)を保持するストレージとセマンティック検索エンジンとしてデータベースを使用します。Langchain フレームワークを使用してエンベディングを操作し、Vertex AI で利用可能な Gemini モデルを使用します。
Langchain は、多くの ML タスクを簡素化し、さまざまなベクトル データベースや AI サービスと統合するためのインターフェースを備えた、よく利用されているオープンソースの Python フレームワークです。
このチュートリアルは、GKE と Cloud Storage に RAG LLM アプリケーションをデプロイすることに関心があるクラウド プラットフォームの管理者とアーキテクト、ML エンジニア、MLOps(DevOps)の専門家を対象としています。
クラスタの作成
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 CONTROL_PLANE_LOCATION=us-central1 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 CONTROL_PLANE_LOCATION=us-central1 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 CONTROL_PLANE_LOCATION=us-central1 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 CONTROL_PLANE_LOCATION=us-central1 export REGION=us-central1 export DB_NAMESPACE=weaviate
PROJECT_ID
は、実際のGoogle Cloud プロジェクト ID に置き換えます。GKE クラスタが実行されていることを確認します。
gcloud container clusters list --project=${PROJECT_ID} --location=${CONTROL_PLANE_LOCATION}
出力は次のようになります。
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 \ --location=${CONTROL_PLANE_LOCATION} \ --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 をデプロイします。Deployment は、クラスタ内のノードに分散された Pod の複数のレプリカを実行できる Kubernetes API オブジェクトです。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
バケットにアップロードします。gcloud storage 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
を返します。