1. Présentation
Imaginez que vous pénétriez dans un magasin de jouets en ligne ou en magasin, où trouver le cadeau idéal est un jeu d'enfant. Vous pouvez décrire ce que vous recherchez, importer une photo d'un jouet ou même concevoir votre propre création. La boutique comprendra instantanément vos besoins et vous proposera une expérience personnalisée. Il ne s'agit pas d'une fantaisie futuriste, mais d'une réalité alimentée par l'IA, la technologie cloud et une vision de l'e-commerce personnalisé.
Défi:trouver le produit parfait qui correspond à votre imagination peut s'avérer difficile. Les termes de recherche génériques, les mots clés et les recherches floues ne sont souvent pas suffisants, la navigation sur des pages sans fin peut être fastidieuse, et le décalage entre ce que vous imaginez et ce qui est disponible peut être frustrant.
Solution:L'application de démonstration relève ce défi de front, en exploitant la puissance de l'IA pour offrir une expérience véritablement personnalisée et fluide avec la recherche contextuelle et la génération personnalisée du produit correspondant au contexte de recherche.
Ce que vous allez faire
Au cours de cet atelier, vous allez:
- Créer une instance AlloyDB et charger l'ensemble de données Toys
- Activer les extensions pgvector et de modèle d'IA générative dans AlloyDB
- Générer des représentations vectorielles continues à partir de la description du produit et effectuer une recherche de similarité cosinus en temps réel pour le texte de recherche de l'utilisateur
- Appeler Gemini 2.0 Flash pour décrire l'image importée par l'utilisateur pour la recherche de jouets contextuelle
- Appeler Imagen 3 pour créer un jouet personnalisé en fonction des centres d'intérêt de l'utilisateur
- Appeler un outil de prédiction des prix créé à l'aide de la boîte à outils d'IA générative pour les bases de données afin d'obtenir des informations sur le prix du jouet créé sur mesure
- Déployer la solution dans des fonctions Cloud Run sans serveur
Conditions requises
2. Architecture
Flux de données: examinons de plus près le flux des données dans notre système:
- Recherche contextuelle avec génération augmentée de récupération (RAG) optimisée par l'IA
Considérez-le comme suit: au lieu de rechercher simplement "voiture rouge", le système comprend ce qui suit:
"Petit véhicule adapté à un garçon de 3 ans."
AlloyDB comme base:nous utilisons AlloyDB, la base de données PostgreSQL entièrement gérée de Google Cloud, pour stocker nos données sur les jouets, y compris les descriptions, les URL des images et d'autres attributs pertinents.
pgvector pour la recherche sémantique:pgvector, une extension PostgreSQL, nous permet de stocker des embeddings vectoriels à la fois des descriptions de jouets et des requêtes de recherche des utilisateurs. Cela permet la recherche sémantique, c'est-à-dire que le système comprend le sens des mots, et non seulement les mots clés exacts.
Similarité cosinus pour la pertinence:nous utilisons la similarité cosinus pour mesurer la similarité sémantique entre le vecteur de recherche de l'utilisateur et les vecteurs de description des jouets, afin de présenter les résultats les plus pertinents.
Index ScaNN pour plus de rapidité et de précision:pour obtenir des résultats rapides et précis, en particulier à mesure que notre inventaire de jouets augmente, nous intégrons l'index ScaNN (Scalable Nearest Neighbors). Cela améliore considérablement l'efficacité et le rappel de notre recherche vectorielle.
- Recherche et compréhension basées sur l'image avec Gemini 2.0 Flash
Imaginons que l'utilisateur souhaite importer une photo d'un jouet familier avec lequel il souhaite effectuer une recherche, au lieu de saisir le contexte sous forme de texte. Les utilisateurs peuvent importer une image d'un jouet qui leur plaît et obtenir des fonctionnalités pertinentes. Nous utilisons le modèle Flash Gemini 2.0 de Google, appelé à l'aide de LangChain4j, pour analyser l'image et en extraire le contexte pertinent, comme la couleur, le matériau, le type et la tranche d'âge du jouet.
- Créer le jouet de vos rêves avec l'IA générative: Imagen 3
La vraie magie opère lorsque les utilisateurs décident de créer leur propre jouet. Grâce à Imagen 3, nous leur permettons de décrire le jouet de leurs rêves à l'aide de requêtes textuelles simples. Imaginez pouvoir dire: "Je veux un dragon en peluche avec des ailes violettes et un visage amical", et voir ce dragon prendre vie sur votre écran ! Imagen 3 génère ensuite une image du jouet personnalisé, ce qui permet à l'utilisateur de visualiser clairement sa création.
- Prédiction des prix basée sur des agents et boîte à outils d'IA générative pour les bases de données
Nous avons implémenté une fonctionnalité de prédiction des prix qui estime le coût de production du jouet personnalisé. Cette fonctionnalité est fournie par un agent qui inclut un outil de calcul des prix sophistiqué.
Gen AI Toolbox for Databases:cet agent est parfaitement intégré à notre base de données à l'aide du nouvel outil Open Source de Google, Gen AI Toolbox for Databases. L'agent peut ainsi accéder à des données en temps réel sur les coûts des matériaux, les processus de fabrication et d'autres facteurs pertinents pour fournir une estimation de prix précise. En savoir plus
- Java Spring Boot, Gemini Code Assist et Cloud Run pour un développement et un déploiement sans serveur simplifiés
L'ensemble de l'application est conçu à l'aide de Java Spring Boot, un framework robuste et évolutif. Nous avons utilisé Gemini Code Assist tout au long du processus de développement, en particulier pour le développement front-end, ce qui a considérablement accéléré le cycle de développement et amélioré la qualité du code. Nous avons utilisé Cloud Run pour déployer l'ensemble de l'application et Cloud Run Functions pour déployer la base de données et les fonctionnalités d'agent en tant que points de terminaison indépendants.
3. Avant de commencer
Créer un projet
- Dans la console Google Cloud, sur la page du sélecteur de projet, sélectionnez ou créez un projet Google Cloud.
- Assurez-vous que la facturation est activée pour votre projet Cloud. Découvrez comment vérifier si la facturation est activée sur un projet .
- Vous allez utiliser Cloud Shell, un environnement de ligne de commande exécuté dans Google Cloud et fourni avec bq. Cliquez sur "Activer Cloud Shell" en haut de la console Google Cloud.
- Une fois connecté à Cloud Shell, vérifiez que vous êtes déjà authentifié et que le projet est défini avec votre ID de projet à l'aide de la commande suivante:
gcloud auth list
- Exécutez la commande suivante dans Cloud Shell pour vérifier que la commande gcloud connaît votre projet.
gcloud config list project
- Si votre projet n'est pas défini, utilisez la commande suivante pour le définir :
gcloud config set project <YOUR_PROJECT_ID>
- Activez les API requises en exécutant les commandes suivantes une par une dans votre terminal Cloud Shell:
Il existe également une seule commande pour exécuter les commandes ci-dessous. Toutefois, si vous utilisez un compte d'essai, vous risquez de rencontrer des problèmes de quota si vous essayez de les activer de manière groupée. C'est pourquoi les commandes sont séparées les unes des autres sur une ligne.
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
Vous pouvez également rechercher chaque produit dans la console ou utiliser ce lien.
Si une API est manquante, vous pouvez toujours l'activer au cours de l'implémentation.
Consultez la documentation pour connaître les commandes gcloud ainsi que leur utilisation.
4. Configuration de la base de données
Dans cet atelier, nous utiliserons AlloyDB comme base de données pour stocker les données de la boutique de jouets. Il utilise des clusters pour stocker toutes les ressources, telles que les bases de données et les journaux. Chaque cluster dispose d'une instance principale qui fournit un point d'accès aux données. Les tables contiennent les données réelles.
Créons un cluster, une instance et une table AlloyDB dans lesquels l'ensemble de données sur l'e-commerce sera chargé.
Créer un cluster et une instance
- Accédez à la page AlloyDB dans Cloud Console. Pour trouver facilement la plupart des pages de la console Cloud, recherchez-les à l'aide de la barre de recherche de la console.
- Sélectionnez CRÉER UN CLUSTER sur cette page:
- Un écran semblable à celui ci-dessous s'affiche. Créez un cluster et une instance avec les valeurs suivantes (assurez-vous que les valeurs correspondent au cas où vous cloneriez le code de l'application à partir du dépôt):
- ID de cluster: "
vector-cluster
" - password: "
alloydb
" - Compatible avec PostgreSQL 15
- Région: "
us-central1
" - Networking (Mise en réseau) : "
default
"
- Lorsque vous sélectionnez le réseau par défaut, un écran semblable à celui ci-dessous s'affiche.
Sélectionnez CONFIGURER LA CONNEXION.
- Sélectionnez ensuite Utiliser une plage d'adresses IP automatiquement allouée, puis cliquez sur "Continuer". Après avoir examiné les informations, sélectionnez "CRÉER UNE CONNEXION".
- Une fois votre réseau configuré, vous pouvez continuer à créer votre cluster. Cliquez sur CRÉER UN CLUSTER pour terminer la configuration du cluster, comme illustré ci-dessous:
Assurez-vous de remplacer l'ID d'instance par "
vector-instance"
.
Notez que la création du cluster prendra environ 10 minutes. Une fois l'opération terminée, un écran présentant une vue d'ensemble du cluster que vous venez de créer devrait s'afficher.
5. Ingestion de données
Il est maintenant temps d'ajouter un tableau contenant les données sur le magasin. Accédez à AlloyDB, sélectionnez le cluster principal, puis AlloyDB Studio:
Vous devrez peut-être attendre que la création de votre instance soit terminée. Connectez-vous à AlloyDB avec les identifiants que vous avez créés lors de la création du cluster. Utilisez les données suivantes pour vous authentifier auprès de PostgreSQL:
- Nom d'utilisateur : "
postgres
" - Base de données : "
postgres
" - Mot de passe : "
alloydb
"
Une fois que vous vous êtes authentifié dans AlloyDB Studio, vous pouvez saisir des commandes SQL dans l'éditeur. Vous pouvez ajouter plusieurs fenêtres de l'éditeur à l'aide du signe plus à droite de la dernière fenêtre.
Vous allez saisir des commandes pour AlloyDB dans les fenêtres d'éditeur, en utilisant les options "Run" (Exécuter), "Format" (Mettre en forme) et "Clear" (Effacer) si nécessaire.
Activer les extensions
Pour créer cette application, nous utiliserons les extensions pgvector
et google_ml_integration
. L'extension pgvector vous permet de stocker et de rechercher des embeddings vectoriels. L'extension google_ml_integration fournit des fonctions que vous pouvez utiliser pour accéder aux points de terminaison de prédiction Vertex AI afin d'obtenir des prédictions en SQL. Activez ces extensions en exécutant les LDD suivantes:
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
Si vous souhaitez vérifier les extensions qui ont été activées dans votre base de données, exécutez cette commande SQL:
select extname, extversion from pg_extension;
Créer une table
Créez une table à l'aide de l'instruction LDD ci-dessous:
CREATE TABLE toys ( id VARCHAR(25), name VARCHAR(25), description VARCHAR(20000), quantity INT, price FLOAT, image_url VARCHAR(200), text_embeddings vector(768)) ;
Une fois la commande ci-dessus exécutée, vous devriez pouvoir afficher le tableau dans la base de données.
Ingérer des données
Pour cet atelier, nous disposons de données de test d'environ 72 enregistrements dans ce fichier SQL. Il contient les champs id, name, description, quantity, price, image_url
. Les autres champs seront remplis plus tard dans l'atelier.
Copiez les lignes/instructions d'insertion à partir de là, puis collez-les dans un onglet d'éditeur vide et sélectionnez "EXÉCUTER".
Pour afficher le contenu de la table, développez la section "Explorer" jusqu'à ce que la table intitulée "vêtements" s'affiche. Sélectionnez les trois points (⋮) pour afficher l'option permettant d'interroger le tableau. Une instruction SELECT s'ouvre dans un nouvel onglet de l'éditeur.
Accorder l'autorisation
Exécutez l'instruction ci-dessous pour accorder à l'utilisateur postgres
des droits d'exécution sur la fonction embedding
:
GRANT EXECUTE ON FUNCTION embedding TO postgres;
Attribuer le rôle d'utilisateur Vertex AI au compte de service AlloyDB
Accédez au terminal Cloud Shell et exécutez la commande suivante:
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. Créer des embeddings pour le contexte
Les ordinateurs traitent beaucoup plus facilement les nombres que le texte. Un système d'intégration convertit le texte en une série de nombres à virgule flottante qui doivent le représenter, quelle que soit la formulation, la langue utilisée, etc.
Imaginez que vous décrivez un lieu en bord de mer. Il peut s'agir de "sur l'eau", "en bord de mer", "à pied de la mer", "sur la mer", "на берегу океана", etc. Ces termes semblent tous différents, mais leur signification sémantique (ou, en termes d'apprentissage automatique, leurs représentations vectorielles continues) devrait être très proche.
Maintenant que les données et le contexte sont prêts, nous allons exécuter la requête SQL pour ajouter les représentations vectorielles continues de la description du produit à la table dans le champ embedding
. Vous pouvez utiliser différents modèles d'embedding. Nous utilisons text-embedding-005
de Vertex AI. Veillez à utiliser le même modèle d'encapsulation tout au long du projet.
Remarque: Si vous utilisez un projet Google Cloud existant créé il y a quelque temps, vous devrez peut-être continuer à utiliser d'anciennes versions du modèle d'encapsulation de texte, comme textembedding-gecko.
Revenez à l'onglet AlloyDB Studio et saisissez la DML suivante:
UPDATE toys set text_embeddings = embedding( 'text-embedding-005', description);
Examinez à nouveau le tableau toys
pour voir quelques embeddings. N'oubliez pas de relancer l'instruction SELECT pour voir les modifications.
SELECT id, name, description, price, quantity, image_url, text_embeddings FROM toys;
Le vecteur d'embeddings, qui ressemble à un tableau de nombres à virgule flottante, devrait être renvoyé pour la description du jouet, comme indiqué ci-dessous:
Remarque:Les projets Google Cloud nouvellement créés dans le niveau sans frais peuvent rencontrer des problèmes de quota concernant le nombre de requêtes d'embedding autorisées par seconde pour les modèles d'embedding. Nous vous recommandons d'utiliser une requête de filtrage pour l'ID, puis de sélectionner de manière sélective 1 à 5 enregistrements, etc., lors de la génération de l'encapsulation.
7. Effectuer une recherche vectorielle
Maintenant que le tableau, les données et les embeddings sont prêts, effectuons la recherche vectorielle en temps réel pour le texte de recherche de l'utilisateur.
Supposons que l'utilisateur demande:
"I want a white plush teddy bear toy with a floral pattern
."
Pour trouver des correspondances, exécutez la requête ci-dessous:
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;
Examinons cette requête en détail:
Dans cette requête,
- Le texte de recherche de l'utilisateur est: "
I want a white plush teddy bear toy with a floral pattern.
" - Nous le convertissons en représentations vectorielles continues dans la méthode
embedding()
à l'aide du modèletext-embedding-005
. Cette étape devrait vous sembler familière après la dernière, où nous avons appliqué la fonction d'encapsulation à tous les éléments du tableau. - "
<=>
" représente l'utilisation de la méthode de distance COSINE SIMILARITY. Vous trouverez toutes les mesures de similarité disponibles dans la documentation de pgvector. - Nous convertissons le résultat de la méthode d'embedding en type de vecteur pour le rendre compatible avec les vecteurs stockés dans la base de données.
- LIMIT 5 indique que nous souhaitons extraire cinq voisins les plus proches du texte de recherche.
Le résultat se présente comme suit:
Comme vous pouvez le constater dans vos résultats, les correspondances sont assez proches du texte de recherche. Essayez de modifier le texte pour voir comment les résultats changent.
Remarque importante :
Supposons maintenant que nous souhaitions améliorer les performances (temps de requête), l'efficacité et le rappel de ce résultat de recherche vectorielle à l'aide de l'index ScaNN. Veuillez suivre les étapes décrites dans cet article de blog pour comparer les résultats avec et sans indice.
Étape facultative: Améliorez l'efficacité et la mémorisation avec l'indice ScaNN
Voici les étapes de création d'un index pour plus de commodité:
- Étant donné que le cluster, l'instance, le contexte et les représentations vectorielles continues sont déjà créés, il nous suffit d'installer l'extension ScaNN à l'aide de l'instruction suivante:
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- Nous allons ensuite créer l'index (ScaNN):
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);
Dans la LDD ci-dessus, apparel_index est le nom de l'index.
"jouets" est ma table
"scann" est la méthode d'indexation.
"embedding" est la colonne du tableau que je souhaite indexer.
"cosine" est la méthode de calcul de la distance que je souhaite utiliser avec l'index.
"8" correspond au nombre de partitions à appliquer à cet indice. Définissez cette valeur sur une valeur comprise entre 1 et 1048576. Pour savoir comment déterminer cette valeur, consultez Configurer un indice ScaNN.
J'ai utilisé la RACINE CARREE du nombre de points de données, comme recommandé dans le dépôt de code de SCANN (lors du partitionnement, num_leaves doit être approximativement égal à la racine carrée du nombre de points de données).
- Vérifiez si l'index est créé à l'aide de la requête:
SELECT * FROM pg_stat_ann_indexes;
- Effectuez une recherche vectorielle à l'aide de la même requête que celle utilisée sans l'index:
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 requête ci-dessus est la même que celle que nous avons utilisée à l'étape 8 de l'atelier. Toutefois, le champ est maintenant indexé.
- Testez avec une requête de recherche simple avec et sans l'index (en supprimant l'index):
Ce cas d'utilisation ne comporte que 72 enregistrements. L'index n'a donc pas vraiment d'effet. Pour un test effectué dans un autre cas d'utilisation, les résultats sont les suivants:
La même requête Vector Search sur les données d'embedding INDEXED génère des résultats de recherche de qualité et une efficacité. L'efficacité est considérablement améliorée (en termes de temps d'exécution: 10,37 ms sans ScaNN et 0,87 ms avec ScaNN) avec l'index. Pour en savoir plus à ce sujet, consultez cet article de blog.
8. Validation des correspondances avec le LLM
Avant de créer un service permettant de renvoyer les meilleures correspondances à une application, utilisons un modèle d'IA générative pour vérifier si ces réponses potentielles sont vraiment pertinentes et peuvent être partagées avec l'utilisateur.
Vérifier que l'instance est configurée pour Gemini
Vérifiez d'abord si l'intégration du ML Google est déjà activée pour votre cluster et votre instance. Dans AlloyDB Studio, exécutez la commande suivante:
show google_ml_integration.enable_model_support;
Si la valeur affichée est "on", vous pouvez ignorer les deux étapes suivantes et passer directement à la configuration de l'intégration d'AlloyDB et du modèle Vertex AI.
- Accédez à l'instance principale de votre cluster AlloyDB, puis cliquez sur MODIFIER L'INSTANCE PRINCIPALE.
- Accédez à la section "Options" dans les options de configuration avancées. et assurez-vous que
google_ml_integration.enable_model_support flag
est défini sur "on
", comme indiqué ci-dessous:
Si ce n'est pas le cas, activez-la, puis cliquez sur le bouton METTRE À JOUR L'INSTANCE. Cette étape prend quelques minutes.
Intégration d'AlloyDB et de Vertex AI Model
Vous pouvez maintenant vous connecter à AlloyDB Studio et exécuter l'instruction DML suivante pour configurer l'accès au modèle Gemini à partir d'AlloyDB, en utilisant votre ID de projet là où il est indiqué. Vous pouvez être averti d'une erreur de syntaxe avant d'exécuter la commande, mais celle-ci devrait s'exécuter correctement.
Tout d'abord, nous créons la connexion au modèle Gemini 1.5, comme indiqué ci-dessous. N'oubliez pas de remplacer $PROJECT_ID
dans la commande ci-dessous par l'ID de votre projet 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');
Vous pouvez vérifier les modèles configurés pour l'accès à l'aide de la commande suivante dans AlloyDB Studio:
select model_id,model_type from google_ml.model_info_view;
Enfin, nous devons autoriser les utilisateurs de la base de données à exécuter la fonction ml_predict_row pour effectuer des prédictions via les modèles Google Vertex AI. Exécutez la commande suivante :
GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;
Remarque: Si vous utilisez un projet Google Cloud et un cluster/une instance AlloyDB existants créés il y a quelque temps, vous devrez peut-être supprimer les anciennes références au modèle gemini-1.5, puis le recréer avec l'instruction CALL ci-dessus et exécuter à nouveau grant execute sur la fonction ml_predict_row au cas où vous rencontreriez des problèmes lors des prochaines invocations de gemini-1.5.
Évaluer les réponses
Bien que nous utilisions une grande requête dans la section suivante pour nous assurer que les réponses sont raisonnables, elle peut être difficile à comprendre. Nous allons maintenant examiner les éléments et voir comment ils s'assemblent dans quelques minutes.
- Nous commençons par envoyer une requête à la base de données pour obtenir les 10 meilleurs résultats correspondant à la requête de l'utilisateur.
- Pour déterminer la validité des réponses, nous allons utiliser une requête externe dans laquelle nous expliquerons comment les évaluer. Elle utilise le champ
recommended_text
, qui correspond au texte de recherche, etcontent
(qui correspond au champ de description des jouets) de la table interne dans la requête. - Nous examinerons ensuite la qualité des réponses renvoyées.
predict_row
renvoie son résultat au format JSON. Le code "-> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'"
permet d'extraire le texte réel de ce fichier JSON. Pour afficher le code JSON réel renvoyé, vous pouvez supprimer ce code.- Enfin, pour obtenir la réponse du LLM, nous l'extrayons à l'aide de
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 10) 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%';
Cela peut sembler intimidant, mais j'espère que vous pourrez y voir plus clair. Les résultats indiquent s'il existe une correspondance ou non, le pourcentage de correspondance et une explication de la classification.
Notez que le streaming est activé par défaut pour le modèle Gemini. La réponse réelle est donc répartie sur plusieurs lignes:
9. Déplacer la recherche de jouets vers le cloud sans serveur
Prêt à publier cette application sur le Web ? Pour rendre ce moteur de connaissances sans serveur avec des fonctions Cloud Run, procédez comme suit:
- Accédez à Cloud Run Functions dans la console Google Cloud pour CRÉER une fonction Cloud Run ou utilisez le lien https://console.cloud.google.com/functions/add.
- Sélectionnez "Fonction Cloud Run" comme environnement. Indiquez le nom de la fonction get-toys-alloydb et sélectionnez la région "us-central1". Définissez l'authentification sur "Allow unauthenticated invocations" (Autoriser les appels non authentifiés), puis cliquez sur NEXT (SUIVANT). Choisissez Java 17 comme environnement d'exécution et Éditeur intégré pour le code source.
- Par défaut, le point d'entrée est défini sur "
gcfv2.HelloHttpFunction
". Remplacez le code d'espace réservé dansHelloHttpFunction.java
etpom.xml
de votre fonction Cloud Run par le code de HelloHttpFunction.java et de pom.xml, respectivement. - N'oubliez pas de remplacer l'espace réservé <<YOUR_PROJECT>> et les identifiants de connexion AlloyDB par vos valeurs dans le fichier Java. Les identifiants AlloyDB sont ceux que nous avons utilisés au début de cet atelier de programmation. Si vous avez utilisé des valeurs différentes, veuillez les modifier dans le fichier Java.
- Cliquez sur Déployer.
Une fois déployée, afin d'autoriser la fonction Cloud à accéder à notre instance de base de données AlloyDB, nous créerons le connecteur VPC.
ÉTAPE IMPORTANTE :
Une fois le déploiement effectué, vous devriez pouvoir voir les fonctions dans la console Google Cloud Run Functions. Recherchez la fonction nouvellement créée (get-toys-alloydb
), cliquez dessus, puis sur MODIFIER et modifiez les éléments suivants:
- Accéder aux paramètres d'exécution, de compilation, de connexion et de sécurité
- Augmenter le délai avant expiration à 180 secondes
- Accédez à l'onglet "CONNEXIONS" :
- Sous les paramètres d'entrée, assurez-vous que l'option "Autoriser tout le trafic" est sélectionnée.
- Sous "Paramètres de sortie", cliquez sur la liste déroulante "Réseau", sélectionnez l'option "Ajouter un connecteur VPC", puis suivez les instructions qui s'affichent dans la boîte de dialogue qui s'affiche:
- Attribuez un nom au connecteur VPC et assurez-vous que la région est la même que celle de votre instance. Laissez la valeur "Network" (Réseau) définie par défaut et définissez "Subnet" (Sous-réseau) sur "Custom IP Range" (Plage d'adresses IP personnalisée) avec la plage d'adresses IP 10.8.0.0 ou une autre plage disponible.
- Développez "AFFICHER LES PARAMÈTRES DE MISE À L'ÉCHELLE" et assurez-vous que la configuration est exactement la suivante:
- Cliquez sur "CRÉER". Ce connecteur devrait maintenant figurer dans les paramètres de sortie.
- Sélectionnez le connecteur que vous venez de créer.
- Choisissez d'acheminer tout le trafic via ce connecteur VPC.
- Cliquez sur SUIVANT, puis sur DÉPLOYER.
10. Tester la fonction Cloud Run
Une fois la fonction Cloud mise à jour déployée, le point de terminaison doit s'afficher au format suivant:
https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/get-toys-alloydb
Vous pouvez également tester la fonction Cloud Run comme suit:
PROJECT_ID=$(gcloud config get-value project)
curl -X POST https://us-central1-$PROJECT_ID.cloudfunctions.net/get-toys-alloydb \
-H 'Content-Type: application/json' \
-d '{"search":"I want a standing pink panther toy"}' \
| jq .
Et le résultat:
Et voilà ! Il est si simple d'effectuer une recherche vectorielle de similarité à l'aide du modèle d'embeddings sur les données AlloyDB.
11. Créer le client de l'application Web
Dans cette partie, nous allons créer une application Web permettant à l'utilisateur d'interagir avec des jouets et de trouver des jouets correspondants en fonction du texte et de l'image, et même de créer un jouet en fonction de ses besoins. Comme l'application est déjà compilée, vous pouvez suivre les étapes ci-dessous pour la copier dans votre IDE et la mettre en service.
- Comme nous utilisons Gemini 2.0 Flash pour décrire l'image que l'utilisateur peut importer pour trouver des jouets correspondants, nous devons obtenir la clé API de cette application. Pour ce faire, accédez à https://aistudio.google.com/apikey et récupérez la clé API de votre projet Google Cloud actif dans lequel vous implémentez cette application, puis enregistrez-la quelque part:
- Accédez au terminal Cloud Shell.
- Clonez le dépôt à l'aide de la commande suivante:
git clone https://github.com/AbiramiSukumaran/toysearch
cd toysearch
- Une fois le dépôt cloné, vous devriez pouvoir accéder au projet depuis l'éditeur Cloud Shell.
- Vous devez supprimer les dossiers "get-toys-alloydb" et "toolbox-toys" du projet cloné, car ces deux éléments sont du code de fonctions Cloud Run qui peut être référencé à partir du dépôt lorsque vous en avez besoin.
- Assurez-vous que toutes les variables d'environnement nécessaires sont définies avant de créer et de déployer l'application. Accédez au terminal Cloud Shell et exécutez les commandes suivantes:
PROJECT_ID=$(gcloud config get-value project)
export PROJECT_ID $PROJECT_ID
export GOOGLE_API_KEY <YOUR API KEY that you saved>
- Créez et exécutez l'application en local:
Assurez-vous d'être dans le répertoire du projet, puis exécutez les commandes suivantes:
mvn package
mvn spring-boot:run
- Déployer sur Cloud Run
gcloud run deploy --source .
12. Comprendre les détails de l'IA générative
Aucune action de votre part n'est requise. Pour information:
Maintenant que vous avez déployé l'application, prenez le temps de comprendre comment nous avons effectué la recherche (texte et image) et la génération.
- Recherche vectorielle basée sur le texte de l'utilisateur:
Ce problème est déjà traité dans les fonctions Cloud Run que nous avons déployées dans la section "Explorer l'application Web Vector Search".
- Recherche vectorielle basée sur l'importation d'images:
Imaginons que l'utilisateur souhaite importer une photo d'un jouet familier avec lequel il souhaite effectuer une recherche, au lieu de saisir le contexte sous forme de texte. Les utilisateurs peuvent importer une image d'un jouet qui leur plaît et obtenir des fonctionnalités pertinentes.
Nous utilisons le modèle Flash Gemini 2.0 de Google, appelé à l'aide de LangChain4j, pour analyser l'image et en extraire le contexte pertinent, comme la couleur, le matériau, le type et la tranche d'âge du jouet.
En seulement cinq étapes, nous avons utilisé les données multimodales de l'utilisateur pour mettre en correspondance les résultats avec l'appel d'un grand modèle de langage à l'aide d'un framework Open Source. Découvrez comment :
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;
}
}
- Découvrez comment nous avons utilisé Imagen 3 pour créer un jouet personnalisé en fonction de la demande de l'utilisateur avec l'IA générative.
Imagen 3 génère ensuite une image du jouet personnalisé, ce qui permet à l'utilisateur de visualiser clairement sa création. Voici comment nous y sommes parvenus en seulement cinq étapes:
// 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();
}
}
Prévisions de prix
Dans la section précédente, nous avons expliqué comment Imagen génère l'image d'un jouet que l'utilisateur souhaite concevoir lui-même. Pour que l'utilisateur puisse l'acheter, l'application doit définir un prix. Nous avons utilisé une logique intuitive pour définir un prix pour le jouet personnalisé. La logique consiste à utiliser le prix moyen des cinq jouets les plus proches (en termes de description) du jouet que l'utilisateur conçoit.
La prévision du prix du jouet généré est une partie importante de cette application. Nous avons utilisé une approche agentique pour la générer. Présentation de la boîte à outils d'IA générative pour les bases de données
13. Boîte à outils d'IA générative pour les bases de données
La boîte à outils d'IA générative pour les bases de données est un serveur Open Source de Google qui facilite la création d'outils d'IA générative pour interagir avec les bases de données. Il vous permet de développer des outils plus facilement, plus rapidement et de manière plus sécurisée en gérant les complexités telles que le pool de connexions, l'authentification, etc. Il vous aide à créer des outils d'IA générative qui permettent à vos agents d'accéder aux données de votre base de données.
Voici la procédure à suivre pour configurer votre outil et rendre notre application agentique: Lien vers l'atelier de programmation Toolbox
Votre application peut désormais utiliser ce point de terminaison de fonction Cloud Run déployé pour renseigner le prix ainsi que le résultat Imagen généré pour l'image du jouet sur mesure.
14. Tester votre application Web
Maintenant que tous les composants de votre application sont compilés et déployés, elle est prête à être diffusée dans le cloud. Testez votre application pour tous les scénarios. Voici un lien vers une vidéo qui vous explique ce à quoi vous pouvez vous attendre:
https://www.youtube.com/shorts/ZMqUAWsghYQ
Voici à quoi ressemble la page de destination:
15. Effectuer un nettoyage
Pour éviter que les ressources utilisées dans cet article soient facturées sur votre compte Google Cloud, procédez comme suit:
- Dans la console Google Cloud, accédez à la page Gérer les ressources.
- Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
- Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.
16. Félicitations
Félicitations ! Vous avez effectué une recherche et une génération contextuelles dans une boutique de jouets à l'aide d'AlloyDB, pgvector, Imagen et Gemini 2.0, tout en utilisant des bibliothèques Open Source pour créer des intégrations robustes. En combinant les fonctionnalités d'AlloyDB, de Vertex AI et de Vector Search, nous avons fait un grand pas en avant pour rendre les recherches contextuelles et vectorielles accessibles, efficaces et véritablement axées sur le sens.