Dowiedz się, jak utworzyć i wdrożyć aplikację LangChain w Cloud Run

1. Przegląd

W tym module dowiesz się, jak wdrożyć aplikację LangChain, która korzysta z Gemini, aby umożliwić zadawanie pytań dotyczących informacji o wersji Cloud Run.

Oto przykład działania aplikacji: jeśli zapytasz „Czy mogę zamontować zasobnik Cloud Storage jako wolumin w Cloud Run?”, aplikacja odpowie „Tak, od 19 stycznia 2024 r.” lub podobnie.

Aby zwracać odpowiedzi oparte na faktach, aplikacja najpierw pobiera informacje o wersji Cloud Run podobne do pytania, a następnie przekazuje Gemini zarówno pytanie, jak i informacje o wersji. (Jest to wzorzec powszechnie określany jako RAG). Oto diagram przedstawiający architekturę aplikacji:

2. Konfiguracja i wymagania

Najpierw upewnijmy się, że środowisko programistyczne jest prawidłowo skonfigurowane.

  • Aby wdrożyć zasoby potrzebne do działania aplikacji, musisz mieć projekt Google Cloud.
  • Aby wdrożyć aplikację, musisz mieć zainstalowane na komputerze lokalnym narzędzie gcloud, uwierzytelnione i skonfigurowane do używania projektu.
    • gcloud auth login
    • gcloud config set project
  • Jeśli chcesz uruchomić aplikację na komputerze lokalnym (co zalecam), musisz się upewnić, że domyślne dane logowania aplikacji są prawidłowo skonfigurowane, w tym ustawienie projektu limitu.
    • gcloud auth application-default login
    • gcloud auth application-default set-quota-project
  • Musisz też mieć zainstalowane to oprogramowanie:
    • Python (wymagana jest wersja 3.11 lub nowsza)
    • Interfejs wiersza poleceń LangChain
    • poetry do zarządzania zależnościami,
    • pipx do instalowania i uruchamiania interfejsu wiersza poleceń LangChain i poetry w izolowanych środowiskach wirtualnych.

Na tym blogu znajdziesz informacje o instalowaniu narzędzi potrzebnych do tego przewodnika.

Cloud Workstations

Zamiast komputera lokalnego możesz też używać Cloud Workstations w Google Cloud. Pamiętaj, że od kwietnia 2024 r. używa on wersji Pythona starszej niż 3.11, więc przed rozpoczęciem pracy może być konieczne uaktualnienie Pythona.

Włączanie interfejsów Cloud API

Najpierw uruchom to polecenie, aby sprawdzić, czy masz skonfigurowany odpowiedni projekt Google Cloud:

gcloud config list project

Jeśli nie widzisz właściwego projektu, możesz go ustawić za pomocą tego polecenia:

gcloud config set project <PROJECT_ID>

Teraz włącz te interfejsy 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

Wybierz region

Google Cloud jest dostępna w wielu lokalizacjach na całym świecie. Musisz wybrać jedną z nich, aby wdrożyć zasoby, których będziesz używać w tym module. Ustaw region jako zmienną środowiskową w powłoce (późniejsze polecenia będą używać tej zmiennej):

export REGION=us-central1

3. Tworzenie instancji bazy danych wektorowych

Kluczową częścią tej aplikacji jest pobieranie informacji o wersji, które są istotne dla pytania użytkownika. Aby to lepiej zobrazować, jeśli zadajesz pytanie dotyczące Cloud Storage, chcesz, aby do promptu dodano tę informację o wersji:

Aby znaleźć podobne semantycznie informacje o wersji, możesz użyć wektorów dystrybucyjnych tekstu i wektorowej bazy danych.

Pokażę Ci, jak używać PostgreSQL w Cloud SQL jako bazy danych wektorów. Utworzenie nowej instancji Cloud SQL zajmuje trochę czasu, więc zróbmy to teraz.

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

Możesz uruchomić to polecenie i przejść do kolejnych kroków. W pewnym momencie musisz utworzyć bazę danych i dodać użytkownika, ale nie traćmy teraz czasu na obserwowanie wskaźnika postępu.

PostgreSQL to serwer relacyjnej bazy danych, a każda nowa instancja Cloud SQL ma domyślnie zainstalowane rozszerzenie pgvector, co oznacza, że możesz jej używać również jako bazy danych wektorowych.

4. Tworzenie szkieletu aplikacji LangChain

Aby kontynuować, musisz mieć zainstalowany interfejs LangChain CLI i narzędzie poetry do zarządzania zależnościami. Oto jak je zainstalować za pomocą pipx:

pipx install langchain-cli poetry

Utwórz szkielet aplikacji LangChain za pomocą tego polecenia. Gdy pojawi się prośba, nadaj folderowi nazwę run-rag i pomiń instalowanie pakietów, naciskając Enter:

langchain app new

Przejdź do katalogu run-rag i zainstaluj zależności.

poetry install

Właśnie utworzono aplikację LangServe. LangServe otacza łańcuch LangChain za pomocą FastAPI. Zawiera wbudowany plac zabaw, który ułatwia wysyłanie promptów i sprawdzanie wyników, w tym wszystkich etapów pośrednich. Otwórz folder run-rag w edytorze i sprawdź, co się w nim znajduje.

5. Tworzenie zadania indeksowania

Zanim zaczniesz tworzyć aplikację internetową, upewnij się, że informacje o wersji Cloud Run są indeksowane w bazie danych Cloud SQL. W tej sekcji utworzysz zadanie indeksowania, które będzie wykonywać te czynności:

Zadanie indeksowania pobiera informacje o wersji, przekształca je w wektory za pomocą modelu wektorów dystrybucyjnych tekstu i przechowuje je w bazie danych wektorów. Umożliwia to wydajne wyszukiwanie podobnych informacji o wersji na podstawie ich znaczenia semantycznego.

W folderze run-rag/app utwórz plik indexer.py o tej treści:

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

Dodaj wymagane zależności:

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

Utwórz bazę danych i użytkownika

Utwórz bazę danych release-notes na instancji Cloud SQL sql-instance:

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

Utwórz użytkownika bazy danych o nazwie app:

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

Wdrażanie i uruchamianie zadania indeksowania

Teraz wdróż i uruchom zadanie:

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

To długie polecenie. Zobaczmy, co się dzieje:

Pierwsze polecenie pobiera nazwę połączenia (unikalny identyfikator w formacie project:region:instance) i ustawia ją jako wartość zmiennej środowiskowej DB_INSTANCE_NAME.

Drugie polecenie wdraża zadanie Cloud Run. Oto co oznaczają flagi:

  • --source .: określa, że kod źródłowy zadania znajduje się w bieżącym katalogu roboczym (katalogu, w którym uruchamiasz polecenie).
  • --command python: określa polecenie do wykonania w kontenerze. W tym przypadku jest to uruchomienie Pythona.
  • --args app/indexer.py: podaje argumenty polecenia python. Oznacza to, że skrypt indexer.py ma zostać uruchomiony w katalogu aplikacji.
  • --set-env-vars: ustawia zmienne środowiskowe, do których skrypt w Pythonie może uzyskać dostęp podczas wykonywania.
  • --region=$REGION: określa region, w którym ma zostać wdrożone zadanie.
  • --execute-now: informuje Cloud Run, że zadanie ma się rozpocząć natychmiast po wdrożeniu.

Aby sprawdzić, czy zadanie zostało wykonane, możesz wykonać te czynności:

  • Odczytaj logi wykonania zadania w konsoli internetowej. Powinien wyświetlać komunikat „Zapisano: xxx informacji o wersji” (gdzie xxx to liczba zapisanych informacji o wersji).
  • Możesz też przejść do instancji Cloud SQL w konsoli internetowej i użyć Cloud SQL Studio, aby wysłać zapytanie o liczbę rekordów w tabeli langchain_pg_embedding.

6. Tworzenie aplikacji internetowej

Otwórz plik app/server.py w edytorze. Znajdziesz wiersz z tym tekstem:

# Edit this to add the chain you want to add

Zastąp ten komentarz tym fragmentem kodu:

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

Musisz też dodać te instrukcje importu:

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

Na koniec zmień wiersz „NotImplemented” na:

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

7. Wdrażanie aplikacji internetowej w Cloud Run

W katalogu run-rag użyj tego polecenia, aby wdrożyć aplikację w 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

To polecenie wykonuje te czynności:

  • Przesyłanie kodu źródłowego do Cloud Build
  • Uruchom kompilację Dockera.
  • Prześlij powstały obraz kontenera do Artifact Registry.
  • Utwórz usługę Cloud Run przy użyciu obrazu kontenera.

Po zakończeniu polecenia wyświetli ono adres URL HTTPS w domenie run.app. Jest to publiczny adres URL nowej usługi Cloud Run.

8. Poznaj plac zabaw

Otwórz adres URL usługi Cloud Run i kliknij /playground. Wyświetli się pole tekstowe. Możesz go używać do zadawania pytań dotyczących informacji o wersji Cloud Run, np. w ten sposób:

9. Gratulacje

Udało Ci się utworzyć i wdrożyć aplikację LangChain w Cloud Run. Brawo!

Oto najważniejsze pojęcia:

  • Korzystanie z platformy LangChain do tworzenia aplikacji do generowania rozszerzonego przez wyszukiwanie w zapisanych informacjach (RAG).
  • Używanie PostgreSQL w Cloud SQL jako bazy danych wektorów z pgvector, który jest domyślnie zainstalowany w Cloud SQL.
  • Uruchom dłużej działające zadanie indeksowania jako zadanie Cloud Run, a aplikację internetową jako usługę Cloud Run.
  • Owiń łańcuch LangChain w aplikację FastAPI za pomocą LangServe, aby zapewnić wygodny interfejs do interakcji z aplikacją RAG.

Czyszczenie danych

Aby uniknąć obciążenia konta Google Cloud Platform opłatami za zasoby zużyte w tym samouczku:

  • W Cloud Console otwórz stronę Zarządzaj zasobami.
  • Na liście projektów wybierz projekt, a następnie kliknij Usuń.
  • W oknie wpisz identyfikator projektu i kliknij Wyłącz, aby usunąć projekt.

Jeśli chcesz zachować projekt, usuń te zasoby:

  • Instancja Cloud SQL
  • Usługa Cloud Run
  • Zadanie Cloud Run