Découvrez comment créer et déployer une application LangChain sur Cloud Run

1. Présentation

Dans cet atelier de programmation, vous allez apprendre à déployer une application LangChain qui utilise Gemini pour vous permettre de poser des questions sur les notes de version de Cloud Run.

Voici un exemple de fonctionnement de l'application: si vous posez la question "Puis-je installer un bucket Cloud Storage en tant que volume dans Cloud Run ?", l'application répond "Oui, depuis le 19 janvier 2024" ou quelque chose de similaire.

Pour renvoyer des réponses fondées, l'application récupère d'abord les notes de version Cloud Run qui sont similaires à la question, puis transmet à Gemini à la fois la question et les notes de version. (C'est un modèle communément appelé RAG.) Voici un schéma illustrant l'architecture de l'application:

2. Préparation

Tout d'abord, assurons-nous que votre environnement de développement est correctement configuré.

  • Vous aurez besoin d'un projet Google Cloud pour déployer les ressources dont vous avez besoin pour l'application.
  • Pour déployer l'application, vous devez avoir installé gcloud sur votre ordinateur local, authentifié et configuré pour utiliser le projet.
    • gcloud auth login
    • gcloud config set project
  • Si vous souhaitez exécuter l'application sur votre ordinateur local, ce que je vous recommande, vous devez vous assurer que les identifiants par défaut de l'application sont correctement configurés. Vous devez également définir le projet de quota.
    • gcloud auth application-default login
    • gcloud auth application-default set-quota-project
  • Vous devez également avoir installé les logiciels suivants:
    • Python (version 3.11 ou ultérieure requise)
    • La CLI LangChain
    • poésie pour la gestion des dépendances
    • pipx pour installer et exécuter la CLI LangChain et poetry dans des environnements virtuels isolés

Cet article de blog vous aidera à installer les outils nécessaires à ce tutoriel.

Cloud Workstations

Au lieu de votre ordinateur local, vous pouvez également utiliser des stations de travail Cloud sur Google Cloud. Notez qu'à partir d'avril 2024, il exécutera une version de Python antérieure à 3.11. Vous devrez peut-être mettre à niveau Python avant de commencer.

Activer les API Cloud

Commencez par exécuter la commande suivante pour vous assurer que vous avez configuré le bon projet Google Cloud à utiliser :

gcloud config list project

Si le projet approprié ne s'affiche pas, vous pouvez le définir avec la commande suivante :

gcloud config set project <PROJECT_ID>

Activez maintenant les API suivantes :

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

Sélectionner une région

Google Cloud est disponible dans de nombreux pays à travers le monde. Vous devez en choisir un pour déployer les ressources que vous utiliserez pour cet atelier. Définissez la région en tant que variable d'environnement dans votre shell (les commandes ultérieures utilisent cette variable) :

export REGION=us-central1

3. Créer l'instance de base de données vectorielle

Un élément clé de cette application consiste à récupérer les notes de version qui correspondent à la question de l'utilisateur. Pour être plus concret, si vous posez une question sur Cloud Storage, vous souhaitez que la note de version suivante soit ajoutée à l'invite :

Vous pouvez utiliser des représentations vectorielles continues de texte et une base de données vectorielle pour trouver des notes de version sémantiquement similaires.

Je vais vous montrer comment utiliser PostgreSQL sur Cloud SQL en tant que base de données vectorielle. La création d'une instance Cloud SQL prend un certain temps. Nous allons donc le faire maintenant.

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

Vous pouvez laisser cette commande s'exécuter et passer aux étapes suivantes. À un moment donné, vous devrez créer une base de données et ajouter un utilisateur, mais ne perdons pas de temps à regarder la roue de chargement.

PostgreSQL est un serveur de base de données relationnelle. L'extension pgvector est installée par défaut dans chaque nouvelle instance de Cloud SQL. Vous pouvez donc également l'utiliser comme base de données vectorielle.

4. Échafauder l'application LangChain

Pour continuer, vous devez installer la CLI LangChain et poetry pour gérer les dépendances. Pour les installer à l'aide de pipx :

pipx install langchain-cli poetry

Créez une structure pour l'application LangChain à l'aide de la commande suivante. Lorsque vous y êtes invité, nommez le dossier run-rag et ignorez l'installation des packages en appuyant sur Entrée:

langchain app new

Accédez au répertoire run-rag et installez les dépendances

poetry install

Vous venez de créer une application LangServe. LangServe encapsule FastAPI autour d'une chaîne LangChain. Il est fourni avec un bac à sable intégré qui permet d'envoyer facilement des invites et d'inspecter les résultats, y compris toutes les étapes intermédiaires. Je vous suggère d'ouvrir le dossier run-rag dans votre éditeur et d'explorer son contenu.

5. Créer la tâche d'indexation

Avant de commencer à assembler l'application Web, assurez-vous que les notes de version de Cloud Run sont indexées dans la base de données Cloud SQL. Dans cette section, vous allez créer un job d'indexation qui effectue les opérations suivantes:

Le job d'indexation prend des notes de version, les convertit en vecteurs à l'aide d'un modèle de représentation vectorielle continue de texte et les stocke dans une base de données vectorielle. Cela permet de rechercher efficacement des notes de version similaires en fonction de leur signification sémantique.

Dans le dossier run-rag/app, créez un fichier indexer.py avec le contenu suivant:

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")

Ajoutez les dépendances requises :

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

Créer la base de données et un utilisateur

Créez une base de données release-notes sur l'instance Cloud SQL sql-instance:

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

Créez un utilisateur de base de données appelé app:

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

Déployer et exécuter la tâche d'indexation

Déployez et exécutez maintenant la tâche :

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

Il s'agit d'une commande longue. Voyons ce qui se passe :

La première commande récupère le nom de la connexion (un ID unique au format project:region:instance) et le définit comme variable d'environnement DB_INSTANCE_NAME.

La deuxième commande déploie la tâche Cloud Run. Voici ce que font les indicateurs :

  • --source .: indique que le code source de la tâche se trouve dans le répertoire de travail actuel (le répertoire dans lequel vous exécutez la commande).
  • --command python: définit la commande à exécuter à l'intérieur du conteneur. Dans ce cas, il s'agit d'exécuter Python.
  • --args app/indexer.py: fournit les arguments à la commande Python. Cela lui indique d'exécuter le script indexer.py dans le répertoire de l'application.
  • --set-env-vars : définit les variables d'environnement auxquelles le script Python peut accéder lors de l'exécution.
  • --region=$REGION: spécifie la région dans laquelle le job doit être déployé.
  • --execute-now : indique à Cloud Run de démarrer la tâche immédiatement après son déploiement.

Pour vérifier que la tâche a bien été effectuée, procédez comme suit :

  • Consultez les journaux d'exécution du job via la console Web. Le message "Enregistrement terminé : xxx notes de version" (où xxx correspond au nombre de notes de version enregistrées) doit s'afficher.
  • Vous pouvez également accéder à l'instance Cloud SQL dans la console Web et utiliser Cloud SQL Studio pour interroger le nombre d'enregistrements dans la table langchain_pg_embedding.

6. Écrire l'application Web

Ouvrez le fichier app/server.py dans votre éditeur. La ligne suivante s'affiche:

# Edit this to add the chain you want to add

Remplacez ce commentaire par l'extrait suivant :

# (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()
)

Vous devez également ajouter les importations suivantes :

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

Enfin, remplacez la ligne "NotImplemented" par :

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

7. Déployer l'application Web sur Cloud Run

Depuis le répertoire run-rag, utilisez la commande suivante pour déployer l'application sur 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

Cette commande effectue les opérations suivantes :

  • Importer le code source dans Cloud Build
  • Exécutez la compilation Docker.
  • Transférez l'image de conteneur obtenue vers Artifact Registry.
  • Créez un service Cloud Run à l'aide de l'image de conteneur.

Une fois la commande exécutée, une URL HTTPS s'affiche sur le domaine run.app. Il s'agit de l'URL publique de votre nouveau service Cloud Run

8. Explorer le terrain de jeu

Ouvrez l'URL du service Cloud Run, puis accédez à /playground. Un champ de texte s'affiche. Utilisez-le pour poser des questions sur les notes de version de Cloud Run, par exemple :

9. Félicitations

Vous avez créé et déployé une application LangChain sur Cloud Run. Bravo !

Voici les concepts clés :

  • Utilisation du framework LangChain pour créer une application de génération augmentée de récupération (RAG).
  • Utilisation de PostgreSQL sur Cloud SQL comme base de données vectorielle avec pgvector, qui est installé par défaut sur Cloud SQL.
  • Exécuter un job d'indexation plus long en tant que job Cloud Run et une application Web en tant que service Cloud Run
  • Encapsulez une chaîne LangChain dans une application FastAPI avec LangServe, ce qui vous fournit une interface pratique pour interagir avec votre application RAG.

Effectuer un nettoyage

Afin d'éviter la facturation sur votre compte Google Cloud Platform des ressources utilisées dans ce tutoriel, procédez comme suit :

  • Dans Cloud Console, accédez à la page "Gérer les ressources".
  • Dans la liste des projets, sélectionnez votre projet, puis cliquez sur "Supprimer".
  • Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur "Arrêter" pour supprimer le projet.

Si vous souhaitez conserver le projet, veillez à supprimer les ressources suivantes :

  • Instance Cloud SQL
  • Service Cloud Run
  • Job Cloud Run