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

1. Omówienie

Z tego modułu dotyczącego kodu dowiesz się, jak wdrożyć aplikację LangChain, która korzysta z Gemini, aby umożliwić Ci zadawanie pytań w informacjach o wersji Cloud Run.

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

Aby zwrócić odpowiedzi oparte na faktach, aplikacja najpierw pobiera informacje o wersjach Cloud Run, które są podobne do pytania, a następnie przekazuje Gemini zarówno pytanie, jak i informacje o wersji. (jest to wzór, który jest powszechnie nazywany RAG). Oto diagram przedstawiający architekturę aplikacji:

2. Konfiguracja i wymagania

Najpierw sprawdźmy, czy ś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, które jest uwierzytelnione i skonfigurowane do korzystania z projektu.
    • gcloud auth login
    • gcloud config set project
  • Jeśli chcesz uruchomić aplikację na komputerze lokalnym (co jest zalecane), musisz się upewnić, że dane logowania domyślne 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 te programy:
    • Python (wymagana wersja 3.11 lub nowsza)
    • interfejs wiersza poleceń LangChain,
    • poezja na temat zarządzania zależnościami.
    • pipx do instalowania i uruchamiania interfejsu wiersza poleceń LangChain i poetry w odizolowanych środowiskach wirtualnych.

Oto blog, który pomoże Ci rozpocząć instalowanie narzędzi wymaganych do wykonania tej procedury.

Cloud Workstations

Zamiast komputera lokalnego możesz też korzystać z komputerów Cloud Workstations w Google Cloud. Pamiętaj, że w kwietniu 2024 r. używa ona Pythona w wersji starszej niż 3.11, więc zanim zaczniesz z niego korzystać, konieczne może być jego uaktualnienie.

Włączanie Cloud APIs

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

gcloud config list project

Jeśli nie widzisz prawidłowego 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ępny w wielu lokalizacjach na całym świecie. Musisz wybrać jedną z nich, aby wdrożyć zasoby, których użyjesz w tym laboratorium. Ustaw region jako zmienną środowiskową w powłoce (późniejsze polecenia korzystają z tej zmiennej):

export REGION=us-central1

3. Tworzenie instancji bazy danych wektorów

Kluczową funkcją tej aplikacji jest pobieranie informacji o wersji, które są istotne w stosunku do pytania użytkownika. Aby to zilustrować, jeśli zadajesz pytanie dotyczące Cloud Storage, możesz dodać do promptu następującą informację z notatki o wersji:

Za pomocą wektorów dystrybucyjnych i bazy danych wektorowych możesz znaleźć informacje o wersji podobne semantycznie.

Pokażę Ci, jak używać PostgreSQL w Cloud SQL jako bazy danych wektorowej. Tworzenie 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 kontynuować kolejne kroki. W pewnym momencie konieczne będzie utworzenie bazy danych i dodanie użytkownika, ale nie traćmy czasu na obserwowanie wskaźnika postępu.

PostgreSQL to serwer relacyjnej bazy danych, a w każdej nowej instancji Cloud SQL jest domyślnie instalowane rozszerzenie pgvector, co oznacza, że możesz też używać tej bazy danych jako bazy danych wektorowej.

4. Scaffold the LangChain

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

pipx install langchain-cli poetry

Utwórz szablon aplikacji LangChain za pomocą tego polecenia. Gdy pojawi się prośba, nadaj folderowi nazwę run-rag i przejdź przez instalację pakietów, naciskając klawisz Enter:

langchain app new

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

poetry install

Właśnie utworzysz aplikację LangServe. LangServe otacza FastAPI łańcuchem LangChain. Zawiera wbudowane środowisko testowe, które ułatwia wysyłanie promptów i sprawdzanie wyników, w tym wszystkich pośrednich kroków. Otwórz folder run-rag w edytorze i sprawdź, co się w nim znajduje.

5. Tworzenie zadania indeksowania

Zanim zaczniesz tworzyć aplikację internetową, sprawdź, czy informacje o wersji Cloud Run są zindeksowane w bazie danych Cloud SQL. W tej sekcji utworzysz zadanie indeksowania, które:

Zadaniem indeksowania jest pobieranie informacji o wersji, konwertowanie ich na wektory za pomocą modelu tekstowego i przechowywanie w bazie danych wektorów. Umożliwia to wydajne wyszukiwanie podobnych notatek o wersji na podstawie ich znaczenia semantycznego.

W folderze run-rag/app utwórz plik indexer.py z podaną niżej 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 w 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 (wyjątkowy identyfikator w formacie project:region:instance) i ustala go jako zmienną środowiskową DB_INSTANCE_NAME.

Drugie polecenie wdraża zadanie Cloud Run. Flagi mogą sprawiać takie problemy:

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

Aby sprawdzić, czy zadanie zostało ukończone, wykonaj te czynności:

  • odczytywać logi wykonania zadania w konsoli internetowej. Powinien on zawierać komunikat „Zakończono zapisywanie: xxx informacji o wersji” (gdzie xxx to liczba zapisanych informacji o wersji).
  • Możesz też przejść do instancji Cloud SQL w konsoli sieciowej i użyć Cloud SQL Studio, aby zapytać o liczbę rekordów w tabeli langchain_pg_embedding.

6. Tworzenie aplikacji internetowej

Otwórz plik app/server.py w edytorze. Znajdziesz tam wiersz z tą informacją:

# Edit this to add the chain you want to add

Zastąp ten komentarz następującym fragmentem:

# (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 importy:

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, w którym jest napisane „Nieimplementowane” na:

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

7. Wdrażanie aplikacji internetowej w Cloud Run

W katalogu run-rag wdróż aplikację w Cloud Run, używając tego polecenia:

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 wykonywania polecenia wyświetla adres URL HTTPS w domenie run.app. To jest publiczny adres URL nowej usługi Cloud Run.

8. Poznawanie placu zabaw

Otwórz adres URL usługi Cloud Run i przejdź do /playground. Otworzy się pole tekstowe. Możesz go używać do zadawania pytań dotyczących informacji o wersji Cloud Run, np. takich jak te:

9. Gratulacje

Udało Ci się skompilować 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 wektorowej z pgvector, która jest domyślnie instalowana w Cloud SQL.
  • Uruchomić zadanie indeksowania o dłuższym czasie działania jako zadanie Cloud Run i aplikację internetową jako usługę Cloud Run.
  • Owiń łańcuch LangChain w aplikacji FastAPI za pomocą LangServe, aby uzyskać 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 konsoli Cloud otwórz stronę Zarządzanie zasobami.
  • Na liście projektów wybierz swój projekt i 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