了解如何在 Cloud Run 上构建和部署 LangChain 应用

1. 概览

在此 Codelab 中,您将学习如何部署使用 Gemini 的 LangChain 应用,使您能够通过 Cloud Run 版本说明提问。

下面是一个示例,展示了该应用的运作方式:如果您询问“我可以在 Cloud Run 中将 Cloud Storage 存储桶挂载为卷吗?”,该应用会回答“可以,自 2024 年 1 月 19 日起”,或类似的回答。

为了返回有依据的回答,该应用会先检索与问题相似的 Cloud Run 版本说明,然后将问题和版本说明一并提示给 Gemini。(该模式通常称为 RAG。)下图展示了该应用的架构:

2. 设置和要求

首先,让我们确保您的开发环境设置正确。

  • 您需要一个 Google Cloud 项目来部署应用所需的资源。
  • 如需部署应用,您需要在本地计算机上安装 gcloud、进行身份验证,并将其配置为使用相应项目。
    • gcloud auth login
    • gcloud config set project
  • 如果您想在本地计算机上运行应用(建议您这样做),请务必正确设置您的应用默认凭据,包括设置配额项目
    • gcloud auth application-default login
    • gcloud auth application-default set-quota-project
  • 您还需要安装以下软件:
    • Python(必须是 3.11 或更高版本)
    • LangChain CLI
    • 用于依赖项管理的 poetry
    • pipx:用于在隔离的虚拟环境中安装和运行 LangChain CLI 和诗歌

以下博文可帮助您开始安装此演示文稿所需的工具

Cloud Workstations

您还可以使用 Google Cloud 上的 Cloud Workstations,而不是本地机器。请注意,自 2024 年 4 月起,该服务将运行低于 3.11 的 Python 版本,因此您可能需要先升级 Python 才能开始使用。

启用 Cloud API

首先,运行以下命令,确保您已配置要使用的正确 Google Cloud 项目:

gcloud config list project

如果未显示正确的项目,您可以使用以下命令进行设置:

gcloud config set project <PROJECT_ID>

现在,启用以下 API:

gcloud services enable \
  bigquery.googleapis.com \
  sqladmin.googleapis.com \
  aiplatform.googleapis.com \
  cloudresourcemanager.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  run.googleapis.com \
  secretmanager.googleapis.com

请选择区域

Google Cloud 在全球许多位置都可用,您需要选择其中一个位置来部署本实验将要使用的资源。在 shell 中将区域设置为环境变量(后续命令会使用此变量):

export REGION=us-central1

3. 创建矢量数据库实例

此应用的关键部分是检索与用户问题相关的版本说明。举个更具体的例子,如果您要问 Cloud Storage 相关问题,则需要在问题中添加以下版本说明:

您可以使用文本嵌入和向量数据库来查找语义相似的版本说明。

我将向您展示如何在 Cloud SQL 上将 PostgreSQL 用作矢量数据库。创建新的 Cloud SQL 实例需要一些时间,因此我们现在就开始吧。

gcloud sql instances create sql-instance \
  --database-version POSTGRES_14 \
  --tier db-f1-micro \
  --region $REGION

您可以让此命令运行,然后继续执行后续步骤。在某个时刻,您需要创建数据库并添加用户,但现在先别浪费时间看看旋转图标了。

PostgreSQL 是一个关系型数据库服务器,默认情况下,每个新的 Cloud SQL 实例都安装了扩展程序 pgvector,这意味着您也可以将其用作矢量数据库。

4. 为 LangChain 应用搭建框架

如需继续,您需要安装 LangChain CLI 并使用 poetry 来管理依赖项。以下是使用 pipx 安装这些软件的方法:

pipx install langchain-cli poetry

使用以下命令为 LangChain 应用创建框架。当系统询问时,将文件夹命名为 run-rag,并按 Enter 键跳过安装软件包:

langchain app new

切换到 run-rag 目录并安装依赖项

poetry install

您刚刚创建了一个 LangServe 应用。LangServe 会将 FastAPI 封装在 LangChain 链中。它内置了一个 Playground,可让您轻松发送提示并检查结果,包括所有中间步骤。建议您在编辑器中打开文件夹 run-rag,然后浏览其中的内容。

5. 创建索引编制作业

在开始组合 Web 应用之前,我们先确保 Cloud Run 版本说明已在 Cloud SQL 数据库中编入索引。在本部分中,您将创建一个执行以下操作的索引作业:

索引编制作业会记录版本说明,使用文本嵌入模型将其转换为向量,并将它们存储在向量数据库中。这样,您就可以根据发布说明的语义含义高效地搜索类似的发布说明。

run-rag/app 文件夹中,创建一个包含以下内容的 indexer.py 文件:

import os
from google.cloud.sql.connector import Connector
import pg8000
from langchain_community.vectorstores.pgvector import PGVector
from langchain_google_vertexai import VertexAIEmbeddings
from google.cloud import bigquery


# Retrieve all Cloud Run release notes from BigQuery 
client = bigquery.Client()
query = """
SELECT
  CONCAT(FORMAT_DATE("%B %d, %Y", published_at), ": ", description) AS release_note
FROM `bigquery-public-data.google_cloud_release_notes.release_notes`
WHERE product_name= "Cloud Run"
ORDER BY published_at DESC
"""
rows = client.query(query)

print(f"Number of release notes retrieved: {rows.result().total_rows}")

# Set up a PGVector instance 
connector = Connector()

def getconn() -> pg8000.dbapi.Connection:
    conn: pg8000.dbapi.Connection = connector.connect(
        os.getenv("DB_INSTANCE_NAME", ""),
        "pg8000",
        user=os.getenv("DB_USER", ""),
        password=os.getenv("DB_PASS", ""),
        db=os.getenv("DB_NAME", ""),
    )
    return conn

store = PGVector(
    connection_string="postgresql+pg8000://",
    use_jsonb=True,
    engine_args=dict(
        creator=getconn,
    ),
    embedding_function=VertexAIEmbeddings(
        model_name="textembedding-gecko@003"
    ),
    pre_delete_collection=True  
)

# Save all release notes into the Cloud SQL database
texts = list(row["release_note"] for row in rows)
ids = store.add_texts(texts)

print(f"Done saving: {len(ids)} release notes")

添加所需的依赖项:

poetry add \
  "cloud-sql-python-connector[pg8000]" \
  langchain-google-vertexai==1.0.5 \
  langchain-community==0.2.5 \
  pgvector

创建数据库和用户

在 Cloud SQL 实例 sql-instance 上创建数据库 release-notes

gcloud sql databases create release-notes --instance sql-instance

创建名为 app 的数据库用户:

gcloud sql users create app --instance sql-instance --password "myprecious"

部署并运行索引编制作业

现在,部署并运行该作业:

DB_INSTANCE_NAME=$(gcloud sql instances describe sql-instance --format="value(connectionName)")

gcloud run jobs deploy indexer \
  --source . \
  --command python \
  --args app/indexer.py \
  --set-env-vars=DB_INSTANCE_NAME=$DB_INSTANCE_NAME \
  --set-env-vars=DB_USER=app \
  --set-env-vars=DB_NAME=release-notes \
  --set-env-vars=DB_PASS=myprecious \
  --region=$REGION \
  --execute-now

这是一个很长的命令,我们来看看其中发生了什么:

第一个命令会检索连接名称(格式为 project:region:instance 的唯一 ID),并将其设置为环境变量 DB_INSTANCE_NAME

第二个命令会部署 Cloud Run 作业。这些标志的作用如下:

  • --source .:指定作业的源代码位于当前工作目录(您运行命令的目录)中。
  • --command python:设置要在容器内执行的命令。在本例中,它用于运行 Python。
  • --args app/indexer.py:提供 Python 命令的参数。这将指示其在应用目录中运行脚本 indexer.py。
  • --set-env-vars:设置 Python 脚本在执行期间可以访问的环境变量。
  • --region=$REGION:指定应部署作业的区域。
  • --execute-now:告知 Cloud Run 在作业部署后立即启动作业。

如需验证作业是否已成功完成,您可以执行以下操作:

  • 通过 Web 控制台读取作业执行日志。它应报告“已保存:xxx 个版本说明”(其中 xxx 是已保存的版本说明数量)。
  • 您还可以在 Web 控制台中前往 Cloud SQL 实例,然后使用 Cloud SQL Studio 查询 langchain_pg_embedding 表中的记录数量。

6. 编写 Web 应用

在编辑器中打开 app/server.py 文件。您会看到以下内容的一行:

# Edit this to add the chain you want to add

将该注释替换为以下代码段:

# (1) Initialize VectorStore
connector = Connector()


def getconn() -> pg8000.dbapi.Connection:
    conn: pg8000.dbapi.Connection = connector.connect(
        os.getenv("DB_INSTANCE_NAME", ""),
        "pg8000",
        user=os.getenv("DB_USER", ""),
        password=os.getenv("DB_PASS", ""),
        db=os.getenv("DB_NAME", ""),
    )
    return conn


vectorstore = PGVector(
    connection_string="postgresql+pg8000://",
    use_jsonb=True,
    engine_args=dict(
        creator=getconn,
    ),
    embedding_function=VertexAIEmbeddings(
        model_name="textembedding-gecko@003"
    )
)

# (2) Build retriever


def concatenate_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)


notes_retriever = vectorstore.as_retriever() | concatenate_docs

# (3) Create prompt template
prompt_template = PromptTemplate.from_template(
    """You are a Cloud Run expert answering questions. 
Use the retrieved release notes to answer questions
Give a concise answer, and if you are unsure of the answer, just say so.

Release notes: {notes}

Here is your question: {query}
Your answer: """)

# (4) Initialize LLM
llm = VertexAI(
    model_name="gemini-1.0-pro-001",
    temperature=0.2,
    max_output_tokens=100,
    top_k=40,
    top_p=0.95
)

# (5) Chain everything together
chain = (
    RunnableParallel({
        "notes": notes_retriever,
        "query": RunnablePassthrough()
    })
    | prompt_template
    | llm
    | StrOutputParser()
)

您还需要添加以下导入:

import pg8000
import os
from google.cloud.sql.connector import Connector
from langchain_google_vertexai import VertexAI
from langchain_google_vertexai import VertexAIEmbeddings
from langchain_core.runnables import RunnablePassthrough, RunnableParallel
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_community.vectorstores.pgvector import PGVector

最后,将显示“NotImplemented”的行更改为:

# add_routes(app, NotImplemented)
add_routes(app, chain)

7. 将 Web 应用部署到 Cloud Run

run-rag 目录中,使用以下命令将应用部署到 Cloud Run:

DB_INSTANCE_NAME=$(gcloud sql instances describe sql-instance --format="value(connectionName)")

gcloud run deploy run-rag \
  --source . \
  --set-env-vars=DB_INSTANCE_NAME=$DB_INSTANCE_NAME \
  --set-env-vars=DB_USER=app \
  --set-env-vars=DB_NAME=release-notes \
  --set-env-vars=DB_PASS=myprecious \
  --region=$REGION \
  --allow-unauthenticated

此命令执行以下操作:

  • 将源代码上传到 Cloud Build
  • 运行 docker build。
  • 将生成的容器映像推送到 Artifact Registry。
  • 使用容器映像创建 Cloud Run 服务。

命令运行完毕后,系统会列出 run.app 网域中的 HTTPS 网址。这是新 Cloud Run 服务的公开网址

8. 探索 Playground

打开 Cloud Run 服务网址并导航到 /playground。它会调出一个文本字段。您可以使用它就 Cloud Run 版本说明提出问题,如下所示:

9. 恭喜

您已在 Cloud Run 上成功构建并部署了 LangChain 应用。非常棒!

以下是关键概念:

  • 使用 LangChain 框架构建检索增强生成 (RAG) 应用。
  • 在 Cloud SQL 上使用 PostgreSQL 作为矢量数据库,并搭配使用 Cloud SQL 上默认安装的 pgvector。
  • 将运行时间较长的索引编制作业作为 Cloud Run 作业运行,并将 Web 应用作为 Cloud Run 服务运行。
  • 使用 LangServe 将 LangChain 链封装在 FastAPI 应用程序中,提供与您的 RAG 应用程序进行交互的便捷接口。

清理

为避免因本教程中使用的资源导致您的 Google Cloud Platform 账号产生费用,请执行以下操作:

  • 在 Cloud Console 中,转到“管理资源”页面。
  • 在项目列表中,选择您的项目,然后点击“删除”。
  • 在对话框中输入项目 ID,然后点击“关停”以删除项目。

如果您想保留该项目,请务必删除以下资源:

  • Cloud SQL 实例
  • Cloud Run 服务
  • Cloud Run 作业