本教程介绍如何将基于检索增强生成 (RAG) 的大语言模型 (LLM) 应用与上传到 Cloud Storage 存储桶的 PDF 文件集成。
本指南使用数据库作为存储和语义搜索引擎,用于保存所上传文档的表示法(嵌入)。您将使用 Langchain 框架与嵌入进行交互,并使用通过 Vertex AI 提供的 Gemini 模型。
Langchain 是一种流行的开源 Python 框架,可简化许多机器学习任务,并具有与不同矢量数据库和 AI 服务集成的界面。
本教程适用于想要将 RAG LLM 应用部署到 GKE 和 Cloud Storage 的云平台管理员和架构师、机器学习工程师以及 MLOps (DevOps) 专业人员。
目标
在本教程中,您将学习如何:
- 构建和部署应用,以创建文档嵌入并将其存储在矢量数据库中。
- 让应用自动执行,以触发将新文档上传到 Cloud Storage 存储桶的操作。
- 部署使用语义搜索根据文档内容回答问题的聊天机器人应用。
部署架构
在本教程中,您将创建 Cloud Storage 存储桶、Eventarc 触发器和以下 Service:
embed-docs
:每当用户向 Cloud Storage 存储桶上传新文档时,Eventarc 都会触发此 Service。此 Service 会启动一个 Kubernetes 作业,该作业会为上传的文档创建嵌入,并将相应嵌入插入到矢量数据库中。chatbot
:此 Service 使用语义搜索和 Gemini API 回答与上传的文档有关的自然语言问题。
下图显示了文档文档和矢量化过程:
在该图中,用户将文件上传到 Cloud Storage 存储桶。Eventarc 会订阅该存储桶的对象 metadataUpdated
事件,并使用 Eventarc 的事件转发器(一个 Kubernetes 工作负载)在您上传新文档时调用 embed-docs
Service。该 Service 随后会为上传的文档创建嵌入。embed-docs
Service 会使用 Vertex AI 嵌入模型将嵌入存储在矢量数据库中。
下图显示使用 chatbot
Service 提出有关所上传文档内容的问题的过程:
用户可以使用自然语言提出问题,聊天机器人只会根据所上传文件的内容生成回答。聊天机器人使用语义搜索从矢量数据库检索上下文,然后将问题和上下文发送给 Gemini。
费用
在本文档中,您将使用 Google Cloud 的以下收费组件:
您可使用价格计算器根据您的预计使用情况来估算费用。
完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理。
准备工作
在本教程中,您将使用 Cloud Shell 运行命令。Cloud Shell 是一种 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 映像,并将 Docker 映像推送到 Artifact Registry:
创建 Artifact Registry 代码库:
gcloud artifacts repositories create ${KUBERNETES_CLUSTER_PREFIX}-images \ --repository-format=docker \ --location=${REGION} \ --description="Vector database images repository" \ --async
为 Compute Engine 服务账号设置
storage.objectAdmin
和artifactregistry.admin
权限,以使用 Cloud Build 为embed-docs
和chatbot
Service 构建和推送 Docker 映像。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
和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 作业的权限的 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 中拉取映像。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
Service 时,节点在尝试从 Artifact Registry 拉取映像时可能会遇到权限问题。为
embed-docs
和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 触发器
- 名为
service_account_eventarc_name
且有权使用 Eventarc 的 Google Cloud 服务账号。 - 名为
service_account_bucket_name
且有权读取存储桶和访问 Vertex AI 模型的 Google Cloud 服务账号。
输出类似于以下内容:
... # Several lines of output omitted Apply complete! Resources: 15 added, 0 changed, 0 destroyed. ... # Several lines of output omitted
加载文档并运行聊天机器人查询
上传演示文档,然后运行查询以使用聊天机器人搜索演示文档:
将示例
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
聊天机器人会返回类似于如下所示的消息:
How can I help you?
提出与所上传文档的内容相关的问题。如果聊天机器人找不到任何内容,则会回答
I don't know
。例如,您可能会提出以下问题:You: Hi, what are Google plans for the future?
聊天机器人的示例输出类似于以下内容:
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.
向聊天机器人提出与上传的文档无关的问题。例如,您可能会提出以下问题:
You: What are Google plans to colonize Mars?
聊天机器人的示例输出类似于以下内容:
Bot: I don't know. The provided context does not mention anything about Google's plans to colonize Mars.
关于应用代码
本部分介绍应用代码的工作原理。Docker 映像中包含三个脚本:
endpoint.py
:在每次上传文档时接收 Eventarc 事件,并启动 Kubernetes 作业来处理这些事件。embedding-job.py
:从存储桶下载文档,创建嵌入,然后将嵌入插入到矢量数据库中。chat.py
:对存储的文档内容运行查询。
该图展示了使用文档数据生成回答的过程:
在该图中,应用会加载 PDF 文件,将文件拆分为多个分块,然后将这些分块转换为矢量,最后将相应矢量发送到矢量数据库。之后,用户向聊天机器人提问。RAG 链使用语义搜索来搜索矢量数据库,然后将上下文与问题一起返回给 LLM。LLM 会回答问题,并将问题存储到聊天记录中。
关于 endpoint.py
此文件处理来自 Eventarc 的消息,创建用于嵌入文档的 Kubernetes 作业,并通过端口 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 运行数据密集型工作负载的解决方案。