1. Wprowadzenie
W tym ćwiczeniu z programowania dowiesz się, jak korzystać z AI w AlloyDB, łącząc wyszukiwanie wektorów z wektorami dystrybucyjnymi Vertex AI.
Wymagania wstępne
- podstawowa znajomość konsoli Google Cloud;
- podstawowe umiejętności w zakresie interfejsu wiersza poleceń i Google Shell;
Czego się nauczysz
- Jak wdrożyć klaster i instancję główną AlloyDB
- Jak połączyć się z AlloyDB z maszyny wirtualnej Google Compute Engine
- Jak utworzyć bazę danych i włączyć AlloyDB AI
- Wczytywanie danych do bazy danych
- Jak używać modelu wstawiania Vertex AI w AlloyDB
- Wzbogacanie wyników za pomocą modelu generatywnego Vertex AI
- Jak poprawić wydajność za pomocą indeksu wektorów
Czego potrzebujesz
- Konto Google Cloud i projekt Google Cloud
- przeglądarki, np. Chrome;
2. Konfiguracja i wymagania
Samodzielne konfigurowanie środowiska
- Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub użyj istniejącego. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.
- Nazwa projektu to wyświetlana nazwa uczestników tego projektu. Jest to ciąg znaków, którego nie używają interfejsy API Google. Zawsze możesz ją zaktualizować.
- Identyfikator projektu jest niepowtarzalny w ramach wszystkich projektów Google Cloud i nie można go zmienić (po ustawieniu). Cloud Console automatycznie wygeneruje unikalny ciąg znaków. zwykle nieważne, co ona jest. W większości ćwiczeń w Codelabs musisz podać swój identyfikator projektu (zwykle identyfikowany jako
PROJECT_ID
). Jeśli nie podoba Ci się wygenerowany identyfikator, możesz wygenerować kolejny losowy. Możesz też spróbować własnych sił i sprawdzić, czy jest dostępna. Po wykonaniu tej czynności nie można jej już zmienić. Pozostanie ona przez cały czas trwania projektu. - Informacyjnie: istnieje jeszcze 3 wartość, numer projektu, której używają niektóre interfejsy API. Więcej informacji o wszystkich 3 wartościach znajdziesz w dokumentacji.
- Następnie musisz włączyć rozliczenia w konsoli Cloud, aby korzystać z zasobów i interfejsów API Cloud. Ukończenie tego ćwiczenia z programowania nic nie kosztuje. Aby wyłączyć zasoby w celu uniknięcia naliczania opłat po zakończeniu tego samouczka, możesz usunąć utworzone zasoby lub projekt. Nowi użytkownicy Google Cloud mogą skorzystać z programu bezpłatnego okresu próbnego o wartości 300 USD.
Uruchamianie Cloud Shell
Google Cloud można obsługiwać zdalnie z laptopa, ale w tym ćwiczeniu będziesz używać Google Cloud Shell, czyli środowiska wiersza poleceń działającego w chmurze.
W konsoli Google Cloud kliknij ikonę Cloud Shell na górnym pasku narzędzi:
Uzyskanie dostępu do środowiska i połączenie się z nim powinno zająć tylko kilka chwil. Po jego zakończeniu powinno wyświetlić się coś takiego:
Ta maszyna wirtualna ma wszystkie potrzebne narzędzia dla programistów. Zawiera stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie poprawia wydajność sieci i uwierzytelnianie. Wszystkie zadania w ramach tego ćwiczenia z programowania można wykonywać w przeglądarce. Nie musisz niczego instalować.
3. Zanim zaczniesz
Włącz API
Dane wyjściowe:
W Cloud Shell sprawdź, czy identyfikator projektu jest skonfigurowany:
gcloud config set project [YOUR-PROJECT-ID]
Ustaw zmienną środowiskową PROJECT_ID:
PROJECT_ID=$(gcloud config get-value project)
Włącz wszystkie niezbędne usługi:
gcloud services enable alloydb.googleapis.com \
compute.googleapis.com \
cloudresourcemanager.googleapis.com \
servicenetworking.googleapis.com \
aiplatform.googleapis.com
Oczekiwany wynik
student@cloudshell:~ (test-project-001-402417)$ gcloud config set project test-project-001-402417 Updated property [core/project]. student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=$(gcloud config get-value project) Your active configuration is: [cloudshell-14650] student@cloudshell:~ (test-project-001-402417)$ student@cloudshell:~ (test-project-001-402417)$ gcloud services enable alloydb.googleapis.com \ compute.googleapis.com \ cloudresourcemanager.googleapis.com \ servicenetworking.googleapis.com \ aiplatform.googleapis.com Operation "operations/acat.p2-4470404856-1f44ebd8-894e-4356-bea7-b84165a57442" finished successfully.
Skonfiguruj domyślny region, aby używać modeli embeddingu Vertex AI. Dowiedz się więcej o dostępnych lokalizacjach Vertex AI. W przykładzie używamy regionu us-central1.
gcloud config set compute/region us-central1
4. Wdrażanie AlloyDB
Zanim utworzysz klaster AlloyDB, musisz mieć dostępny zakres prywatnych adresów IP w VPC, który będzie używany przez przyszłą instancję AlloyDB. Jeśli go nie mamy, musimy go utworzyć, przypisać do użytku przez wewnętrzne usługi Google, a następnie utworzyć klaster i instancję.
Utwórz zakres prywatnych adresów IP
Musimy skonfigurować dostęp do usług prywatnych w VPC dla AlloyDB. W tym ujęciu zakładamy, że „domyślna” Sieć VPC w projekcie, która będzie używana do wszystkich działań.
Utwórz zakres prywatnych adresów IP:
gcloud compute addresses create psa-range \
--global \
--purpose=VPC_PEERING \
--prefix-length=24 \
--description="VPC private service access" \
--network=default
Utwórz połączenie prywatne, używając przydzielonego zakresu adresów IP:
gcloud services vpc-peerings connect \
--service=servicenetworking.googleapis.com \
--ranges=psa-range \
--network=default
Oczekiwane dane wyjściowe konsoli:
student@cloudshell:~ (test-project-402417)$ gcloud compute addresses create psa-range \ --global \ --purpose=VPC_PEERING \ --prefix-length=24 \ --description="VPC private service access" \ --network=default Created [https://www.googleapis.com/compute/v1/projects/test-project-402417/global/addresses/psa-range]. student@cloudshell:~ (test-project-402417)$ gcloud services vpc-peerings connect \ --service=servicenetworking.googleapis.com \ --ranges=psa-range \ --network=default Operation "operations/pssn.p24-4470404856-595e209f-19b7-4669-8a71-cbd45de8ba66" finished successfully. student@cloudshell:~ (test-project-402417)$
Tworzenie klastra AlloyDB
Utwórz klaster AlloyDB w regionie us-central1.
Zdefiniuj hasło dla użytkownika postgres. Możesz zdefiniować własne hasło lub użyć funkcji losowania, aby je wygenerować.
export PGPASSWORD=`openssl rand -hex 12`
Oczekiwane dane wyjściowe konsoli:
student@cloudshell:~ (test-project-402417)$ export PGPASSWORD=`openssl rand -hex 12`
Zanotuj hasło do PostgreSQL – do wykorzystania w przyszłości:
echo $PGPASSWORD
Oczekiwane dane wyjściowe konsoli:
student@cloudshell:~ (test-project-402417)$ echo $PGPASSWORD bbefbfde7601985b0dee5723
Zdefiniuj region i nazwę klastra AlloyDB. Wykorzystamy region us-central1 i Alloydb-aip-01 jako nazwę klastra:
export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
Uruchom polecenie, aby utworzyć klaster:
gcloud alloydb clusters create $ADBCLUSTER \
--password=$PGPASSWORD \
--network=default \
--region=$REGION
Oczekiwane dane wyjściowe konsoli:
export REGION=us-central1 export ADBCLUSTER=alloydb-aip-01 gcloud alloydb clusters create $ADBCLUSTER \ --password=$PGPASSWORD \ --network=default \ --region=$REGION Operation ID: operation-1697655441138-6080235852277-9e7f04f5-2012fce4 Creating cluster...done.
Tworzenie instancji głównej AlloyDB
Utwórz instancję główną AlloyDB dla naszego klastra w tej samej sesji Cloud Shell. Jeśli nastąpi rozłączenie, musisz ponownie zdefiniować zmienne środowiskowe nazwy regionu i klastra.
gcloud alloydb instances create $ADBCLUSTER-pr \
--instance-type=PRIMARY \
--cpu-count=2 \
--region=$REGION \
--cluster=$ADBCLUSTER
Oczekiwane dane wyjściowe konsoli:
student@cloudshell:~ (test-project-402417)$ gcloud alloydb instances create $ADBCLUSTER-pr \ --instance-type=PRIMARY \ --cpu-count=2 \ --region=$REGION \ --availability-type ZONAL \ --cluster=$ADBCLUSTER Operation ID: operation-1697659203545-6080315c6e8ee-391805db-25852721 Creating instance...done.
5. Łączenie z AlloyDB
AlloyDB jest wdrażane z użyciem połączenia tylko prywatnego, dlatego do pracy z bazą danych potrzebuje maszyny wirtualnej z zainstalowanym klientem PostgreSQL.
Wdrażanie maszyny wirtualnej GCE
Utwórz maszynę wirtualną GCE w tym samym regionie i sieci VPC co klaster AlloyDB.
W Cloud Shell wykonaj te czynności:
export ZONE=us-central1-a
gcloud compute instances create instance-1 \
--zone=$ZONE \
--create-disk=auto-delete=yes,boot=yes,image=projects/debian-cloud/global/images/$(gcloud compute images list --filter="family=debian-12 AND family!=debian-12-arm64" --format="value(name)") \
--scopes=https://www.googleapis.com/auth/cloud-platform
Oczekiwane dane wyjściowe konsoli:
student@cloudshell:~ (test-project-402417)$ export ZONE=us-central1-a student@cloudshell:~ (test-project-402417)$ export ZONE=us-central1-a gcloud compute instances create instance-1 \ --zone=$ZONE \ --create-disk=auto-delete=yes,boot=yes,image=projects/debian-cloud/global/images/$(gcloud compute images list --filter="family=debian-12 AND family!=debian-12-arm64" --format="value(name)") \ --scopes=https://www.googleapis.com/auth/cloud-platform Created [https://www.googleapis.com/compute/v1/projects/test-project-402417/zones/us-central1-a/instances/instance-1]. NAME: instance-1 ZONE: us-central1-a MACHINE_TYPE: n1-standard-1 PREEMPTIBLE: INTERNAL_IP: 10.128.0.2 EXTERNAL_IP: 34.71.192.233 STATUS: RUNNING
Zainstaluj klienta Postgres
Instalowanie oprogramowania klienta PostgreSQL na wdrożonej maszynie wirtualnej
Połącz się z maszyną wirtualną:
gcloud compute ssh instance-1 --zone=us-central1-a
Oczekiwane dane wyjściowe konsoli:
student@cloudshell:~ (test-project-402417)$ gcloud compute ssh instance-1 --zone=us-central1-a Updating project ssh metadata...working..Updated [https://www.googleapis.com/compute/v1/projects/test-project-402417]. Updating project ssh metadata...done. Waiting for SSH key to propagate. Warning: Permanently added 'compute.5110295539541121102' (ECDSA) to the list of known hosts. Linux instance-1.us-central1-a.c.gleb-test-short-001-418811.internal 6.1.0-18-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.76-1 (2024-02-01) x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. student@instance-1:~$
Zainstaluj polecenie uruchamiania oprogramowania w maszynie wirtualnej:
sudo apt-get update
sudo apt-get install --yes postgresql-client
Oczekiwane dane wyjściowe konsoli:
student@instance-1:~$ sudo apt-get update sudo apt-get install --yes postgresql-client Get:1 https://packages.cloud.google.com/apt google-compute-engine-bullseye-stable InRelease [5146 B] Get:2 https://packages.cloud.google.com/apt cloud-sdk-bullseye InRelease [6406 B] Hit:3 https://deb.debian.org/debian bullseye InRelease Get:4 https://deb.debian.org/debian-security bullseye-security InRelease [48.4 kB] Get:5 https://packages.cloud.google.com/apt google-compute-engine-bullseye-stable/main amd64 Packages [1930 B] Get:6 https://deb.debian.org/debian bullseye-updates InRelease [44.1 kB] Get:7 https://deb.debian.org/debian bullseye-backports InRelease [49.0 kB] ...redacted... update-alternatives: using /usr/share/postgresql/13/man/man1/psql.1.gz to provide /usr/share/man/man1/psql.1.gz (psql.1.gz) in auto mode Setting up postgresql-client (13+225) ... Processing triggers for man-db (2.9.4-2) ... Processing triggers for libc-bin (2.31-13+deb11u7) ...
Łączenie z instancją
połączyć się z instancją główną z maszyny wirtualnej za pomocą psql;
Na tej samej karcie Cloud Shell z otwartą sesją SSH do maszyny wirtualnej instance-1.
Aby połączyć się z AlloyDB z maszyny wirtualnej GCE, użyj podanego hasła AlloyDB (PGPASSWORD) i identyfikatora klastra AlloyDB:
export PGPASSWORD=<Noted password>
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
export INSTANCE_IP=$(gcloud alloydb instances describe $ADBCLUSTER-pr --cluster=$ADBCLUSTER --region=$REGION --format="value(ipAddress)")
psql "host=$INSTANCE_IP user=postgres sslmode=require"
Oczekiwane dane wyjściowe konsoli:
student@instance-1:~$ export PGPASSWORD=CQhOi5OygD4ps6ty student@instance-1:~$ ADBCLUSTER=alloydb-aip-01 student@instance-1:~$ REGION=us-central1 student@instance-1:~$ INSTANCE_IP=$(gcloud alloydb instances describe $ADBCLUSTER-pr --cluster=$ADBCLUSTER --region=$REGION --format="value(ipAddress)") gleb@instance-1:~$ psql "host=$INSTANCE_IP user=postgres sslmode=require" psql (15.6 (Debian 15.6-0+deb12u1), server 15.5) SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off) Type "help" for help. postgres=>
Zamknij sesję psql:
exit
6. Przygotuj bazę danych
Musimy utworzyć bazę danych, włączyć integrację z Vertex AI, utworzyć obiekty bazy danych i zaimportować dane.
Przyznanie AlloyDB niezbędnych uprawnień
Dodaj uprawnienia Vertex AI do agenta usługi AlloyDB.
Otwórz kolejną kartę Cloud Shell, klikając znak „+” u góry.
Na nowej karcie Cloud Shell wykonaj te czynności:
PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
Oczekiwane dane wyjściowe konsoli:
student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=$(gcloud config get-value project) Your active configuration is: [cloudshell-11039] student@cloudshell:~ (test-project-001-402417)$ gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \ --role="roles/aiplatform.user" Updated IAM policy for project [test-project-001-402417]. bindings: - members: - serviceAccount:service-4470404856@gcp-sa-alloydb.iam.gserviceaccount.com role: roles/aiplatform.user - members: ... etag: BwYIEbe_Z3U= version: 1
Zamknij kartę, używając polecenia „exit”:
exit
Utwórz bazę danych
Tworzenie bazy danych – krótkie wprowadzenie.
W sesji maszyny wirtualnej GCE wykonaj te czynności:
Utwórz bazę danych:
psql "host=$INSTANCE_IP user=postgres" -c "CREATE DATABASE quickstart_db"
Oczekiwane dane wyjściowe konsoli:
student@instance-1:~$ psql "host=$INSTANCE_IP user=postgres" -c "CREATE DATABASE quickstart_db" CREATE DATABASE student@instance-1:~$
Włączanie integracji z Vertex AI
Włącz integrację Vertex AI i rozszerzenia pgvector w bazie danych.
W maszynie wirtualnej GCE wykonaj te czynności:
psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE"
psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS vector"
Oczekiwane dane wyjściowe konsoli:
student@instance-1:~$ psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE" psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS vector" CREATE EXTENSION CREATE EXTENSION student@instance-1:~$
Importowanie danych
Pobierz przygotowane dane i zaimportuj je do nowej bazy danych.
W maszynie wirtualnej GCE wykonaj te czynności:
gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"
gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_products from stdin csv header"
gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_inventory from stdin csv header"
gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_stores from stdin csv header"
Oczekiwane dane wyjściowe konsoli:
student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" 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@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_products from stdin csv header" COPY 941 student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_inventory from stdin csv header" COPY 263861 student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_stores from stdin csv header" COPY 4654 student@instance-1:~$
7. Obliczanie wektorów
Po zaimportowaniu danych otrzymaliśmy dane o produktach w tabeli cymbal_products, podając liczbę dostępnych produktów w każdym sklepie w tabeli cymbal_inventory oraz listę sklepów w tabeli cymbal_stores. Musimy obliczyć dane wektorowe na podstawie opisów naszych produktów i użyć do tego funkcji umieszczania. Za pomocą funkcji użyjemy integracji Vertex AI do obliczenia danych wektorowych na podstawie opisów naszych produktów i dodania ich do tabeli. Więcej informacji o zastosowanej technologii znajdziesz w dokumentacji.
Tworzenie kolumny do umieszczania treści
Połącz się z bazą danych za pomocą psql i utwórz kolumnę wirtualną z danymi wektorowymi, używając funkcji embeddingu w tabeli cymbal_products. Funkcja umieszczania zwraca dane wektorowe z Vertex AI na podstawie danych przesłanych z kolumny product_description.
psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"
W sesji psql po połączeniu się z bazą danych wykonaj:
ALTER TABLE cymbal_products ADD COLUMN embedding vector(768) GENERATED ALWAYS AS (embedding('text-embedding-004',product_description)) STORED;
Polecenie utworzy kolumnę wirtualną i wypełni ją danymi wektorowymi.
Oczekiwane dane wyjściowe konsoli:
student@instance-1:~$ psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" psql (13.11 (Debian 13.11-0+deb11u1), server 14.7) WARNING: psql major version 13, server major version 14. Some psql features might not work. SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off) Type "help" for help. quickstart_db=> ALTER TABLE cymbal_products ADD COLUMN embedding vector(768) GENERATED ALWAYS AS (embedding('text-embedding-004',product_description)) STORED; ALTER TABLE quickstart_db=>
8. Uruchamianie wyszukiwania podobnych treści
Teraz możemy wykonać wyszukiwanie z użyciem wyszukiwania podobieństwa na podstawie wartości wektorowych obliczonych dla opisów i wartości wektorowej uzyskanej dla naszego żądania.
Zapytanie SQL można wykonać w tym samym interfejsie wiersza poleceń psql lub alternatywnie w AlloyDB Studio. Wyniki złożone i wielorzedowe mogą wyglądać lepiej w AlloyDB Studio.
Połączenie z AlloyDB Studio
W poniższych rozdziałach wszystkie polecenia SQL wymagające połączenia z bazą danych można także wykonać w AlloyDB Studio. Aby uruchomić polecenie, otwórz interfejs konsoli internetowej klastra AlloyDB przez kliknięcie instancji głównej.
Następnie po lewej stronie kliknij AlloyDB Studio:
Wybierz bazę danych quickstart_db, użytkownika postgres i podaj hasło zapisane podczas tworzenia klastra. Następnie kliknij przycisk „Uwierzytelnij”.
Otworzy się interfejs AlloyDB Studio. Aby wykonać polecenia w bazie danych, kliknij kartę „Editor 1” po prawej stronie.
Otwiera interfejs, w którym można uruchamiać polecenia SQL
Jeśli wolisz użyć wiersza poleceń psql, skorzystaj z alternatywnej trasy i połącz się z bazą danych przez sesję SSH maszyny wirtualnej w sposób opisany w poprzednich rozdziałach.
Wyszukiwanie podobnych za pomocą psql
Jeśli sesja bazy danych została rozłączona, ponownie połącz się z bazą danych za pomocą psql lub AlloyDB Studio.
Połącz się z bazą danych:
psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"
Przeprowadzanie zapytania w celu uzyskania listy dostępnych produktów najbardziej pasujących do żądań klienta. Żądanie, które będziemy przekazywać do Vertex AI, aby uzyskać wartość wektora, brzmi na przykład „Jakiego rodzaju drzewa owocowe dobrze tu radzą?”.
Oto zapytanie, które możesz wykonać, aby wybrać 10 elementów najbardziej pasujących do Twojego zapytania:
SELECT
cp.product_name,
left(cp.product_description,80) as description,
cp.sale_price,
cs.zip_code,
(cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) as distance
FROM
cymbal_products cp
JOIN cymbal_inventory ci on
ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
cs.store_id=ci.store_id
AND ci.inventory>0
AND cs.store_id = 1583
ORDER BY
distance ASC
LIMIT 10;
A tak powinny wyglądać dane wyjściowe:
quickstart_db=> SELECT cp.product_name, left(cp.product_description,80) as description, cp.sale_price, cs.zip_code, (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) as distance FROM cymbal_products cp JOIN cymbal_inventory ci on ci.uniq_id=cp.uniq_id JOIN cymbal_stores cs on cs.store_id=ci.store_id AND ci.inventory>0 AND cs.store_id = 1583 ORDER BY distance ASC LIMIT 10; 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.43922018972266397 Meyer Lemon Tree | Meyer Lemon trees are California's favorite lemon tree! Grow your own lemons by | 34 | 93230 | 0.4685112926118228 Toyon | This is a beautiful toyon tree that can grow to be over 20 feet tall. It is an e | 10.00 | 93230 | 0.4835677149651668 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.4947204525907498 California Peppertree | This is a beautiful peppertree that can grow to be over 30 feet tall. It is an e | 25.00 | 93230 | 0.5054166905547247 California Black Walnut | This is a beautiful walnut tree that can grow to be over 80 feet tall. It is a d | 100.00 | 93230 | 0.5084219510932597 California Sycamore | This is a beautiful sycamore tree that can grow to be over 100 feet tall. It is | 300.00 | 93230 | 0.5140519790508755 Coast Live Oak | This is a beautiful oak tree that can grow to be over 100 feet tall. It is an ev | 500.00 | 93230 | 0.5143126438081371 Fremont Cottonwood | This is a beautiful cottonwood tree that can grow to be over 100 feet tall. It i | 200.00 | 93230 | 0.5174774727252058 Madrone | This is a beautiful madrona tree that can grow to be over 80 feet tall. It is an | 50.00 | 93230 | 0.5227400803389093
9. Popraw odpowiedź
Możesz ulepszyć odpowiedź dla aplikacji klienckiej, korzystając z wyników zapytania, i przygotować znaczące dane wyjściowe, używając podanych wyników zapytania jako części promptu dla generatywnego modelu językowego Vertex AI.
Aby to osiągnąć, planujemy wygenerować plik JSON z naszym wynikiem wyszukiwania wektorów, a potem użyć wygenerowanego pliku JSON jako uzupełnienia promptu dla modelu LLM do tekstu w Vertex AI, aby utworzyć sensowny wynik. W pierwszym kroku generujemy plik JSON, następnie testujemy go w Vertex AI Studio, a w ostatnim kroku włączamy go do instrukcji SQL, której można użyć w aplikacji.
Generowanie danych wyjściowych w formacie JSON
Zmodyfikuj zapytanie, aby wygenerować dane wyjściowe w formacie JSON i zwrócić tylko 1 wiersz, który zostanie przekazany do Vertex AI
Oto przykład zapytania:
WITH trees as (
SELECT
cp.product_name,
left(cp.product_description,80) as description,
cp.sale_price,
cs.zip_code,
cp.uniq_id as product_id
FROM
cymbal_products cp
JOIN cymbal_inventory ci on
ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
cs.store_id=ci.store_id
AND ci.inventory>0
AND cs.store_id = 1583
ORDER BY
(cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;
A tutaj oczekiwany format danych wyjściowych JSON:
[{"product_name":"Cherry Tree","description":"This is a beautiful cherry tree that will produce delicious cherries. It is an d","sale_price":75.00,"zip_code":93230,"product_id":"d536e9e823296a2eba198e52dd23e712"}]
Uruchamianie promptu w Vertex AI Studio
Możemy użyć wygenerowanego pliku JSON, aby dostarczyć go jako część promptu do modelu tekstowego generatywnej AI w Vertex AI Studio
Otwórz Vertex AI Studio w konsoli Google Cloud.
Może pojawić się prośba o włączenie dodatkowych interfejsów API, ale możesz to zignorować. Do ukończenia laboratorium nie potrzebujemy żadnych dodatkowych interfejsów API.
Oto prompt, którego użyjemy:
Jesteś przyjaznym doradcą i pomagasz znaleźć produkt dostosowany do potrzeb klienta.
Na prośbę klienta załadowaliśmy listę produktów ściśle związanych z wyszukiwaniem.
Lista w formacie JSON z listą wartości takich jak {"product_name":"name","description":"some description","sale_price":10,"zip_code": 10234, "produt_id": "02056727942aeb714dc9a2313654e1b0"}
Oto lista usług:
[miejsce na kod JSON]
Klient zapytał: „Które drzewo rośnie tu najlepiej?”
Podaj informacje o produkcie, cenie i niektórych informacjach dodatkowych.
A tak wygląda wynik, gdy uruchomimy prompt z wartościami JSON i modelem gemini-1.5-flash:
Odpowiedź uzyskana na podstawie modelu w tym przykładzie jest: Pamiętaj, że odpowiedź może być inna ze względu na zmiany modelu i parametrów z biegiem czasu:
„Widzę, że szukasz drzewa, które kwitnie w Twojej okolicy. Na podstawie Twojego kodu pocztowego 93230 uważamy, że drzewo wiśniowe to świetna opcja.
Jest opisany jako piękne drzewo, które wydaje pyszne wiśnie. Obecnie jest w promocji za 75 PLN.
Chociaż nie znam tempa wzrostu w Twoim regionie, mogę powiedzieć, że wiśnie na ogół preferują dobrze nawodnioną glebę i pełne nasłonecznienie.
Aby uzyskać najlepsze wyniki, zalecam skonsultowanie się z lokalną szkółką roślin lub ekspertem ogrodniczym, który może udzielić bardziej szczegółowych porad dotyczących Twojej lokalizacji i warunków glebowych. Mogą też pomóc Ci wybrać odmianę najlepiej odpowiadającą Twoim potrzebom oraz udzielić wskazówek dotyczących sadzenia i pielęgnacji.
Uruchamianie promptu w PSQL
Możemy użyć integracji AlloyDB AI z Vertex AI, aby uzyskać tę samą odpowiedź z modelu generatywnego korzystającego z SQL bezpośrednio w bazie danych. Aby jednak używać modelu gemini-1.5-flash, musimy go najpierw zarejestrować.
Uaktualnij rozszerzenie do wersji 1.4.1 (jeśli bieżąca wersja jest starsza). Połącz się z bazą danych quickstart_db za pomocą psql (jak pokazano wcześniej) lub AlloyDB Studio i wykonaj:
SELECT extversion from pg_extension where extname='google_ml_integration';
Jeśli zwrócona wartość jest mniejsza niż 1.4.1, wykonaj:
ALTER EXTENSION google_ml_integration UPDATE TO '1.4.1';
Następnie musimy ustawić flagę bazy danych google_ml_integration.enable_model_support na „on”. Możesz to zrobić w interfejsie konsoli AlloyDB lub uruchomić to polecenie gcloud.
PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
ADBCLUSTER=alloydb-aip-01
gcloud beta alloydb instances update $ADBCLUSTER-pr \
--database-flags google_ml_integration.enable_model_support=on \
--region=$REGION \
--cluster=$ADBCLUSTER \
--project=$PROJECT_ID \
--update-mode=FORCE_APPLY
Polecenie zostanie wykonane w tle po około 3–5 minutach. Następnie możesz sprawdzić nową flagę w sesji psql lub za pomocą AlloyDB Studio połączyć się z bazą danych quickstart_db.
show google_ml_integration.enable_model_support;
Oczekiwane dane wyjściowe z sesji psql to „on”:
postgres=> show google_ml_integration.enable_model_support; google_ml_integration.enable_model_support -------------------------------------------- on (1 row)
Następnie musimy zarejestrować 2 modele. Pierwszy z nich to już używany model text-embedding-004. Musisz go zarejestrować, ponieważ włączyliśmy możliwość rejestracji modeli.
Aby zarejestrować uruchomiony model w psql lub AlloyDB Studio, użyj tego kodu:
CALL
google_ml.create_model(
model_id => 'text-embedding-004',
model_provider => 'google',
model_qualified_name => 'text-embedding-004',
model_type => 'text_embedding',
model_auth_type => 'alloydb_service_agent_iam',
model_in_transform_fn => 'google_ml.vertexai_text_embedding_input_transform',
model_out_transform_fn => 'google_ml.vertexai_text_embedding_output_transform');
Kolejnym modelem, który musimy zarejestrować, jest gemini-1.5-flash-002. Będzie on używany do generowania przyjaznych dla użytkownika danych wyjściowych.
CALL
google_ml.create_model(
model_id => 'gemini-1.5-flash-002',
model_request_url => 'https://$REGION-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/publishers/google/models/gemini-1.5-flash-002:streamGenerateContent',
model_provider => 'google',
model_auth_type => 'alloydb_service_agent_iam');
Listę zarejestrowanych modeli możesz sprawdzić w dowolnym momencie, wybierając informacje z elementu google_ml.model_info_view.
select model_id,model_type from google_ml.model_info_view;
Oto przykładowe dane wyjściowe
quickstart_db=> select model_id,model_type from google_ml.model_info_view; model_id | model_type -------------------------+---------------- textembedding-gecko | text_embedding textembedding-gecko@001 | text_embedding text-embedding-004 | text_embedding gemini-1.5-flash-001 | generic (4 rows)
Teraz możemy użyć danych wygenerowanych w pliku JSON podzapytania, aby przekazać je jako część promptu do generatywnego modelu tekstowego AI za pomocą kodu SQL.
Uruchom zapytanie w sesji psql lub AlloyDB Studio w bazie danych
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_inventory ci ON
ci.uniq_id = cp.uniq_id
JOIN cymbal_stores cs ON
cs.store_id = ci.store_id
AND ci.inventory>0
AND cs.store_id = 1583
ORDER BY
(cp.embedding <=> embedding('text-embedding-004',
'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
json_array_elements(google_ml.predict_row( model_id =>'gemini-1.5-flash-002',
request_body => json_build_object('contents',
json_build_object('role',
'user',
'parts',
json_build_object('text',
prompt_text)))))->'candidates'->0->'content'->'parts'->0->'text' AS resp
FROM
prompt)
SELECT
string_agg(resp::text,
' ')
FROM
response;
Oto oczekiwane dane wyjściowe. Dane wyjściowe mogą się różnić w zależności od wersji modelu i parametrów:
"That" "'s a great question! Based on your location (assuming you're" " in zip code 93230), I have a suggestion for a" " fruit tree that should thrive.\n\nWe have the **Cherry Tree** available.\n\n**Product Name:** Cherry Tree\n\n**Description:** This is a beautiful cherry" " tree that will produce delicious cherries. It's a deciduous tree (meaning it loses its leaves in the fall) growing to about 15 feet tall." " The leaves are dark green in summer, turning a beautiful red in the fall. Cherry trees are known for their beauty, shade, and privacy.\n\n**Sale Price:** $75.00\n\n**Important Considerations for Growing" " Cherry Trees:**\n\n* **Climate:** Cherry trees prefer a cool, moist climate, and 93230 falls within a suitable range (USDA zones 4-9). However, it's always a good idea to" " check the specific microclimate of your property (sun exposure, drainage etc.).\n* **Soil:** They do best in sandy soil. If your soil is different, you may need to amend it to improve drainage.\n* **Pollination:** Many cherry varieties require a second, compatible cherry tree for proper pollination" ". Check the specific pollination needs of this variety before purchase if you want a significant cherry yield.\n\nThis cherry tree is a beautiful addition to any yard and will provide you with delicious cherries if you can meet its needs. Would you like to know more about its pollination requirements, or perhaps see if we have any other" " fruit trees suitable for your area?\n" ""
10. Tworzenie indeksu wektorowego
Nasz zbiór danych jest dość mały, a czas odpowiedzi zależy głównie od interakcji z modelami AI. Jeśli jednak masz miliony wektorów, wyszukiwanie wektorowe może zajmować znaczną część czasu odpowiedzi i znacznie obciążać system. Aby to poprawić, możemy utworzyć indeks na podstawie naszych wektorów.
Utwórz indeks ScaNN
Aby utworzyć indeks SCANN, musimy włączyć jeszcze jedno rozszerzenie. Rozszerzenie alloydb_scann udostępnia nam interfejs do pracy z indeksem wektorowym typu ANN za pomocą algorytmu Google ScaNN.
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
Oczekiwany wynik:
quickstart_db=> CREATE EXTENSION IF NOT EXISTS alloydb_scann; CREATE EXTENSION Time: 27.468 ms quickstart_db=>
Teraz możemy utworzyć indeks. W tym przykładzie pozostawiam większość parametrów w wartościach domyślnych i podaję tylko liczbę partycji (num_leaves) indeksu:
CREATE INDEX cymbal_products_embeddings_scann ON cymbal_products
USING scann (embedding cosine)
WITH (num_leaves=31, max_num_levels = 2);
Więcej informacji o dostrajaniu parametrów indeksu znajdziesz w dokumentacji.
Oczekiwane dane wyjściowe:
quickstart_db=> CREATE INDEX cymbal_products_embeddings_scann ON cymbal_products USING scann (embedding cosine) WITH (num_leaves=31, max_num_levels = 2); CREATE INDEX quickstart_db=>
Porównaj odpowiedź
Możemy teraz uruchomić wyszukiwanie wektorowe w trybie EXPLAIN i sprawdzić, czy użyto indeksu.
EXPLAIN (analyze)
WITH trees as (
SELECT
cp.product_name,
left(cp.product_description,80) as description,
cp.sale_price,
cs.zip_code,
cp.uniq_id as product_id
FROM
cymbal_products cp
JOIN cymbal_inventory ci on
ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
cs.store_id=ci.store_id
AND ci.inventory>0
AND cs.store_id = 1583
ORDER BY
(cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;
Oczekiwany wynik:
Aggregate (cost=16.59..16.60 rows=1 width=32) (actual time=2.875..2.877 rows=1 loops=1) -> Subquery Scan on trees (cost=8.42..16.59 rows=1 width=142) (actual time=2.860..2.862 rows=1 loops=1) -> Limit (cost=8.42..16.58 rows=1 width=158) (actual time=2.855..2.856 rows=1 loops=1) -> Nested Loop (cost=8.42..6489.19 rows=794 width=158) (actual time=2.854..2.855 rows=1 loops=1) -> Nested Loop (cost=8.13..6466.99 rows=794 width=938) (actual time=2.742..2.743 rows=1 loops=1) -> Index Scan using cymbal_products_embeddings_scann on cymbal_products cp (cost=7.71..111.99 rows=876 width=934) (actual time=2.724..2.724 rows=1 loops=1) Order By: (embedding <=> '[0.008864171,0.03693164,-0.024245683,-0.00355923,0.0055611245,0.015985578,...<redacted>...5685,-0.03914233,-0.018452475,0.00826032,-0.07372604]'::vector) -> Index Scan using walmart_inventory_pkey on cymbal_inventory ci (cost=0.42..7.26 rows=1 width=37) (actual time=0.015..0.015 rows=1 loops=1) Index Cond: ((store_id = 1583) AND (uniq_id = (cp.uniq_id)::text))
Na podstawie danych wyjściowych wyraźnie widać, że w zapytaniu użyto polecenia „Index Scan using cymbal_products_embeddings_scann na cymbal_products”.
A jeśli uruchomimy zapytanie bez wyjaśnienia:
WITH trees as (
SELECT
cp.product_name,
left(cp.product_description,80) as description,
cp.sale_price,
cs.zip_code,
cp.uniq_id as product_id
FROM
cymbal_products cp
JOIN cymbal_inventory ci on
ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
cs.store_id=ci.store_id
AND ci.inventory>0
AND cs.store_id = 1583
ORDER BY
(cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;
Oczekiwany wynik:
[{"product_name":"Meyer Lemon Tree","description":"Meyer Lemon trees are California's favorite lemon tree! Grow your own lemons by ","sale_price":34,"zip_code":93230,"product_id":"02056727942aeb714dc9a2313654e1b0"}]
Widać, że wynik jest nieco inny i zwraca nie drzewo wiśniowe, które było na szczycie wyników wyszukiwania bez indeksu, ale drugie drzewo cytrynowe Meyer. Indeks pokazuje nam wydajność, ale nadal wystarczająco dokładny, aby dostarczać dobre wyniki.
Możesz wypróbować różne indeksy dostępne dla wektorów oraz inne moduły i przykłady dzięki integracji z interfejsem langchain, która jest dostępna na stronie dokumentacji.
11. Czyszczenie środowiska
Po zakończeniu pracy z tym modułem usuń instancje i klastry AlloyDB
Usuwanie klastra AlloyDB i wszystkich jego instancji
Klaster jest usuwany z opcją wymuszania, która powoduje również usunięcie wszystkich instancji należących do klastra.
W Cloud Shell zdefiniuj zmienne projektu i środowiskowego, jeśli konto jest odłączone i stracone są wszystkie poprzednie ustawienia:
gcloud config set project <your project id>
export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
export PROJECT_ID=$(gcloud config get-value project)
Usuń klaster:
gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force
Oczekiwane dane wyjściowe konsoli:
student@cloudshell:~ (test-project-001-402417)$ gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force All of the cluster data will be lost when the cluster is deleted. Do you want to continue (Y/n)? Y Operation ID: operation-1697820178429-6082890a0b570-4a72f7e4-4c5df36f Deleting cluster...done.
Usuwanie kopii zapasowych AlloyDB
Usuń wszystkie kopie zapasowe AlloyDB dla klastra:
for i in $(gcloud alloydb backups list --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" --format="value(name)" --sort-by=~createTime) ; do gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done
Oczekiwane dane wyjściowe konsoli:
student@cloudshell:~ (test-project-001-402417)$ for i in $(gcloud alloydb backups list --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" --format="value(name)" --sort-by=~createTime) ; do gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done Operation ID: operation-1697826266108-60829fb7b5258-7f99dc0b-99f3c35f Deleting backup...done.
Teraz możemy usunąć maszynę wirtualną.
Usuwanie maszyny wirtualnej GCE
W Cloud Shell wykonaj te czynności:
export GCEVM=instance-1
export ZONE=us-central1-a
gcloud compute instances delete $GCEVM \
--zone=$ZONE \
--quiet
Oczekiwane dane wyjściowe konsoli:
student@cloudshell:~ (test-project-001-402417)$ export GCEVM=instance-1 export ZONE=us-central1-a gcloud compute instances delete $GCEVM \ --zone=$ZONE \ --quiet Deleted
12. Gratulacje
Gratulujemy ukończenia ćwiczeń z programowania.
Omówione zagadnienia
- Jak wdrożyć klaster i instancję główną AlloyDB
- Jak połączyć się z AlloyDB z maszyny wirtualnej Google Compute Engine
- Jak utworzyć bazę danych i włączyć AlloyDB AI
- Wczytywanie danych do bazy danych
- Jak używać modelu wstawiania Vertex AI w AlloyDB
- Wzbogacanie wyników za pomocą modelu generatywnego Vertex AI
- Jak zwiększyć wydajność dzięki indeksowi wektorowemu
13. Ankieta
Dane wyjściowe: