AI serverless: incorporare Gemma con Cloud Run

1. Introduzione

In questo codelab imparerai a eseguire il deployment di EmbeddingGemma, un potente modello di incorporamento di testo multilingue, su Cloud Run utilizzando le GPU. Utilizzerai poi questo servizio di deployment per generare embedding per un'applicazione di ricerca semantica.

A differenza dei modelli linguistici di grandi dimensioni (LLM) tradizionali che generano testo, i modelli di embedding convertono il testo in vettori numerici. Questi vettori sono fondamentali per la creazione di sistemi di Retrieval-Augmented Generation (RAG), che consentono di trovare i documenti più pertinenti per la query di un utente.

In questo lab proverai a:

  • Inserisci il modello EmbeddingGemma in un container utilizzando Ollama.
  • Esegui il deployment del container in Cloud Run con l'accelerazione GPU.
  • Testa il modello di cui è stato eseguito il deployment generando embedding per il testo di esempio.
  • Crea un sistema di ricerca semantica leggero utilizzando il servizio di cui hai eseguito il deployment.

Che cosa ti serve

  • Un progetto Google Cloud con la fatturazione abilitata.
  • Familiarità di base con Docker e la riga di comando.

2. Prima di iniziare

Configurazione del progetto

  1. Se non hai ancora un Account Google, devi crearne uno.
    • Utilizza un account personale anziché un account di lavoro o della scuola. Gli account di lavoro e della scuola potrebbero avere limitazioni che impediscono l'attivazione delle API necessarie per questo lab.
  2. Accedi a Google Cloud Console.
  3. Abilita la fatturazione nella console Cloud.
    • Il completamento di questo lab dovrebbe costare meno di 1 $in risorse cloud.
    • Per evitare ulteriori addebiti, puoi seguire i passaggi alla fine di questo lab per eliminare le risorse.
    • I nuovi utenti hanno diritto alla prova senza costi di 300$.
  4. Crea un nuovo progetto o scegli di riutilizzarne uno esistente.
    • Se visualizzi un errore relativo alla quota del progetto, riutilizza un progetto esistente o eliminalo per crearne uno nuovo.

Avvia Cloud Shell

Cloud Shell è un ambiente a riga di comando in esecuzione in Google Cloud che viene precaricato con gli strumenti necessari.

  1. Fai clic su Attiva Cloud Shell nella parte superiore della console Google Cloud.
  2. Una volta connesso a Cloud Shell, verifica l'autenticazione:
    gcloud auth list
    
  3. Verifica che il progetto sia selezionato:
    gcloud config get project
    
  4. Impostalo se necessario:
    gcloud config set project <YOUR_PROJECT_ID>
    

Abilita API

Esegui questo comando per abilitare tutte le API richieste:

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

3. Containerizza il modello

Per eseguire EmbeddingGemma in modalità serverless, dobbiamo pacchettizzarlo in un container. Utilizzeremo Ollama, un framework leggero per l'esecuzione di LLM, e Docker.

Crea il Dockerfile

In Cloud Shell, crea una nuova directory per il tuo progetto e accedi alla directory:

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

Crea un file denominato Dockerfile con i seguenti contenuti:

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

Questo Dockerfile esegue le seguenti operazioni:

  1. Inizia dall'immagine di base ufficiale di Ollama.
  2. Configura Ollama per l'ascolto sulla porta 8080 (valore predefinito di Cloud Run).
  3. Il comando RUN avvia il server ollama e scarica il modello embeddinggemma durante il processo di build, in modo che venga incorporato nell'immagine.
  4. Imposta OLLAMA_KEEP_ALIVE=-1 per garantire che il modello rimanga caricato nella memoria della GPU per richieste successive più rapide.

4. Creazione e deployment

Utilizzeremo il deployment dell'origine Cloud Run per creare ed eseguire il deployment del nostro container in un unico passaggio. Questo comando crea l'immagine utilizzando Cloud Build, la archivia in Artifact Registry e ne esegue il deployment su Cloud Run.

Esegui questo comando per eseguire il deployment:

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

Informazioni sulla configurazione

  • --source . specifica la directory corrente come origine della build.
  • --region europe-west1 utilizziamo una regione che supporta le GPU su Cloud Run.
  • --concurrency 4 è impostato in modo che corrisponda al valore della variabile di ambiente OLLAMA_NUM_PARALLEL.
  • --gpu 1 con --gpu-type nvidia-l4 assegna una GPU NVIDIA L4 a ogni istanza Cloud Run nel servizio.
  • --max-instances 1 specifica il numero massimo di istanze a cui eseguire lo scale up. Deve essere uguale o inferiore alla quota di GPU NVIDIA L4 del tuo progetto.
  • --no-allow-unauthenticated limita l'accesso non autenticato al servizio. Mantenendo privato il servizio, puoi fare affidamento sull'autenticazione Identity and Access Management (IAM) integrata di Cloud Run per la comunicazione tra servizi.
  • --no-cpu-throttling è necessario per abilitare la GPU.
  • --no-gpu-zonal-redundancy imposta le opzioni di ridondanza a livello di zona in base ai requisiti di failover a livello di zona e alla quota disponibile.

Considerazioni sulle regioni

Le GPU su Cloud Run sono disponibili in regioni specifiche. Puoi controllare le regioni supportate nella documentazione.

Output del deployment

Dopo alcuni minuti, il deployment verrà completato e verrà visualizzato un messaggio simile a questo:

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. Testare il deployment

Poiché abbiamo eseguito il deployment del servizio con --no-allow-unauthenticated, non possiamo semplicemente curl l'URL pubblico. Innanzitutto, dobbiamo concederci l'autorizzazione per accedere al servizio e utilizzare il token di autenticazione nella richiesta.

  1. Concedi al tuo account utente l'autorizzazione per chiamare il servizio:
    gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
        --member=user:$(gcloud config get-value account) \
        --role='roles/run.invoker'
    
  2. Salva le credenziali Google Cloud e il numero di progetto nelle variabili di ambiente da utilizzare nella richiesta:
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    export ID_TOKEN=$(gcloud auth print-identity-token)
    
  3. Esegui questo comando per generare un embedding per "Sample text":
    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"
        }'
    

Dovresti visualizzare una risposta JSON contenente un vettore (un lungo elenco di numeri) nel campo embedding. Ciò conferma che il modello di incorporamento serverless basato su GPU funziona.

La risposta sarà simile alla seguente: EmbeddingGemma Curl Output

Client Python

Puoi anche utilizzare Python per interagire con il servizio. Crea un file denominato 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)

Esegui:

python test_client.py

6. Creare un'applicazione di ricerca semantica

Ora che abbiamo un servizio di incorporamento funzionante, creiamo una semplice applicazione di ricerca semantica. Utilizzeremo gli incorporamenti generati per trovare il documento più pertinente per una determinata query.

Dipendenze

Utilizzeremo chromadb come database vettoriale e la libreria client ollama.

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

Crea l'applicazione di ricerca

Crea un file denominato semantic_search.py con il seguente codice:

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

Esegui l'applicazione

Esegui lo script:

uv run semantic_search.py

Dovresti visualizzare un output simile a questo:

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.

Questo script mostra il nucleo di un sistema RAG: l'utilizzo del servizio EmbeddingGemma serverless per convertire sia i documenti che le query in vettori, consentendoti di trovare le informazioni esatte necessarie per rispondere alla domanda di un utente.

7. Esegui la pulizia

Per evitare addebiti continui al tuo account Google Cloud, elimina le risorse create durante questo codelab.

Elimina il servizio Cloud Run

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

Elimina l'immagine container

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

8. Complimenti

Complimenti! Hai eseguito il deployment di EmbeddingGemma su Cloud Run con GPU e lo hai utilizzato per potenziare un'applicazione di ricerca semantica.

Ora hai una base scalabile e serverless per creare applicazioni di AI che richiedono la comprensione del significato del testo.

Cosa hai imparato

  • Come containerizzare un modello Ollama con Docker.
  • Come eseguire il deployment di un servizio abilitato alla GPU su Cloud Run.
  • Come utilizzare il modello di cui è stato eseguito il deployment per la ricerca semantica (RAG).

Passaggi successivi

Documenti di riferimento