1. Panoramica
Immagina di entrare in un negozio di giocattoli virtualmente o di persona, dove trovare il regalo perfetto è un gioco da ragazzi. Puoi descrivere ciò che stai cercando, caricare l'immagine di un giocattolo o persino progettare la tua creazione e lo store comprende immediatamente le tue esigenze e ti offre un'esperienza personalizzata. Non si tratta di una fantasia futuristica, ma di una realtà basata sull'AI, sulla tecnologia cloud e su una visione dell'e-commerce personalizzato.
La sfida:trovare il prodotto perfetto che corrisponda alla tua immaginazione può essere difficile. Termini di ricerca generici, parole chiave e ricerche approssimative spesso non sono sufficienti, la navigazione in pagine infinite può essere noiosa e la discrepanza tra ciò che immagini e ciò che è disponibile può portare a frustrazione.
La soluzione: l'applicazione demo affronta questa sfida sfruttando la potenza dell'AI per offrire un'esperienza davvero personalizzata e fluida con la ricerca contestuale e la generazione personalizzata del prodotto corrispondente al contesto di ricerca.
Cosa creerai
Nell'ambito di questo lab, imparerai a:
- Crea un'istanza AlloyDB e carica il set di dati Toys
- Abilita le estensioni pgvector e del modello di AI generativa in AlloyDB
- Genera gli embedding dalla descrizione del prodotto ed esegui la ricerca di similarità del coseno in tempo reale per il testo di ricerca dell'utente
- Richiamare Gemini 2.0 Flash per descrivere l'immagine caricata dall'utente per la ricerca contestuale di giocattoli
- Richiedi a Imagen 3 di creare un giocattolo personalizzato in base agli interessi dell'utente
- Richiama uno strumento di previsione dei prezzi creato utilizzando Gen AI Toolbox for Databases per i dettagli sui prezzi del giocattolo creato personalizzato
- Esegui il deployment della soluzione in Cloud Run Functions serverless
Requisiti
2. Architettura
Flusso di dati: vediamo più da vicino come si spostano i dati nel nostro sistema:
- Ricerca contestuale con RAG (Retrieval Augmented Generation) basata sull'AI
Funziona così: anziché cercare solo "auto rossa", il sistema comprende quanto segue:
"piccolo veicolo adatto a un bambino di 3 anni".
AlloyDB come base: utilizziamo AlloyDB, il database di Google Cloud completamente gestito e compatibile con PostgreSQL, per archiviare i dati dei nostri giocattoli, tra cui descrizioni, URL delle immagini e altri attributi pertinenti.
pgvector per la ricerca semantica:pgvector, un'estensione PostgreSQL, ci consente di archiviare gli embedding vettoriali delle descrizioni dei giocattoli e delle query di ricerca degli utenti. Ciò consente la ricerca semantica, il che significa che il sistema comprende il significato delle parole, non solo le parole chiave esatte.
Somiglianza del coseno per la pertinenza:utilizziamo la somiglianza del coseno per misurare la somiglianza semantica tra il vettore di ricerca dell'utente e i vettori della descrizione del giocattolo, mostrando i risultati più pertinenti.
Indice ScaNN per velocità e precisione:per garantire risultati rapidi e accurati, soprattutto man mano che il nostro inventario di giocattoli cresce, integriamo l'indice ScaNN (Scalable Nearest Neighbors). Ciò migliora significativamente l'efficienza e il richiamo della nostra ricerca vettoriale.
- Ricerca e comprensione basate sulle immagini con Gemini 2.0 Flash
Invece di digitare il contesto come testo, supponiamo che l'utente voglia caricare l'immagine di un giocattolo familiare con cui vuole eseguire la ricerca. Gli utenti possono caricare un'immagine di un giocattolo che gli piace e ottenere funzionalità pertinenti. Sfruttiamo il modello Gemini 2.0 Flash di Google, richiamato utilizzando LangChain4j, per analizzare l'immagine ed estrarre il contesto pertinente, come il colore, il materiale, il tipo e la fascia d'età prevista del giocattolo.
- Building Your Dream Toy Customized with Generative AI: Imagen 3
La vera magia si verifica quando gli utenti decidono di creare il proprio giocattolo. Con Imagen 3, consentiamo loro di descrivere il giocattolo dei loro sogni utilizzando semplici prompt di testo. Immagina di poter dire: "Voglio un drago di peluche con ali viola e un muso simpatico" e di vederlo prendere vita sullo schermo. Imagen 3 genera quindi un'immagine del giocattolo progettato su misura, offrendo all'utente una visualizzazione chiara della sua creazione.
- Previsione dei prezzi basata su agenti e MCP Toolbox per database
Abbiamo implementato una funzionalità di previsione del prezzo che stima il costo di produzione del giocattolo progettato su misura. Questa funzionalità è basata su un agente che include uno strumento sofisticato di calcolo dei prezzi.
MCP Toolbox per database: questo agente è perfettamente integrato con il nostro database utilizzando il nuovo strumento open source di Google, MCP Toolbox per database. In questo modo, l'agente può accedere a dati in tempo reale su costi dei materiali, processi di produzione e altri fattori pertinenti per fornire una stima accurata del prezzo. Scopri di più qui.
- Java Spring Boot, Gemini Code Assist e Cloud Run per uno sviluppo semplificato e un deployment serverless
L'intera applicazione è creata utilizzando Java Spring Boot, un framework solido e scalabile. Abbiamo sfruttato Gemini Code Assist durante tutto il processo di sviluppo, in particolare per lo sviluppo front-end, accelerando in modo significativo il ciclo di sviluppo e migliorando la qualità del codice. Abbiamo utilizzato Cloud Run per il deployment dell'intera applicazione e Cloud Run Functions per il deployment del database e delle funzionalità agentic come endpoint indipendenti.
3. Prima di iniziare
Crea un progetto
- Nella console Google Cloud, nella pagina di selezione del progetto, seleziona o crea un progetto Google Cloud.
- Verifica che la fatturazione sia attivata per il tuo progetto Cloud. Scopri come verificare se la fatturazione è abilitata per un progetto .
- Utilizzerai Cloud Shell, un ambiente a riga di comando in esecuzione in Google Cloud precaricato con bq. Fai clic su Attiva Cloud Shell nella parte superiore della console Google Cloud.

- Una volta eseguita la connessione a Cloud Shell, verifica di essere già autenticato e che il progetto sia impostato sul tuo ID progetto utilizzando il seguente comando:
gcloud auth list
- Esegui questo comando in Cloud Shell per verificare che il comando gcloud conosca il tuo progetto.
gcloud config list project
- Se il progetto non è impostato, utilizza il seguente comando per impostarlo:
gcloud config set project <YOUR_PROJECT_ID>
- Abilita le API richieste eseguendo i seguenti comandi uno alla volta nel terminale Cloud Shell:
Esiste anche un singolo comando per eseguire le operazioni riportate di seguito, ma se utilizzi un account di prova, potresti riscontrare problemi di quota durante il tentativo di abilitare queste operazioni collettivamente. Per questo motivo, i comandi vengono selezionati uno per riga.
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
L'alternativa al comando gcloud è tramite la console, cercando ogni prodotto o utilizzando questo link.
Se manca un'API, puoi sempre abilitarla durante l'implementazione.
Consulta la documentazione per i comandi e l'utilizzo di gcloud.
4. Configurazione del database
In questo lab utilizzeremo AlloyDB come database per contenere i dati del negozio di giocattoli. Utilizza i cluster per contenere tutte le risorse, come database e log. Ogni cluster ha un'istanza primaria che fornisce un punto di accesso ai dati. Le tabelle conterranno i dati effettivi.
Creiamo un cluster, un'istanza e una tabella AlloyDB in cui verrà caricato il set di dati di e-commerce.
Crea un cluster e un'istanza
- Vai alla pagina AlloyDB nella console Cloud. Un modo semplice per trovare la maggior parte delle pagine in Cloud Console è cercarle utilizzando la barra di ricerca della console.
- Seleziona CREA CLUSTER da questa pagina:

- Verrà visualizzata una schermata come quella riportata di seguito. Crea un cluster e un'istanza con i seguenti valori (assicurati che i valori corrispondano se cloni il codice dell'applicazione dal repository):
- cluster id: "
vector-cluster" - password: "
alloydb" - Compatibile con PostgreSQL 15
- Regione: "
us-central1" - Networking: "
default"

- Quando selezioni la rete predefinita, viene visualizzata una schermata come quella mostrata di seguito.
Seleziona CONFIGURA CONNESSIONE.
- Da qui, seleziona "Utilizza un intervallo IP allocato automaticamente" e fai clic su Continua. Dopo aver esaminato le informazioni, seleziona CREA CONNESSIONE.

- Una volta configurata la rete, puoi continuare a creare il cluster. Fai clic su CREA CLUSTER per completare la configurazione del cluster come mostrato di seguito:

Assicurati di modificare l'ID istanza in
vector-instance
Se non riesci a modificarlo, ricordati di modificare l'ID istanza in tutti i riferimenti futuri.
Tieni presente che la creazione del cluster richiederà circa 10 minuti. Una volta completata l'operazione, dovresti visualizzare una schermata che mostra la panoramica del cluster che hai appena creato.
5. Importazione dati
Ora è il momento di aggiungere una tabella con i dati del negozio. Vai ad AlloyDB, seleziona il cluster principale e poi AlloyDB Studio:

Potrebbe essere necessario attendere il completamento della creazione dell'istanza. Una volta creato, accedi ad AlloyDB utilizzando le credenziali che hai creato durante la creazione del cluster. Utilizza i seguenti dati per l'autenticazione a PostgreSQL:
- Nome utente : "
postgres" - Database : "
postgres" - Password : "
alloydb"
Una volta eseguita l'autenticazione in AlloyDB Studio, i comandi SQL vengono inseriti nell'editor. Puoi aggiungere più finestre dell'editor utilizzando il segno più a destra dell'ultima finestra.

Inserirai i comandi per AlloyDB nelle finestre dell'editor, utilizzando le opzioni Esegui, Formatta e Cancella in base alle necessità.
Attivare le estensioni
Per creare questa app, utilizzeremo le estensioni pgvector e google_ml_integration. L'estensione pgvector consente di archiviare ed eseguire ricerche di vector embedding. L'estensione google_ml_integration fornisce funzioni che utilizzi per accedere agli endpoint di previsione Vertex AI per ottenere previsioni in SQL. Attiva queste estensioni eseguendo i seguenti DDL:
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
Se vuoi controllare le estensioni abilitate sul tuo database, esegui questo comando SQL:
select extname, extversion from pg_extension;
Creare una tabella
Crea una tabella utilizzando l'istruzione DDL riportata di seguito:
CREATE TABLE toys ( id VARCHAR(25), name VARCHAR(25), description VARCHAR(20000), quantity INT, price FLOAT, image_url VARCHAR(200), text_embeddings vector(768)) ;
Se il comando precedente viene eseguito correttamente, dovresti essere in grado di visualizzare la tabella nel database.
Importa i dati
Per questo lab, abbiamo dati di test di circa 72 record in questo file SQL. Contiene i campi id, name, description, quantity, price, image_url. Gli altri campi verranno compilati più tardi nel lab.
Copia solo le prime 5 righe/istruzioni di inserimento da lì, poi incollale in una scheda dell'editor vuota e seleziona ESEGUI. Se NON utilizzi un account di fatturazione di prova, probabilmente puoi copiare tutte le istruzioni di inserimento ed eseguirle.
Per visualizzare i contenuti della tabella, espandi la sezione Explorer finché non vedi la tabella denominata apparels. Seleziona il simbolo dei tre puntini (⋮) per visualizzare l'opzione per eseguire una query sulla tabella. Un'istruzione SELECT si aprirà in una nuova scheda dell'editor.

Concedi autorizzazione
Esegui l'istruzione riportata di seguito per concedere i diritti di esecuzione sulla funzione embedding all'utente postgres:
GRANT EXECUTE ON FUNCTION embedding TO postgres;
Concedi il ruolo Utente Vertex AI al service account AlloyDB
Vai al terminale Cloud Shell ed esegui questo comando:
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. Crea incorporamenti per il contesto
Per i computer è molto più facile elaborare i numeri che il testo. Un sistema di incorporamento converte il testo in una serie di numeri in virgola mobile che dovrebbero rappresentare il testo, indipendentemente dalla formulazione, dalla lingua utilizzata e così via.
Prendi in considerazione la descrizione di una località balneare. Potrebbe essere chiamato "on the water", "beachfront", "walk from your room to the ocean", "sur la mer", "на берегу океана" e così via. Questi termini hanno un aspetto diverso, ma il loro significato semantico o, in termini di machine learning, i loro incorporamenti dovrebbero essere molto simili tra loro.
Ora che i dati e il contesto sono pronti, eseguiamo il codice SQL per aggiungere gli incorporamenti della descrizione del prodotto alla tabella nel campo embedding. Esistono diversi modelli di incorporamento che puoi utilizzare. Stiamo utilizzando text-embedding-005 da Vertex AI. Assicurati di utilizzare lo stesso modello di embedding per tutto il progetto.
Nota: se utilizzi un progetto Google Cloud esistente creato un po' di tempo fa, potresti dover continuare a utilizzare versioni precedenti del modello di incorporamento di testo, come textembedding-gecko.
Torna alla scheda AlloyDB Studio e digita il seguente DML:
UPDATE toys set text_embeddings = embedding( 'text-embedding-005', description);
Dai un'occhiata di nuovo alla tabella toys per vedere alcuni incorporamenti. Assicurati di eseguire di nuovo l'istruzione SELECT per visualizzare le modifiche.
SELECT id, name, description, price, quantity, image_url, text_embeddings FROM toys;
Dovrebbe restituire il vettore di incorporamento, che ha l'aspetto di un array di numeri in virgola mobile, per la descrizione del giocattolo, come mostrato di seguito:

Nota:i progetti Google Cloud appena creati nel livello senza costi potrebbero riscontrare problemi di quota per quanto riguarda il numero di richieste di incorporamento consentite al secondo per i modelli di incorporamento. Ti suggeriamo di utilizzare una query di filtro per l'ID e poi di scegliere in modo selettivo 1-5 record e così via, durante la generazione dell'incorporamento.
7. Esegui la ricerca vettoriale
Ora che la tabella, i dati e gli embedding sono pronti, eseguiamo la ricerca vettoriale in tempo reale per il testo di ricerca dell'utente.
Supponiamo che l'utente chieda:
"I want a white plush teddy bear toy with a floral pattern."
Puoi trovare le corrispondenze eseguendo la query riportata di seguito:
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;
Analizziamo questa query nel dettaglio:
In questa query,
- Il testo di ricerca dell'utente è: "
I want a white plush teddy bear toy with a floral pattern." - Lo stiamo convertendo in incorporamenti nel metodo
embedding()utilizzando il modello:text-embedding-005. Questo passaggio dovrebbe sembrarti familiare dopo l'ultimo, in cui abbiamo applicato la funzione di incorporamento a tutti gli elementi della tabella. - "
<=>" rappresenta l'utilizzo del metodo di distanza COSINE SIMILARITY. Puoi trovare tutte le misure di similarità disponibili nella documentazione di pgvector. - Stiamo convertendo il risultato del metodo di embedding in tipo vettoriale per renderlo compatibile con i vettori archiviati nel database.
- LIMIT 5 indica che vogliamo estrarre i 5 vicini più prossimi per il testo di ricerca.
Il risultato è simile al seguente:

Come puoi notare nei risultati, le corrispondenze sono molto simili al testo di ricerca. Prova a modificare il testo per vedere come cambiano i risultati.
Nota importante:
Supponiamo ora di voler aumentare le prestazioni (tempo di query), l'efficienza e il richiamo di questo risultato della ricerca vettoriale utilizzando l'indice ScaNN. Leggi i passaggi descritti in questo blog per confrontare la differenza nel risultato con e senza l'indice.
Passaggio facoltativo: migliora l'efficienza e il richiamo con l'indice ScaNN
Ignora questo passaggio se il conteggio dei record è inferiore a 100.
Per comodità, ecco i passaggi per la creazione dell'indice:
- Poiché abbiamo già creato il cluster, l'istanza, il contesto e gli incorporamenti, dobbiamo solo installare l'estensione ScaNN utilizzando la seguente istruzione:
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- A questo punto, creiamo l'indice (ScaNN):
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);
Nel DDL riportato sopra, apparel_index è il nome dell'indice
"toys" è la mia tabella
"scann" è il metodo di indicizzazione
"embedding" è la colonna della tabella che voglio indicizzare
"cosine" è il metodo di distanza che voglio utilizzare con l'indice
"8" è il numero di partizioni da applicare a questo indice. Imposta un valore compreso tra 1 e 1048576. Per ulteriori informazioni su come decidere questo valore, vedi Ottimizzare un indice ScaNN.
Ho utilizzato la RADICE QUADRATA del numero di punti dati come consigliato nel repository ScaNN (durante il partizionamento, num_leaves deve essere approssimativamente la radice quadrata del numero di punti dati).
- Controlla se l'indice è stato creato utilizzando la query:
SELECT * FROM pg_stat_ann_indexes;
- Esegui Vector Search utilizzando la stessa query che abbiamo utilizzato senza l'indice:
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;
La query precedente è la stessa che abbiamo utilizzato nel lab al passaggio 8. Tuttavia, ora il campo è indicizzato.
- Esegui il test con una semplice query di ricerca con e senza l'indice (eliminando l'indice):
Questo caso d'uso ha solo 72 record, quindi l'indice non ha effetto. Per un test condotto in un altro caso d'uso, i risultati sono i seguenti:
La stessa query Vector Search sui dati degli incorporamenti INDICIZZATI produce risultati di ricerca di qualità ed efficienza. L'efficienza è notevolmente migliorata (in termini di tempo di esecuzione: 10,37 ms senza ScaNN e 0,87 ms con ScaNN) con l'indice. Per saperne di più su questo argomento, consulta questo blog.
8. Convalida della corrispondenza con l'LLM
Prima di andare avanti e creare un servizio per restituire le corrispondenze migliori a un'applicazione, utilizziamo un modello di AI generativa per verificare se queste potenziali risposte sono davvero pertinenti e sicure da condividere con l'utente.
Assicurarsi che l'istanza sia configurata per Gemini
Innanzitutto, controlla se l'integrazione di Google ML è già attivata per il tuo cluster e la tua istanza. In AlloyDB Studio, esegui questo comando:
show google_ml_integration.enable_model_support;
Se il valore è visualizzato come "on", puoi saltare i due passaggi successivi e passare direttamente alla configurazione dell'integrazione di AlloyDB e del modello Vertex AI.
- Vai all'istanza principale del cluster AlloyDB e fai clic su MODIFICA ISTANZA PRINCIPALE.

- Vai alla sezione Flag nelle opzioni di configurazione avanzata. e assicurati che
google_ml_integration.enable_model_support flagsia impostato su "on" come mostrato di seguito:

Se non è impostato su "on", impostalo su "on" e poi fai clic sul pulsante AGGIORNA ISTANZA. Questo passaggio richiederà alcuni minuti.
Integrazione di AlloyDB e Vertex AI Model
Ora puoi connetterti ad AlloyDB Studio ed eseguire la seguente istruzione DML per configurare l'accesso al modello Gemini da AlloyDB, utilizzando l'ID progetto dove indicato. Potresti ricevere un avviso di errore di sintassi prima di eseguire il comando, ma dovrebbe funzionare correttamente.
Innanzitutto, creiamo la connessione al modello Gemini 1.5 come mostrato di seguito. Ricorda di sostituire $PROJECT_ID nel comando seguente con il tuo ID progetto 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');
Puoi controllare i modelli configurati per l'accesso tramite il seguente comando in AlloyDB Studio:
select model_id,model_type from google_ml.model_info_view;
Infine, dobbiamo concedere l'autorizzazione agli utenti del database per eseguire la funzione ml_predict_row per eseguire le previsioni tramite i modelli Google Vertex AI. Esegui questo comando:
GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;
Nota: se utilizzi un progetto Google Cloud esistente e un cluster/un'istanza di AlloyDB esistente creati un po' di tempo fa, potresti dover eliminare i vecchi riferimenti al modello gemini-1.5 e crearli di nuovo con l'istruzione CALL riportata sopra ed eseguire di nuovo grant execute on function ml_predict_row nel caso in cui si verifichino problemi nelle prossime invocazioni di gemini-1.5.
Valutazione delle risposte
Anche se nella sezione successiva utilizzeremo una query di grandi dimensioni per assicurarci che le risposte siano ragionevoli, la query può essere difficile da comprendere. Ora esamineremo i vari elementi e vedremo come si combinano tra loro tra qualche minuto.
- Innanzitutto invieremo una richiesta al database per ottenere i 10 risultati più pertinenti per una query utente.
- Per determinare la validità delle risposte, utilizzeremo una query esterna in cui spieghiamo come valutare le risposte. Utilizza il campo
recommended_text, che è il testo di ricerca, econtent(il campo della descrizione del giocattolo) della tabella interna come parte della query. - In base a questo, esamineremo la "qualità" delle risposte restituite.
predict_rowrestituisce il risultato in formato JSON. Il codice "-> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'"" viene utilizzato per estrarre il testo effettivo dal JSON. Per visualizzare il JSON effettivo restituito, puoi rimuovere questo codice.- Infine, per ottenere la risposta LLM, la estraiamo utilizzando
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%';
Anche se può sembrare ancora scoraggiante, spero che ora tu possa capirci qualcosa in più. I risultati indicano se è presente una corrispondenza, la percentuale di corrispondenza e una spiegazione della classificazione.
Tieni presente che lo streaming è attivo per impostazione predefinita nel modello Gemini, quindi la risposta effettiva è distribuita su più righe:

9. Trasferire la ricerca di giocattoli sul cloud in modalità serverless
È tutto pronto per portare questa app sul web? Per rendere Knowledge Engine serverless con Cloud Run Functions, segui questi passaggi:
- Vai a Cloud Run Functions nella console Google Cloud per CREARE una nuova funzione Cloud Run o utilizza il link: https://console.cloud.google.com/functions/add.
- Seleziona "Cloud Run function" come ambiente. Fornisci il nome della funzione "get-toys-alloydb" e scegli la regione "us-central1". Imposta l'autenticazione su "Consenti chiamate non autenticate" e fai clic su AVANTI. Scegli Java 17 come runtime e Editor incorporato per il codice sorgente.
- Per impostazione predefinita, l'entry point viene impostato su "
gcfv2.HelloHttpFunction". Sostituisci il codice segnaposto inHelloHttpFunction.javaepom.xmldella tua funzione Cloud Run con il codice di HelloHttpFunction.java e pom.xml rispettivamente. - Ricorda di modificare il segnaposto <<YOUR_PROJECT>> e le credenziali di connessione AlloyDB con i tuoi valori nel file Java. Le credenziali di AlloyDB sono quelle che abbiamo utilizzato all'inizio di questo codelab. Se hai utilizzato valori diversi, modificali nel file Java.
- Fai clic su Esegui il deployment.
Una volta eseguito il deployment, per consentire alla funzione Cloud Functions di accedere all'istanza del database AlloyDB, creeremo il connettore VPC.
PASSAGGIO IMPORTANTE:
Una volta impostato il deployment, dovresti essere in grado di visualizzare le funzioni nella console Cloud Run Functions di Google. Cerca la funzione appena creata (get-toys-alloydb), fai clic su di essa, poi su MODIFICA e modifica quanto segue:
- Vai a Impostazioni di runtime, build, connessioni e sicurezza
- Aumenta il timeout a 180 secondi
- Vai alla scheda CONNESSIONI:

- Nelle impostazioni di Ingress, assicurati che sia selezionata l'opzione "Consenti tutto il traffico".
- Nella sezione Impostazioni traffico in uscita, fai clic sul menu a discesa Rete, seleziona l'opzione "Aggiungi nuovo connettore VPC" e segui le istruzioni visualizzate nella finestra di dialogo visualizzata:

- Fornisci un nome per il connettore VPC e assicurati che la regione sia la stessa dell'istanza. Lascia il valore Rete come predefinito e imposta Subnet come intervallo IP personalizzato con l'intervallo IP 10.8.0.0 o un valore simile disponibile.
- Espandi MOSTRA IMPOSTAZIONI SCALATURA e assicurati che la configurazione sia impostata esattamente come segue:

- Fai clic su CREA e il connettore dovrebbe essere ora elencato nelle impostazioni di uscita.
- Seleziona il connettore appena creato.
- Scegli di instradare tutto il traffico tramite questo connettore VPC.
- Fai clic su AVANTI e poi su ESEGUI IL DEPLOYMENT.
10. Testa la funzione Cloud Run
Una volta eseguito il deployment della funzione Cloud Functions aggiornata, dovresti visualizzare l'endpoint generato. Copia questo valore e sostituiscilo nel seguente comando:
In alternativa, puoi testare la funzione Cloud Run nel seguente modo:
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 .
Il risultato:

È tutto. Eseguire la ricerca vettoriale di similarità utilizzando il modello di embedding sui dati AlloyDB è semplicissimo.
11. Creazione del client dell'applicazione web.
In questa parte, creeremo un'applicazione web con cui l'utente potrà interagire e trovare giocattoli corrispondenti in base a testo e immagine, nonché creare un nuovo giocattolo in base alle sue esigenze. Poiché l'applicazione è già creata, puoi seguire i passaggi riportati di seguito per copiarla nel tuo IDE e avviare l'app.
- Poiché utilizziamo Gemini 2.0 Flash per descrivere l'immagine che l'utente può caricare per trovare giocattoli corrispondenti, dobbiamo ottenere la chiave API per questa applicazione. Per farlo, vai su https://aistudio.google.com/apikey, recupera la chiave API per il tuo progetto Google Cloud attivo in cui stai implementando questa applicazione e salvala da qualche parte:

- Vai al terminale Cloud Shell
- Clona il repository con il comando seguente:
git clone https://github.com/AbiramiSukumaran/toysearch
cd toysearch
- Una volta clonato il repository, dovresti essere in grado di accedere al progetto da Cloud Shell Editor.
- Devi eliminare le cartelle "get-toys-alloydb" e "toolbox-toys" dal progetto clonato perché queste due contengono il codice di Cloud Run Functions a cui puoi fare riferimento dal repository quando ne hai bisogno.
- Vai a GenerateToy.java nella cartella web, trova la riga seguente ed eliminala perché l'opzione per consentire contenuti per adulti potrebbe richiedere un'autorizzazione speciale che potrebbe non essere disponibile per alcuni account di fatturazione di prova:
paramsMap.put("personGeneration", "allow_adult");
- Assicurati che tutte le variabili di ambiente necessarie siano impostate prima di creare e implementare l'app. Vai al terminale Cloud Shell ed esegui questo comando:
PROJECT_ID=$(gcloud config get-value project)
export PROJECT_ID=$PROJECT_ID
export GOOGLE_API_KEY=<YOUR API KEY that you saved>
- Crea ed esegui l'app localmente:
Assicurati di trovarti nella directory del progetto ed esegui questi comandi:
mvn package
mvn spring-boot:run
- Esegui il deployment su Cloud Run
gcloud run deploy --source .
12. Informazioni dettagliate sull'AI generativa
Nessuna azione richiesta. Per tua informazione:
Ora che hai l'applicazione da distribuire, prenditi un momento per capire come abbiamo eseguito la ricerca (testo e immagine) e la generazione.
- Ricerca vettoriale basata sul testo dell'utente:
Questo problema è già stato risolto nelle funzioni Cloud Run che abbiamo eseguito il deployment nella sezione "Crea l'applicazione di ricerca vettoriale".
- Ricerca vettoriale basata sul caricamento di immagini:
Invece di digitare il contesto come testo, supponiamo che l'utente voglia caricare l'immagine di un giocattolo familiare con cui vuole eseguire la ricerca. Gli utenti possono caricare un'immagine di un giocattolo che gli piace e ottenere funzionalità pertinenti.
Sfruttiamo il modello Gemini 2.0 Flash di Google, richiamato utilizzando LangChain4j, per analizzare l'immagine ed estrarre il contesto pertinente, come il colore, il materiale, il tipo e la fascia d'età prevista del giocattolo.
In soli 5 passaggi, abbiamo trasformato l'input di dati multimodali dell'utente in risultati corrispondenti con l'invocazione di un modello linguistico di grandi dimensioni utilizzando un framework open source. Scopri come:
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;
}
}
- Scopri come abbiamo utilizzato Imagen 3 per creare un giocattolo personalizzato in base alla richiesta dell'utente con l'AI generativa.
Imagen 3 genera quindi un'immagine del giocattolo progettato su misura, offrendo all'utente una visualizzazione chiara della sua creazione. Ecco come abbiamo fatto in soli 5 passaggi:
// 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();
}
}
Previsione del prezzo
Nella sezione precedente abbiamo discusso di come Imagen genera l'immagine di un giocattolo che l'utente vuole progettare da solo. Affinché l'utente possa acquistarlo, l'applicazione deve impostare un prezzo e abbiamo utilizzato una logica intuitiva per definire un prezzo per il giocattolo personalizzato su ordinazione. La logica è quella di utilizzare il prezzo medio dei primi 5 giocattoli con la corrispondenza più vicina (in termini di descrizione) del giocattolo progettato dall'utente.
La previsione del prezzo del giocattolo generato è una parte importante di questa applicazione e abbiamo utilizzato un approccio basato su agenti per generarla. Ti presentiamo Gen AI Toolbox for Databases.
13. Gen AI Toolbox for Databases
Gen AI Toolbox for Databases è un server open source di Google che semplifica la creazione di strumenti di AI generativa per interagire con i database. Ti consente di sviluppare strumenti in modo più semplice, rapido e sicuro gestendo le complessità come il pooling di connessioni, l'autenticazione e altro ancora. Ti aiuta a creare strumenti di AI generativa che consentono ai tuoi agenti di accedere ai dati nel tuo database.
Ecco i passaggi da seguire per configurare questa funzionalità in modo da preparare lo strumento e rendere la nostra applicazione agentica: Link a Toolbox Codelab
Ora la tua applicazione può utilizzare questo endpoint Cloud Run Function di cui è stato eseguito il deployment per compilare il prezzo insieme al risultato generato da Imagen per l'immagine del giocattolo personalizzato su ordinazione.
14. Testare l'applicazione web
Ora che tutti i componenti dell'applicazione sono stati creati e sottoposti a deployment, è pronta per essere pubblicata sul cloud. Testa l'applicazione per tutti gli scenari. Ecco un link a un video che mostra cosa puoi aspettarti:
https://www.youtube.com/shorts/ZMqUAWsghYQ
Ecco l'aspetto della pagina di destinazione:

15. Esegui la pulizia
Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo post, segui questi passaggi:
- Nella console Google Cloud, vai alla pagina Gestisci risorse.
- Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
- Nella finestra di dialogo, digita l'ID progetto, quindi fai clic su Chiudi per eliminare il progetto.
16. Complimenti
Complimenti! Hai eseguito correttamente una ricerca e una generazione contestuale di Toystore utilizzando AlloyDB, pgvector, Imagen e Gemini 2.0, sfruttando le librerie open source per creare integrazioni robuste. Combinando le funzionalità di AlloyDB, Vertex AI e Vector Search, abbiamo fatto un enorme passo avanti nel rendere le ricerche contestuali e vettoriali accessibili, efficienti e realmente basate sul significato.