IA sans serveur : EmbeddingGemma avec Cloud Run

1. Introduction

Dans cet atelier de programmation, vous allez apprendre à déployer EmbeddingGemma, un puissant modèle d'embedding de texte multilingue, sur Cloud Run à l'aide de GPU. Vous utiliserez ensuite ce service déployé pour générer des embeddings pour une application de recherche sémantique.

Contrairement aux grands modèles de langage (LLM) traditionnels qui génèrent du texte, les modèles d'embedding convertissent le texte en vecteurs numériques. Ces vecteurs sont essentiels pour créer des systèmes de génération augmentée par récupération (RAG), qui vous permettent de trouver les documents les plus pertinents pour la requête d'un utilisateur.

Objectifs de l'atelier

  • Conteneurisez le modèle EmbeddingGemma à l'aide d'Ollama.
  • Déployez le conteneur sur Cloud Run avec accélération GPU.
  • Testez le modèle déployé en générant des embeddings pour un exemple de texte.
  • Créez un système de recherche sémantique léger à l'aide de votre service déployé.

Prérequis

  • Un projet Google Cloud avec facturation activée.
  • Connaissances de base de Docker et de la ligne de commande.

2. Avant de commencer

Configuration du projet

  1. Si vous ne possédez pas encore de compte Google, vous devez en créer un.
    • Utilisez un compte personnel au lieu d'un compte professionnel ou scolaire. Il est possible que des restrictions s'appliquent aux comptes professionnels et scolaires, ce qui vous empêche d'activer les API nécessaires pour cet atelier.
  2. Connectez-vous à la console Google Cloud.
  3. Activez la facturation dans la console Cloud.
    • Cet atelier devrait vous coûter moins de 1 USD en ressources Cloud.
    • Vous pouvez suivre les étapes à la fin de cet atelier pour supprimer les ressources et éviter ainsi des frais supplémentaires.
    • Les nouveaux utilisateurs peuvent bénéficier d'un essai sans frais pour bénéficier d'un crédit de 300$.
  4. Créez un projet ou réutilisez-en un existant.
    • Si vous voyez une erreur concernant le quota de projet, réutilisez un projet existant ou supprimez-en un pour en créer un.

Démarrer Cloud Shell

Cloud Shell est un environnement de ligne de commande exécuté dans Google Cloud et fourni avec les outils nécessaires.

  1. Cliquez sur Activer Cloud Shell en haut de la console Google Cloud.
  2. Une fois connecté à Cloud Shell, vérifiez votre authentification :
    gcloud auth list
    
  3. Vérifiez que votre projet est sélectionné :
    gcloud config get project
    
  4. Définissez-le si nécessaire :
    gcloud config set project <YOUR_PROJECT_ID>
    

Activer les API

Exécutez cette commande pour activer toutes les API requises :

gcloud services enable \
  run.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com

3. Conteneuriser le modèle

Pour exécuter EmbeddingGemma sans serveur, nous devons l'empaqueter dans un conteneur. Nous utiliserons Ollama, un framework léger pour exécuter des LLM, et Docker.

Créer le fichier Dockerfile

Dans Cloud Shell, créez un répertoire pour votre projet et accédez-y :

mkdir embedding-gemma-codelab
cd embedding-gemma-codelab

Créez un fichier nommé Dockerfile avec le contenu suivant :

FROM ollama/ollama:latest

# Listen on all interfaces, port 8080
ENV OLLAMA_HOST=0.0.0.0:8080

# Store model weight files in /models
ENV OLLAMA_MODELS=/models

# Reduce logging verbosity
ENV OLLAMA_DEBUG=false

# Never unload model weights from the GPU
ENV OLLAMA_KEEP_ALIVE=-1

# Store the model weights in the container image
ENV MODEL=embeddinggemma:latest
RUN ollama serve & sleep 5 && ollama pull $MODEL

# Start Ollama
ENTRYPOINT ["ollama", "serve"]

Ce fichier Dockerfile effectue les opérations suivantes :

  1. Démarrer à partir de l'image de base Ollama officielle
  2. Configure Ollama pour qu'il écoute sur le port 8080 (port par défaut de Cloud Run).
  3. La commande RUN démarre le serveur ollama et télécharge le modèle embeddinggemma pendant le processus de compilation afin qu'il soit intégré à l'image.
  4. Définit OLLAMA_KEEP_ALIVE=-1 pour s'assurer que le modèle reste chargé dans la mémoire GPU afin d'accélérer les requêtes ultérieures.

4. Compiler et déployer

Nous allons utiliser le déploiement de source Cloud Run pour créer et déployer notre conteneur en une seule étape. Cette commande crée l'image à l'aide de Cloud Build, la stocke dans Artifact Registry et la déploie sur Cloud Run.

Exécutez la commande suivante pour effectuer le déploiement :

gcloud run deploy embedding-gemma \
  --source . \
  --region europe-west1 \
  --concurrency 4 \
  --cpu 8 \
  --set-env-vars OLLAMA_NUM_PARALLEL=4 \
  --gpu 1 \
  --gpu-type nvidia-l4 \
  --max-instances 1 \
  --memory 32Gi \
  --no-allow-unauthenticated \
  --no-cpu-throttling \
  --no-gpu-zonal-redundancy \
  --timeout=600 \
  --labels dev-tutorial=codelab-embedding-gemma

Comprendre la configuration

  • --source . spécifie le répertoire actuel comme source de compilation.
  • --region europe-west1, nous utilisons une région compatible avec les GPU sur Cloud Run.
  • --concurrency 4 est défini pour correspondre à la valeur de la variable d'environnement OLLAMA_NUM_PARALLEL.
  • --gpu 1 avec --gpu-type nvidia-l4 attribue un GPU NVIDIA L4 à chaque instance Cloud Run du service.
  • --max-instances 1 spécifie le nombre maximal d'instances à mettre à l'échelle. Elle doit être égale ou inférieure au quota de GPU NVIDIA L4 de votre projet.
  • --no-allow-unauthenticated limite l'accès non authentifié au service. En gardant le service privé, vous pouvez vous appuyer sur l'authentification Identity and Access Management (IAM) intégrée à Cloud Run pour la communication de service à service.
  • --no-cpu-throttling est requis pour activer le GPU.
  • --no-gpu-zonal-redundancy Définissez les options de redondance zonale en fonction de vos exigences de basculement zonal et du quota disponible.

Points à prendre en compte concernant les régions

Les GPU sur Cloud Run sont disponibles dans des régions spécifiques. Vous pouvez consulter les régions disponibles dans la documentation.

Résultat du déploiement

Au bout de quelques minutes, le déploiement sera terminé et un message semblable à celui-ci s'affichera :

Service [embedding-gemma] revision [embedding-gemma-12345-abc] has been deployed and is serving 100 percent of traffic.
Service URL: https://embedding-gemma-123456789012.europe-west1.run.app

5. Tester le déploiement

Comme nous avons déployé le service avec --no-allow-unauthenticated, nous ne pouvons pas simplement curl l'URL publique. Nous devons d'abord nous accorder l'autorisation d'accéder au service et d'utiliser le jeton d'authentification dans la requête.

  1. Autorisez votre compte utilisateur à appeler le service :
    gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
        --member=user:$(gcloud config get-value account) \
        --role='roles/run.invoker'
    
  2. Enregistrez vos identifiants Google Cloud et le numéro de votre projet dans des variables d'environnement à utiliser dans la requête :
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    export ID_TOKEN=$(gcloud auth print-identity-token)
    
  3. Exécutez la commande suivante pour générer un embedding pour "Texte exemple" :
    curl -X POST "https://embedding-gemma-$PROJECT_NUMBER.europe-west1.run.app/api/embed" \
        -H "Authorization: Bearer $ID_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{
            "model": "embeddinggemma",
            "input": "Sample text"
        }'
    

Vous devriez obtenir une réponse JSON contenant un vecteur (une longue liste de nombres) dans le champ embedding. Cela confirme que votre modèle d'embedding sans serveur basé sur GPU fonctionne.

La réponse doit ressembler à ceci : Sortie Curl d&#39;EmbeddingGemma

Client Python

Vous pouvez également utiliser Python pour interagir avec le service. Créez un fichier nommé test_client.py :

import urllib.request
import urllib.parse
import json
import os

# 1. Setup the URL and Payload
url = f"https://embedding-gemma-{os.environ['PROJECT_NUMBER']}.europe-west1.run.app/api/embed"
payload = {
    "model": "embeddinggemma",
    "input": "Sample text"
}

# 2. Create the Request object
# Note: Providing 'data' automatically makes this a POST request
req = urllib.request.Request(
    url,
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {os.environ['ID_TOKEN']}",
        "Content-Type": "application/json"
    }
)

# 3. Execute and print the response
response = urllib.request.urlopen(req)
result = json.loads(response.read().decode("utf-8"))
print(result)

Exécutez l'agent :

python test_client.py

6. Créer une application de recherche sémantique

Maintenant que nous disposons d'un service d'embedding fonctionnel, créons une application de recherche sémantique simple. Nous utiliserons les embeddings générés pour trouver le document le plus pertinent pour une requête donnée.

Dépendances

Nous utiliserons chromadb comme base de données vectorielle et la bibliothèque cliente ollama.

uv init semantic-search --description "Semantic Search Application"
cd semantic-search
uv add chromadb ollama

Créer l'application de recherche

Créez un fichier nommé semantic_search.py avec le code suivant :

import ollama
import chromadb
import os

# 1. Define our knowledge base
documents = [
    "Poland is a country located in Central Europe.",
    "The capital and largest city of Poland is Warsaw.",
    "Poland's official language is Polish, which is a West Slavic language.",
    "Marie Curie, the pioneering scientist who conducted groundbreaking research on radioactivity, was born in Warsaw, Poland.",
    "Poland is famous for its traditional dish called pierogi, which are filled dumplings.",
    "The Białowieża Forest in Poland is one of the last and largest remaining parts of the immense primeval forest that once stretched across the European Plain.",
]

print("Initializing Vector Database...")
client = chromadb.Client()
collection = client.create_collection(name="docs")

# Configure the client to point to our Cloud Run proxy
ollama_client = ollama.Client(
    host=f"https://embedding-gemma-{os.environ['PROJECT_NUMBER']}.europe-west1.run.app",
    headers={'Authorization': 'Bearer ' + os.environ['ID_TOKEN']}
)

print("Generating embeddings and indexing documents...")
# 2. Store each document in the vector database
for i, d in enumerate(documents):
    # This calls our Cloud Run service to get the embedding
    response = ollama_client.embed(model="embeddinggemma", input=d)
    embeddings = response["embeddings"]
    collection.add(ids=[str(i)], embeddings=embeddings, documents=[d])

print("Indexing complete.\n")

# 3. Perform a Semantic Search
question = "What is Poland's official language?"
print(f"Query: {question}")

# Generate an embedding for the question
response = ollama_client.embed(model="embeddinggemma", input=question)

# Query the database for the most similar document
results = collection.query(
    query_embeddings=[response["embeddings"][0]],
    n_results=1
)

best_match = results["documents"][0][0]
print(f"Best Match Document: {best_match}")

Exécuter l'application

Exécutez le script suivant :

uv run semantic_search.py

Le résultat doit ressembler à ce qui suit :

Initializing Vector Database...
Generating embeddings and indexing documents...
Indexing complete.

Query: What is Poland's official language?
Best Match Document: Poland's official language is Polish, which is a West Slavic language.

Ce script illustre le cœur d'un système RAG : l'utilisation de votre service EmbeddingGemma sans serveur pour convertir les documents et les requêtes en vecteurs, ce qui vous permet de trouver les informations exactes nécessaires pour répondre à la question d'un utilisateur.

7. Effectuer un nettoyage

Pour éviter que les ressources créées lors de cet atelier de programmation soient facturées en permanence sur votre compte Google Cloud, supprimez-les.

Supprimer le service Cloud Run

gcloud run services delete embedding-gemma --region europe-west1 --quiet

Supprimer l'image de conteneur

gcloud artifacts docker images delete \
    europe-west1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/cloud-run-source-deploy/embedding-gemma \
    --quiet

8. Félicitations

Félicitations ! Vous avez déployé EmbeddingGemma sur Cloud Run avec des GPU et l'avez utilisé pour alimenter une application de recherche sémantique.

Vous disposez désormais d'une base évolutive et sans serveur pour créer des applications d'IA qui nécessitent de comprendre la signification du texte.

Connaissances acquises

  • Comment conteneuriser un modèle Ollama avec Docker
  • Découvrez comment déployer un service avec GPU sur Cloud Run.
  • Utiliser le modèle déployé pour la recherche sémantique (RAG)

Étapes suivantes

Documents de référence