AlloyDB Omni i EmbeddingGemma z Gemma 4 w Kubernetes

1. Wprowadzenie

W tym ćwiczeniu dowiesz się, jak wdrożyć bazę danych AlloyDB Omni w Google Kubernetes Engine (GKE) i używać jej z otwartymi modelami, takimi jak EmbeddingGemma i Gemma 4, do tworzenia wektorów dystrybucyjnych i prognoz. Uruchamianie bazy danych i modeli w tym samym klastrze zmniejsza opóźnienie sieci i pozwala uniknąć zależności od usług innych firm. Pomaga też spełniać wymagania dotyczące zgodności i miejsca przechowywania danych, ponieważ dane nigdy nie opuszczają Twojego środowiska.

Schemat architektury AlloyDB Omni i EmbeddingGemma w GKE

Wymagania wstępne

  • Podstawowa wiedza o Google Cloud i konsoli Google Cloud
  • Podstawowa znajomość Kubernetes i GKE
  • Znajomość interfejsu wiersza poleceń i Google Cloud Shell

Czego się nauczysz

  • Jak wdrożyć AlloyDB Omni w klastrze GKE
  • Łączenie się z AlloyDB Omni
  • Wczytywanie danych do AlloyDB Omni
  • Jak wdrażać modele AI (wektorów dystrybucyjnych i LLM) w GKE
  • Jak rejestrować modele AI w AlloyDB Omni
  • Jak generować wektory dystrybucyjne na potrzeby wyszukiwania semantycznego
  • Jak uruchamiać zapytania wyszukiwania semantycznego w AlloyDB Omni
  • Jak tworzyć i używać indeksów wektorowych w AlloyDB Omni

Czego potrzebujesz

  • konto Google Cloud i projekt w chmurze Google Cloud,
  • przeglądarka, np. Chrome;

2. Konfiguracja i wymagania

Konfigurowanie projektu

  1. Zaloguj się w konsoli Google Cloud. Jeśli nie masz jeszcze konta Gmail lub Google Workspace, utwórz je. Używaj konta osobistego zamiast konta służbowego lub szkolnego.
  1. Utwórz nowy projekt lub wybierz już istniejący. W nagłówku konsoli Google Cloud kliknij Wybierz projekt, a następnie Nowy projekt.

Okno wyboru projektu w konsoli Google Cloud

W oknie Wybierz projekt kliknij Nowy projekt, aby otworzyć okno tworzenia projektu.

Okno tworzenia nowego projektu

W oknie wpisz nazwę projektu i wybierz organizację lub lokalizację.

Pola do wprowadzania szczegółów projektu

  • Nazwa projektu to wyświetlana nazwa dla uczestników tego projektu. Nazwa projektu nie jest używana przez interfejsy API Google i możesz ją w każdej chwili zmienić.
  • Identyfikator projektu jest unikalny we wszystkich projektach Google Cloud i nie można go zmienić po ustawieniu. Konsola Google Cloud automatycznie wygeneruje unikalny identyfikator, ale możesz też podać własny. W tym samouczku identyfikator projektu jest oznaczony symbolem zastępczym .
  • Numer projektu to trzeci identyfikator używany przez niektóre interfejsy API. Więcej informacji znajdziesz w dokumentacji Resource Managera.

Włącz płatności

Jeśli skonfigurujesz płatności za pomocą środków w Google Cloud, możesz pominąć ten krok.

Aby skonfigurować osobiste konto rozliczeniowe, włącz rozliczenia w konsoli Google Cloud.

  • Ukończenie tego modułu kosztuje mniej niż 5 USD w zasobach Google Cloud.
  • Aby usunąć zasoby i uniknąć dalszych opłat, wykonaj czynności opisane na końcu tego modułu.
  • Nowi użytkownicy mogą skorzystać z bezpłatnego okresu próbnego o wartości 300 USD.

Uruchamianie Cloud Shell

W tym ćwiczeniu użyjesz Google Cloud Shell, czyli środowiska wiersza poleceń działającego w chmurze.

W konsoli Google Cloud kliknij ikonę Aktywuj Cloud Shell na pasku narzędzi w prawym górnym rogu:

Przycisk aktywacji Cloud Shell

Możesz też nacisnąć G, a potem S lub otworzyć Google Cloud Shell bezpośrednio.

Po nawiązaniu połączenia w Cloud Shell pojawi się prompt terminala:

Zrzut ekranu przedstawiający terminal Google Cloud Shell

Cloud Shell obejmuje pamięć trwałą i narzędzia dla programistów. Wszystkie kroki w tym laboratorium możesz wykonać w przeglądarce.

3. Włącz interfejsy API

Aby używać Google Kubernetes Engine (GKE) do wdrażania AlloyDB Omni i modeli, włącz w projekcie Google Cloud interfejsy API Compute Engine i GKE.

W Cloud Shell sprawdź, czy identyfikator projektu jest skonfigurowany:

PROJECT_ID=$(gcloud config get-value project)
echo $PROJECT_ID

Jeśli identyfikator projektu nie jest zdefiniowany, skonfiguruj go:

export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID

Włącz wymagane interfejsy API:

gcloud services enable compute.googleapis.com
gcloud services enable container.googleapis.com

Oczekiwane dane wyjściowe:

student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=test-project-001-402417
student@cloudshell:~ (test-project-001-402417)$ gcloud config set project test-project-001-402417
Updated property [core/project].
student@cloudshell:~ (test-project-001-402417)$ gcloud services enable compute.googleapis.com
gcloud services enable container.googleapis.com
Operation "operations/acat.p2-4470404856-1f44ebd8-894e-4356-bea7-b84165a57442" finished successfully.

Informacje o każdym włączonym interfejsie API znajdziesz w dokumentacji.

4. Wdrażanie AlloyDB Omni w GKE

Aby wdrożyć AlloyDB Omni w GKE, przygotuj klaster Kubernetes zgodnie z wymaganiami operatora AlloyDB Omni.

Tworzenie klastra GKE

Wdróż standardowy klaster GKE o pojemności wystarczającej do uruchomienia kontenerów AlloyDB Omni, operatora i monitorowania. AlloyDB Omni wymaga co najmniej 2 procesorów i 8 GB pamięci RAM. W tym samouczku używany jest typ maszyny n2-standard-4.

Ustaw zmienne środowiskowe dla wdrożenia:

export PROJECT_ID=$(gcloud config get-value project)
export LOCATION=us-central1
export CLUSTER_NAME=alloydb-ai-gke
export MACHINE_TYPE=n2-standard-4

Utwórz standardowy klaster GKE:

gcloud container clusters create ${CLUSTER_NAME} \
  --project=${PROJECT_ID} \
  --region=${LOCATION} \
  --workload-pool=${PROJECT_ID}.svc.id.goog \
  --release-channel=rapid \
  --machine-type=${MACHINE_TYPE} \
  --num-nodes=1

Oczekiwane dane wyjściowe konsoli:

student@cloudshell:~ (test-project-001-402417)$ export PROJECT_ID=$(gcloud config get project)
export LOCATION=us-central1
export CLUSTER_NAME=alloydb-ai-gke
export MACHINE_TYPE=n2-standard-4
Your active configuration is: [test-project-001-402417]
student@cloudshell:~ (test-project-001-402417)$ gcloud container clusters create ${CLUSTER_NAME} \
  --project=${PROJECT_ID} \
  --region=${LOCATION} \
  --workload-pool=${PROJECT_ID}.svc.id.goog \
  --release-channel=rapid \
  --machine-type=${MACHINE_TYPE} \
  --num-nodes=1
Note: Your Pod address range (`--cluster-ipv4-cidr`) can accommodate at most 1008 node(s).
Creating cluster alloydb-ai-gke in us-central1... Cluster is being health-checked (Kubernetes Control Plane is healthy)...done.                                                                                            
Created [https://container.googleapis.com/v1/projects/test-project-001-402417/zones/us-central1/clusters/alloydb-ai-gke].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1/alloydb-ai-gke?project=test-project-001-402417
kubeconfig entry generated for alloydb-ai-gke.
NAME: alloydb-ai-gke
LOCATION: us-central1
MASTER_VERSION: 1.36.3-gke.1640000
MASTER_IP: 34.121.243.65
MACHINE_TYPE: n2-standard-4
NODE_VERSION: 1.36.3-gke.1640000
NUM_NODES: 3
STATUS: RUNNING
STACK_TYPE: IPV4

Przygotowywanie klastra

Zainstaluj wymagane komponenty, takie jak cert-manager, natywny kontroler certyfikatów dla Kubernetes. Szczegółowe informacje znajdziesz w dokumentacji instalacji cert-manager.

Cloud Shell zawiera narzędzie wiersza poleceń Kubernetes kubectl. Uzyskaj dane logowania do klastra za pomocą polecenia gcloud:

gcloud container clusters get-credentials ${CLUSTER_NAME} --region=${LOCATION}

Zainstaluj cert-manager za pomocą narzędzia kubectl:

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.21.1/cert-manager.yaml

Oczekiwane dane wyjściowe konsoli (zredagowane):

student@cloudshell:~$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.21.1/cert-manager.yaml
namespace/cert-manager created
customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
...
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created

Instalowanie operatora AlloyDB Omni

Zainstaluj operatora AlloyDB Omni za pomocą narzędzia Helm.

Pobierz i zainstaluj wykres operatora AlloyDB Omni:

helm install alloydbomni-operator oci://gcr.io/alloydb-omni/alloydbomni-operator \
--version 1.8.1 \
--create-namespace \
--namespace alloydb-omni-system \
--atomic \
--timeout 5m

Oczekiwane dane wyjściowe konsoli (zredagowane):

student@cloudshell:~$ helm install alloydbomni-operator oci://gcr.io/alloydb-omni/alloydbomni-operator \
> --version 1.8.0 \
> --create-namespace \
> --namespace alloydb-omni-system \
> --atomic \
> --timeout 5m
Flag --atomic has been deprecated, use --rollback-on-failure instead
Pulled: gcr.io/alloydb-omni/alloydbomni-operator:1.8.0
Digest: sha256:f2d98fa7a3b08dfc1e83b811582718b94e5c017b81aade700c83e917c59f0395
NAME: alloydbomni-operator
LAST DEPLOYED: Thu Aug 27 17:57:30 2026
NAMESPACE: alloydb-omni-system
STATUS: deployed
REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None

Wdróż klaster bazy danych.

Poniższy manifest konfiguruje klaster bazy danych z włączonym googleMLExtension i wewnętrznym modułem równoważenia obciążenia:

cat << 'EOF' > my-omni.yaml
apiVersion: v1
kind: Secret
metadata:
  name: db-pw-my-omni
type: Opaque
data:
  my-omni: "VmVyeVN0cm9uZ1Bhc3N3b3Jk"
---
apiVersion: alloydbomni.dbadmin.goog/v1
kind: DBCluster
metadata:
  name: my-omni
spec:
  databaseVersion: "18.3.0"
  primarySpec:
    adminUser:
      passwordRef:
        name: db-pw-my-omni
    features:
      googleMLExtension:
        enabled: true
    resources:
      cpu: 1
      memory: 8Gi
      disks:
      - name: DataDisk
        size: 20Gi
        storageClass: standard
    dbLoadBalancerOptions:
      annotations:
        networking.gke.io/load-balancer-type: "internal"
  allowExternalIncomingTraffic: true
EOF

Wartość tajnego hasła to reprezentacja VeryStrongPassword w formacie Base64. W środowiskach produkcyjnych do zarządzania hasłami należy używać narzędzia Google Secret Manager. Więcej informacji znajdziesz w dokumentacji Secret Manager.

Plik manifestu zostanie zapisany jako my-omni.yaml. W Cloud Shell kliknij Otwórz edytor w prawym górnym rogu okna terminala i odczytaj plik.

Otwórz edytor w Cloud Shell

Po przeczytaniu manifestu my-omni.yaml kliknij Otwórz terminal, aby powrócić do wiersza poleceń.

Otwieranie terminala w Cloud Shell

Zastosuj manifest my-omni.yaml:

kubectl apply -f my-omni.yaml

Oczekiwane dane wyjściowe konsoli:

secret/db-pw-my-omni created
dbcluster.alloydbomni.dbadmin.goog/my-omni created

Sprawdź status klastra my-omni:

kubectl get dbclusters.alloydbomni.dbadmin.goog my-omni -n default

Podczas wdrażania klaster bazy danych przechodzi przez fazy konfiguracji, aż osiągnie stan DBClusterReady.

Oczekiwane dane wyjściowe konsoli:

$ kubectl get dbclusters.alloydbomni.dbadmin.goog my-omni -n default
NAME      PRIMARYENDPOINT   PRIMARYPHASE   DBCLUSTERPHASE   HAREADYSTATUS   HAREADYREASON
my-omni   10.131.0.33        Ready          DBClusterReady

Opcjonalnie możesz monitorować wdrażanie klastra za pomocą polecenia kubectl log:

kubectl logs -l alloydbomni.internal.dbadmin.goog/dbcluster=my-omni --all-containers -f

Połącz się z AlloyDB Omni

Gdy klaster będzie gotowy, połącz się z podejściem bazy danych za pomocą klienta PostgreSQL (psql). Hasło to VeryStrongPassword, zgodnie z definicją w my-omni.yaml:

DB_CLUSTER_NAME=my-omni
DB_CLUSTER_NAMESPACE=default
DBPOD=`kubectl get pod --selector=alloydbomni.internal.dbadmin.goog/dbcluster=$DB_CLUSTER_NAME,alloydbomni.internal.dbadmin.goog/task-type=database -n $DB_CLUSTER_NAMESPACE -o jsonpath='{.items[0].metadata.name}'`
kubectl exec -ti $DBPOD -n $DB_CLUSTER_NAMESPACE -c database -- psql -h localhost -U postgres

Przykładowe dane wyjściowe konsoli:

DB_CLUSTER_NAME=my-omni
DB_CLUSTER_NAMESPACE=default
DBPOD=`kubectl get pod --selector=alloydbomni.internal.dbadmin.goog/dbcluster=$DB_CLUSTER_NAME,alloydbomni.internal.dbadmin.goog/task-type=database -n $DB_CLUSTER_NAMESPACE -o jsonpath='{.items[0].metadata.name}'`
kubectl exec -ti $DBPOD -n $DB_CLUSTER_NAMESPACE -c database -- psql -h localhost -U postgres
Password for user postgres:
psql (18.3)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_128_GCM_SHA256, compression: off, ALPN: postgresql)
Type "help" for help.

postgres=#

Zakończ sesję psql, wpisując \q i naciskając Enter:

postgres=# \q

5. Wdrażanie modelu EmbeddingGemma w GKE

Aby przetestować integrację AI w AlloyDB Omni z modelami lokalnymi, wdróż model wektorów dystrybucyjnych w klastrze GKE. W tym samouczku używany jest model EmbeddingGemma od Google.

Tworzenie puli węzłów dla modelu

Aby uruchomić wnioskowanie modelu, przygotuj dedykowaną pulę węzłów. Możesz użyć puli węzłów tylko z procesorem lub puli węzłów z akceleracją GPU (np. g2-standard-8 z procesorem graficznym NVIDIA L4). W tym samouczku używana jest pula węzłów oparta na procesorze z typami maszyn c3-standard-8.

Utwórz pulę węzłów CPU z 1 węzłem:

export PROJECT_ID=$(gcloud config get-value project)
export LOCATION=us-central1
export CLUSTER_NAME=alloydb-ai-gke
gcloud container node-pools create cpupool \
  --project=${PROJECT_ID} \
  --location=${LOCATION} \
  --node-locations=${LOCATION}-a \
  --cluster=${CLUSTER_NAME} \
  --machine-type=c3-standard-8 \
  --num-nodes=1

Oczekiwane dane wyjściowe:

student@cloudshell$ export PROJECT_ID=$(gcloud config get project)
Your active configuration is: [pant]
export LOCATION=us-central1
export CLUSTER_NAME=alloydb-ai-gke
student@cloudshell$ gcloud container node-pools create cpupool \
>   --project=${PROJECT_ID} \
>   --location=${LOCATION} \
>   --node-locations=${LOCATION}-a \
>   --cluster=${CLUSTER_NAME} \
>   --machine-type=c3-standard-8 \
>   --num-nodes=1
Creating node pool cpupool...done.
Created [https://container.googleapis.com/v1/projects/gleb-test-short-003-483115/zones/us-central1/clusters/alloydb-ai-gke/nodePools/cpupool].
NAME     MACHINE_TYPE    DISK_SIZE_GB  NODE_VERSION
cpupool  c3-standard-8  100           1.34.1-gke.3355002

Uzyskiwanie tokena Hugging Face

W tym samouczku wdrażamy model EmbeddingGemma z Hugging Face. Aby uzyskać dostęp do wag modelu, wygeneruj token dostępu Hugging Face:

  1. Zaloguj się lub utwórz konto na platformie Hugging Face.
  2. Kliknij Twój profil > Tokeny dostępu.
  3. Kliknij Utwórz nowy token.
  4. Wpisz nazwę tokena i wybierz rolę Odczyt.
  5. Kliknij Utwórz token i skopiuj wygenerowaną wartość tokena.
  6. Zaakceptuj warunki modelu na stronie modelu EmbeddingGemma, jeśli nie zostały jeszcze przez Ciebie zaakceptowane.

Utwórz w Cloud Shell klucz tajny Kubernetes zawierający token Hugging Face (zastąp symbol zastępczy tokena swoim tokenem):

export HF_TOKEN=<YOUR_HUGGING_FACE_TOKEN>
kubectl create secret generic hf-secret \
  --from-literal=hf_api_token=$HF_TOKEN \
  --dry-run=client -o yaml | kubectl apply -f -

Przygotuj plik manifestu wdrożenia

Aby wdrożyć model, użyj pakietu kontenera Hugging Face Text Embeddings Inference (TEI). Więcej informacji znajdziesz w dokumentacji Hugging Face GKE TEI.

Sklonuj repozytorium wdrożenia z GitHuba:

git clone https://github.com/huggingface/Google-Cloud-Containers

Sprawdź i zmodyfikuj manifest konfiguracji procesora:

edit Google-Cloud-Containers/examples/gke/tei-deployment/cpu-config/deployment.yaml

Zaktualizowany plik manifestu wdrożenia na procesorze:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tei-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tei-server
  template:
    metadata:
      labels:
        app: tei-server
        hf.co/model: Google--embeddinggemma-300m
        hf.co/task: text-embeddings
    spec:
      containers:
        - name: tei-container
          image: ghcr.io/huggingface/text-embeddings-inference:cpu-latest
          resources:
            requests:
              cpu: "6"
              memory: "24Gi"
            limits:
              cpu: "6"
              memory: "24Gi"
          env:
            - name: MODEL_ID
              value: google/embeddinggemma-300m
            - name: NUM_SHARD
              value: "1"
            - name: PORT
              value: "8080"
            - name: HF_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_api_token
          volumeMounts:
            - mountPath: /tmp
              name: tmp
      volumes:
        - name: tmp
          emptyDir: {}
      nodeSelector:
        cloud.google.com/machine-family: "c3"

Zapisz zmiany, naciskając ctrl+s, i wróć do terminala.

Wdróż model

Zastosuj plik manifestu, aby wdrożyć serwer TEI:

kubectl apply -f Google-Cloud-Containers/examples/gke/tei-deployment/cpu-config

Monitoruj wdrożenie, aż osiągnie stan gotowości:

printf "Waiting for model to load..."; until kubectl logs -l app=tei-server --tail=50 2>/dev/null | grep -q "Ready"; do printf "."; sleep 3; done; printf '\n\033[1;32m========================================\n[SUCCESS] Model is loaded and ready!\nYou can now proceed to the next step.\n========================================\033[0m\n'

Zaznacz tei-service Usługa Kubernetes:

kubectl get service tei-service

Oczekiwane dane wyjściowe:

student@cloudshell$ kubectl get service tei-service
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
tei-service   ClusterIP   34.118.233.48   <none>        8080/TCP   10m

Usługa CLUSTER-IP obsługuje żądania wewnętrznie pod adresem http://34.118.233.48:8080/embed.

Przetestuj lokalnie punkt końcowy modelu za pomocą kubectl port-forward:

kubectl port-forward service/tei-service 8080:8080

Otwórz drugą kartę Cloud Shell, klikając + u góry terminala:

Dodawanie karty Cloud Shell

Na nowej karcie przetestuj generowanie wektorów dystrybucyjnych za pomocą curl:

curl http://localhost:8080/embed \
  -X POST \
  -d '{"inputs":"Test"}' \
  -H 'Content-Type: application/json'

Oczekiwane dane wyjściowe (tablica wektorów):

curl http://localhost:8080/embed \
>     -X POST \
>     -d '{"inputs":"Test"}' \
>     -H 'Content-Type: application/json'
[[-0.018975832,0.0071419072,0.06347208,0.022992613,0.014205903
...
-0.03677433,0.01636146,0.06731572]]

Zatrzymaj przekierowywanie portów na pierwszej karcie, naciskając ctrl+c.

6. Zarejestruj model wektorów dystrybucyjnych w AlloyDB Omni

Aby użyć wdrożonego modelu w AlloyDB Omni, utwórz bazę danych, zdefiniuj funkcje przekształcania i zarejestruj punkt końcowy modelu.

Tworzenie klienckiej maszyny wirtualnej i bazy danych

Utwórz w tej samej sieci VPC instancję maszyny wirtualnej Compute Engine, która będzie pełnić rolę serwera skokowego klienta:

Schemat architektury sieci przedstawiający wirtualną maszynę klienta i AlloyDB Omni

W Cloud Shell utwórz kliencką maszynę wirtualną:

export ZONE=us-central1-a
gcloud compute instances create instance-1 \
  --zone=$ZONE

Pobierz adres IP punktu końcowego AlloyDB Omni:

echo "INSTANCE_IP=$(kubectl get dbclusters.alloydbomni.dbadmin.goog my-omni -n default -o jsonpath='{.status.primary.endpoint}')"

Oczekiwane dane wyjściowe:

INSTANCE_IP=10.128.0.33

Wartość INSTANCE_IP to wewnętrzny adres IP systemu równoważenia obciążenia dla klastra AlloyDB Omni. W tym przykładzie jest to 10.131.0.33.

Połącz się z instancją maszyny wirtualnej za pomocą SSH:

gcloud compute ssh instance-1 --zone=$ZONE

W sesji SSH na serwerze instance-1 zainstaluj klienta PostgreSQL:

sudo apt-get update && sudo apt-get install --yes postgresql-client 

Wyeksportuj adres IP systemu równoważenia obciążenia AlloyDB Omni (zastąp PRIMARYENDPOINT adresem IP):

export INSTANCE_IP=10.131.0.33

Połącz się z AlloyDB Omni za pomocą psql (hasło to VeryStrongPassword):

psql "host=$INSTANCE_IP user=postgres sslmode=require"

W sesji psql utwórz bazę danych demo:

CREATE DATABASE demo;

Przełącz się na bazę danych demo:

\c demo

Tworzenie funkcji przekształcenia

Niestandardowe punkty końcowe wektorów dystrybucyjnych wymagają funkcji przekształcania danych wejściowych i wyjściowych, aby dostosowywać formaty danych między AlloyDB Omni a interfejsem API modelu.

Utwórz funkcję przekształcenia danych wejściowych:

CREATE OR REPLACE FUNCTION tei_text_input_transform(model_id VARCHAR(100), input_text TEXT)
RETURNS JSON
LANGUAGE plpgsql
AS $$
DECLARE
  transformed_input JSON;
BEGIN
  SELECT json_build_object('inputs', input_text, 'truncate', true)::JSON INTO transformed_input;
  RETURN transformed_input;
END;
$$;

Oczekiwane dane wyjściowe:

demo=# CREATE OR REPLACE FUNCTION tei_text_input_transform(model_id VARCHAR(100), input_text TEXT)
RETURNS JSON
LANGUAGE plpgsql
AS $$
DECLARE
  transformed_input JSON;
BEGIN
  SELECT json_build_object('inputs', input_text, 'truncate', true)::JSON INTO transformed_input;
  RETURN transformed_input;
END;
$$;
CREATE FUNCTION
demo=#

Utwórz funkcję przekształcania danych wyjściowych, aby przeanalizować odpowiedź w postaci tablicy wektorów:

CREATE OR REPLACE FUNCTION tei_text_output_transform(model_id VARCHAR(100), response_json JSON)
RETURNS REAL[]
LANGUAGE plpgsql
AS $$
DECLARE
  transformed_output REAL[];
BEGIN
  SELECT ARRAY(SELECT json_array_elements_text(response_json->0)) INTO transformed_output;
  RETURN transformed_output;
END;
$$;

Oczekiwane dane wyjściowe:

demo=# CREATE OR REPLACE FUNCTION tei_text_output_transform(model_id VARCHAR(100), response_json JSON)
RETURNS REAL[]
LANGUAGE plpgsql
AS $$
DECLARE
  transformed_output REAL[];
BEGIN
  SELECT ARRAY(SELECT json_array_elements_text(response_json->0)) INTO transformed_output;
  RETURN transformed_output;
END;
$$;
CREATE FUNCTION
demo=#

Rejestrowanie modelu

Zarejestruj model w AlloyDB Omni za pomocą procedury google_ml.create_model. Określ http://tei-service:8080/embed jako model_request_url, aby kierować żądania do usługi klastra Kubernetes:

CALL
  google_ml.create_model(
    model_id => 'embeddinggemma',
    model_request_url => 'http://tei-service:8080/embed',
    model_provider => 'custom',
    model_type => 'text_embedding',
    model_in_transform_fn => 'tei_text_input_transform',
    model_out_transform_fn => 'tei_text_output_transform');

Oczekiwane dane wyjściowe:

demo=# CALL
  google_ml.create_model(
    model_id => 'embeddinggemma',
    model_request_url => 'http://tei-service:8080/embed',
    model_provider => 'custom',
    model_type => 'text_embedding',
    model_in_transform_fn => 'tei_text_input_transform',
    model_out_transform_fn => 'tei_text_output_transform');
CALL
demo=#

Przetestuj zarejestrowany model za pomocą przykładowego zapytania SQL:

SELECT google_ml.embedding('embeddinggemma', 'What is AlloyDB Omni?');

Funkcja zwraca reprezentację tablicy liczb rzeczywistych wygenerowaną przez lokalny model EmbeddingGemma działający w GKE.

Naciśnij q, aby wrócić do promptu sesji psql.

Zakończ sesję psql:

\q

7. Testowanie modelu za pomocą przykładowych danych

Wczytaj przykładowe dane

W tym samouczku używamy zbioru danych Cymbal dotyczących sprzedaży detalicznej, aby zademonstrować wyszukiwanie podobieństwa wektorowego. Do zaimportowania danych do AlloyDB Omni użyjesz pakietu Google Cloud SDK i klienta PostgreSQL.

W sesji SSH na serwerze instance-1 połącz się z bazą danych demo i włącz rozszerzenie vector:

psql "host=$INSTANCE_IP user=postgres sslmode=require dbname=demo"

W sesji psql:

CREATE EXTENSION IF NOT EXISTS vector;

Zakończ sesję psql:

\q

Pobierz i zastosuj schemat, aby utworzyć tabele w bazie danych demo:

gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |psql "host=$INSTANCE_IP user=postgres dbname=demo"

Oczekiwane dane wyjściowe:

student@cloudshell:~$ gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |psql "host=$INSTANCE_IP user=postgres dbname=demo"
Password for user postgres:
SET
SET
SET
SET
SET
 set_config
------------

(1 row)

SET
SET
SET
SET
SET
SET
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE SEQUENCE
ALTER TABLE
ALTER SEQUENCE
ALTER TABLE
ALTER TABLE
ALTER TABLE
student@cloudshell:~$

Sprawdź utworzone tabele:

psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\dt+"

Oczekiwane dane wyjściowe:

student@cloudshell:~$ psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\dt+"
Password for user postgres: 
                                           List of relations
 Schema |       Name       | Type  |  Owner   | Persistence | Access method |    Size    | Description 
--------+------------------+-------+----------+-------------+---------------+------------+-------------
 public | cymbal_embedding | table | postgres | permanent   | heap          | 8192 bytes | 
 public | cymbal_inventory | table | postgres | permanent   | heap          | 8192 bytes | 
 public | cymbal_products  | table | postgres | permanent   | heap          | 8192 bytes | 
 public | cymbal_stores    | table | postgres | permanent   | heap          | 8192 bytes | 
(4 rows)

Wczytaj dane do tabeli cymbal_products:

gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_products from stdin csv header"

Oczekiwane dane wyjściowe:

student@cloudshell:~$ gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_products from stdin csv header"
COPY 941
student@cloudshell:~$ 

Oto przykładowe wiersze z tabeli cymbal_products.

psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT uniq_id,left(product_name,30),left(product_description,50),sale_price FROM cymbal_products limit 3"

Oczekiwane dane wyjściowe:

student@cloudshell:~$ psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT uniq_id,left(product_name,30),left(product_description,50),sale_price FROM cymbal_products limit 3"
Password for user postgres: 
             uniq_id              |              left              |                        left                        | sale_price 
----------------------------------+--------------------------------+----------------------------------------------------+------------
 a73d5f754f225ecb9fdc64232a57bc37 | Laundry Tub Strainer Cup       |   Laundry tub strainer cup Chrome For 1-.50, drain |      11.74
 41b8993891aa7d39352f092ace8f3a86 | LED Starry Star Night Light La |  LED Starry Star Night Light Laser Projector 3D Oc |      46.97
 ed4a5c1b02990a1bebec908d416fe801 | Surya Horizon HRZ-1060 Area Ru |  The 100% polypropylene construction of the Surya  |       77.4
(3 rows)
student@cloudshell:~$ 

Wczytaj dane do tabeli cymbal_inventory:

gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_inventory from stdin csv header"

Oczekiwane dane wyjściowe:

student@cloudshell:~$ gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_inventory from stdin csv header"
Password for user postgres: 
COPY 263861
student@cloudshell:~$ 

Oto przykładowe wiersze z tabeli cymbal_inventory.

psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT * FROM cymbal_inventory LIMIT 3"

Dane wyjściowe:

student@cloudshell:~$ psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT * FROM cymbal_inventory LIMIT 3"
Password for user postgres: 
 store_id |             uniq_id              | inventory 
----------+----------------------------------+-----------
     1583 | adc4964a6138d1148b1d98c557546695 |         5
     1490 | adc4964a6138d1148b1d98c557546695 |         4
     1492 | adc4964a6138d1148b1d98c557546695 |         3
(3 rows)
student@cloudshell:~$ 

Wczytaj dane do tabeli cymbal_stores:

gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_stores from stdin csv header"

Oczekiwane dane wyjściowe konsoli:

student@cloudshell:~$ gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_stores from stdin csv header"
Password for user postgres: 
COPY 4654
student@cloudshell:~$

Oto przykładowe wiersze z tabeli cymbal_stores.

psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT store_id, name, zip_code FROM cymbal_stores limit 3"

Dane wyjściowe:

student@cloudshell:~$ psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT store_id, name, zip_code FROM cymbal_stores limit 3"
Password for user postgres: 
 store_id |       name        | zip_code 
----------+-------------------+----------
     1990 | Mayaguez Store    |      680
     2267 | Ware Supercenter  |     1082
     4359 | Ponce Supercenter |      780
(3 rows)
student@cloudshell:~$ 

Tworzenie wektorów dystrybucyjnych

Połącz się z bazą danych demonstracyjnych za pomocą psql i utwórz wektory osadzeń dla produktów opisanych w tabeli cymbal_products na podstawie opisów produktów.

Połącz się z bazą danych wersji demonstracyjnej:

psql "host=$INSTANCE_IP user=postgres sslmode=require dbname=demo"

Użyj kolumny embedding typu vector, aby przechowywać wygenerowane wektory dystrybucyjne tekstu dla opisów produktów.

Włącz pomiar czasu zapytań:

\timing

Wygeneruj wektory dystrybucyjne dla każdego opisu produktu i zapisz je w tabeli cymbal_embedding:

INSERT INTO cymbal_embedding (uniq_id, embedding)
SELECT uniq_id, google_ml.embedding('embeddinggemma', product_description)::vector
FROM cymbal_products;

Oczekiwane dane wyjściowe:

demo=# INSERT INTO cymbal_embedding(uniq_id,embedding)  SELECT uniq_id, google_ml.embedding('embeddinggemma',product_description)::vector FROM cymbal_products;
INSERT 0 941
Time: 497878.136 ms (08:17.878)
demo=#

Uruchamianie zapytań wyszukiwania semantycznego

psql sesji znajdź 5 najpopularniejszych produktów pasujących do pytania "What kind of fruit trees grow well here?", korzystając z odległości cosinusowej (<=>):

SELECT
    cp.product_name,
    left(cp.product_description, 80) AS description,
    cp.sale_price,
    cs.zip_code,
    (ce.embedding <=> google_ml.embedding('embeddinggemma', 'What kind of fruit trees grow well here?')::vector) AS distance
FROM
    cymbal_products cp
JOIN cymbal_embedding ce ON ce.uniq_id = cp.uniq_id
JOIN cymbal_inventory ci ON ci.uniq_id = cp.uniq_id
JOIN cymbal_stores cs ON cs.store_id = ci.store_id
WHERE
    ci.inventory > 0
    AND cs.store_id = 1583
ORDER BY
    distance ASC
LIMIT 5;

Oczekiwane dane wyjściowe:

demo=# SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        (ce.embedding <=> google_ml.embedding('embeddinggemma','What kind of fruit trees grow well here?')::vector) as distance
FROM
        cymbal_products cp
JOIN cymbal_embedding ce on ce.uniq_id=cp.uniq_id
JOIN cymbal_inventory ci on ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on cs.store_id=ci.store_id
WHERE
    ci.inventory > 0
    AND cs.store_id = 1583
ORDER BY
    distance ASC
LIMIT 5;
     product_name      |                                   description                                    | sale_price | zip_code |      distance
-----------------------+----------------------------------------------------------------------------------+------------+----------+--------------------
 Cherry Tree           | This is a beautiful cherry tree that will produce delicious cherries. It is an d |      75.00 |    93230 | 0.5210549378080666
 California Lilac      | This is a beautiful lilac tree that can grow to be over 10 feet tall. It is an d |       5.00 |    93230 | 0.5639421771781971
 Toyon                 | This is a beautiful toyon tree that can grow to be over 20 feet tall. It is an e |      10.00 |    93230 | 0.5670010914504852
 Rose Bush             | This is a beautiful rose bush that will produce fragrant roses. It is a perennia |      50.00 |    93230 | 0.5731542622882957
 California Peppertree | This is a beautiful peppertree that can grow to be over 30 feet tall. It is an e |      25.00 |    93230 | 0.5750934653011995
(5 rows)

Time: 83.610 ms
demo=#

Zapytanie zostało wykonane w 83 ms i zwróciło listę drzew z tabeli cymbal_products, które pasują do żądania i są dostępne w sklepie o numerze 1583.

Tworzenie indeksu ANN

W przypadku małego zbioru danych łatwo jest używać dokładnego wyszukiwania, które skanuje wszystkie osadzenia, ale gdy dane rosną, zwiększa się też czas ładowania i odpowiedzi. Aby zwiększyć wydajność, możesz utworzyć indeksy na podstawie danych o osadzaniu. Oto przykład, jak to zrobić za pomocą indeksu Google ScaNN w przypadku danych wektorowych.

Jeśli połączenie z bazą danych wersji demonstracyjnej zostało utracone, połącz się z nią ponownie:

psql "host=$INSTANCE_IP user=postgres sslmode=require dbname=demo"

Włącz rozszerzenie alloydb_scann:

CREATE EXTENSION IF NOT EXISTS alloydb_scann;

Utwórz indeks ScaNN w kolumnie embedding:

CREATE INDEX cymbal_products_embeddings_scann ON cymbal_embedding
  USING scann (embedding cosine)
  WITH (num_leaves=10, max_num_levels = 1);

Ponownie uruchom zapytanie wyszukiwania semantycznego, aby porównać skuteczność wykonania:

SELECT
    cp.product_name,
    left(cp.product_description, 80) AS description,
    cp.sale_price,
    cs.zip_code,
    (ce.embedding <=> google_ml.embedding('embeddinggemma', 'What kind of fruit trees grow well here?')::vector) AS distance
FROM
    cymbal_products cp
JOIN cymbal_embedding ce ON ce.uniq_id = cp.uniq_id
JOIN cymbal_inventory ci ON ci.uniq_id = cp.uniq_id
JOIN cymbal_stores cs ON cs.store_id = ci.store_id
WHERE
    ci.inventory > 0
    AND cs.store_id = 1583
ORDER BY
    distance ASC
LIMIT 5;

Oczekiwane dane wyjściowe:

demo=# SELECT
    cp.product_name,
    left(cp.product_description,80) as description,
    cp.sale_price,
    cs.zip_code,
    (ce.embedding <=> google_ml.embedding('embeddinggemma', 'What kind of fruit trees grow well here?')::vector) AS distance
FROM
    cymbal_products cp
JOIN cymbal_embedding ce ON ce.uniq_id = cp.uniq_id
JOIN cymbal_inventory ci ON ci.uniq_id = cp.uniq_id
JOIN cymbal_stores cs ON cs.store_id = ci.store_id
WHERE
    ci.inventory > 0
    AND cs.store_id = 1583
ORDER BY
    distance ASC
LIMIT 5;
     product_name      |                                   description                                    | sale_price | zip_code |      distance
-----------------------+----------------------------------------------------------------------------------+------------+----------+--------------------
 Cherry Tree           | This is a beautiful cherry tree that will produce delicious cherries. It is an d |      75.00 |    93230 | 0.5210549378080666
 California Lilac      | This is a beautiful lilac tree that can grow to be over 10 feet tall. It is an d |       5.00 |    93230 | 0.5639421771781971
 Toyon                 | This is a beautiful toyon tree that can grow to be over 20 feet tall. It is an e |      10.00 |    93230 | 0.5670010914504852
 Rose Bush             | This is a beautiful rose bush that will produce fragrant roses. It is a perennia |      50.00 |    93230 | 0.5731542622882957
 California Peppertree | This is a beautiful peppertree that can grow to be over 30 feet tall. It is an e |      25.00 |    93230 | 0.5750934653011995
(5 rows)

Time: 64.783 ms

Czas wykonywania zapytania nieco się skrócił, a wzrost wydajności będzie bardziej widoczny w przypadku większych zbiorów danych. Zwrócone dane powinny być takie same lub bardzo podobne do tych, które otrzymaliśmy bez indeksu.

Wypróbuj inne zapytania i dowiedz się więcej o optymalizacji indeksu wektorowego w dokumentacji.

Zakończ sesję psql:

\q

Wróć do Google Cloud Shell, odłączając się od sesji SSH instance-1, naciskając CTRL+D lub wpisując exit.

8. Wdrażanie Gemma z vLLM

Dodawanie puli węzłów dla Gemy

Najpierw sprawdź, jakie typy węzłów są dostępne w Twoim regionie:

export LOCATION=us-central1-a
gcloud compute accelerator-types list --filter="zone:${LOCATION}"

Powinna się wyświetlić lista dostępnych typów akceleratorów, w tym akcelerator nvidia-l4. Teraz utwórz pulę węzłów z akceleratorem typu nvidia-l4:

export PROJECT_ID=$(gcloud config get project)
export LOCATION=us-central1
export CLUSTER_NAME=alloydb-ai-gke
gcloud container node-pools create gpupool \
    --accelerator type=nvidia-l4,count=1,gpu-driver-version=latest \
    --project=${PROJECT_ID} \
    --location=${LOCATION} \
    --node-locations=${LOCATION}-a \
    --cluster=${CLUSTER_NAME} \
    --machine-type=g2-standard-8 \
    --num-nodes=1

Utwórz plik manifestu wdrożenia dla modelu Google Gemini 4 12B za pomocą vLLM:

cat << 'EOF' > gemma-12b-gpu-vllm-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gemma-12b-gpu-vllm-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gemma-12b-gpu-vllm
  template:
    metadata:
      labels:
        app: gemma-12b-gpu-vllm
        ai.gke.io/model: gemma-4-12b-it
        ai.gke.io/inference-server: vllm
        examples.ai.gke.io/source: user-guide
    spec:
      containers:
      - name: inference-server
        image: us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:latest
        resources:
          requests:
            cpu: "4"
            memory: "16Gi"
            ephemeral-storage: "30Gi"
            nvidia.com/gpu: "1"
          limits:
            cpu: "8"
            memory: "24Gi"
            ephemeral-storage: "30Gi"
            nvidia.com/gpu: "1"
        command: ["python3", "-m", "vllm.entrypoints.api_server"]
        args:
          - --model=$(MODEL_ID)
          - --host=0.0.0.0
          - --port=8000
          - --tensor-parallel-size=1
          - --enable-log-requests
          - --enable-chunked-prefill
          - --enable-prefix-caching
          - --enable-auto-tool-choice
          - --generation-config=auto
          - --tool-call-parser=gemma4
          - --dtype=bfloat16
          - --max-num-seqs=16
          - --max-model-len=32768
          - --gpu-memory-utilization=0.95
          - --reasoning-parser=gemma4
          - --trust-remote-code
          - --quantization=fp8
        env:
        - name: LD_LIBRARY_PATH
          value: ${LD_LIBRARY_PATH}:/usr/local/nvidia/lib64
        - name: MODEL_ID
          value: google/gemma-4-12b-it
        - name: HF_TOKEN
          valueFrom:
            secretKeyRef:
              name: hf-secret
              key: hf_api_token
        volumeMounts:
        - mountPath: /dev/shm
          name: dshm
      volumes:
      - name: dshm
        emptyDir:
            medium: Memory
      nodeSelector:
        cloud.google.com/gke-accelerator: nvidia-l4
        cloud.google.com/gke-gpu-driver-version: latest
---
apiVersion: v1
kind: Service
metadata:
  name: gemma-12b-gpu-vllm-service
spec:
  selector:
    app: gemma-12b-gpu-vllm
  type: ClusterIP
  ports:
    - protocol: TCP
      port: 8000
      targetPort: 8000
EOF

Zastosuj zapisane wdrożenie gemma-12b-gpu-vllm-deployment.yaml:

kubectl apply -f gemma-12b-gpu-vllm-deployment.yaml

Oczekiwane dane wyjściowe:

$ kubectl apply -f gemma-12b-gpu-vllm-deployment.yaml
deployment.apps/gemma-12b-gpu-vllm-deployment created
service/gemma-12b-gpu-vllm-service created

Poczekaj na zakończenie wdrażania i załadowanie modelu. Może to potrwać kilka minut.

printf "Waiting for model to load..."; until kubectl logs -l app=gemma-12b-gpu-vllm --tail=50 2>/dev/null | grep -q "Application startup complete"; do printf "."; sleep 3; done; printf '\n\033[1;32m========================================\n[SUCCESS] Model is loaded and ready!\nYou can now proceed to the next step.\n========================================\033[0m\n'

Oczekiwane dane wyjściowe:

Waiting for model to load...
========================================
[SUCCESS] Model is loaded and ready!
You can now proceed to the next step.
========================================

przetestować model. Włącz przekierowanie portów, aby uzyskać dostęp do modelu:

kubectl port-forward svc/gemma-12b-gpu-vllm-service 8090:8000

W innym oknie terminala użyj polecenia curl, aby wysłać prompt do modelu:

curl http://localhost:8090/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {"role": "system", "content": "You are a helpful assistant running on GKE."},
      {"role": "user", "content": "What is AlloyDB Omni."}
    ],
    "temperature": 0.7
  }' | jq -r '.choices[0].message.content'

Oczekiwane dane wyjściowe:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3957  100  3761  100   196     85      4  0:00:49  0:00:43  0:00:06   830
**AlloyDB Omni** is a fully managed, PostgreSQL-compatible database engine from Google Cloud that can be run **on-premises, in other clouds, or in your own data centers.**

To understand it simply: It allows you to run the high-performance, enterprise-grade capabilities of Google's **AlloyDB** (a cloud-native database) on your own infrastructure.

Here is a breakdown of what makes it significant:

### 1. The "Best of Both Worlds" Architecture
Normally, you have to choose between:
*   **Managed Cloud Databases:** Easy to scale and manage, but you are locked into the cloud provider's infrastructure.
*   **Self-Managed Databases:** You have full control over the hardware/location, but you are responsible for scaling, patching, and high availability.

**AlloyDB Omni** bridges this gap. It provides the advanced features of a cloud-native database (like intelligent indexing, high availability, and massive scalability) while allowing you to run it anywhere.

Zatrzymaj przekierowywanie portów w pierwszym terminalu (jeśli nadal działa), naciskając Ctrl+C.

9. Rejestrowanie modelu Gemma 4 w AlloyDB Omni

Zarejestruj model Gemma 12B w AlloyDB Omni za pomocą procedury google_ml.create_model. Określ http://gemma-12b-gpu-vllm-service:8000/v1/chat/completions jako model_request_url, aby kierować żądania do usługi klastra Kubernetes:

Pobierz adres IP punktu końcowego AlloyDB Omni:

echo "INSTANCE_IP=$(kubectl get dbclusters.alloydbomni.dbadmin.goog my-omni -n default -o jsonpath='{.status.primary.endpoint}')"

Połącz się z instancją maszyny wirtualnej za pomocą SSH:

export ZONE=us-central1-a
gcloud compute ssh instance-1 --zone=$ZONE

Po połączeniu z maszyną wirtualną wyeksportuj zmienną INSTANCE_IP z poprzedniego kroku (wartość 10.128.0.33 jest podana jako przykład – zastąp ją swoim adresem IP):

export INSTANCE_IP=10.128.0.33

Eksportowanie hasła AlloyDB:

export PGPASSWORD=VeryStrongPassword

Nawiąż połączenie z bazą danych demo:

psql "host=$INSTANCE_IP user=postgres sslmode=require dbname=demo"

Zarejestruj model w sesji psql:

CALL
  google_ml.create_model(
    model_id => 'gemma-12b-gpu',
    model_request_url => 'http://gemma-12b-gpu-vllm-service:8000/v1/chat/completions',
    model_provider => 'custom',
    model_type => 'llm');

Przetestuj model za pomocą przykładowego zapytania SQL:

SELECT google_ml.predict_row(
  model_id => 'gemma-12b-gpu',
  request_body => json_build_object(
    'messages', json_build_array(
      json_build_object('role', 'user', 'content', 'What is AlloyDB Omni?'))))->'choices'->0->'message'->'content';

Naciśnij q, aby zamknąć okno wyników i wrócić do promptu psql.

Łączenie wyszukiwania wektorowego z RAG LLM w AlloyDB Omni

Użyj wyszukiwania wektorowego z żądaniem LLM, aby zademonstrować generowanie wspomagane wyszukiwaniem (RAG) z LLM.

Uruchom zapytanie SQL w plsql:

WITH trees AS (
SELECT
        cp.product_name,
        cp.product_description AS description,
        cp.sale_price,
        cs.zip_code,
        cp.uniq_id AS product_id
FROM
    cymbal_products cp
JOIN cymbal_embedding ce ON ce.uniq_id = cp.uniq_id
JOIN cymbal_inventory ci ON ci.uniq_id = cp.uniq_id
JOIN cymbal_stores cs ON cs.store_id = ci.store_id
WHERE
        ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        (ce.embedding <=> embedding('embeddinggemma',
        'What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1),
prompt AS (
SELECT
        'You are a friendly advisor helping to find a product based on the customer''s needs.
Based on the client request we have loaded a list of products closely related to search.
The list in JSON format with list of values like {"product_name":"name","product_description":"some description","sale_price":10}
Here is the list of products:' || json_agg(trees) || 'The customer asked "What kind of fruit trees grow well here?"
You should give information about the product, price and some supplemental information' AS prompt_text
FROM
        trees),
response AS (
SELECT
        google_ml.predict_row(
          model_id =>'gemma-12b-gpu',
          request_body => json_build_object(
            'messages', json_build_array(
              json_build_object('role', 'user', 'content',prompt_text)
            )))->'choices'->0->'message'->'content' AS resp
FROM
        prompt)
SELECT
REPLACE(resp::text, '\n', CHR(10))
FROM
        response;

Oczekiwane dane wyjściowe:

----------------------------------------------------------------------------------------------------------------------------------------------
 "Hello there! I'd be happy to help you find the perfect tree for your garden.                                                               +
                                                                                                                                             +
 Based on your location, we have a wonderful option that would grow beautifully in your area:                                                +
                                                                                                                                             +
 **Cherry Tree**                                                                                                                             +
 *   **Price:** $75.00                                                                                                                       +
 *   **Description:** This is a stunning deciduous tree that not only provides a beautiful landscape but also produces delicious cherries.   +
 *   **Supplemental Information:**                                                                                                           +
     *   **Growth:** It grows to about 15 feet tall.                                                                                         +
     *   **Appearance:** You can look forward to dark green leaves in the summer that transform into a vibrant red in the fall.              +
     *   **Benefits:** It's a great choice if you're looking for both fruit and extra shade or privacy in your yard.                         +
     *   **Care Tips:** It performs best in a cool, moist climate with sandy soil. Since you are in a suitable zone, it should thrive nicely!+
                                                                                                                                             +
 Would you like more details on how to plant this, or would you like to proceed with an order?"
(1 row)

Zapytanie uzupełnia prompt do LLM o wyniki wyszukiwania wektorowego.

Wypróbuj inne zapytania i poeksperymentuj z wzorcami RAG. Zaletą przedstawionej architektury jest jej pełna samowystarczalność. Dane nie są wysyłane poza klaster i może on działać w całkowicie odizolowanych środowiskach.

Zakończ sesję psql:

\q

Odłącz się od sesji SSH na maszynie wirtualnej:

exit

Nie zapomnij, że AlloyDB Omni ma więcej funkcji i laboratoriów.

10. Zwalnianie miejsca w środowisku

Aby uniknąć obciążenia konta Google Cloud bieżącymi opłatami, usuń zasoby utworzone w tym samouczku.

Usuwanie klastra GKE

W Cloud Shell usuń klaster GKE:

export PROJECT_ID=$(gcloud config get-value project)
export LOCATION=us-central1
export CLUSTER_NAME=alloydb-ai-gke
gcloud container clusters delete ${CLUSTER_NAME} \
  --project=${PROJECT_ID} \
  --region=${LOCATION}

Oczekiwane dane wyjściowe:

student@cloudshell:~$ gcloud container clusters delete ${CLUSTER_NAME} \
>   --project=${PROJECT_ID} \
>   --region=${LOCATION}
The following clusters will be deleted.
 - [alloydb-ai-gke] in [us-central1]

Do you want to continue (Y/n)?  Y

Deleting cluster alloydb-ai-gke...done.
Deleted

Usuwanie klienckiej maszyny wirtualnej

W Cloud Shell usuń instancję Compute Engine:

export PROJECT_ID=$(gcloud config get-value project)
export ZONE=us-central1-a
gcloud compute instances delete instance-1 \
  --project=${PROJECT_ID} \
  --zone=${ZONE}

Oczekiwane dane wyjściowe:

student@cloudshell:~$ export PROJECT_ID=$(gcloud config get project)
export ZONE=us-central1-a
gcloud compute instances delete instance-1 \
  --project=${PROJECT_ID} \
  --zone=${ZONE}
Your active configuration is: [cloudshell-5399]
The following instances will be deleted. Any attached disks configured to be auto-deleted will be deleted unless they are attached to any other instances or the `--keep-disks` flag is given and specifies them for keeping. Deleting a disk 
is irreversible and any data on the disk will be lost.
 - [instance-1] in [us-central1-a]

Do you want to continue (Y/n)?  Y

Deleted

Jeśli do wykonania zadań z tego laboratorium posłużył Ci nowy, specjalnie utworzony projekt, możesz go usunąć w Google Cloud Resource Managerze.

11. Gratulacje

Gratulujemy ukończenia warsztatów!

Co obejmuje ochrona

  • Jak wdrożyć AlloyDB Omni w klastrze GKE
  • Łączenie się z AlloyDB Omni
  • Wczytywanie danych do AlloyDB Omni
  • Jak wdrażać modele AI (wektorów dystrybucyjnych i LLM) w GKE
  • Jak rejestrować modele AI w AlloyDB Omni
  • Jak generować wektory dystrybucyjne na potrzeby wyszukiwania semantycznego
  • Jak uruchamiać zapytania wyszukiwania semantycznego w AlloyDB Omni
  • Jak tworzyć i używać indeksów wektorowych w AlloyDB Omni

Więcej informacji o pracy z AI w AlloyDB Omni znajdziesz w dokumentacji.

Ankieta

Dane wyjściowe:

Jak zamierzasz wykorzystać ten samouczek?

Tylko przeczytaj Przeczytaj i wykonaj ćwiczenia