1. Introduction
Dans cet atelier de programmation, vous allez créer un agent Barista IA interactif pour un café. À l'aide du Agent Development Kit (ADK) Open Source de Google et du modèle Gemini 3.5 Flash, vous implémenterez la génération augmentée par récupération (RAG) pour ancrer les recommandations de l'agent dans un ensemble de données de menu fictif. Enfin, vous allez envelopper l'agent dans une interface utilisateur Streamlit et le déployer sur Cloud Run.
Objectifs de l'atelier
- Créez une source de données RAG (
menu.json) contenant des articles de café, des tags et des allergènes. - Créez un agent d'IA à l'aide de l'ADK
LlmAgentet connectez un outil Python pour charger les données du menu. - Encapsulez l'agent dans une application de chat Streamlit qui gère l'historique des conversations.
- Déployez l'application Streamlit sur Cloud Run à l'aide du déploiement basé sur la source.
- Testez l'ancrage RAG et la sensibilisation aux allergènes.

Prérequis
- Un navigateur Web tel que Chrome.
- Un projet Google Cloud avec facturation activée.
- Connaître les bases de Python
Cet atelier de programmation s'adresse aux développeurs de tous niveaux, y compris aux débutants.
Coût estimé : moins de 1 USD.
2. Avant de commencer
Créer un projet Google Cloud
- Dans la console Google Cloud, sélectionnez ou créez un projet Google Cloud.
- Assurez-vous que la facturation est activée pour votre projet Cloud.
Démarrer Cloud Shell
- Cliquez sur Activer Cloud Shell en haut de la console Google Cloud.

- Vérifiez l'authentification :

gcloud auth list
- Vérifiez que votre projet actif est défini :
gcloud config get project
Si l'ID de projet affiché est incorrect ou si aucun ID n'est défini, exécutez la commande suivante :
gcloud config set project <YOUR_PROJECT_ID>
Activer les API
Exécutez la commande suivante pour activer toutes les API requises :
gcloud services enable \
run.googleapis.com \
aiplatform.googleapis.com \
cloudbuild.googleapis.com
3. Configurer votre projet
Au cours de cette étape, vous allez initialiser les variables d'environnement de votre projet et créer un répertoire de travail pour celui-ci.
- Dans votre session Cloud Shell active, initialisez les variables d'environnement du projet suivantes :
export PROJECT_ID=$(gcloud config get-value project)
Remarque : Utilisez la région la plus proche.
Trouvez la région la plus proche et remplacez insert-region-here par celle-ci dans la commande suivante :
export REGION=[insert-region-here]
- Créez un répertoire de projet nommé
coffee-barista-agentet accédez-y :
mkdir coffee-barista-agent && cd coffee-barista-agent
4. Créer la source de données du menu fictif
Pour ancrer l'IA Barista et l'empêcher d'halluciner des éléments inexistants, vous allez créer un ensemble de données de menu local. L'agent lira ce fichier au moment de l'exécution à l'aide d'un outil personnalisé.
- Créez et ouvrez
menu.jsondans l'éditeur Cloud Shell :
cloudshell edit menu.json
- Collez le contenu JSON suivant dans l'éditeur et enregistrez le fichier :
[
{
"name": "Espresso Solo",
"description": "A single shot of rich, bold espresso.",
"price": 2.50,
"tags": ["strong", "hot", "dairy-free", "sugar-free"],
"allergens": []
},
{
"name": "Oat Milk Honey Latte",
"description": "Creamy steamed oat milk with espresso and a touch of honey.",
"price": 5.00,
"tags": ["sweet", "hot", "dairy-free"],
"allergens": []
},
{
"name": "Cold Brew Coffee",
"description": "Smooth, slow-steeped cold brew served over ice.",
"price": 4.00,
"tags": ["strong", "cold", "dairy-free", "sugar-free"],
"allergens": []
},
{
"name": "Seasonal Pumpkin Latte",
"description": "Spiced pumpkin sauce, espresso, and steamed milk, topped with whipped cream.",
"price": 5.50,
"tags": ["sweet", "hot", "seasonal"],
"allergens": ["dairy"]
},
{
"name": "Classic Croissant",
"description": "Flaky, buttery traditional French pastry.",
"price": 3.50,
"tags": ["bakery", "savory"],
"allergens": ["wheat", "dairy"]
},
{
"name": "Vegan Blueberry Muffin",
"description": "Soft, sweet muffin packed with real blueberries, entirely plant-based.",
"price": 3.75,
"tags": ["bakery", "sweet", "dairy-free", "vegan"],
"allergens": ["wheat"]
},
{
"name": "Nitro Cold Brew",
"description": "Cold brew infused with nitrogen for a super smooth, creamy head.",
"price": 4.50,
"tags": ["strong", "cold", "dairy-free", "sugar-free"],
"allergens": []
},
{
"name": "Iced Caramel Macchiato",
"description": "Chilled milk and vanilla syrup marked with espresso and caramel drizzle.",
"price": 5.25,
"tags": ["sweet", "cold"],
"allergens": ["dairy"]
}
]
- Vérifiez que le fichier JSON est correctement formaté :
cat menu.json | python3 -m json.tool > /dev/null && echo "Valid JSON!"
💬 Discussion : JSON local ou bases de données en direct
Pourquoi utilisons-nous un simple fichier menu.json local au lieu d'une base de données en direct ?
Pour un tutoriel ou un prototype rapide, un fichier JSON local élimine le temps et la complexité de la configuration initiale de la base de données. Toutefois, dans une application de production d'entreprise réelle, vous connecteriez l'agent à une base de données gérée telle que Cloud Firestore, AlloyDB ou Cloud SQL.
L'utilisation d'une base de données en direct permet aux responsables de cafés d'ajouter des articles saisonniers, de modifier les prix ou d'ajuster les tags d'allergènes de manière dynamique, sans avoir à reconstruire l'image de conteneur ni à redéployer le code de l'application. Nous utiliserons une base de données en direct comme étape facultative plus loin dans l'atelier de programmation.
5. Créer l'agent ADK
Vous allez maintenant installer les packages requis et créer la logique de l'agent ADK principal. Vous définirez un outil get_menu() et le transmettrez à un LlmAgent.
- Créez et ouvrez
requirements.txtdans l'éditeur Cloud Shell :
cloudshell edit requirements.txt
- Collez les dépendances suivantes dans l'éditeur et enregistrez le fichier :
google-adk==2.2.0
streamlit==1.58.0
- Créez et ouvrez
agent.pydans l'éditeur Cloud Shell :
cloudshell edit agent.py
- Collez le code suivant dans
agent.py:
# agent.py
import json
from google.adk.agents import LlmAgent
# [START get_menu]
def get_menu() -> str:
"""Retrieves the coffee shop menu from menu.json.
Returns:
str: A JSON string representing the list of menu items.
"""
try:
with open("menu.json", "r") as f:
menu_data = json.load(f)
return json.dumps(menu_data)
except Exception as e:
return json.dumps({"error": f"Could not retrieve menu: {str(e)}"})
# [END get_menu]
# Create the barista agent
barista_agent = LlmAgent(
name="barista_agent",
model="gemini-3.5-flash",
instruction="""You are a friendly barista at ☕ Coffee Shop.
Your job is to recommend drinks and pastries to customers based on their preferences.
Rules you MUST follow:
1. You must recommend items ONLY from the menu returned by get_menu().
2. Do NOT recommend or suggest any item that is not present in the menu.
3. If a user's preference is vague or unclear, ask exactly ONE friendly clarifying question to narrow down what they want (e.g., cold or hot, sweet or strong, coffee or pastry).
4. Be warm and welcoming, but remain professional.
5. Ground your recommendations in the actual tags, descriptions, and allergens listed in the menu (e.g., if a user is dairy-free, recommend ONLY items tagged 'dairy-free' or with no dairy allergens).
""",
tools=[get_menu]
)
from google.adk.apps import App
# Define the App object
app = App(
name="coffee_barista_app",
root_agent=barista_agent
)
- Créez et ouvrez
app.pydans l'éditeur Cloud Shell :
cloudshell edit app.py
- Collez le code suivant dans
app.py:
# app.py
import streamlit as st
import json
# Set page config for a premium look
st.set_page_config(
page_title="☕ Coffee Shop - Barista Bot",
page_icon="☕",
layout="wide",
initial_sidebar_state="expanded"
)
# Custom CSS to make the header sticky (adapts to light/dark themes)
st.markdown("""
<style>
div[data-testid="element-container"]:has(.header-container),
div.element-container:has(.header-container) {
position: sticky;
top: 2.875rem;
z-index: 999;
background-color: transparent;
padding-bottom: 10px;
}
</style>
""", unsafe_allow_html=True)
# App Header (using inline styles for the permanent coffee theme look)
st.markdown("""
<div class="header-container" style="text-align: center; padding: 20px; background: linear-gradient(135deg, #8B5E3C, #6F4E37); color: white; border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.1);">
<h1 style="margin: 0; font-size: 2.5rem; font-weight: 700; color: white;">☕ ☕ Coffee Shop</h1>
<p style="margin: 5px 0 0 0; font-size: 1.1rem; opacity: 0.9; color: white;">Your friendly AI Barista is ready to help you find the perfect drink or pastry!</p>
</div>
""", unsafe_allow_html=True)
# Load Menu for the sidebar
# [START load_menu]
try:
with open("menu.json", "r") as f:
menu_items = json.load(f)
except Exception as e:
st.error(f"Error loading menu: {e}")
menu_items = []
# [END load_menu]
# Sidebar Menu & Configuration
with st.sidebar:
st.markdown("## ☕ Coffee Shop Menu")
st.markdown("Explore our offerings and ask the barista for recommendations.")
st.markdown("---")
for item in menu_items:
with st.container(border=True):
st.markdown(f"**{item['name']}** • **${item['price']:.2f}**")
st.caption(item['description'])
# Tags & Allergens as native badges
tags = " ".join([f"`{t}`" for t in item.get("tags", [])])
if tags:
st.markdown(tags)
allergens = ", ".join(item.get("allergens", []))
if allergens:
st.markdown(f"⚠️ *Allergens: {allergens}*")
# Chat Interface
if "session_id" not in st.session_state:
import uuid
st.session_state.session_id = str(uuid.uuid4())
if "runner" not in st.session_state:
from google.adk.runners import InMemoryRunner
from agent import app
st.session_state.runner = InMemoryRunner(app=app)
if "messages" not in st.session_state:
st.session_state.messages = [
{"role": "assistant", "content": "Welcome to ☕ Coffee Shop! What can I get started for you today?"}
]
# Display existing messages
for msg in st.session_state.messages:
with st.chat_message(msg["role"]):
st.markdown(msg["content"])
# User Input
if prompt := st.chat_input("Ask for recommendations (e.g., 'What dairy-free pastries do you have?')"):
# Display user message
with st.chat_message("user"):
st.markdown(prompt)
st.session_state.messages.append({"role": "user", "content": prompt})
# Generate response
with st.chat_message("assistant"):
try:
import asyncio
# Run the ADK runner asynchronously using asyncio.run
async def fetch_response():
return await st.session_state.runner.run_debug(
prompt,
session_id=st.session_state.session_id
)
res_events = asyncio.run(fetch_response())
response_text = "".join([
part.text
for event in res_events
if event.content and event.content.parts
for part in event.content.parts
if part.text
])
st.markdown(response_text)
st.session_state.messages.append({"role": "assistant", "content": response_text})
except Exception as e:
st.error(f"Apologies, I ran into an error: {e}")
💬 Discussion : compromis du modèle et efficacité des jetons de récupération
Pourquoi appeler un outil de fonction pour récupérer le menu au lieu de simplement coller l'intégralité du texte du menu dans les instructions système de l'agent ?
L'économie des jetons ! Placer huit éléments dans le prompt est peu coûteux, mais que se passe-t-il si le café propose 500 articles, y compris des ingrédients personnalisés ? Si vous collez de grands ensembles de données directement dans l'invite système, le nombre de jetons de votre requête augmente, ce qui accroît les coûts de transaction et la latence de réponse de l'API pour chaque requête.
En utilisant un outil ADK, l'agent demande dynamiquement à lire le menu UNIQUEMENT lorsque cela est nécessaire. Le LLM ne reçoit que les données de menu pertinentes comme contexte, ce qui minimise la taille des jetons du prompt.
💬 Discussion : magasins d'état et de production de mémoire
L'historique des discussions stocké dans st.session_state de Streamlit est-il conservé lorsqu'un utilisateur ferme l'onglet de son navigateur ?
Non. st.session_state est entièrement en mémoire et unique à la connexion de navigateur active. Si un utilisateur actualise la page ou ferme l'onglet, l'historique de ses conversations avec le barista est perdu.
Pour une application de production, vous devez connecter l'exécuteur ADK à un backend de stockage persistant tel que Cloud Firestore ou Redis. ADK fournit des abstractions de service intégrées (comme SessionService) qui permettent d'enregistrer et de reprendre facilement l'historique des discussions lors des rechargements de page et sur différents appareils.
6. Déployer l'agent sur Cloud Run
Vous allez déployer l'application Streamlit directement à partir de la source à l'aide des buildpacks intégrés de Cloud Run. Pour respecter le principe du moindre privilège, vous allez créer et déployer un compte de service personnalisé dédié au lieu d'utiliser le compte de service Compute Engine par défaut.
- Créez un compte de service dédié :
gcloud iam service-accounts create barista-agent-sa \
--description="Service account for Coffee Barista ADK agent on Cloud Run" \
--display-name="Barista Agent Service Account"
- Attribuez le rôle utilisateur Gemini Enterprise Agent Platform (
roles/aiplatform.user) au nouveau compte de service :
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
- Déployez le service à l'aide de
gcloud run deploy, en transmettant la nouvelle adresse e-mail du compte de service via l'option--service-account:
gcloud run deploy coffee-barista \
--source . \
--region $REGION \
--allow-unauthenticated \
--labels dev-tutorial=codelab-streamlit-rag-adk \
--command "/cnb/lifecycle/launcher" \
--args "sh,-c,python3 -m streamlit run app.py --server.port=\$PORT --server.address=0.0.0.0 --server.enableCORS=false --server.enableXsrfProtection=false" \
--service-account "barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com" \
--set-env-vars GOOGLE_GENAI_USE_VERTEXAI=TRUE,GOOGLE_CLOUD_PROJECT=$PROJECT_ID,GOOGLE_CLOUD_LOCATION=global
- Une fois le service déployé, recherchez son URL dans le résultat de la commande.
💬 Discussion : Déployer des conteneurs ou des sources, et sécurité IAM
Nous avons déployé l'application sur Cloud Run à l'aide de la commande gcloud run deploy --source, sans créer de fichier Dockerfile ni de fichier Procfile. Comment Cloud Run a-t-il fait pour compiler et exécuter notre application Python ?
Cloud Run utilise des buildpacks en arrière-plan pour analyser votre dépôt. Lorsqu'il détecte la présence de fichiers sourcesrequirements.txt et Python, le moteur compile et package automatiquement un conteneur d'exécution Python.
Écrire un Dockerfile personnalisé vous permet de contrôler entièrement les packages système et les couches de base de votre conteneur. Un Procfile est un moyen plus simple de déclarer la commande de démarrage sans configurer entièrement un conteneur. Toutefois, pour les déploiements rapides, le déploiement à partir de la source (--source) est très efficace.
Pourquoi avons-nous créé un compte de service personnalisé barista-agent-sa au lieu d'utiliser le compte de service Compute Engine par défaut ?
La sécurité avant tout ! Le compte de service Compute Engine par défaut dispose d'autorisations d'éditeur extrêmement étendues par défaut. Si nous exécutons notre conteneur Cloud Run sous le compte de service par défaut, un pirate informatique pourrait potentiellement lire, écrire ou supprimer d'autres ressources de notre projet Google Cloud si notre application présente un bug de sécurité.
En créant un compte de service dédié et en ne lui attribuant que le rôle roles/aiplatform.user, nous respectons le principe du moindre privilège : l'application dispose exactement de l'accès dont elle a besoin pour appeler Gemini, et rien de plus.
7. Tester le comportement du RAG
Ouvrez l'URL du service Cloud Run dans un navigateur Web et posez des questions à l'AI Barista pour tester ses contraintes d'ancrage et de sécurité.
- Demande dans le menu : demandez "Recommande-moi une boisson forte et chaude." Résultat attendu : l'agent recommande un expresso.
- Piège hors menu : demande : "Avez-vous un frappuccino au matcha ?" ; réponse attendue : l'agent refuse poliment et explique que ce produit ne figure pas au menu.
- Demande tenant compte des allergènes : demandez "Je suis intolérant au lactose, que puis-je prendre ?". Résultat attendu : l'agent ne recommande que des plats sans produits laitiers (comme le latte au lait d'avoine, l'expresso ou le café infusé à froid). Il ne recommande PAS Cappuccino ni Croissant.

8. Facultatif : Ancrez votre agent dans Firestore à l'aide de Vector Search
Dans un scénario de production, il n'est pas idéal de stocker vos éléments de menu dans un fichier menu.json local, car toute modification du menu nécessite de reconstruire l'image de conteneur et de redéployer le service Cloud Run.
Pour rendre l'application dynamique et évolutive, vous pouvez migrer les données de votre menu vers Cloud Firestore et utiliser la recherche vectorielle pour récupérer uniquement les éléments de menu les plus pertinents en fonction de la similarité sémantique.

1. Activer l'API Firestore et initialiser la base de données
Exécutez les commandes suivantes pour activer l'API Firestore et créer une base de données Firestore nommée coffee-menu en mode natif :
gcloud services enable firestore.googleapis.com
gcloud firestore databases create --database="coffee-menu" --location=$REGION
Remarque : L'activation de l'API peut prendre une à deux minutes. Si la commande de création de base de données vous invite à saisir API [firestore.googleapis.com] not enabled on project... Would you like to enable and retry?, saisissez Y pour continuer, ou patientez une minute et réexécutez la commande.
2. Initialiser Firestore avec les données du menu
Pour amorcer rapidement votre base de données Firestore avec les éléments de menu de votre fichier menu.json, vous pouvez exécuter un script Python localement dans Cloud Shell.
- Installez localement les bibliothèques clientes Firestore et GenAI dans Cloud Shell pour exécuter le script de seeding :
pip3 install google-cloud-firestore==2.27.0 google-genai==2.11.0
- Créez un script de seeding
seed.py:
cloudshell edit seed.py
- Collez le code suivant dans
seed.py:
# seed.py
import json
import os
from google import genai
from google.cloud import firestore
from google.cloud.firestore_v1.vector import Vector
db = firestore.Client(database="coffee-menu")
client = genai.Client(
vertexai=True,
project=os.environ.get("PROJECT_ID"),
location=os.environ.get("REGION", "us-central1")
)
with open("menu.json", "r") as f:
menu_items = json.load(f)
for item in menu_items:
# Use the name as the document ID
doc_id = item["name"].lower().replace(" ", "-")
# Generate text embedding using Vertex AI text-embedding-004 model
text_to_embed = f"{item['name']}: {item['description']}"
response = client.models.embed_content(
model="text-embedding-004",
contents=text_to_embed,
)
embedding = response.embeddings[0].values
# Add embedding vector to the menu item data
item["embedding"] = Vector(embedding)
db.collection("menu").document(doc_id).set(item)
print("Firestore menu collection seeded with vector embeddings successfully!")
- Exécutez le script :
python3 seed.py
3. Créer un index vectoriel Firestore
Pour effectuer des recherches vectorielles sur vos éléments de menu, vous devez créer un index vectoriel composite sur le champ embedding de votre base de données Firestore.
Exécutez la commande suivante dans le terminal Cloud Shell :
gcloud firestore indexes composite create \
--collection-group=menu \
--query-scope=COLLECTION \
--database="coffee-menu" \
--field-config=field-path=embedding,vector-config='{"dimension":"768", "flat": "{}"}'
Remarque : La création d'index Firestore s'exécute en arrière-plan et peut prendre quelques minutes. Vous pouvez passer aux étapes suivantes de l'atelier de programmation pendant que l'index est en cours de création.
4. Accorder l'accès à Firestore au compte de service
Pour que votre service Cloud Run puisse interroger Firestore, vous devez attribuer le rôle Utilisateur Cloud Datastore (roles/datastore.user) à son compte de service :
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/datastore.user"
Remarque : Bien que nous utilisions Cloud Firestore en mode natif, Google Cloud utilise les rôles IAM Cloud Datastore unifiés (roles/datastore.viewer ou roles/datastore.user) pour gérer le contrôle des accès.
5. Mettre à jour le code
Mettez à jour votre code pour récupérer le menu à partir de Firestore au lieu de le lire à partir de menu.json.
- Ouvrez
requirements.txtdans l'éditeur Cloud Shell :
cloudshell edit requirements.txt
- Ajoutez les bibliothèques clientes Firestore et GenAI à la fin du fichier, puis enregistrez-le :
google-cloud-firestore==2.27.0
google-genai==2.11.0
- Ouvrez
agent.pydans l'éditeur Cloud Shell :
cloudshell edit agent.py
- Recherchez le bloc
# [START get_menu]dansagent.pyet remplacez-le entièrement (de# [START get_menu]à# [END get_menu]) par l'implémentation Firestore suivante :
# [START get_menu]
from google import genai
from google.cloud import firestore
from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
from google.cloud.firestore_v1.vector import Vector
def get_menu(query: str) -> str:
"""Retrieves coffee shop menu items matching the user's query.
Args:
query: The search query or preference to find matching menu items.
Returns:
str: A JSON string representing the list of top matching menu items.
"""
try:
# Initialize clients
db = firestore.Client(database="coffee-menu")
client = genai.Client()
# Generate embedding for the search query
response = client.models.embed_content(
model="text-embedding-004",
contents=query,
)
query_vector = response.embeddings[0].values
# Search the Firestore database using Vector Search
results = db.collection("menu").find_nearest(
vector_field="embedding",
query_vector=Vector(query_vector),
distance_measure=DistanceMeasure.COSINE,
limit=3,
).stream()
menu_data = []
for doc in results:
item = doc.to_dict()
# Remove embedding field to save tokens
item.pop("embedding", None)
menu_data.append(item)
return json.dumps(menu_data)
except Exception as e:
return json.dumps({"error": f"Could not retrieve menu: {str(e)}"})
# [END get_menu]
- Ouvrez
app.pydans l'éditeur Cloud Shell :
cloudshell edit app.py
- Recherchez le bloc
# [START load_menu]dansapp.pyet remplacez-le entièrement (de# [START load_menu]à# [END load_menu]) par la logique de chargement Firestore suivante :
# [START load_menu]
from google.cloud import firestore
try:
db = firestore.Client(database="coffee-menu")
docs = db.collection("menu").stream()
menu_items = []
for doc in docs:
item = doc.to_dict()
item.pop("embedding", None)
menu_items.append(item)
except Exception as e:
st.error(f"Error loading menu from Firestore: {e}")
menu_items = []
# [END load_menu]
6. Redéployer sur Cloud Run
Déployez l'application mise à jour :
gcloud run deploy coffee-barista \
--source . \
--region $REGION \
--allow-unauthenticated \
--command "/cnb/lifecycle/launcher" \
--args "sh,-c,python3 -m streamlit run app.py --server.port=\$PORT --server.address=0.0.0.0 --server.enableCORS=false --server.enableXsrfProtection=false" \
--service-account "barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com" \
--set-env-vars GOOGLE_GENAI_USE_VERTEXAI=TRUE,GOOGLE_CLOUD_PROJECT=$PROJECT_ID,GOOGLE_CLOUD_LOCATION=global
7. Vérifier l'intégration de Firestore
Pour tester la connexion de l'agent à Firestore, ajoutez un tout nouvel élément de menu directement dans Firestore et vérifiez que l'agent le recommande.
- Exécutez la commande suivante dans Cloud Shell pour écrire un nouveau document dans la collection
menude Firestore à l'aide de Python :
python3 -c "
import os
from google import genai
from google.cloud import firestore
from google.cloud.firestore_v1.vector import Vector
db = firestore.Client(database='coffee-menu')
client = genai.Client(
vertexai=True,
project=os.environ.get('PROJECT_ID'),
location=os.environ.get('REGION', 'us-central1')
)
name = 'Matcha Green Tea Latte'
desc = 'Creamy steamed milk infused with premium Japanese matcha powder.'
res = client.models.embed_content(
model='text-embedding-004',
contents=f'{name}: {desc}'
)
embedding = res.embeddings[0].values
db.collection('menu').document('matcha-latte').set({
'name': name,
'description': desc,
'price': 5.50,
'tags': ['sweet', 'hot', 'dairy-free'],
'allergens': [],
'embedding': Vector(embedding)
})
print('Successfully added Matcha Latte with vector embeddings!')
"
- Actualisez votre application Streamlit dans le navigateur pour effacer la session de chat et charger le nouvel état de la base de données.
- Remarque :
- Matcha Green Tea Latte s'affiche automatiquement dans le menu latéral.
- Demandez au chatbot : "Avez-vous des boissons au matcha ?"
- L'agent doit recommander le nouveau Matcha Green Tea Latte avec la description et le prix que vous venez d'ajouter. Cela confirme que l'agent est ancré sur les requêtes directement dans votre base de données Firestore active.
9. Effectuer un nettoyage
Pour éviter que des frais ne soient facturés sur votre compte de facturation Google Cloud, supprimez le service Cloud Run déployé et le compte de service personnalisé.
Supprimez le service Cloud Run :
gcloud run services delete coffee-barista --region $REGION --quiet
Supprimez le compte de service personnalisé :
gcloud iam service-accounts delete barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com --quiet
(Facultatif) Supprimez la base de données Firestore (si elle a été créée) :
gcloud firestore databases delete --database="coffee-menu" --quiet
Étape facultative : Supprimez l'intégralité du projet. ⚠️ Ne procédez ainsi que si vous avez créé un projet dédié pour cet atelier.
gcloud projects delete $PROJECT_ID
10. Félicitations
Félicitations ! Vous avez créé et déployé un agent Barista d'IA avec génération augmentée par récupération (RAG) à l'aide de l'ADK de Google et de Cloud Run.
Connaissances acquises
- Construire des outils RAG simples en Python.
- Utilisez les valeurs
LlmAgentetInMemoryRunnerde l'ADK. - Créer des expériences de chat avec état dans Streamlit.
- Déployer Streamlit sur Cloud Run à l'aide de compilations basées sur la source.