Suchanwendung für Spielzeuggeschäfte mit Cloud-Datenbanken, serverlosen Laufzeiten und Open-Source-Integrationen

1. Übersicht

Stellen Sie sich vor, Sie betreten einen Spielzeugladen – virtuell oder persönlich – und finden mühelos das perfekte Geschenk. Sie können beschreiben, wonach Sie suchen, ein Bild eines Spielzeugs hochladen oder sogar ein eigenes Spielzeug entwerfen. Der Store versteht sofort Ihre Anforderungen und bietet Ihnen ein maßgeschneidertes Erlebnis. Das ist keine futuristische Fantasie, sondern eine Realität, die durch KI, Cloud-Technologie und eine Vision für personalisierten E‑Commerce ermöglicht wird.

Die Herausforderung:Das perfekte Produkt zu finden, das Ihren Vorstellungen entspricht, kann schwierig sein. Allgemeine Suchbegriffe, Keywords und unscharfe Suchanfragen reichen oft nicht aus, das Durchsuchen endloser Seiten kann mühsam sein und die Diskrepanz zwischen dem, was Sie sich vorstellen, und dem, was verfügbar ist, kann zu Frustration führen.

Die Lösung:Die Demoanwendung geht diese Herausforderung direkt an und nutzt die Leistungsfähigkeit von KI, um eine wirklich personalisierte und nahtlose Erfahrung mit kontextbezogener Suche und benutzerdefinierter Generierung des Produkts zu bieten, das dem Suchkontext entspricht.

Aufgaben

In diesem Lab haben Sie folgende Aufgaben:

  1. AlloyDB-Instanz erstellen und Toys-Dataset laden
  2. pgvector- und generative KI-Modellerweiterungen in AlloyDB aktivieren
  3. Einbettungen aus der Produktbeschreibung generieren und in Echtzeit eine Suche nach Kosinusähnlichkeit für den Suchtext des Nutzers durchführen
  4. Gemini 2.0 Flash aufrufen, um das vom Nutzer hochgeladene Bild für die kontextbezogene Spielzeugsuche zu beschreiben
  5. Imagen 3 aufrufen, um ein Spielzeug basierend auf den Interessen des Nutzers zu erstellen
  6. Ein mit der Gen AI Toolbox for Databases erstelltes Tool zur Preisvorhersage für Preisdetails des benutzerdefinierten Spielzeugs aufrufen
  7. Lösung in serverlosen Cloud Run Functions bereitstellen

Voraussetzungen

  • Ein Browser, z. B. Chrome oder Firefox
  • Google Cloud-Projekt mit aktivierter Abrechnungsfunktion.

2. Architektur

Datenfluss: Sehen wir uns genauer an, wie Daten durch unser System fließen:

  1. Kontextbezogene Suche mit KI-basierter RAG (Retrieval-Augmented Generation)

Stellen Sie sich Folgendes vor: Anstatt nur nach „rotes Auto“ zu suchen, versteht das System Folgendes:

„kleines Fahrzeug, das für einen 3-jährigen Jungen geeignet ist“

AlloyDB als Grundlage:Wir verwenden AlloyDB, die vollständig verwaltete, PostgreSQL-kompatible Datenbank von Google Cloud, um unsere Testdaten zu speichern, einschließlich Beschreibungen, Bild-URLs und anderer relevanter Attribute.

pgvector für die semantische Suche:Mit pgvector, einer PostgreSQL-Erweiterung, können wir Vektoreinbettungen von Spielzeugbeschreibungen und Nutzeranfragen speichern. Das ermöglicht die semantische Suche. Das System versteht also die Bedeutung der Wörter und nicht nur die genauen Suchbegriffe.

Kosinus-Ähnlichkeit für Relevanz:Wir verwenden die Kosinus-Ähnlichkeit, um die semantische Ähnlichkeit zwischen dem Suchvektor des Nutzers und den Vektoren der Spielzeugbeschreibung zu messen und die relevantesten Ergebnisse zu präsentieren.

ScaNN-Index für Geschwindigkeit und Genauigkeit:Um schnelle und genaue Ergebnisse zu gewährleisten, insbesondere wenn unser Spielzeugbestand wächst, integrieren wir den ScaNN-Index (Scalable Nearest Neighbors). Dadurch werden Effizienz und Recall unserer Vektorsuche deutlich verbessert.

  1. Bildbasierte Suche und Analyse mit Gemini 2.0 Flash

Anstatt den Kontext als Text einzugeben, möchte der Nutzer beispielsweise ein Bild eines bekannten Spielzeugs hochladen, mit dem er suchen möchte. Nutzer können ein Bild eines Spielzeugs hochladen, das ihnen gefällt, und erhalten dann relevante Funktionen. Wir verwenden das Gemini 2.0 Flash-Modell von Google, das mit LangChain4j aufgerufen wird, um das Bild zu analysieren und relevanten Kontext wie Farbe, Material, Typ und Altersgruppe des Spielzeugs zu extrahieren.

  1. Mit generativer KI ein individuelles Spielzeug entwerfen: Imagen 3

Das volle Potenzial entfaltet sich jedoch erst, wenn Nutzer ihr eigenes Spielzeug erstellen. Mit Imagen 3 können sie ihr Traumspielzeug mit einfachen Text-Prompts beschreiben. Stellen Sie sich vor, Sie könnten sagen: „Ich möchte einen Plüschdrachen mit lila Flügeln und einem freundlichen Gesicht“ und sehen, wie dieser Drache auf Ihrem Bildschirm zum Leben erwacht. Imagen 3 generiert dann ein Bild des selbst gestalteten Spielzeugs, sodass der Nutzer eine klare Visualisierung seiner Kreation erhält.

  1. Preisvorhersage mit Agents und Gen AI Toolbox for Databases

Wir haben eine Funktion zur Preisvorhersage implementiert, die die Kosten für die Herstellung des individuell gestalteten Spielzeugs schätzt. Dafür wird ein Agent mit einem ausgefeilten Tool zur Preisberechnung verwendet.

Gen AI Toolbox for Databases:Dieser Agent ist nahtlos in unsere Datenbank integriert und nutzt das neue Open-Source-Tool von Google, die Gen AI Toolbox for Databases. So kann der Agent auf Echtzeitdaten zu Materialkosten, Fertigungsprozessen und anderen relevanten Faktoren zugreifen, um eine genaue Preisschätzung zu erstellen. Weitere Informationen

  1. Java Spring Boot, Gemini Code Assist und Cloud Run für optimierte Entwicklung und serverlose Bereitstellung

Die gesamte Anwendung wurde mit Java Spring Boot erstellt, einem robusten und skalierbaren Framework. Wir haben Gemini Code Assist während des gesamten Entwicklungsprozesses eingesetzt, insbesondere für die Front-End-Entwicklung. Dadurch wurde der Entwicklungszyklus erheblich beschleunigt und die Codequalität verbessert. Wir haben Cloud Run für die Bereitstellung der gesamten Anwendung und Cloud Run Functions für die Bereitstellung der Datenbank- und Agent-Funktionen als unabhängige Endpunkte verwendet.

3. Hinweis

Projekt erstellen

  1. Wählen Sie in der Google Cloud Console auf der Seite zur Projektauswahl ein Google Cloud-Projekt aus oder erstellen Sie eines.
  2. Die Abrechnung für das Cloud-Projekt muss aktiviert sein. So prüfen Sie, ob die Abrechnung für ein Projekt aktiviert ist .
  3. Sie verwenden Cloud Shell, eine Befehlszeilenumgebung, die in Google Cloud ausgeführt wird und in der bq vorinstalliert ist. Klicken Sie oben in der Google Cloud Console auf „Cloud Shell aktivieren“.

Bild der Schaltfläche „Cloud Shell aktivieren“

  1. Sobald die Verbindung mit der Cloud Shell hergestellt ist, prüfen Sie mit dem folgenden Befehl, ob Sie bereits authentifiziert sind und für das Projekt schon Ihre Projekt-ID eingestellt ist:
gcloud auth list
  1. Führen Sie den folgenden Befehl in Cloud Shell aus, um zu bestätigen, dass der gcloud-Befehl Ihr Projekt kennt.
gcloud config list project
  1. Wenn Ihr Projekt nicht festgelegt ist, verwenden Sie den folgenden Befehl, um es festzulegen:
gcloud config set project <YOUR_PROJECT_ID>
  1. Aktivieren Sie die erforderlichen APIs, indem Sie die folgenden Befehle einzeln in Ihrem Cloud Shell-Terminal ausführen:

Es gibt auch einen einzelnen Befehl, mit dem Sie die unten aufgeführten Aktionen ausführen können. Wenn Sie jedoch ein Testkonto verwenden, kann es zu Kontingentproblemen kommen, wenn Sie versuchen, diese Aktionen im Bulk zu aktivieren. Deshalb werden die Befehle einzeln pro Zeile aufgeführt.

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

Alternativ zum gcloud-Befehl können Sie in der Konsole nach den einzelnen Produkten suchen oder diesen Link verwenden.

Wenn eine API fehlt, können Sie sie jederzeit während der Implementierung aktivieren.

Informationen zu gcloud-Befehlen und deren Verwendung finden Sie in der Dokumentation.

4. Datenbank einrichten

In diesem Lab verwenden wir AlloyDB als Datenbank für die Speicherung der Daten des Spielzeuggeschäfts. Darin werden Cluster verwendet, um alle Ressourcen wie Datenbanken und Logs zu speichern. Jeder Cluster hat eine primäre Instanz, die einen Zugriffspunkt auf die Daten bietet. Tabellen enthalten die tatsächlichen Daten.

Erstellen wir einen AlloyDB-Cluster, eine AlloyDB-Instanz und eine AlloyDB-Tabelle, in die das E-Commerce-Dataset geladen wird.

Cluster und Instanz erstellen

  1. Rufen Sie in der Cloud Console die AlloyDB-Seite auf. Die meisten Seiten in der Cloud Console lassen sich ganz einfach über die Suchleiste der Console finden.
  2. Wählen Sie auf dieser Seite CLUSTER ERSTELLEN aus:

f76ff480c8c889aa.png

  1. Sie sehen einen Bildschirm wie den unten. Erstellen Sie einen Cluster und eine Instanz mit den folgenden Werten. Achten Sie darauf, dass die Werte übereinstimmen, wenn Sie den Anwendungscode aus dem Repository klonen:
  • Cluster-ID: „vector-cluster
  • password: "alloydb"
  • Kompatibel mit PostgreSQL 15
  • Region: „us-central1
  • Netzwerk: „default

538dba58908162fb.png

  1. Wenn Sie das Standardnetzwerk auswählen, wird ein Bildschirm wie der unten angezeigt.

Wählen Sie VERBINDUNG EINRICHTEN aus.
7939bbb6802a91bf.png

  1. Wählen Sie dort Automatisch zugewiesenen IP-Bereich verwenden aus und klicken Sie auf „Weiter“. Nachdem Sie die Informationen geprüft haben, wählen Sie „VERBINDUNG ERSTELLEN“ aus. 768ff5210e79676f.png
  2. Nachdem Sie Ihr Netzwerk eingerichtet haben, können Sie mit der Clustererstellung fortfahren. Klicken Sie auf CLUSTER ERSTELLEN, um die Einrichtung des Clusters abzuschließen (siehe unten):

e06623e55195e16e.png

Achten Sie darauf, die Instanz-ID zu ändern.

vector-instance

Wenn Sie sie nicht ändern können, müssen Sie die Instanz-ID in allen nachfolgenden Verweisen ändern.

Die Clustererstellung dauert etwa 10 Minuten. Wenn die Einrichtung erfolgreich war, wird ein Bildschirm mit der Übersicht des gerade erstellten Clusters angezeigt.

5. Datenaufnahme

Jetzt ist es an der Zeit, eine Tabelle mit den Daten zum Geschäft hinzuzufügen. Rufen Sie AlloyDB auf, wählen Sie den primären Cluster und dann AlloyDB Studio aus:

847e35f1bf8a8bd8.png

Möglicherweise müssen Sie warten, bis die Instanz erstellt wurde. Melden Sie sich dann mit den Anmeldedaten in AlloyDB an, die Sie beim Erstellen des Clusters erstellt haben. Verwenden Sie die folgenden Daten für die Authentifizierung bei PostgreSQL:

  • Nutzername: „postgres
  • Datenbank: „postgres
  • Passwort: „alloydb

Nachdem Sie sich erfolgreich in AlloyDB Studio authentifiziert haben, werden SQL-Befehle im Editor eingegeben. Sie können mehrere Editorfenster hinzufügen, indem Sie auf das Pluszeichen rechts neben dem letzten Fenster klicken.

91a86d9469d499c4.png

Sie geben Befehle für AlloyDB in Editorfenstern ein und verwenden bei Bedarf die Optionen „Ausführen“, „Formatieren“ und „Löschen“.

Erweiterungen aktivieren

Für die Entwicklung dieser App verwenden wir die Erweiterungen pgvector und google_ml_integration. Mit der pgvector-Erweiterung können Sie Vektoreinbettungen speichern und durchsuchen. Die Erweiterung google_ml_integration bietet Funktionen, mit denen Sie auf Vertex AI-Vorhersageendpunkte zugreifen können, um Vorhersagen in SQL zu erhalten. Aktivieren Sie diese Erweiterungen, indem Sie die folgenden DDLs ausführen:

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

Wenn Sie prüfen möchten, welche Erweiterungen für Ihre Datenbank aktiviert wurden, führen Sie diesen SQL-Befehl aus:

select extname, extversion from pg_extension;

Tabelle erstellen

Erstellen Sie eine Tabelle mit der folgenden DDL-Anweisung:

CREATE TABLE toys ( id VARCHAR(25), name VARCHAR(25), description VARCHAR(20000), quantity INT, price FLOAT, image_url VARCHAR(200), text_embeddings vector(768)) ;

Nach erfolgreicher Ausführung des oben genannten Befehls sollte die Tabelle in der Datenbank zu sehen sein.

Daten aufnehmen

Für dieses Lab haben wir Testdaten mit etwa 72 Datensätzen in dieser SQL-Datei. Sie enthält die Felder id, name, description, quantity, price, image_url. Die anderen Felder werden später im Lab ausgefüllt.

Kopieren Sie nur die ersten fünf Zeilen/Insert-Anweisungen und fügen Sie sie dann in einen leeren Editor-Tab ein. Wählen Sie „Ausführen“ aus. Wenn Sie KEIN Test-Rechnungskonto haben, können Sie wahrscheinlich alle INSERT-Anweisungen kopieren und ausführen.

Wenn Sie den Tabelleninhalt sehen möchten, maximieren Sie den Explorer-Bereich, bis Sie die Tabelle „apparels“ sehen. Wählen Sie das Dreipunkt-Menü (⋮) aus, um die Option zum Abfragen der Tabelle aufzurufen. Eine SELECT-Anweisung wird in einem neuen Editor-Tab geöffnet.

cfaa52b717f9aaed.png

Berechtigung gewähren

Führen Sie die folgende Anweisung aus, um dem Nutzer postgres Ausführungsrechte für die Funktion embedding zu gewähren:

GRANT EXECUTE ON FUNCTION embedding TO postgres;

AlloyDB-Dienstkonto die Rolle „Vertex AI User“ gewähren

Rufen Sie das Cloud Shell-Terminal auf und geben Sie den folgenden Befehl ein:

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. Einbettungen für den Kontext erstellen

Für Computer ist es viel einfacher, Zahlen als Text zu verarbeiten. Ein Einbettungssystem wandelt Text in eine Reihe von Fließkommazahlen um, die den Text repräsentieren sollen, unabhängig davon, wie er formuliert ist, in welcher Sprache er verfasst ist usw.

Beschreiben Sie einen Ort am Meer. Sie können beispielsweise „am Wasser“, „direkt am Strand“, „vom Zimmer zum Meer laufen“, „sur la mer“ oder „на берегу океана“ lauten. Diese Begriffe sehen alle unterschiedlich aus, ihre semantische Bedeutung oder, in der Terminologie des maschinellen Lernens, ihre Einbettungen sollten jedoch sehr ähnlich sein.

Nachdem die Daten und der Kontext bereit sind, führen wir den SQL-Code aus, um die Einbettungen der Produktbeschreibung in der Tabelle im Feld embedding hinzuzufügen. Es gibt verschiedene Einbettungsmodelle, die Sie verwenden können. Wir verwenden text-embedding-005 von Vertex AI. Achten Sie darauf, im gesamten Projekt dasselbe Einbettungsmodell zu verwenden.

Hinweis: Wenn Sie ein vorhandenes Google Cloud-Projekt verwenden, das vor einiger Zeit erstellt wurde, müssen Sie möglicherweise weiterhin ältere Versionen des Text-Embedding-Modells wie „textembedding-gecko“ verwenden.

Kehren Sie zum Tab „AlloyDB Studio“ zurück und geben Sie die folgende DML ein:

UPDATE toys set text_embeddings = embedding( 'text-embedding-005', description);

Sehen Sie sich noch einmal die Tabelle toys an, um einige Einbettungen zu sehen. Führen Sie die SELECT-Anweisung noch einmal aus, um die Änderungen zu sehen.

SELECT id, name, description, price, quantity, image_url, text_embeddings FROM toys;

Dadurch sollte der Einbettungsvektor für die Spielzeugbeschreibung zurückgegeben werden, der wie ein Array von Gleitkommazahlen aussieht:

7d32f7cd7204e1f3.png

Hinweis:Bei neu erstellten Google Cloud-Projekten im Rahmen des kostenlosen Kontingents kann es zu Kontingentproblemen bei der Anzahl der Einbettungsanfragen pro Sekunde für die Einbettungsmodelle kommen. Wir empfehlen, eine Filterabfrage für die ID zu verwenden und dann beim Generieren des Einbettungsvektors selektiv 1–5 Datensätze auszuwählen.

7. Vektorsuche durchführen

Nachdem die Tabelle, die Daten und die Einbettungen bereit sind, führen wir die Echtzeit-Vektorsuche für den Suchtext des Nutzers durch.

Angenommen, der Nutzer fragt:

I want a white plush teddy bear toy with a floral pattern.“

Mit der folgenden Abfrage können Sie Übereinstimmungen dafür finden:

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;

Sehen wir uns diese Anfrage genauer an:

In dieser Abfrage

  1. Der Suchtext des Nutzers lautet: „I want a white plush teddy bear toy with a floral pattern.
  2. Wir wandeln sie in der Methode embedding() mit dem Modell text-embedding-005 in Einbettungen um. Dieser Schritt sollte Ihnen nach dem letzten Schritt, in dem wir die Einbettungsfunktion auf alle Elemente in der Tabelle angewendet haben, bekannt vorkommen.
  3. <=>“ steht für die Verwendung der Distanzmethode KOSINUS-ÄHNLICHKEIT. Alle verfügbaren Ähnlichkeitsmessungen finden Sie in der Dokumentation von pgvector.
  4. Wir konvertieren das Ergebnis der Einbettungsmethode in den Vektortyp, damit es mit den in der Datenbank gespeicherten Vektoren kompatibel ist.
  5. LIMIT 5 gibt an, dass wir 5 nächste Nachbarn für den Suchtext extrahieren möchten.

Das Ergebnis sieht so aus:

fa7f0fc3a4c68804.png

Wie Sie in den Ergebnissen sehen können, sind die Übereinstimmungen sehr nah am Suchtext. Ändern Sie den Text, um zu sehen, wie sich die Ergebnisse ändern.

Wichtiger Hinweis:

Angenommen, wir möchten die Leistung (Abfragezeit), Effizienz und den Recall dieses Vektorsuchergebnisses mit dem ScaNN-Index verbessern. In diesem Blog finden Sie eine Anleitung, wie Sie die Ergebnisse mit und ohne Index vergleichen können.

Optionaler Schritt: Effizienz und Recall mit ScaNN-Index verbessern

Ignorieren Sie diesen Schritt, wenn die Anzahl der Datensätze weniger als 100 beträgt.

Hier sind die Schritte zum Erstellen des Index noch einmal aufgeführt:

  1. Da wir den Cluster, die Instanz, den Kontext und die Einbettungen bereits erstellt haben, müssen wir nur noch die ScaNN-Erweiterung mit der folgenden Anweisung installieren:
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
  1. Als Nächstes erstellen wir den Index (ScaNN):
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);

Im obigen DDL-Code ist „apparel_index“ der Name des Index.

„toys“ ist meine Tabelle

„scann“ ist die Indexmethode.

„embedding“ ist die Spalte in der Tabelle, die ich indexieren möchte.

„cosine“ ist die Distanzmethode, die ich für den Index verwenden möchte.

„8“ ist die Anzahl der Partitionen, die auf diesen Index angewendet werden sollen. Kann auf einen beliebigen Wert zwischen 1 und 1.048.576 festgelegt werden. Weitere Informationen dazu, wie Sie diesen Wert festlegen, finden Sie unter ScaNN-Index abstimmen.

Ich habe die QUADRATWURZEL der Anzahl der Datenpunkte verwendet, wie im ScaNN-Repository empfohlen (Beim Partitionieren sollte „num_leaves“ ungefähr der Quadratwurzel der Anzahl der Datenpunkte entsprechen).

  1. Prüfen Sie mit der folgenden Abfrage, ob der Index erstellt wurde:
SELECT * FROM pg_stat_ann_indexes;
  1. Führen Sie die Vektorsuche mit derselben Anfrage aus, die Sie ohne Index verwendet haben:
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;

Die obige Abfrage ist dieselbe, die wir im Lab in Schritt 8 verwendet haben. Das Feld ist jetzt jedoch indexiert.

  1. Testen Sie mit einer einfachen Suchanfrage mit und ohne Index (indem Sie den Index löschen):

Dieser Anwendungsfall hat nur 72 Datensätze, sodass der Index nicht wirklich zum Tragen kommt. Bei einem Test in einem anderen Anwendungsfall sind die Ergebnisse so:

Dieselbe Vektorsuchanfrage für die INDEXED-Einbettungsdaten führt zu hochwertigen Suchergebnissen und Effizienz. Die Effizienz wird mit dem Index erheblich verbessert (in Bezug auf die Ausführungszeit: 10,37 ms ohne ScaNN und 0,87 ms mit ScaNN). Weitere Informationen zu diesem Thema finden Sie in diesem Blog.

8. Abstimmung der Validierung mit dem LLM

Bevor wir fortfahren und einen Dienst erstellen, der die besten Übereinstimmungen für eine Anwendung zurückgibt, verwenden wir ein generatives KI-Modell, um zu prüfen, ob diese potenziellen Antworten wirklich relevant und sicher für die Weitergabe an den Nutzer sind.

Prüfen, ob die Instanz für Gemini eingerichtet ist

Prüfen Sie zuerst, ob die Google ML-Integration bereits für Ihren Cluster und Ihre Instanz aktiviert ist. Geben Sie in AlloyDB Studio den folgenden Befehl ein:

show google_ml_integration.enable_model_support;

Wenn der Wert als on angezeigt wird, können Sie die nächsten beiden Schritte überspringen und direkt mit dem Einrichten der Integration von AlloyDB und Vertex AI-Modell fortfahren.

  1. Rufen Sie die primäre Instanz Ihres AlloyDB-Clusters auf und klicken Sie auf „PRIMÄRE INSTANZ BEARBEITEN“.

cb76b934ba3735bd.png

  1. Rufen Sie im Bereich „Erweiterte Konfigurationsoptionen“ den Abschnitt „Flags“ auf. Achten Sie darauf, dass google_ml_integration.enable_model_support flag auf „on“ gesetzt ist, wie unten dargestellt:

6a59351fcd2a9d35.png

Wenn sie nicht auf „on“ gesetzt ist, setzen Sie sie auf „on“ und klicken Sie dann auf die Schaltfläche UPDATE INSTANCE (INSTANZ AKTUALISIEREN). Dieser Schritt dauert einige Minuten.

Einbindung von AlloyDB und Vertex AI-Modellen

Sie können jetzt eine Verbindung zu AlloyDB Studio herstellen und die folgende DML-Anweisung ausführen, um den Zugriff auf Gemini-Modelle über AlloyDB einzurichten. Verwenden Sie dazu Ihre Projekt-ID, wo angegeben. Möglicherweise werden Sie vor der Ausführung des Befehls vor einem Syntaxfehler gewarnt, aber der Befehl sollte trotzdem ausgeführt werden.

Zuerst erstellen wir die Verbindung zum Gemini 1.5-Modell, wie unten dargestellt. Ersetzen Sie im folgenden Befehl $PROJECT_ID durch Ihre Google Cloud-Projekt-ID.

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');

Mit dem folgenden Befehl in AlloyDB Studio können Sie prüfen, welche Modelle für den Zugriff konfiguriert sind:

select model_id,model_type from google_ml.model_info_view;        

Schließlich müssen wir Datenbanknutzern die Berechtigung erteilen, die Funktion ml_predict_row auszuführen, um Vorhersagen über Google Vertex AI-Modelle zu treffen. Führen Sie dazu diesen Befehl aus:

GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;

Hinweis: Wenn Sie ein vorhandenes Google Cloud-Projekt und einen vorhandenen Cluster/eine vorhandene Instanz von AlloyDB verwenden, die vor einiger Zeit erstellt wurden, müssen Sie möglicherweise die alten Verweise auf das Modell „gemini-1.5“ löschen und mit der oben genannten CALL-Anweisung neu erstellen. Führen Sie „grant execute on function ml_predict_row“ noch einmal aus, falls bei den anstehenden Aufrufen von „gemini-1.5“ Probleme auftreten.

Antworten bewerten

Im nächsten Abschnitt verwenden wir eine große Abfrage, um sicherzustellen, dass die Antworten der Abfrage angemessen sind. Die Abfrage kann jedoch schwer zu verstehen sein. Wir sehen uns die einzelnen Teile jetzt an und schauen uns in wenigen Minuten an, wie sie zusammenpassen.

  1. Zuerst senden wir eine Anfrage an die Datenbank, um die zehn besten Übereinstimmungen mit einer Nutzeranfrage zu erhalten.
  2. Um die Gültigkeit der Antworten zu ermitteln, verwenden wir eine äußere Abfrage, in der wir erklären, wie die Antworten bewertet werden sollen. Dabei werden das Feld recommended_text (der Suchtext) und content (das Feld für die Spielzeugbeschreibung) der inneren Tabelle als Teil der Abfrage verwendet.
  3. Anhand dieser Daten bewerten wir dann die Qualität der zurückgegebenen Antworten.
  4. Die predict_row gibt ihr Ergebnis im JSON-Format zurück. Mit dem Code -> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'" wird der tatsächliche Text aus diesem JSON extrahiert. Wenn Sie das zurückgegebene JSON sehen möchten, können Sie diesen Code entfernen.
  5. Schließlich extrahieren wir die LLM-Antwort mit 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%';

Auch wenn das immer noch kompliziert aussieht, können Sie hoffentlich etwas mehr damit anfangen. Die Ergebnisse geben an, ob es eine Übereinstimmung gibt, wie hoch der Prozentsatz der Übereinstimmung ist und enthalten eine Erklärung der Bewertung.

Beachten Sie, dass das Gemini-Modell standardmäßig Streaming verwendet, sodass die tatsächliche Antwort auf mehrere Zeilen verteilt ist:

c2b006aeb3f3a2fc.png

9. Serverlose Migration der Spielzeugsuche in die Cloud

Sind Sie bereit, diese App im Web zu nutzen? Führen Sie die folgenden Schritte aus, um Knowledge Engine Serverless mit Cloud Run-Funktionen zu erstellen:

  1. Rufen Sie in der Google Cloud Console „Cloud Run-Funktionen“ auf, um eine neue Cloud Run-Funktion zu ERSTELLEN, oder verwenden Sie den Link https://console.cloud.google.com/functions/add.
  2. Wählen Sie als Umgebung Cloud Run-Funktion aus. Geben Sie den Funktionsnamen get-toys-alloydb ein und wählen Sie als Region „us-central1“ aus. Legen Sie die Authentifizierung auf „Nicht authentifizierte Aufrufe zulassen“ fest und klicken Sie auf WEITER. Wählen Sie Java 17 als Laufzeit und Inline-Editor für den Quellcode aus.
  3. Standardmäßig wird der Einstiegspunkt auf „gcfv2.HelloHttpFunction“ festgelegt. Ersetzen Sie den Platzhaltercode in HelloHttpFunction.java und pom.xml Ihrer Cloud Run-Funktion durch den Code aus HelloHttpFunction.java bzw. pom.xml.
  4. Denken Sie daran, den Platzhalter <<YOUR_PROJECT>> und die AlloyDB-Verbindungsanmeldedaten in der Java-Datei durch Ihre Werte zu ersetzen. Die AlloyDB-Anmeldedaten sind die, die wir zu Beginn dieses Codelabs verwendet haben. Wenn Sie andere Werte verwendet haben, ändern Sie diese in der Java-Datei.
  5. Klicken Sie auf Bereitstellen.

Nach der Bereitstellung erstellen wir den VPC-Connector, damit die Cloud-Funktion auf unsere AlloyDB-Datenbankinstanz zugreifen kann.

WICHTIGER SCHRITT:

Sobald Sie die Bereitstellung gestartet haben, sollten Sie die Funktionen in der Cloud Run Functions-Konsole von Google sehen können. Suchen Sie nach der neu erstellten Funktion (get-toys-alloydb), klicken Sie darauf und dann auf BEARBEITEN. Nehmen Sie die folgenden Änderungen vor:

  1. Zu den Laufzeit-, Build-, Verbindungs- und Sicherheitseinstellungen
  2. Zeitlimit auf 180 Sekunden erhöhen
  3. Rufen Sie den Tab „VERBINDUNGEN“ auf:

4e83ec8a339cda08.png

  1. Achten Sie darauf, dass unter den Ingress-Einstellungen die Option „Gesamten Traffic zulassen“ ausgewählt ist.
  2. Klicken Sie unter „Einstellungen für ausgehenden Traffic“ auf das Drop-down-Menü „Netzwerk“, wählen Sie die Option „Neuen VPC-Connector hinzufügen“ aus und folgen Sie der Anleitung im Pop-up-Dialogfeld:

8126ec78c343f199.png

  1. Geben Sie einen Namen für den VPC-Connector an und achten Sie darauf, dass die Region mit der Ihrer Instanz übereinstimmt. Lassen Sie den Netzwerk-Wert auf dem Standardwert und legen Sie das Subnetz als benutzerdefinierten IP-Bereich mit dem IP-Bereich 10.8.0.0 oder einem ähnlichen verfügbaren Bereich fest.
  2. Klicken Sie auf „SHOW SCALING SETTINGS“ (Skalierungseinstellungen anzeigen) und prüfen Sie, ob die Konfiguration genau wie unten angegeben ist:

7baf980463a86a5c.png

  1. Klicken Sie auf „ERSTELLEN“. Der Connector sollte jetzt in den Einstellungen für ausgehenden Traffic aufgeführt sein.
  2. Wählen Sie den neu erstellten Connector aus.
  3. Wählen Sie aus, dass der gesamte Traffic über diesen VPC-Connector weitergeleitet werden soll.
  4. Klicken Sie auf WEITER und dann auf BEREITSTELLEN.

10. Cloud Run-Funktion testen

Nachdem die aktualisierte Cloud-Funktion bereitgestellt wurde, sollte der Endpunkt generiert werden. Kopieren Sie das und ersetzen Sie es im folgenden Befehl:

Alternativ können Sie die Cloud Run-Funktion so testen:

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 .

Das Ergebnis:

23861e9091565a64.png

Geschafft! So einfach ist es, mit dem Einbettungsmodell für AlloyDB-Daten eine Suche nach ähnlichen Vektoren durchzuführen.

11. Webanwendungsclient erstellen

In diesem Teil erstellen wir eine Webanwendung, mit der Nutzer interagieren und passende Spielzeuge anhand von Text oder Bildern finden können. Außerdem können sie ein neues Spielzeug basierend auf ihren Anforderungen erstellen. Da die Anwendung bereits erstellt wurde, können Sie sie einfach in Ihre IDE kopieren und ausführen.

  1. Da wir Gemini 2.0 Flash verwenden, um das Bild zu beschreiben, das der Nutzer hochladen kann, um passende Spielzeuge zu finden, benötigen wir den API-SCHLÜSSEL für diese Anwendung. Rufen Sie dazu https://aistudio.google.com/apikey auf und rufen Sie den API-Schlüssel für Ihr aktives Google Cloud-Projekt ab, in dem Sie diese Anwendung implementieren. Speichern Sie den Schlüssel an einem geeigneten Ort:

ae2db169e6a94e4a.png

  1. Cloud Shell-Terminal aufrufen
  2. Klonen Sie das Repository mit dem folgenden Befehl:
git clone https://github.com/AbiramiSukumaran/toysearch

cd toysearch
  1. Sobald das Repository geklont wurde, sollten Sie über den Cloud Shell-Editor auf das Projekt zugreifen können.
  2. Sie müssen die Ordner „get-toys-alloydb“ und „toolbox-toys“ aus dem geklonten Projekt löschen, da es sich dabei um Cloud Run Functions-Code handelt, auf den bei Bedarf über das Repository verwiesen werden kann.
  3. Rufen Sie die Datei „GenerateToy.java“ im Webordner auf, suchen Sie die folgende Zeile und entfernen Sie sie, da für „allow adult“ möglicherweise eine spezielle Berechtigung erforderlich ist, die für einige Testabrechnungskonten nicht verfügbar ist:

paramsMap.put("personGeneration", "allow_adult");

  1. Achten Sie darauf, dass alle erforderlichen Umgebungsvariablen festgelegt sind, bevor Sie die App erstellen und bereitstellen. Rufen Sie das Cloud Shell-Terminal auf und führen Sie Folgendes aus:
PROJECT_ID=$(gcloud config get-value project)

export PROJECT_ID=$PROJECT_ID

export GOOGLE_API_KEY=<YOUR API KEY that you saved>
  1. So erstellen Sie die App und führen sie lokal aus:

Führen Sie die folgenden Befehle aus, um sicherzustellen, dass Sie sich im Projektverzeichnis befinden:

mvn package

mvn spring-boot:run 
  1. In Cloud Run bereitstellen
gcloud run deploy --source .

12. Details zur generativen KI

Es sind keine Maßnahmen erforderlich. Zur Information:

Nachdem Sie die Anwendung bereitgestellt haben, nehmen Sie sich einen Moment Zeit, um zu verstehen, wie wir die Suche (Text und Bild) und die Generierung umgesetzt haben.

  1. Vektorsuche auf Grundlage von Nutzertext:

Dies wird bereits in den Cloud Run Functions behandelt, die wir im Abschnitt „Vektorsuchanwendung im Web verwenden“ bereitgestellt haben.

  1. Vektorsuche basierend auf dem Hochladen von Bildern:

Anstatt den Kontext als Text einzugeben, möchte der Nutzer beispielsweise ein Bild eines bekannten Spielzeugs hochladen, mit dem er suchen möchte. Nutzer können ein Bild eines Spielzeugs hochladen, das ihnen gefällt, und erhalten dann relevante Funktionen.

Wir verwenden das Gemini 2.0 Flash-Modell von Google, das mit LangChain4j aufgerufen wird, um das Bild zu analysieren und relevanten Kontext wie Farbe, Material, Typ und Altersgruppe des Spielzeugs zu extrahieren.

In nur fünf Schritten haben wir multimodale Nutzereingaben in passende Ergebnisse umgewandelt, indem wir ein Large Language Model mit einem Open-Source-Framework aufgerufen haben. Weitere Informationen:

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;
  }
}
  1. Erfahren Sie, wie wir mit Imagen 3 und generativer KI ein benutzerdefiniertes Spielzeug auf Grundlage einer Nutzeranfrage erstellt haben.

Imagen 3 generiert dann ein Bild des selbst gestalteten Spielzeugs, sodass der Nutzer eine klare Visualisierung seiner Kreation erhält. So sind wir in nur fünf Schritten vorgegangen:

// 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();
    }
  }

Preisvorhersage

Im vorherigen Abschnitt haben wir beschrieben, wie Imagen das Bild eines Spielzeugs generiert, das der Nutzer selbst gestalten möchte. Damit sie es kaufen können, muss in der Anwendung ein Preis dafür festgelegt werden. Wir haben eine intuitive Logik verwendet, um einen Preis für das maßgeschneiderte Spielzeug festzulegen. Die Logik besteht darin, den durchschnittlichen Preis der fünf Spielzeuge zu verwenden, die dem vom Nutzer entworfenen Spielzeug am ähnlichsten sind (in Bezug auf die Beschreibung).

Die Preisvorhersage für das generierte Spielzeug ist ein wichtiger Bestandteil dieser Anwendung. Wir haben einen agentenbasierten Ansatz verwendet, um sie zu generieren. Einführung der Gen AI Toolbox for Databases

13. Gen AI Toolbox for Databases

Die Gen AI Toolbox for Databases ist ein Open-Source-Server von Google, der die Entwicklung von Gen AI-Tools für die Interaktion mit Datenbanken vereinfacht. Damit können Sie Tools einfacher, schneller und sicherer entwickeln, da Komplexitäten wie Connection Pooling und Authentifizierung abgedeckt werden. Damit können Sie Tools für generative KI erstellen, mit denen Ihre Agents auf Daten in Ihrer Datenbank zugreifen können.

So richten Sie das Tool ein, damit es einsatzbereit ist und unsere Anwendung agentisch wird: Link zum Toolbox-Codelab

Ihre Anwendung kann jetzt diesen bereitgestellten Cloud Run-Funktionsendpunkt verwenden, um den Preis zusammen mit dem generierten Imagen-Ergebnis für das benutzerdefinierte Bild des Spielzeugs zu ermitteln.

14. Webanwendung testen

Nachdem alle Komponenten Ihrer Anwendung erstellt und bereitgestellt wurden, kann sie in der Cloud bereitgestellt werden. Testen Sie Ihre Anwendung für alle Szenarien. Hier ist ein Videolink, der Ihnen einen Eindruck davon vermittelt:

https://www.youtube.com/shorts/ZMqUAWsghYQ

So sieht die Landingpage aus:

241db19e7176e93e.png

15. Bereinigen

So vermeiden Sie, dass Ihrem Google Cloud-Konto die in diesem Beitrag verwendeten Ressourcen in Rechnung gestellt werden:

  1. Wechseln Sie in der Google Cloud Console zur Seite Ressourcen verwalten.
  2. Wählen Sie in der Projektliste das Projekt aus, das Sie löschen möchten, und klicken Sie auf Löschen.
  3. Geben Sie im Dialogfeld die Projekt-ID ein und klicken Sie auf Beenden, um das Projekt zu löschen.

16. Glückwunsch

Glückwunsch! Sie haben erfolgreich eine kontextbezogene Suche und Generierung für einen Spielzeugladen mit AlloyDB, pgvector, Imagen und Gemini 2.0 durchgeführt und dabei Open-Source-Bibliotheken verwendet, um robuste Integrationen zu erstellen. Durch die Kombination der Funktionen von AlloyDB, Vertex AI und Vector Search haben wir einen großen Schritt nach vorn gemacht, um kontextbezogene und Vektorsuchen zugänglich, effizient und wirklich aussagekräftig zu gestalten.