Pierwsze kroki z wektorami dystrybucyjnymi w Cloud SQL for PostgreSQL

1. Wprowadzenie

Z tego samouczka dowiesz się, jak korzystać z integracji Cloud SQL for PostgreSQL z AI, łącząc wyszukiwanie wektorowe z wektorami dystrybucyjnymi Vertex AI.

8aa6ba3bc12a1593.png

Wymagania wstępne

  • Podstawowa wiedza o Google Cloud i konsoli
  • Podstawowe umiejętności w zakresie interfejsu wiersza poleceń i Cloud Shell

Czego się nauczysz

  • Jak wdrożyć instancję Cloud SQL dla PostgreSQL
  • Jak utworzyć bazę danych i włączyć integrację Cloud SQL z AI
  • Wczytywanie danych do bazy danych
  • Jak korzystać z Cloud SQL Studio
  • Jak używać modelu wektorów dystrybucyjnych Vertex AI w Cloud SQL
  • Jak korzystać z Vertex AI Studio
  • Jak wzbogacić wynik za pomocą modelu generatywnego Vertex AI
  • Jak poprawić skuteczność za pomocą indeksu wektorów

Czego potrzebujesz

  • Konto Google Cloud i projekt Google Cloud
  • przeglądarka internetowa, np. Chrome, obsługująca konsolę Google Cloud i Cloud Shell;

2. Konfiguracja i wymagania

Konfiguracja projektu

  1. Zaloguj się w konsoli Google Cloud. Jeśli nie masz jeszcze konta Gmail lub Google Workspace, musisz je utworzyć.

Użyj konta osobistego zamiast konta służbowego lub szkolnego.

  1. Utwórz nowy projekt lub użyj istniejącego. Aby utworzyć nowy projekt w konsoli Google Cloud, w nagłówku kliknij przycisk Wybierz projekt. Otworzy się okno wyskakujące.

295004821bab6a87.png

W oknie Wybierz projekt kliknij przycisk Nowy projekt, który otworzy okno dialogowe nowego projektu.

37d264871000675d.png

W oknie dialogowym wpisz preferowaną nazwę projektu i wybierz lokalizację.

96d86d3d5655cdbe.png

  • Nazwa projektu to wyświetlana nazwa uczestników tego projektu. Nazwa projektu nie jest używana przez interfejsy API Google i można ją w dowolnym momencie zmienić.
  • Identyfikator projektu jest unikalny we wszystkich projektach Google Cloud i nie można go zmienić po ustawieniu. Konsola Google Cloud automatycznie generuje unikalny identyfikator, ale możesz go dostosować. Jeśli wygenerowany identyfikator Ci się nie podoba, możesz wygenerować inny losowy identyfikator lub podać własny, aby sprawdzić jego dostępność. W większości ćwiczeń z programowania musisz odwoływać się do identyfikatora projektu, który jest zwykle oznaczony zmienną PROJECT_ID.
  • Warto wiedzieć, że istnieje trzecia wartość, numer projektu, której używają niektóre interfejsy API. Więcej informacji o tych 3 wartościach znajdziesz w dokumentacji.

Włącz płatności

Płatności możesz włączyć na 2 sposoby. Możesz użyć osobistego konta rozliczeniowego lub wykorzystać środki, wykonując te czynności.

Wykorzystaj środki na Google Cloud o wartości 5 USD (opcjonalnie)

Aby przeprowadzić te warsztaty, musisz mieć konto rozliczeniowe z określonymi środkami. Jeśli planujesz używać własnego konta rozliczeniowego, możesz pominąć ten krok.

  1. Kliknij ten link i zaloguj się na osobiste konto Google.
  2. Zobaczysz coś takiego:

f54628965f465486.png

  1. Kliknij przycisk KLIKNIJ TUTAJ, ABY UZYSKAĆ DOSTĘP DO ŚRODKÓW. Spowoduje to otwarcie strony, na której możesz skonfigurować profil płatności. Jeśli pojawi się ekran rejestracji w bezpłatnym okresie próbnym, kliknij Anuluj i przejdź do połączenia rozliczeń.

20e88842cf2a732e.png

  1. Kliknij Potwierdź. Nastąpi połączenie z próbnym kontem rozliczeniowym Google Cloud Platform.

cdc87f1c57777951.png

Konfigurowanie osobistego konta rozliczeniowego

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 płatności w Cloud Console.

Uwagi:

Uruchamianie Cloud Shell

Google Cloud można obsługiwać zdalnie z laptopa, ale w tym module praktycznym 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 pasku narzędzi w prawym górnym rogu:

Aktywowanie Cloud Shell

Możesz też nacisnąć G, a potem S. Ta sekwencja aktywuje Cloud Shell, jeśli korzystasz z konsoli Google Cloud. Możesz też użyć tego linku.

Udostępnienie środowiska i połączenie się z nim może zająć tylko kilka chwil. Po zakończeniu powinno wyświetlić się coś takiego:

Zrzut ekranu terminala Google Cloud Shell pokazujący, że środowisko zostało połączone

Ta maszyna wirtualna zawiera 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 zwiększa wydajność sieci i uwierzytelnianie. Wszystkie zadania w tym laboratorium możesz wykonać w przeglądarce. Nie musisz niczego instalować.

3. Zanim zaczniesz

Włącz API

Dane wyjściowe:

Aby korzystać z usług Cloud SQL, Compute Engine, usług sieciowych i Vertex AI, musisz włączyć odpowiednie interfejsy API w projekcie Google Cloud.

W terminalu 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 sqladmin.googleapis.com \
                       compute.googleapis.com \
                       cloudresourcemanager.googleapis.com \
                       servicenetworking.googleapis.com \
                       aiplatform.googleapis.com

Oczekiwane dane wyjściowe

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 sqladmin.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.

Przedstawiamy interfejsy API

  • Cloud SQL Admin API (sqladmin.googleapis.com) umożliwia programowe tworzenie, konfigurowanie i zarządzanie instancjami Cloud SQL. Zapewnia płaszczyznę sterowania dla w pełni zarządzanej usługi relacyjnej bazy danych Google (obsługującej MySQL, PostgreSQL i SQL Server), która obsługuje zadania takie jak udostępnianie, tworzenie kopii zapasowych, wysoka dostępność i skalowanie.
  • Compute Engine API (compute.googleapis.com) umożliwia tworzenie maszyn wirtualnych, dysków trwałych i ustawień sieciowych oraz zarządzanie nimi. Zapewnia podstawową infrastrukturę jako usługę (IaaS) potrzebną do uruchamiania zbiorów zadań i hostowania infrastruktury bazowej dla wielu usług zarządzanych.
  • Cloud Resource Manager API (cloudresourcemanager.googleapis.com) umożliwia zautomatyzowane zarządzanie metadanymi i konfiguracją projektu Google Cloud. Umożliwia organizowanie zasobów, obsługę zasad Identity and Access Management (IAM) oraz weryfikowanie uprawnień w hierarchii projektu.
  • Service Networking API (servicenetworking.googleapis.com) umożliwia automatyzację konfiguracji prywatnej łączności między siecią Virtual Private Cloud (VPC) a usługami zarządzanymi Google. Jest to szczególnie ważne w przypadku zapewnienia dostępu do usług takich jak AlloyDB za pomocą prywatnego adresu IP, aby mogły one bezpiecznie komunikować się z innymi zasobami.
  • Interfejs Vertex AI API (aiplatform.googleapis.com) umożliwia aplikacjom tworzenie, wdrażanie i skalowanie modeli uczenia maszynowego. Zapewnia ujednolicony interfejs dla wszystkich usług AI w Google Cloud, w tym dostęp do modeli generatywnej AI (takich jak Gemini) i trenowania modeli niestandardowych.

4. Tworzenie instancji Cloud SQL

Utwórz instancję Cloud SQL z integracją bazy danych z Vertex AI.

Utwórz hasło do bazy danych

Określ hasło domyślnego użytkownika bazy danych. Możesz zdefiniować własne hasło lub użyć funkcji losowej, aby je wygenerować:

export CLOUDSQL_PASSWORD=`openssl rand -hex 12`

Zanotuj wygenerowaną wartość hasła:

echo $CLOUDSQL_PASSWORD

Tworzenie instancji Cloud SQL for PostgreSQL

Instancje Cloud SQL można tworzyć na różne sposoby, np. za pomocą konsoli Google Cloud, narzędzi do automatyzacji, takich jak Terraform, lub pakietu SDK Google Cloud. W tym module będziemy używać głównie narzędzia gcloud z pakietu Google Cloud SDK. W dokumentacji znajdziesz informacje o tym, jak utworzyć instancję za pomocą innych narzędzi.

W sesji Cloud Shell wykonaj to polecenie:

gcloud sql instances create my-cloudsql-instance \
--database-version=POSTGRES_17 \
--tier=db-custom-1-3840 \
--region=us-central1 \
--edition=ENTERPRISE \
--enable-google-ml-integration \
--database-flags cloudsql.enable_google_ml_integration=on

Po utworzeniu instancji musimy ustawić hasło domyślnego użytkownika w instancji i sprawdzić, czy możemy się połączyć za pomocą tego hasła.

gcloud sql users set-password postgres \
    --instance=my-cloudsql-instance \
    --password=$CLOUDSQL_PASSWORD

Uruchom polecenie „gcloud sql connect” w formie podanej w ramce i wpisz hasło w odpowiedzi na wyświetlony monit, gdy będzie można się połączyć.

gcloud sql connect my-cloudsql-instance --user=postgres

Na razie zamknij sesję psql, używając skrótu klawiszowego Ctrl+D lub wykonując polecenie exit.

exit

Włącz integrację z Vertex AI

Przyznaj wewnętrznemu kontu usługi Cloud SQL niezbędne uprawnienia, aby można było korzystać z integracji z Vertex AI.

Znajdź adres e-mail wewnętrznego konta usługi Cloud SQL i wyeksportuj go jako zmienną.

SERVICE_ACCOUNT_EMAIL=$(gcloud sql instances describe my-cloudsql-instance --format="value(serviceAccountEmailAddress)")
echo $SERVICE_ACCOUNT_EMAIL

Przyznaj dostęp do Vertex AI kontu usługi Cloud SQL:

PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
  --role="roles/aiplatform.user"

Więcej informacji o tworzeniu i konfigurowaniu instancji znajdziesz w dokumentacji Cloud SQL tutaj.

5. Przygotowywanie bazy danych

Teraz musimy utworzyć bazę danych i włączyć obsługę wektorów.

Utwórz bazę danych

Utwórz bazę danych o nazwie quickstart_db. Możesz to zrobić na różne sposoby, np. za pomocą klientów bazy danych w wierszu poleceń, takich jak psql w przypadku PostgreSQL, pakietu SDK lub Cloud SQL Studio. Do tworzenia baz danych i łączenia się z instancją będziemy używać pakietu SDK (gcloud).

Wykonywanie polecenia w Cloud Shell w celu utworzenia bazy danych

gcloud sql databases create quickstart_db --instance=my-cloudsql-instance

Włącz rozszerzenia

Aby móc pracować z Vertex AI i wektorami, musimy włączyć w utworzonej bazie danych 2 rozszerzenia.

W Cloud Shell wykonaj polecenie, aby połączyć się z utworzoną bazą danych (musisz podać hasło).

gcloud sql connect my-cloudsql-instance --database quickstart_db --user=postgres

Po nawiązaniu połączenia w sesji SQL musisz uruchomić 2 polecenia:

CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector CASCADE;

Zakończ sesję SQL:

exit;

6. Wczytaj dane

Teraz musimy utworzyć obiekty w bazie danych i wczytać dane. Będziemy używać fikcyjnych danych sklepu Cymbal Store. Dane są dostępne w publicznym zasobniku Google Storage w formacie CSV.

Najpierw musimy utworzyć w bazie danych wszystkie wymagane obiekty. W tym celu użyjemy znanych już poleceń gcloud sql connect i gcloud storage, aby pobrać i zaimportować obiekty schematu do naszej bazy danych.

W Cloud Shell wykonaj to polecenie i podaj hasło, które zostało zapisane podczas tworzenia instancji:

gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |gcloud sql connect my-cloudsql-instance --database quickstart_db --user=postgres

Co dokładnie zrobiliśmy w poprzednim poleceniu? Połączyliśmy się z bazą danych i wykonaliśmy pobrany kod SQL, który utworzył tabele, indeksy i sekwencje.

Następnym krokiem jest wczytanie danych. Aby to zrobić, musimy pobrać pliki CSV z Google Cloud Storage.

gcloud storage cp gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv .
gcloud storage cp gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv .
gcloud storage cp gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv .

Następnie musimy połączyć się z bazą danych.

gcloud sql connect my-cloudsql-instance --database quickstart_db --user=postgres

i importować dane z plików CSV.

\copy cymbal_products from 'cymbal_products.csv' csv header
\copy cymbal_inventory from 'cymbal_inventory.csv' csv header
\copy cymbal_stores from 'cymbal_stores.csv' csv header

Jeśli masz własne dane, a pliki CSV są zgodne z narzędziem do importowania Cloud SQL dostępnym w Cloud Console, możesz użyć tego narzędzia zamiast wiersza poleceń.

7. Tworzenie wektorów dystrybucyjnych

Następnym krokiem jest utworzenie wektorów dystrybucyjnych opisów produktów za pomocą modelu textembedding-004 z Google Vertex AI i zapisanie ich jako danych wektorowych.

Połącz się z bazą danych (jeśli sesja została zakończona lub odłączona):

gcloud sql connect my-cloudsql-instance --database quickstart_db --user=postgres

Następnie utwórz wirtualną kolumnę embedding w tabeli cymbal_products za pomocą funkcji embedding. To polecenie tworzy kolumnę wirtualną „embedding”, w której będą przechowywane nasze wektory z dystrybucjami wygenerowanymi na podstawie kolumny „product_description”. Tworzy też wektory dystrybucyjne dla wszystkich istniejących wierszy w tabeli. Model jest zdefiniowany jako pierwszy parametr funkcji osadzania, a dane źródłowe jako drugi parametr.

ALTER TABLE cymbal_products ADD COLUMN embedding vector(768) GENERATED ALWAYS AS (embedding('text-embedding-005',product_description)) STORED;

Może to zająć trochę czasu, ale w przypadku 900–1000 wierszy nie powinno to trwać dłużej niż 5 minut, a zwykle jest znacznie szybsze.

Gdy wstawimy nowy wiersz do tabeli lub zaktualizujemy kolumnę product_description w dowolnym istniejącym wierszu, dane kolumny wirtualnej „embedding” zostaną ponownie wygenerowane na podstawie kolumny „product_description”.

8. Uruchom wyszukiwanie podobieństw

Możemy teraz przeprowadzić wyszukiwanie podobieństw na podstawie wartości wektorowych obliczonych dla opisów i wartości wektorowej uzyskanej dla naszego żądania.

Zapytanie SQL można wykonać z tego samego interfejsu wiersza poleceń za pomocą polecenia gcloud sql connect lub w Cloud SQL Studio. Wszystkie zapytania wielowierszowe i złożone lepiej jest zarządzać w Cloud SQL Studio.

Uruchamianie Cloud SQL Studio

W konsoli kliknij utworzoną wcześniej instancję Cloud SQL.

903eeb9bbaf4a419.png

Gdy otworzy się w panelu po prawej stronie, zobaczysz Cloud SQL Studio. Kliknij ją.

7874a11b28519b71.png

Otworzy się okno dialogowe, w którym możesz podać nazwę bazy danych i dane logowania:

  • Baza danych: quickstart_db
  • Użytkownik: postgres
  • Hasło: zapisane hasło głównego użytkownika bazy danych.

Następnie kliknij przycisk „AUTHENTICATE” (UWIERZYTELNIJ).

d5ee9e56dfef3905.png

Otworzy się kolejne okno, w którym po prawej stronie kliknij kartę „Edytor”, aby otworzyć edytor SQL.

19a6ebd18ef6ae34.png

Teraz możemy uruchomić zapytania.

Uruchom zapytanie

Uruchom zapytanie, aby uzyskać listę dostępnych produktów najbardziej związanych z prośbą klienta. Żądanie, które przekażemy do Vertex AI, aby uzyskać wartość wektorową, będzie brzmieć: „Jakie drzewa owocowe dobrze tu rosną?”.

Oto zapytanie, które możesz uruchomić, aby wybrać 10 pierwszych elementów najbardziej odpowiednich dla Twojego żądania:

SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        (cp.embedding <=> embedding('text-embedding-005','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;

Skopiuj i wklej zapytanie do edytora Cloud SQL Studio, a następnie kliknij przycisk „URUCHOM” lub wklej je w sesji wiersza poleceń połączonej z bazą danych quickstart_db.

a8a2f83593aa5f37.png

A oto lista wybranych produktów pasujących do zapytania.

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
(10 rows)

9. Ulepszanie odpowiedzi LLM za pomocą pobranych danych

Możemy ulepszyć odpowiedź modelu LLM generatywnej AI na zapytanie aplikacji klienta, korzystając z wyniku wykonanego zapytania, i przygotować przydatne dane wyjściowe, używając dostarczonych wyników zapytania jako części promptu dla generatywnego modelu podstawowego w Vertex AI.

Aby to osiągnąć, musimy wygenerować plik JSON z wynikami wyszukiwania wektorowego, a następnie użyć go jako dodatku do promptu dla modelu LLM w Vertex AI, aby uzyskać przydatne dane wyjściowe. W pierwszym kroku generujemy kod JSON, następnie testujemy go w Vertex AI Studio, a w ostatnim kroku włączamy go do instrukcji SQL, której można używać w aplikacji.

Generowanie danych wyjściowych w formacie JSON

Zmodyfikuj zapytanie, aby wygenerować dane wyjściowe w formacie JSON i zwrócić tylko jeden wiersz do przekazania do Vertex AI.

Cloud SQL dla PostgreSQL

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-005','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;

Oto oczekiwany format JSON w danych wyjściowych:

[{"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

Wygenerowany kod JSON możemy wykorzystać jako część promptu dla modelu generatywnej AI w Vertex AI Studio.

Otwórz Vertex AI Studio w konsoli Google Cloud.

d48549b1b0f449b4.png

Może poprosić Cię o włączenie dodatkowych interfejsów API, ale możesz zignorować tę prośbę. Do ukończenia modułu nie potrzebujemy żadnych dodatkowych interfejsów API.

Wpisz prompt w Studio.

2a6f5a338fefd229.png

Oto prompt, którego użyjemy:

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","description":"some description","sale_price":10,"zip_code": 10234, "produt_id": "02056727942aeb714dc9a2313654e1b0"}
Here is the list of products:
[place your JSON here]
The customer asked "What tree is growing the best here?"
You should give information about the product, price and some supplemental information.
Do not ask any additional questions and assume location based on the zip code provided in the list of products.

A tak wygląda to po zastąpieniu obiektu zastępczego JSON odpowiedzią na zapytanie:

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","description":"some description","sale_price":10,"zip_code": 10234, "produt_id": "02056727942aeb714dc9a2313654e1b0"}
Here is the list of products:
[{"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"}]
The customer asked "What tree is growing the best here?"
You should give information about the product, price and some supplemental information.
Do not ask any additional questions and assume location based on the zip code provided in the list of products.

A oto wynik po uruchomieniu promptu z wartościami JSON:

a0f7ead40d0a1d62.png

Odpowiedź, którą uzyskaliśmy od modelu w tym przykładzie, jest następująca: Pamiętaj, że Twoja odpowiedź może się różnić ze względu na zmiany modelu i parametrów w czasie:

„Na podstawie kodu pocztowego podanego na liście produktów (93230) wygląda na to, że znajdujesz się w okolicach Hanford w Kalifornii.1346 Ten region, położony w dolinie San Joaquin, jest jednym z najlepszych miejsc w kraju do uprawy owoców pestkowych.

Odpowiadając na Twoje pytanie, najlepszym drzewem z naszej oferty, które rośnie w Twojej okolicy, jest wiśnia.

Oto szczegóły:

Produkt: Cherry Tree

Cena: 75,00 PLN

Opis: to piękne drzewo wiśniowe, które będzie rodzić pyszne wiśnie.2

Dlaczego rośnie tu najlepiej: klimat Doliny San Joaquin zapewnia specyficzne warunki, których potrzebują wiśnie do rozwoju: długie, ciepłe letnie dni, które sprzyjają rozwojowi owoców, i chłodne noce.5 Hanford znajduje się w ważnym centrum rolniczym znanym z produkcji owoców pestkowych, więc możesz oczekiwać, że to drzewo będzie bardzo produktywne w Twojej lokalnej glebie. Pamiętaj tylko, aby posadzić ją w miejscu z pełnym nasłonecznieniem i dobrze przepuszczalną glebą, aby uzyskać jak najlepsze zbiory”.

Uruchom prompta w PSQL

Możemy też użyć integracji Cloud SQL AI z Vertex AI, aby uzyskać podobną odpowiedź z modelu generatywnego za pomocą SQL bezpośrednio w bazie danych. Aby jednak używać modelu gemini-2.0-flash-exp, musimy go najpierw zarejestrować.

Uruchamianie w Cloud SQL for PostgreSQL

Zaktualizuj rozszerzenie do wersji 1.4.2 lub nowszej (jeśli bieżąca wersja jest starsza). Połącz się z bazą danych quickstart_db za pomocą polecenia gcloud sql connect, jak pokazano wcześniej (lub użyj Cloud SQL Studio), i wykonaj:

SELECT extversion from pg_extension where extname='google_ml_integration';

Jeśli zwrócona wartość jest mniejsza niż 1.4.3, wykonaj:

ALTER EXTENSION google_ml_integration UPDATE TO '1.4.3';

Następnie musimy ustawić flagę bazy danych google_ml_integration.enable_model_support na „on”. Aby sprawdzić bieżące ustawienia, wykonaj to polecenie.

show google_ml_integration.enable_model_support;

Oczekiwane dane wyjściowe sesji psql to „on”:

quickstart_db => show google_ml_integration.enable_model_support;
 google_ml_integration.enable_model_support 
--------------------------------------------
 on
(1 row)

Jeśli wyświetla się „off”, musimy zaktualizować flagę bazy danych. Możesz to zrobić za pomocą interfejsu konsoli internetowej lub uruchamiając to polecenie gcloud.

gcloud sql instances patch my-cloudsql-instance \
--database-flags google_ml_integration.enable_model_support=on,cloudsql.enable_google_ml_integration=on

Wykonanie tego polecenia w tle zajmuje około 1–3 minut. Następnie możesz sprawdzić nową flagę w sesji psql lub za pomocą Cloud SQL Studio, łącząc się z bazą danych quickstart_db.

show google_ml_integration.enable_model_support;

Oczekiwane dane wyjściowe sesji psql to „on”:

quickstart_db => show google_ml_integration.enable_model_support;
 google_ml_integration.enable_model_support 
--------------------------------------------
 on
(1 row)

Następnie musimy zarejestrować 2 modele. Pierwszy to używany już model text-embedding-005. Musisz go zarejestrować, ponieważ włączyliśmy funkcje rejestracji modeli.

Aby zarejestrować uruchomienie modelu w psql lub Cloud SQL Studio, użyj tego kodu:

CALL
  google_ml.create_model(
    model_id => 'text-embedding-005',
    model_provider => 'google',
    model_qualified_name => 'text-embedding-005',
    model_type => 'text_embedding',
    model_auth_type => 'cloudsql_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');

Kolejny model, który musimy zarejestrować, to gemini-2.0-flash-001. Będzie on używany do generowania przyjaznych dla użytkownika danych wyjściowych.

CALL
  google_ml.create_model(
    model_id => 'gemini-2.5-flash',
    model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/us-central1/publishers/google/models/gemini-2.5-flash:streamGenerateContent',
    model_provider => 'google',
    model_auth_type => 'cloudsql_service_agent_iam');

Listę zarejestrowanych modeli możesz zawsze sprawdzić, wybierając informacje z google_ml.model_info_view.

select model_id,model_type from google_ml.model_info_view;

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
 gemini-1.5-pro:streamGenerateContent | generic
 gemini-1.5-pro:generateContent       | generic
 gemini-1.0-pro:generateContent       | generic
 text-embedding-005                   | text_embedding
 gemini-2.5-flash                     | generic

Teraz możemy użyć wygenerowanego w zapytaniu podrzędnym kodu JSON, aby przekazać go jako część prompta do generatywnego modelu tekstowego AI za pomocą SQL.

W sesji psql lub Cloud SQL Studio w bazie danych uruchom zapytanie.

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 <=> google_ml.embedding('text-embedding-005',
        '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-2.5-flash',
        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. Wynik może się różnić w zależności od wersji modelu i parametrów:

"That's a great question! It sounds like you're looking to add some delicious fruit to your garden.\n\nBased on the products we have that are closely related to your search, I can tell you about a fantastic option:\n\n**Cherry Tree**" "\n* **Description:** This beautiful deciduous tree will produce delicious cherries. It grows to be about 15 feet tall, with dark green leaves in summer that turn a beautiful red in the fall. Cherry trees are known for their beauty, shade, and privacy. They prefer a cool, moist climate and sandy soil." "\n* **Price:** $75.00\n* **Grows well in:** USDA Zones 4-9.\n\nTo confirm if this Cherry Tree will thrive in your specific location, you might want to check which USDA Hardiness Zone your area falls into. If you're in zones 4-9, this" " could be a wonderful addition to your yard!"

10. Tworzenie indeksu najbliższego sąsiada

Nasz zbiór danych jest dość mały, a czas odpowiedzi zależy głównie od interakcji z modelami AI. Jednak w przypadku milionów wektorów wyszukiwanie wektorowe może zajmować znaczną część czasu odpowiedzi i mocno obciążać system. Aby to poprawić, możemy utworzyć indeks na podstawie naszych wektorów.

Tworzenie indeksu HNSW

Do testu użyjemy typu indeksu HNSW. HNSW to skrót od Hierarchical Navigable Small World (hierarchiczna nawigacyjna sieć małego świata). Jest to wielowarstwowy indeks grafu.

Aby utworzyć indeks dla kolumny z wektorami, musimy zdefiniować kolumnę z wektorami, funkcję odległości i opcjonalnie parametry takie jak m lub ef_constructions. Szczegółowe informacje o parametrach znajdziesz w dokumentacji.

CREATE INDEX cymbal_products_embeddings_hnsw ON cymbal_products
  USING hnsw (embedding vector_cosine_ops)
  WITH (m = 16, ef_construction = 64);

Oczekiwane dane wyjściowe:

quickstart_db=> CREATE INDEX cymbal_products_embeddings_hnsw ON cymbal_products
  USING hnsw (embedding vector_cosine_ops)
  WITH (m = 16, ef_construction = 64);
CREATE INDEX
quickstart_db=>

Porównaj odpowiedź

Teraz możemy uruchomić zapytanie w ramach wyszukiwania wektorowego w trybie EXPLAIN i sprawdzić, czy indeks został użyty.

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-005','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;

Oczekiwane dane wyjściowe:

 Aggregate  (cost=779.12..779.13 rows=1 width=32) (actual time=1.066..1.069 rows=1 loops=1)
   ->  Subquery Scan on trees  (cost=769.05..779.12 rows=1 width=142) (actual time=1.038..1.041 rows=1 loops=1)
         ->  Limit  (cost=769.05..779.11 rows=1 width=158) (actual time=1.022..1.024 rows=1 loops=1)
               ->  Nested Loop  (cost=769.05..9339.69 rows=852 width=158) (actual time=1.020..1.021 rows=1 loops=1)
                     ->  Nested Loop  (cost=768.77..9316.48 rows=852 width=945) (actual time=0.858..0.859 rows=1 loops=1)
                           ->  Index Scan using cymbal_products_embeddings_hnsw on cymbal_products cp  (cost=768.34..2572.47 rows=941 width=941) (actual time=0.532..0.539 rows=3 loops=1)
                                 Order By: (embedding <=> '[0.008864171,0.03693164,-0.024245683,...
<redacted>
...,0.017593635,-0.040275685,-0.03914233,-0.018452475,0.00826032,-0.07372604
]'::vector)
                           ->  Index Scan using product_inventory_pkey on cymbal_inventory ci  (cost=0.42..7.17 rows=1 width=37) (actual time=0.104..0.104 rows=0 loops=3)
                                 Index Cond: ((store_id = 1583) AND (uniq_id = (cp.uniq_id)::text))
                                 Filter: (inventory > 0)
                                 Rows Removed by Filter: 1
                     ->  Materialize  (cost=0.28..8.31 rows=1 width=8) (actual time=0.133..0.134 rows=1 loops=1)
                           ->  Index Scan using product_stores_pkey on cymbal_stores cs  (cost=0.28..8.30 rows=1 width=8) (actual time=0.129..0.129 rows=1 loops=1)
                                 Index Cond: (store_id = 1583)
 Planning Time: 112.398 ms
 Execution Time: 1.221 ms

Z danych wyjściowych wyraźnie widać, że zapytanie używało „Index Scan using cymbal_products_embeddings_hnsw”.

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-005','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;

Oczekiwane dane wyjściowe (mogą się różnić w zależności od modelu i indeksu):

[{"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"}]

Widzimy, że wynik jest taki sam, i zwracamy to samo drzewo wiśni, które było na szczycie naszych wyników wyszukiwania bez indeksu. W zależności od parametrów i typu indeksu wynik może się nieco różnić i zwracać inny rekord najwyższego poziomu w drzewie. Podczas testów zapytanie indeksowane zwróciło wyniki w 131,301 ms, a zapytanie bez indeksu – w 167,631 ms. Pracowaliśmy jednak na bardzo małym zbiorze danych, a w przypadku większych zbiorów różnica byłaby większa.

dokumentacji znajdziesz różne indeksy dostępne dla wektorów oraz więcej modułów i przykładów z integracją LangChain.

11. Czyszczenie środowiska

Usuwanie instancji Cloud SQL

Po zakończeniu ćwiczenia usuń instancję Cloud SQL.

W Cloud Shell zdefiniuj projekt i zmienne środowiskowe, jeśli połączenie zostało przerwane i wszystkie poprzednie ustawienia zostały utracone:

export INSTANCE_NAME=my-cloudsql-instance
export PROJECT_ID=$(gcloud config get-value project)

Usuń instancję:

gcloud sql instances delete $INSTANCE_NAME --project=$PROJECT_ID

Oczekiwane dane wyjściowe konsoli:

student@cloudshell:~$ gcloud sql instances delete $INSTANCE_NAME --project=$PROJECT_ID
All of the instance data will be lost when the instance is deleted.

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

Deleting Cloud SQL instance...done.                                                                                                                
Deleted [https://sandbox.googleapis.com/v1beta4/projects/test-project-001-402417/instances/my-cloudsql-instance].

12. Gratulacje

Gratulujemy ukończenia ćwiczenia.

Ten moduł jest częścią ścieżki szkoleniowej Wdrożenie AI w Google Cloud.

Omówione zagadnienia

  • Jak wdrożyć instancję Cloud SQL dla PostgreSQL
  • Jak utworzyć bazę danych i włączyć integrację Cloud SQL z AI
  • Wczytywanie danych do bazy danych
  • Jak korzystać z Cloud SQL Studio
  • Jak używać modelu wektorów dystrybucyjnych Vertex AI w Cloud SQL
  • Jak korzystać z Vertex AI Studio
  • Jak wzbogacić wynik za pomocą modelu generatywnego Vertex AI
  • Jak poprawić skuteczność za pomocą indeksu wektorów

Wypróbuj podobne ćwiczenie programistyczne dotyczące AlloyDB z indeksem ScaNN zamiast HNSW

13. Ankieta

Dane wyjściowe:

Jak zamierzasz wykorzystać ten samouczek?

Tylko przeczytaj Przeczytaj i wykonaj ćwiczenia