1. Przegląd
Wyobraź sobie, że wchodzisz do sklepu z zabawkami wirtualnie lub stacjonarnie i bez trudu znajdujesz idealny prezent. Możesz opisać, czego szukasz, przesłać zdjęcie zabawki lub nawet zaprojektować własną kreację, a sklep od razu zrozumie Twoje potrzeby i zapewni spersonalizowane wrażenia. To nie jest futurystyczna fantazja, ale rzeczywistość oparta na AI, technologii chmurowej i wizji spersonalizowanego e-commerce.
Wyzwanie: znalezienie idealnego produktu, który odpowiada Twoim oczekiwaniom, może być trudne. Ogólne wyszukiwane hasła, słowa kluczowe i wyszukiwania przybliżone często nie przynoszą oczekiwanych rezultatów, przeglądanie nieskończonych stron może być nużące, a rozbieżność między tym, co sobie wyobrażasz, a tym, co jest dostępne, może prowadzić do frustracji.
Rozwiązanie: aplikacja demonstracyjna rozwiązuje ten problem, wykorzystując możliwości AI do zapewnienia prawdziwie spersonalizowanego i płynnego środowiska dzięki wyszukiwaniu kontekstowemu i niestandardowemu generowaniu produktu pasującego do kontekstu wyszukiwania.
Co utworzysz
W tym module wykonasz następujące zadania:
- Tworzenie instancji AlloyDB i wczytywanie zbioru danych Toys
- Włączanie rozszerzeń pgvector i modelu generatywnej AI w AlloyDB
- Generowanie wektorów z opisu produktu i przeprowadzanie w czasie rzeczywistym wyszukiwania podobieństwa kosinusowego dla tekstu wyszukiwanego przez użytkownika
- Wywoływanie Gemini 2.0 Flash w celu opisania obrazu przesłanego przez użytkownika na potrzeby kontekstowego wyszukiwania zabawek
- Wywoływanie Imagen 3 w celu niestandardowego utworzenia zabawki na podstawie zainteresowań użytkownika
- Wywołaj narzędzie do prognozowania cen utworzone za pomocą Gen AI Toolbox for Databases, aby uzyskać szczegółowe informacje o cenie niestandardowej zabawki.
- Wdrażanie rozwiązania w bezserwerowych funkcjach Cloud Run
Wymagania
2. Architektura
Przepływ danych: przyjrzyjmy się bliżej temu, jak dane przemieszczają się w naszym systemie:
- Wyszukiwanie kontekstowe z wykorzystaniem generowania rozszerzonego przez wyszukiwanie w zapisanych informacjach (RAG) opartego na AI
Wyobraź sobie, że zamiast szukać tylko „czerwonego samochodu”, system rozumie te informacje:
„mały pojazd odpowiedni dla 3-letniego chłopca”.
AlloyDB jako podstawa: do przechowywania danych o zabawkach, w tym opisów, adresów URL obrazów i innych istotnych atrybutów, używamy AlloyDB, czyli w pełni zarządzanej i zgodnej z PostgreSQL bazy danych Google Cloud.
pgvector do wyszukiwania semantycznego: pgvector, rozszerzenie PostgreSQL, umożliwia przechowywanie wektorów dystrybucyjnych opisów zabawek i zapytań użytkowników. Umożliwia to wyszukiwanie semantyczne, co oznacza, że system rozumie znaczenie słów, a nie tylko dokładne słowa kluczowe.
Podobieństwo cosinusowe na potrzeby trafności: używamy podobieństwa cosinusowego do pomiaru podobieństwa semantycznego między wektorem wyszukiwania użytkownika a wektorami opisu zabawki, aby wyświetlać najtrafniejsze wyniki.
Indeks ScaNN zapewniający szybkość i dokładność: aby zapewnić szybkie i dokładne wyniki, zwłaszcza w miarę powiększania się naszego asortymentu zabawek, integrujemy indeks ScaNN (Scalable Nearest Neighbors). Znacznie zwiększa to skuteczność i przypominanie wyszukiwania wektorowego.
- Wyszukiwanie i interpretowanie obrazów za pomocą Gemini 2.0 Flash
Załóżmy, że zamiast wpisywać kontekst w postaci tekstu użytkownik chce przesłać zdjęcie znanej zabawki, za pomocą której chce wyszukać informacje. Użytkownicy mogą przesłać zdjęcie zabawki, która im się podoba, i uzyskać odpowiednie funkcje. Do analizy obrazu i wyodrębniania odpowiedniego kontekstu, np. koloru, materiału, typu i grupy wiekowej zabawki, używamy modelu Gemini 2.0 Flash od Google, który jest wywoływany za pomocą LangChain4j.
- Budowanie wymarzonej zabawki dostosowanej za pomocą generatywnej AI: Imagen 3
Prawdziwa magia zaczyna się jednak, gdy użytkownicy postanowią stworzyć własną zabawkę. Dzięki Imagen 3 mogą opisać wymarzoną zabawkę za pomocą prostych promptów tekstowych. Wyobraź sobie, że możesz powiedzieć: „Chcę pluszowego smoka z fioletowymi skrzydłami i przyjazną twarzą”, a potem zobaczyć go na ekranie. Następnie Imagen 3 generuje obraz zaprojektowanej przez użytkownika zabawki, dzięki czemu może on zobaczyć, jak wygląda jego dzieło.
- Prognozowanie cen oparte na agentach i MCP Toolbox for Databases
Wprowadziliśmy funkcję prognozowania ceny, która szacuje koszt wyprodukowania zaprojektowanej przez Ciebie zabawki. Jest to możliwe dzięki agentowi, który zawiera zaawansowane narzędzie do obliczania cen.
MCP Toolbox for Databases: ten agent jest bezproblemowo zintegrowany z naszą bazą danych za pomocą nowego narzędzia open source od Google, MCP Toolbox for Databases. Dzięki temu agent ma dostęp do danych w czasie rzeczywistym dotyczących kosztów materiałów, procesów produkcyjnych i innych istotnych czynników, co pozwala mu podać dokładną szacunkową cenę. Więcej informacji na ten temat znajdziesz tutaj.
- Java Spring Boot, Gemini Code Assist i Cloud Run do sprawnego tworzenia i wdrażania bezserwerowego
Cała aplikacja jest zbudowana przy użyciu Java Spring Boot, solidnej i skalowalnej platformy. W procesie tworzenia korzystaliśmy z Gemini Code Assist, zwłaszcza w przypadku programowania front-endu, co znacznie przyspieszyło cykl programowania i poprawiło jakość kodu. Do wdrożenia całej aplikacji użyliśmy Cloud Run, a do wdrożenia funkcji bazy danych i funkcji agenta jako niezależnych punktów końcowych użyliśmy Cloud Run Functions.
3. Zanim zaczniesz
Utwórz projekt
- W konsoli Google Cloud na stronie wyboru projektu wybierz lub utwórz projekt Google Cloud.
- Sprawdź, czy w projekcie Cloud włączone są płatności. Dowiedz się, jak sprawdzić, czy w projekcie są włączone płatności .
- Będziesz używać Cloud Shell, czyli środowiska wiersza poleceń działającego w Google Cloud, które jest wstępnie załadowane narzędziem bq. U góry konsoli Google Cloud kliknij Aktywuj Cloud Shell.

- Po połączeniu z Cloud Shell sprawdź, czy uwierzytelnianie zostało już przeprowadzone, a projekt jest już ustawiony na Twój identyfikator projektu, używając tego polecenia:
gcloud auth list
- Aby potwierdzić, że polecenie gcloud zna Twój projekt, uruchom w Cloud Shell to polecenie:
gcloud config list project
- Jeśli projekt nie jest ustawiony, użyj tego polecenia, aby go ustawić:
gcloud config set project <YOUR_PROJECT_ID>
- Włącz wymagane interfejsy API, uruchamiając w terminalu Cloud Shell te polecenia:
Istnieje też jedno polecenie, które umożliwia uruchomienie poniższych funkcji, ale jeśli korzystasz z konta próbnego, możesz napotkać problemy z limitami podczas próby włączenia tych funkcji zbiorczo. Dlatego polecenia są wyróżnione po jednym w wierszu.
gcloud services enable alloydb.googleapis.com
gcloud services enable compute.googleapis.com
gcloud services enable cloudresourcemanager.googleapis.com
gcloud services enable servicenetworking.googleapis.com
gcloud services enable run.googleapis.com
gcloud services enable cloudbuild.googleapis.com
gcloud services enable cloudfunctions.googleapis.com
gcloud services enable aiplatform.googleapis.com
Alternatywą dla polecenia gcloud jest wyszukanie poszczególnych usług w konsoli lub skorzystanie z tego linku.
Jeśli pominiesz jakiś interfejs API, możesz go włączyć w trakcie wdrażania.
Informacje o poleceniach gcloud i ich użyciu znajdziesz w dokumentacji.
4. Konfiguracja bazy danych
W tym module użyjemy AlloyDB jako bazy danych do przechowywania danych sklepu z zabawkami. Używa klastrów do przechowywania wszystkich zasobów, takich jak bazy danych i logi. Każdy klaster ma instancję główną, która zapewnia punkt dostępu do danych. Tabele będą zawierać rzeczywiste dane.
Utwórzmy klaster, instancję i tabelę AlloyDB, do których zostanie wczytany zbiór danych e-commerce.
Tworzenie klastra i instancji
- Otwórz stronę AlloyDB w konsoli Cloud. Najprostszym sposobem na znalezienie większości stron w Cloud Console jest wyszukanie ich za pomocą paska wyszukiwania w konsoli.
- Na tej stronie kliknij UTWÓRZ KLASTER:

- Wyświetli się ekran podobny do tego poniżej. Utwórz klaster i instancję z tymi wartościami (upewnij się, że wartości są zgodne, jeśli klonujesz kod aplikacji z repozytorium):
- Identyfikator klastra: „
vector-cluster” - password: "
alloydb" - Zgodność z PostgreSQL 15
- Region: „
us-central1” - Sieć: „
default”

- Po wybraniu sieci domyślnej zobaczysz ekran podobny do tego poniżej.
Wybierz SKONFIGURUJ POŁĄCZENIE.
- Następnie wybierz „Użyj automatycznie przydzielonego zakresu adresów IP” i kliknij Dalej. Po sprawdzeniu informacji kliknij UTWÓRZ POŁĄCZENIE.

- Po skonfigurowaniu sieci możesz utworzyć klaster. Kliknij UTWÓRZ KLASTER, aby dokończyć konfigurowanie klastra w sposób pokazany poniżej:

Pamiętaj, aby zmienić identyfikator instancji na
vector-instance
Jeśli nie możesz go zmienić, pamiętaj, aby zmienić identyfikator instancji we wszystkich kolejnych odwołaniach.
Pamiętaj, że utworzenie klastra zajmie około 10 minut. Po zakończeniu procesu wyświetli się ekran z omówieniem utworzonego klastra.
5. Pozyskiwanie danych
Teraz dodaj tabelę z danymi o sklepie. Otwórz AlloyDB, wybierz klaster główny, a następnie AlloyDB Studio:
Może być konieczne poczekanie na zakończenie tworzenia instancji. Gdy to zrobisz, zaloguj się w AlloyDB przy użyciu danych logowania utworzonych podczas tworzenia klastra. Do uwierzytelniania w PostgreSQL użyj tych danych:
- Nazwa użytkownika: „
postgres” - Baza danych: „
postgres” - Hasło: „
alloydb”
Po pomyślnym uwierzytelnieniu w AlloyDB Studio polecenia SQL są wpisywane w Edytorze. Możesz dodać wiele okien Edytora, klikając znak plusa po prawej stronie ostatniego okna.

Polecenia dla AlloyDB będziesz wpisywać w oknach edytora, korzystając w razie potrzeby z opcji Uruchom, Formatuj i Wyczyść.
Włączanie rozszerzeń
Do utworzenia tej aplikacji użyjemy rozszerzeń pgvector i google_ml_integration. Rozszerzenie pgvector umożliwia przechowywanie wektorów dystrybucyjnych i wyszukiwanie ich. Rozszerzenie google_ml_integration udostępnia funkcje, których możesz używać do uzyskiwania dostępu do punktów końcowych prognozowania Vertex AI w celu uzyskiwania prognoz w SQL. Włącz te rozszerzenia, uruchamiając te DDL:
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
Jeśli chcesz sprawdzić, które rozszerzenia są włączone w bazie danych, uruchom to polecenie SQL:
select extname, extversion from pg_extension;
Tworzenie tabeli
Utwórz tabelę za pomocą poniższej instrukcji DDL:
CREATE TABLE toys ( id VARCHAR(25), name VARCHAR(25), description VARCHAR(20000), quantity INT, price FLOAT, image_url VARCHAR(200), text_embeddings vector(768)) ;
Po pomyślnym wykonaniu powyższego polecenia powinna być widoczna tabela w bazie danych.
Pozyskiwanie danych
Na potrzeby tego laboratorium mamy dane testowe składające się z około 72 rekordów w tym pliku SQL. Zawiera pola id, name, description, quantity, price, image_url. Pozostałe pola wypełnisz w dalszej części tego modułu.
Skopiuj tylko pierwsze 5 wierszy/instrukcji wstawiania i wklej je w pustej karcie edytora, a następnie kliknij URUCHOM. Jeśli NIE korzystasz z próbnego konta rozliczeniowego, prawdopodobnie możesz skopiować wszystkie instrukcje wstawiania i je uruchomić.
Aby wyświetlić zawartość tabeli, rozwiń sekcję Eksplorator, aż zobaczysz tabelę o nazwie apparels. Kliknij trójkropek (⋮), aby wyświetlić opcję Zapytanie do tabeli. Instrukcja SELECT otworzy się w nowej karcie Edytora.

Przyznaj uprawnienia
Uruchom to polecenie, aby przyznać użytkownikowi postgres uprawnienia do wykonywania funkcji embedding:
GRANT EXECUTE ON FUNCTION embedding TO postgres;
Przyznawanie roli Użytkownik Vertex AI kontu usługi AlloyDB
Otwórz terminal Cloud Shell i wpisz to polecenie:
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"
6. Tworzenie wektorów dystrybucyjnych dla kontekstu
Komputery znacznie łatwiej przetwarzają liczby niż tekst. System osadzania przekształca tekst w ciąg liczb zmiennoprzecinkowych, które powinny reprezentować tekst niezależnie od tego, jak jest sformułowany, w jakim języku jest napisany itp.
Opisz lokalizację nad morzem. Może to być np. „nad wodą”, „przy plaży”, „z pokoju na plażę”, „sur la mer”, „на берегу океана” itp. Te terminy wyglądają inaczej, ale ich znaczenie semantyczne, czyli w terminologii uczenia maszynowego ich osadzenia, powinno być bardzo zbliżone.
Teraz, gdy dane i kontekst są gotowe, uruchomimy SQL, aby dodać do tabeli w polu embedding wektory osadzenia opisu produktu. Możesz używać różnych modeli osadzania. Korzystamy z text-embedding-005 z Vertex AI. Pamiętaj, aby w całym projekcie używać tego samego modelu wektorowego.
Uwaga: jeśli używasz istniejącego projektu Google Cloud utworzonego jakiś czas temu, być może musisz nadal używać starszych wersji modelu do osadzania tekstu, takich jak textembedding-gecko.
Wróć na kartę AlloyDB Studio i wpisz ten język DML:
UPDATE toys set text_embeddings = embedding( 'text-embedding-005', description);
Jeszcze raz spójrz na toys tabelę, aby zobaczyć niektóre osadzenia. Aby zobaczyć zmiany, ponownie uruchom instrukcję SELECT.
SELECT id, name, description, price, quantity, image_url, text_embeddings FROM toys;
Powinien on zwrócić wektor osadzania, który wygląda jak tablica liczb zmiennoprzecinkowych, dla opisu zabawki, jak pokazano poniżej:

Uwaga: nowo utworzone projekty Google Cloud w ramach bezpłatnego poziomu mogą mieć problemy z limitami liczby żądań osadzania do modeli osadzania dozwolonych na sekundę. Podczas generowania osadzania zalecamy użycie zapytania filtra dla identyfikatora, a następnie selektywne wybieranie 1–5 rekordów itd.
7. Wykonywanie wyszukiwania wektorowego
Gdy tabela, dane i wektory są gotowe, możemy przeprowadzić wyszukiwanie wektorowe w czasie rzeczywistym dla tekstu wyszukiwanego przez użytkownika.
Załóżmy, że użytkownik zada pytanie:
„I want a white plush teddy bear toy with a floral pattern”.
Aby znaleźć pasujące elementy, uruchom to zapytanie:
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 2;
Przyjrzyjmy się szczegółowo temu zapytaniu:
W tym zapytaniu
- Tekst wyszukiwania użytkownika to: „
I want a white plush teddy bear toy with a floral pattern.” - Przekształcamy go w wektory dystrybucyjne metodą
embedding()za pomocą modelutext-embedding-005. Ten krok powinien być Ci znany z poprzedniego etapu, na którym zastosowaliśmy funkcję osadzania do wszystkich elementów w tabeli. - „
<=>” oznacza użycie metody odległości PODOBIEŃSTWA COSINUSOWEGO. Wszystkie dostępne miary podobieństwa znajdziesz w dokumentacji pgvector. - Wynik metody wektorów dystrybucyjnych przekształcamy w typ wektorowy, aby był zgodny z wektorami przechowywanymi w bazie danych.
- LIMIT 5 oznacza, że chcemy wyodrębnić 5 najbliższych sąsiadów dla tekstu wyszukiwania.
Wynik wygląda tak:

Jak widać w wynikach, dopasowania są dość zbliżone do wyszukiwanego tekstu. Spróbuj zmienić tekst, aby zobaczyć, jak zmieniają się wyniki.
Ważna uwaga:
Załóżmy, że chcemy zwiększyć wydajność (czas zapytania), skuteczność i przypominanie wyników wyszukiwania wektorowego za pomocą indeksu ScaNN. Aby porównać różnice w wynikach z indeksem i bez niego, zapoznaj się z instrukcjami w tym artykule na blogu.
Krok opcjonalny: zwiększanie wydajności i przypominania za pomocą indeksu ScaNN
Zignoruj ten krok, jeśli liczba rekordów jest mniejsza niż 100.
Dla wygody podajemy tutaj tylko kroki tworzenia indeksu:
- Mamy już utworzone klaster, instancję, kontekst i osadzenia, więc wystarczy zainstalować rozszerzenie ScaNN za pomocą tego polecenia:
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- Następnie utworzymy indeks (ScaNN):
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);
W powyższym DDL apparel_index to nazwa indeksu.
„toys” to moja tabela
„scann” to metoda indeksowania.
„embedding” to kolumna w tabeli, którą chcę indeksować.
„cosine” to metoda pomiaru odległości, której chcę używać w indeksie.
„8” to liczba partycji, które mają być zastosowane do tego indeksu. Ustaw dowolną wartość z zakresu od 1 do 1048576. Więcej informacji o tym, jak określić tę wartość, znajdziesz w artykule Dostrajanie indeksu ScaNN.
Użyłem PIERWIASTKA KWADRATOWEGO z liczby punktów danych zgodnie z zaleceniami w repozytorium ScaNN (podczas dzielenia na partycje liczba węzłów powinna być w przybliżeniu pierwiastkiem kwadratowym z liczby punktów danych).
- Sprawdź, czy indeks został utworzony, za pomocą tego zapytania:
SELECT * FROM pg_stat_ann_indexes;
- Przeprowadź wyszukiwanie wektorowe za pomocą tego samego zapytania, którego użyliśmy bez indeksu:
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;
Powyższe zapytanie jest takie samo jak to, którego użyliśmy w laboratorium w kroku 8. Teraz jednak pole jest już zindeksowane.
- Przeprowadź test za pomocą prostego zapytania z indeksem i bez niego (usuwając indeks):
W tym przypadku użycia jest tylko 72 rekordy, więc indeks nie ma większego znaczenia. W przypadku testu przeprowadzonego w innym przypadku użycia wyniki są następujące:
To samo zapytanie wyszukiwania wektorowego dotyczące ZINDEKSOWANYCH danych wektorów dystrybucyjnych zapewnia wysoką jakość wyników wyszukiwania i wydajność. Dzięki indeksowi wydajność znacznie się poprawia (pod względem czasu wykonania: 10,37 ms bez ScaNN i 0,87 ms ze ScaNN). Więcej informacji na ten temat znajdziesz na tym blogu.
8. Weryfikacja dopasowania za pomocą LLM
Zanim przejdziemy dalej i utworzymy usługę zwracającą najlepsze dopasowania do aplikacji, użyjmy modelu generatywnej AI, aby sprawdzić, czy te potencjalne odpowiedzi są rzeczywiście trafne i bezpieczne dla użytkownika.
Sprawdzanie, czy instancja jest skonfigurowana pod kątem Gemini
Najpierw sprawdź, czy integracja Google ML jest już włączona w przypadku Twojego klastra i instancji. W AlloyDB Studio wpisz to polecenie:
show google_ml_integration.enable_model_support;
Jeśli wartość to „włączone”, możesz pominąć 2 kolejne kroki i przejść bezpośrednio do konfigurowania integracji AlloyDB i modelu Vertex AI.
- Otwórz instancję główną klastra AlloyDB i kliknij EDYTUJ INSTANCJĘ GŁÓWNĄ.

- W sekcji Opcje konfiguracji zaawansowanej otwórz sekcję Flagi. i upewnij się, że
google_ml_integration.enable_model_support flagjest ustawiony na „on”, jak pokazano poniżej:

Jeśli nie jest ustawiona na „włączone”, ustaw ją na „włączone”, a następnie kliknij przycisk ZAKTUALIZUJ INSTANCJĘ. Ten krok zajmie kilka minut.
Integracja AlloyDB i modelu Vertex AI
Teraz możesz połączyć się z AlloyDB Studio i uruchomić następującą instrukcję DML, aby skonfigurować dostęp do modelu Gemini z AlloyDB, używając w odpowiednim miejscu identyfikatora projektu. Przed uruchomieniem polecenia może pojawić się ostrzeżenie o błędzie składni, ale powinno ono działać prawidłowo.
Najpierw tworzymy połączenie z modelem Gemini 1.5, jak pokazano poniżej. Pamiętaj, aby w poniższym poleceniu zastąpić $PROJECT_ID identyfikatorem Twojego projektu Google Cloud.
CALL
google_ml.create_model( model_id => 'gemini-1.5',
model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/us-central1/publishers/google/models/gemini-1.5-pro:streamGenerateContent',
model_provider => 'google',
model_auth_type => 'alloydb_service_agent_iam');
Modele skonfigurowane pod kątem dostępu możesz sprawdzić za pomocą tego polecenia w AlloyDB Studio:
select model_id,model_type from google_ml.model_info_view;
Na koniec musimy przyznać użytkownikom bazy danych uprawnienia do wykonywania funkcji ml_predict_row, aby mogli uruchamiać prognozy za pomocą modeli Google Vertex AI. Uruchom to polecenie:
GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;
Uwaga: jeśli używasz istniejącego projektu Google Cloud i istniejącego klastra lub instancji AlloyDB utworzonych jakiś czas temu, może być konieczne usunięcie starych odwołań do modelu gemini-1.5 i ponowne utworzenie ich za pomocą powyższego polecenia CALL oraz ponowne uruchomienie polecenia grant execute on function ml_predict_row w przypadku wystąpienia problemów podczas przyszłych wywołań modelu gemini-1.5.
Ocena odpowiedzi
W następnej sekcji użyjemy jednego dużego zapytania, aby upewnić się, że odpowiedzi są rozsądne, ale samo zapytanie może być trudne do zrozumienia. Za chwilę przyjrzymy się poszczególnym elementom i sprawdzimy, jak się ze sobą łączą.
- Najpierw wyślemy do bazy danych żądanie pobrania 10 najbliższych wyników pasujących do zapytania użytkownika.
- Aby określić, jak trafne są odpowiedzi, użyjemy zapytania zewnętrznego, w którym wyjaśnimy, jak je oceniać. Używa pola
recommended_text, które jest tekstem wyszukiwania, oraz polacontent(czyli pola opisu zabawki) wewnętrznej tabeli jako części zapytania. - Na tej podstawie ocenimy jakość zwróconych odpowiedzi.
- Funkcja
predict_rowzwraca wynik w formacie JSON. Kod „-> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'"” służy do wyodrębniania rzeczywistego tekstu z tego pliku JSON. Aby zobaczyć rzeczywisty zwrócony kod JSON, możesz usunąć ten kod. - Na koniec, aby uzyskać odpowiedź LLM, wyodrębniamy ją za pomocą
REGEXP_REPLACE(gemini_validation,'[^a-zA-Z,: ]','','g').
SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') AS gemini_validation
FROM (SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
CAST(ARRAY_AGG(LLM_RESPONSE) AS TEXT) AS gemini_validation
FROM (SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
json_array_elements(google_ml.predict_row(model_id => 'gemini-1.5',
request_body => CONCAT('{ "contents": [ { "role": "user", "parts": [ { "text": "User wants to buy a toy and this is the description of the toy they wish to buy: ', recommended_text, '. Check if the following product items from the inventory are close enough to really, contextually match the user description. Here are the items: ', content, '. Return a ONE-LINE response with 3 values: 1) MATCH: if the 2 contexts are reasonably matching in terms of any of the color or color family specified in the list, approximate style match with any of the styles mentioned in the user search text: This should be a simple YES or NO. Choose NO only if it is completely irrelevant to users search criteria. 2) PERCENTAGE: percentage of match, make sure that this percentage is accurate 3) DIFFERENCE: A clear one-line easy description of the difference between the 2 products. Remember if the user search text says that some attribute should not be there, and the record has it, it should be a NO match. " } ] } ] }')::JSON)) -> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text' :: TEXT AS LLM_RESPONSE
FROM (SELECT id,
name,
description AS content,
quantity,
price,
image_url,
'Pink panther standing' AS recommended_text
FROM toys
ORDER BY text_embeddings <=> embedding('text-embedding-005',
'Pink panther standing')::VECTOR
LIMIT 1) AS xyz) AS X
GROUP BY id,
name,
content,
quantity,
price,
image_url,
recommended_text) AS final_matches
-- WHERE REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') LIKE '%MATCH%:%YES%';
Może to nadal wyglądać zniechęcająco, ale mam nadzieję, że teraz jest to trochę bardziej zrozumiałe. Wyniki wskazują, czy występuje dopasowanie, jaki jest jego odsetek i zawierają wyjaśnienie oceny.
Zwróć uwagę, że model Gemini ma domyślnie włączone przesyłanie strumieniowe, więc rzeczywista odpowiedź jest rozłożona na kilka wierszy:

9. Przenoszenie wyszukiwarki zabawek do chmury bezserwerowej
Chcesz udostępnić tę aplikację w internecie? Aby przekształcić ten silnik wiedzy w bezserwerowy silnik wiedzy za pomocą funkcji Cloud Run, wykonaj te czynności:
- Otwórz Cloud Run Functions w konsoli Google Cloud, aby UTWORZYĆ nową funkcję Cloud Run, lub użyj tego linku: https://console.cloud.google.com/functions/add.
- Wybierz środowisko „Funkcja Cloud Run”. Podaj nazwę funkcji „get-toys-alloydb” i wybierz region „us-central1”. Ustaw uwierzytelnianie na „Zezwalaj na nieuwierzytelnione wywołania” i kliknij DALEJ. Jako środowisko wykonawcze wybierz Java 17, a jako kod źródłowy – Edytor wbudowany.
- Domyślnie punkt wejścia zostanie ustawiony na „
gcfv2.HelloHttpFunction”. Zastąp kod zastępczy wHelloHttpFunction.javaipom.xmlfunkcji Cloud Run kodem z plików HelloHttpFunction.java i pom.xml. - Pamiętaj, aby w pliku Java zastąpić obiekt zastępczy <<YOUR_PROJECT>> i dane logowania do połączenia z AlloyDB swoimi wartościami. Dane logowania do AlloyDB to te, których użyliśmy na początku tego samouczka. Jeśli używasz innych wartości, zmień je w pliku Java.
- Kliknij Wdróż.
Po wdrożeniu, aby umożliwić funkcji w Cloud Functions dostęp do instancji bazy danych AlloyDB, utworzymy oprogramowanie sprzęgające VPC.
WAŻNY KROK:
Po rozpoczęciu wdrażania funkcje powinny być widoczne w konsoli funkcji Cloud Run w Google. Wyszukaj nowo utworzoną funkcję (get-toys-alloydb), kliknij ją, a następnie kliknij EDYTUJ i zmień te ustawienia:
- Otwórz Ustawienia środowiska wykonawczego, kompilacji, połączeń i zabezpieczeń
- Zwiększ limit czasu do 180 sekund.
- Otwórz kartę POŁĄCZENIA:

- W ustawieniach ruchu przychodzącego upewnij się, że wybrana jest opcja „Zezwalaj na cały ruch”.
- W sekcji Ustawienia ruchu wychodzącego kliknij menu Sieć i wybierz opcję „Dodaj nowe oprogramowanie sprzęgające VPC”. Postępuj zgodnie z instrukcjami wyświetlanymi w oknie dialogowym, które się pojawi:

- Podaj nazwę oprogramowania sprzęgającego VPC i upewnij się, że region jest taki sam jak w przypadku instancji. Pozostaw domyślną wartość Sieć i ustaw Podsieć jako Niestandardowy zakres IP z zakresem IP 10.8.0.0 lub podobnym dostępnym zakresem.
- Rozwiń POKAŻ USTAWIENIA SKALOWANIA i upewnij się, że konfiguracja jest dokładnie taka jak poniżej:

- Kliknij UTWÓRZ. Ten łącznik powinien być teraz widoczny w ustawieniach ruchu wychodzącego.
- Wybierz nowo utworzony łącznik.
- Wybierz opcję kierowania całego ruchu przez to oprogramowanie sprzęgające VPC.
- Kliknij kolejno DALEJ i WDRÓŻ.
10. Testowanie funkcji Cloud Run
Po wdrożeniu zaktualizowanej funkcji w Cloud Functions powinien pojawić się wygenerowany punkt końcowy. Skopiuj go i zastąp nim fragment w tym poleceniu:
Możesz też przetestować funkcję Cloud Run w ten sposób:
PROJECT_ID=$(gcloud config get-value project)
curl -X POST <<YOUR_ENDPOINT>> \
-H 'Content-Type: application/json' \
-d '{"search":"I want a standing pink panther toy"}' \
| jq .
Wynik:

To wszystko. Wyszukiwanie wektorowe podobieństwa za pomocą modelu wektorów dystrybucyjnych w danych AlloyDB jest tak proste.
11. Tworzenie klienta aplikacji internetowej
W tej części stworzymy aplikację internetową, z którą użytkownik będzie mógł wchodzić w interakcje i znajdować pasujące zabawki na podstawie tekstu lub obrazu, a nawet tworzyć nowe zabawki zgodnie ze swoimi potrzebami. Aplikacja jest już utworzona, więc możesz wykonać czynności opisane poniżej, aby skopiować ją do środowiska IDE i uruchomić.
- Do opisywania obrazu, który użytkownik może przesłać w celu znalezienia pasujących zabawek, używamy modelu Gemini 2.0 Flash, dlatego musimy uzyskać klucz interfejsu API dla tej aplikacji. Aby to zrobić, otwórz stronę https://aistudio.google.com/apikey i uzyskaj klucz interfejsu API dla aktywnego projektu Google Cloud, w którym wdrażasz tę aplikację. Zapisz klucz w bezpiecznym miejscu:

- Otwieranie terminala Cloud Shell
- Sklonuj repozytorium za pomocą tego polecenia:
git clone https://github.com/AbiramiSukumaran/toysearch
cd toysearch
- Po sklonowaniu repozytorium będziesz mieć dostęp do projektu z edytora Cloud Shell.
- Musisz usunąć z sklonowanego projektu foldery „get-toys-alloydb” i „toolbox-toys”, ponieważ zawierają one kod funkcji Cloud Run, do którego możesz się odwoływać z repozytorium, gdy będzie Ci potrzebny.
- W folderze web otwórz plik GenerateToy.java i znajdź ten wiersz, a następnie go usuń, ponieważ zezwolenie na treści dla dorosłych może wymagać specjalnych uprawnień, które mogą być niedostępne w przypadku niektórych próbnych kont rozliczeniowych:
paramsMap.put("personGeneration", "allow_adult");
- Zanim skompilujesz i wdrożysz aplikację, sprawdź, czy wszystkie niezbędne zmienne środowiskowe są ustawione. Otwórz terminal Cloud Shell i wykonaj to polecenie:
PROJECT_ID=$(gcloud config get-value project)
export PROJECT_ID=$PROJECT_ID
export GOOGLE_API_KEY=<YOUR API KEY that you saved>
- Skompiluj i uruchom aplikację lokalnie:
Upewnij się, że jesteś w katalogu projektu, i uruchom te polecenia:
mvn package
mvn spring-boot:run
- Wdrażanie w Cloud Run
gcloud run deploy --source .
12. Informacje o generatywnej AI
Nie musisz niczego robić. Dla Twojej informacji:
Teraz, gdy masz już aplikację do wdrożenia, poświęć chwilę na zrozumienie, jak przeprowadziliśmy wyszukiwanie (tekstu i obrazu) oraz generowanie.
- Wyszukiwanie wektorowe na podstawie tekstu użytkownika:
Zostało to już uwzględnione w funkcjach Cloud Run, które wdrożyliśmy w sekcji „Korzystanie z aplikacji internetowej wyszukiwania wektorowego”.
- Wyszukiwanie wektorowe na podstawie przesłanego obrazu:
Załóżmy, że zamiast wpisywać kontekst w postaci tekstu użytkownik chce przesłać zdjęcie znanej zabawki, za pomocą której chce wyszukać informacje. Użytkownicy mogą przesłać zdjęcie zabawki, która im się podoba, i uzyskać odpowiednie funkcje.
Do analizy obrazu i wyodrębniania odpowiedniego kontekstu, np. koloru, materiału, typu i grupy wiekowej zabawki, używamy modelu Gemini 2.0 Flash od Google, który jest wywoływany za pomocą LangChain4j.
W 5 krokach przekształciliśmy dane multimodalne użytkownika w pasujące wyniki, wywołując duży model językowy za pomocą platformy open source. Dowiedz się, jak to zrobić:
package cloudcode.helloworld.web;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;
import java.util.Base64;
import java.util.Optional;
public class GeminiCall {
public String imageToBase64String(byte[] imageBytes) {
String base64Img = Base64.getEncoder().encodeToString(imageBytes);
return base64Img;
}
public String callGemini(String base64ImgWithPrefix) throws Exception {
String searchText = "";
// 1. Remove the prefix
String base64Img = base64ImgWithPrefix.replace("data:image/jpeg;base64,", "");
// 2. Decode base64 to bytes
byte[] imageBytes = Base64.getDecoder().decode(base64Img);
String image = imageToBase64String(imageBytes);
// 3. Get API key from environment variable
String apiKey = Optional.ofNullable(System.getenv("GOOGLE_API_KEY"))
.orElseThrow(() -> new IllegalArgumentException("GOOGLE_API_KEY environment variable not set"));
// 4. Invoke Gemini 2.0
ChatLanguageModel gemini = GoogleAiGeminiChatModel.builder()
.apiKey(apiKey)
.modelName("gemini-2.0-flash-001")
.build();
Response<AiMessage> response = gemini.generate(
UserMessage.from(
ImageContent.from(image, "image/jpeg"),
TextContent.from(
"The picture has a toy in it. Describe the toy in the image in one line. Do not add any prefix or title to your description. Just describe that toy that you see in the image in one line, do not describe the surroundings and other objects around the toy in the image. If you do not see any toy in the image, send response stating that no toy is found in the input image.")));
// 5. Get the text from the response and send it back to the controller
searchText = response.content().text().trim();
System.out.println("searchText inside Geminicall: " + searchText);
return searchText;
}
}
- Dowiedz się, jak wykorzystaliśmy Imagen 3 do stworzenia niestandardowej zabawki na podstawie prośby użytkownika przy użyciu generatywnej AI.
Następnie Imagen 3 generuje obraz zaprojektowanej przez użytkownika zabawki, dzięki czemu może on zobaczyć, jak wygląda jego dzieło. Oto jak to zrobiliśmy w 5 krokach:
// Generate an image using a text prompt using an Imagen model
public String generateImage(String projectId, String location, String prompt)
throws ApiException, IOException {
final String endpoint = String.format("%s-aiplatform.googleapis.com:443", location);
PredictionServiceSettings predictionServiceSettings =
PredictionServiceSettings.newBuilder().setEndpoint(endpoint).build();
// 1. Set up the context and prompt
String context = "Generate a photo-realistic image of a toy described in the following input text from the user. Make sure you adhere to all the little details and requirements mentioned in the prompt. Ensure that the user is only describing a toy. If it is anything unrelated to a toy, politely decline the request stating that the request is inappropriate for the current context. ";
prompt = context + prompt;
// 2. Initialize a client that will be used to send requests. This client only needs to be created
// once, and can be reused for multiple requests.
try (PredictionServiceClient predictionServiceClient =
PredictionServiceClient.create(predictionServiceSettings)) {
// 3. Invoke Imagen 3
final EndpointName endpointName =
EndpointName.ofProjectLocationPublisherModelName(
projectId, location, "google", "imagen-3.0-generate-001"); //"imagegeneration@006"; imagen-3.0-generate-001
Map<String, Object> instancesMap = new HashMap<>();
instancesMap.put("prompt", prompt);
Value instances = mapToValue(instancesMap);
Map<String, Object> paramsMap = new HashMap<>();
paramsMap.put("sampleCount", 1);
paramsMap.put("aspectRatio", "1:1");
paramsMap.put("safetyFilterLevel", "block_few");
paramsMap.put("personGeneration", "allow_adult");
paramsMap.put("guidanceScale", 21);
paramsMap.put("imagenControlScale", 0.95); //Setting imagenControlScale
Value parameters = mapToValue(paramsMap);
// 4. Get prediction response image
PredictResponse predictResponse =
predictionServiceClient.predict(
endpointName, Collections.singletonList(instances), parameters);
// 5. Return the Base64 Encoded String to the controller
for (Value prediction : predictResponse.getPredictionsList()) {
Map<String, Value> fieldsMap = prediction.getStructValue().getFieldsMap();
if (fieldsMap.containsKey("bytesBase64Encoded")) {
bytesBase64EncodedOuput = fieldsMap.get("bytesBase64Encoded").getStringValue();
}
}
return bytesBase64EncodedOuput.toString();
}
}
Prognozowanie cen
W poprzedniej sekcji omówiliśmy, jak Imagen generuje obraz zabawki, którą użytkownik chce zaprojektować samodzielnie. Aby użytkownicy mogli kupić zabawkę, aplikacja musi określić jej cenę. Zastosowaliśmy intuicyjną logikę, aby zdefiniować cenę niestandardowej zabawki na zamówienie. Logika polega na użyciu średniej ceny 5 najbardziej podobnych zabawek (pod względem opisu) do zabawki zaprojektowanej przez użytkownika.
Prognoza ceny wygenerowanej zabawki jest ważną częścią tej aplikacji. Do jej utworzenia użyliśmy podejścia opartego na agentach. Przedstawiamy Toolbox for Databases.
13. Toolbox for Databases
Gen AI Toolbox for Databases to serwer open source od Google, który ułatwia tworzenie narzędzi generatywnej AI do interakcji z bazami danych. Umożliwia łatwiejsze, szybsze i bezpieczniejsze tworzenie narzędzi dzięki obsłudze złożonych procesów, takich jak pula połączeń czy uwierzytelnianie. Umożliwia tworzenie narzędzi opartych na generatywnej AI, które pozwalają agentom uzyskiwać dostęp do danych w bazie danych.
Aby przygotować narzędzie i sprawić, że nasza aplikacja będzie działać jak agent, wykonaj te czynności: Link do laboratorium kodu Toolbox
Aplikacja może teraz używać tego wdrożonego punktu końcowego funkcji Cloud Run do wypełniania ceny wraz z wygenerowanym wynikiem Imagen dla niestandardowego obrazu zabawki na zamówienie.
14. Testowanie aplikacji internetowej
Wszystkie komponenty aplikacji zostały utworzone i wdrożone, więc można ją udostępniać w chmurze. Przetestuj aplikację we wszystkich scenariuszach. Oto link do filmu, który pokazuje, czego możesz się spodziewać:
https://www.youtube.com/shorts/ZMqUAWsghYQ
Tak wygląda strona docelowa:

15. Czyszczenie danych
Aby uniknąć obciążenia konta Google Cloud opłatami za zasoby użyte w tym poście, wykonaj te czynności:
- W konsoli Google Cloud otwórz stronę Zarządzanie zasobami.
- Z listy projektów wybierz projekt do usunięcia, a potem kliknij Usuń.
- W oknie wpisz identyfikator projektu i kliknij Wyłącz, aby usunąć projekt.
16. Gratulacje
Gratulacje! Udało Ci się przeprowadzić wyszukiwanie kontekstowe i generowanie w sklepie z zabawkami przy użyciu AlloyDB, pgvector, Imagen i Gemini 2.0, a także bibliotek open source do tworzenia niezawodnych integracji. Łącząc możliwości AlloyDB, Vertex AI i wyszukiwania wektorowego, zrobiliśmy ogromny krok naprzód w udostępnianiu wyszukiwania kontekstowego i wektorowego, które jest wydajne i naprawdę oparte na znaczeniu.