1. Introduzione
In questo codelab, creerai un agente AI Barista interattivo per una caffetteria. Utilizzando l'Agent Development Kit (ADK) open source di Google e il modello Gemini 3.5 Flash, implementerai la generazione Retrieval-Augmented Generation (RAG) per basare i consigli dell'agente su un set di dati di menu simulato. Infine, racchiuderai l'agente in un'interfaccia utente Streamlit ed eseguirai il deployment su Cloud Run.
In questo lab proverai a:
- Crea un'origine dati RAG (
menu.json) contenente articoli di caffè, tag e allergeni. - Crea un agente AI utilizzando l'ADK
LlmAgente connetti uno strumento Python per caricare i dati del menu. - Incorpora l'agente in un'applicazione di chat Streamlit che gestisce la cronologia delle conversazioni.
- Esegui il deployment dell'app Streamlit in Cloud Run utilizzando il deployment basato sull'origine.
- Testa il grounding RAG e la consapevolezza degli allergeni.

Che cosa ti serve
- Un browser web come Chrome.
- Un progetto Google Cloud con la fatturazione abilitata.
- Conoscenza di base di Python.
Questo codelab è rivolto a sviluppatori di tutti i livelli, inclusi i principianti.
Costo stimato: meno di 1 $.
2. Prima di iniziare
Crea un progetto Google Cloud
- Nella console Google Cloud, seleziona o crea un progetto Google Cloud.
- Verifica che la fatturazione sia attivata per il tuo progetto Cloud.
Avvia Cloud Shell
- Fai clic su Attiva Cloud Shell nella parte superiore della console Google Cloud.

- Verifica l'autenticazione:

gcloud auth list
- Verifica che il progetto attivo sia impostato:
gcloud config get project
Se l'ID progetto visualizzato non è corretto o non è impostato, esegui:
gcloud config set project <YOUR_PROJECT_ID>
Abilita API
Esegui questo comando per abilitare tutte le API richieste:
gcloud services enable \
run.googleapis.com \
aiplatform.googleapis.com \
cloudbuild.googleapis.com
3. Configura il progetto
In questo passaggio, inizializzerai le variabili di ambiente del progetto e creerai una directory di lavoro per il progetto.
- Nella sessione Cloud Shell attiva, inizializza le seguenti variabili di ambiente del progetto:
export PROJECT_ID=$(gcloud config get-value project)
Nota: utilizza la regione più vicina
Trova la regione più vicina e sostituiscila a insert-region-here nel seguente comando:
export REGION=[insert-region-here]
- Crea una nuova directory di progetto denominata
coffee-barista-agente passa a questa directory:
mkdir coffee-barista-agent && cd coffee-barista-agent
4. Crea l'origine dati del menu simulato
Per ancorare l'AI Barista ed evitare che allucini elementi inesistenti, creerai un set di dati del menu locale. L'agente leggerà questo file in fase di runtime tramite uno strumento personalizzato.
- Crea e apri
menu.jsonnell'editor di Cloud Shell:
cloudshell edit menu.json
- Incolla i seguenti contenuti JSON nell'editor e salva il file:
[
{
"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"]
}
]
- Verifica che il file JSON sia formattato correttamente:
cat menu.json | python3 -m json.tool > /dev/null && echo "Valid JSON!"
💬 Discussione: JSON locale e database live
Perché utilizziamo un semplice file local menu.json anziché un database live?
Per un tutorial o un prototipo rapido, un file JSON locale elimina i tempi e la complessità della configurazione iniziale del database. Tuttavia, in un'applicazione di produzione aziendale reale, collegheresti l'agente a un database gestito come Cloud Firestore, AlloyDB o Cloud SQL.
L'utilizzo di un database live consente ai gestori di bar di aggiungere articoli stagionali, aggiornare i prezzi o modificare dinamicamente i tag degli allergeni senza ricompilare l'immagine container o rieseguire il deployment del codice dell'applicazione. Utilizzeremo un database live come passaggio facoltativo più avanti nel codelab.
5. Crea l'agente ADK
Ora installerai i pacchetti richiesti e creerai la logica principale dell'agente ADK. Definisci uno strumento get_menu() e passalo a un LlmAgent.
- Crea e apri
requirements.txtnell'editor di Cloud Shell:
cloudshell edit requirements.txt
- Incolla le seguenti dipendenze nell'editor e salva il file:
google-adk==2.2.0
streamlit==1.58.0
- Crea e apri
agent.pynell'editor di Cloud Shell:
cloudshell edit agent.py
- Incolla il seguente codice in
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
)
- Crea e apri
app.pynell'editor di Cloud Shell:
cloudshell edit app.py
- Incolla il seguente codice in
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}")
💬 Discussione: compromessi del modello ed efficienza dei token di recupero
Perché chiamare uno strumento di funzione per recuperare il menu anziché incollare l'intero testo del menu nelle istruzioni di sistema dell'agente?
Token economy! Inserire 8 elementi nel prompt è economico, ma cosa succede se la caffetteria si espande a 500 articoli, inclusi ingredienti personalizzati? L'incollatura di set di dati di grandi dimensioni direttamente nel prompt di sistema aumenta il conteggio dei token del prompt, incrementando i costi delle transazioni e la latenza della risposta dell'API per ogni singola query.
Utilizzando uno strumento ADK, l'agente chiede dinamicamente di leggere il menu SOLO quando necessario. L'LLM riceve solo i dati di menu pertinenti come contesto, riducendo al minimo le dimensioni del token del prompt.
💬 Discussione: Memory State & Production Stores
La cronologia chat memorizzata in st.session_state di Streamlit viene conservata quando un utente chiude la scheda del browser?
No, non lo fa. st.session_state è completamente in memoria e univoco per la connessione del browser attiva. Se un utente aggiorna la pagina o chiude la scheda, la cronologia della conversazione con il barista viene persa.
Per un'applicazione di produzione, collegheresti il runner ADK a un backend di archiviazione permanente come Cloud Firestore o Redis. L'ADK fornisce astrazioni di servizio integrate (come SessionService) che semplificano il salvataggio e la ripresa della cronologia della chat durante i ricaricamenti di pagina e sui dispositivi.
6. Esegui il deployment dell'agente in Cloud Run
Esegui il deployment dell'applicazione Streamlit direttamente dall'origine utilizzando i buildpack integrati di Cloud Run. Per seguire il principio del privilegio minimo, creerai e implementerai utilizzando un service account personalizzato dedicato anziché utilizzare il service account predefinito di Compute Engine.
- Crea un service account dedicato:
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"
- Concedi il ruolo utente della piattaforma Gemini Enterprise Agent (
roles/aiplatform.user) al nuovo service account:
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
- Esegui il deployment del servizio utilizzando
gcloud run deploy, passando la nuova email del service account tramite il flag--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
- Una volta eseguito il deployment, individua l'URL del servizio nell'output del comando.
💬 Discussione: deployment di container e sorgenti e sicurezza IAM
Abbiamo eseguito il deployment in Cloud Run utilizzando gcloud run deploy --source senza creare un Dockerfile o un Procfile. In che modo Cloud Run ha capito come compilare ed eseguire la nostra app Python?
Cloud Run utilizza Buildpacks per analizzare il repository. Dopo aver rilevato la presenza direquirements.txt e dei file sorgente Python, il motore compila e pacchettizza automaticamente un container di runtime Python.
La scrittura di un Dockerfile personalizzato ti offre il controllo completo dei pacchetti di sistema e dei livelli di base del container. Un Procfile è un modo più semplice per dichiarare il comando di avvio senza configurare completamente un container. Tuttavia, per i deployment rapidi, il deployment dall'origine (--source) è molto efficiente.
Perché abbiamo eseguito il passaggio aggiuntivo di creare un service account personalizzato barista-agent-sa anziché utilizzare semplicemente il service account predefinito di Compute Engine?
La sicurezza prima di tutto. Per impostazione predefinita, il service account Compute Engine predefinito dispone di autorizzazioni Editor estremamente ampie. L'esecuzione del nostro container Cloud Run con il service account predefinito significa che, se la nostra app ha un bug di sicurezza, un malintenzionato potrebbe potenzialmente leggere, scrivere o eliminare altre risorse nel nostro progetto Google Cloud.
Creando un service account dedicato e assegnandogli solo il ruolo roles/aiplatform.user, seguiamo il principio del privilegio minimo: l'app ha esattamente l'accesso necessario per chiamare Gemini e nient'altro.
7. Testare il comportamento di RAG
Apri l'URL del servizio Cloud Run in un browser web e poni domande all'AI Barista per testare i suoi vincoli di grounding e sicurezza.
- Richiesta nel menu:chiedi: "Consigliami qualcosa di forte e caldo". Risposta prevista: l'agente consiglia l'espresso.
- Trappola fuori menu: domanda: "Avete un frappuccino al matcha?"Risposta prevista: l'agente rifiuta gentilmente e spiega che non è nel menu.
- Richiesta consapevole degli allergeni: chiedi: "Sono intollerante al lattosio, cosa posso prendere?"Risultato previsto: l'agente consiglia solo voci di menu senza latticini (come il latte macchiato con latte d'avena, l'espresso e il cold brew). NON consiglia Cappuccino o Croissant.

8. (Facoltativo) Ancora l'agente in Firestore utilizzando la ricerca vettoriale
In uno scenario di produzione, l'archiviazione delle voci di menu in un file menu.json locale non è l'ideale perché qualsiasi modifica al menu richiede la ricompilazione dell'immagine container e il redeploy del servizio Cloud Run.
Per rendere l'applicazione dinamica e scalabile, puoi eseguire la migrazione dei dati del menu a Cloud Firestore e utilizzare la ricerca vettoriale per recuperare solo le voci di menu più pertinenti in base alla somiglianza semantica.

1. Abilita l'API Firestore e inizializza il database
Esegui questi comandi per abilitare l'API Firestore e creare un database Firestore denominato coffee-menu in modalità Native:
gcloud services enable firestore.googleapis.com
gcloud firestore databases create --database="coffee-menu" --location=$REGION
Nota: l'abilitazione dell'API può richiedere 1-2 minuti per la propagazione. Se il comando di creazione del database ti chiede API [firestore.googleapis.com] not enabled on project... Would you like to enable and retry?, digita Y per procedere oppure attendi un minuto ed esegui di nuovo il comando.
2. Inserisci dati in Firestore con i dati del menu
Per inizializzare rapidamente il database Firestore con le voci di menu del file menu.json, puoi eseguire uno script Python localmente in Cloud Shell.
- Installa localmente le librerie client di Firestore e GenAI in Cloud Shell per eseguire lo script di inizializzazione:
pip3 install google-cloud-firestore==2.27.0 google-genai==2.11.0
- Crea uno script di seeding
seed.py:
cloudshell edit seed.py
- Incolla il seguente codice in
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!")
- Esegui lo script:
python3 seed.py
3. Crea indice vettoriale Firestore
Per eseguire ricerche vettoriali sugli elementi del menu, devi creare un indice vettoriale composito sul campo embedding nel database Firestore.
Esegui questo comando nel terminale 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": "{}"}'
Nota: la creazione dell'indice Firestore viene eseguita in background e può richiedere alcuni minuti. Puoi procedere con i passaggi successivi del codelab durante la creazione dell'indice.
4. Concedi l'accesso a Firestore al service account
Affinché il tuo servizio Cloud Run possa eseguire query su Firestore, devi concedere al suo service account il ruolo Utente Cloud Datastore (roles/datastore.user):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/datastore.user"
Nota:anche se utilizziamo Cloud Firestore in modalità nativa, Google Cloud utilizza i ruoli IAM unificati di Cloud Datastore (roles/datastore.viewer o roles/datastore.user) per gestire il controllo dell'accesso.
5. Aggiorna il codice
Ora aggiorna il codice per recuperare il menu da Firestore anziché leggerlo da menu.json.
- Apri
requirements.txtnell'editor di Cloud Shell:
cloudshell edit requirements.txt
- Aggiungi le librerie client di Firestore e GenAI alla fine del file e salvalo:
google-cloud-firestore==2.27.0
google-genai==2.11.0
- Apri
agent.pynell'editor di Cloud Shell:
cloudshell edit agent.py
- Individua il blocco
# [START get_menu]inagent.pye sostituiscilo completamente (da# [START get_menu]a# [END get_menu]) con la seguente implementazione di Firestore:
# [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]
- Apri
app.pynell'editor di Cloud Shell:
cloudshell edit app.py
- Individua il blocco
# [START load_menu]inapp.pye sostituiscilo completamente (da# [START load_menu]a# [END load_menu]) con la seguente logica di caricamento di Firestore:
# [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. Esegui nuovamente il deployment in Cloud Run
Esegui il deployment dell'applicazione aggiornata:
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. Verificare l'integrazione di Firestore
Per testare la connessione dell'agente a Firestore, aggiungi una nuova voce di menu direttamente in Firestore e verifica che l'agente la consigli.
- Esegui questo comando in Cloud Shell per scrivere un nuovo documento nella raccolta
menuin Firestore utilizzando 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!')
"
- Aggiorna l'app Streamlit nel browser per cancellare la sessione di chat e caricare il nuovo stato del database.
- Tieni presente che:
- Matcha Green Tea Latte viene visualizzato automaticamente nel menu della barra laterale.
- Chiedi al chatbot: "Avete bevande a base di matcha?"
- L'agente dovrebbe consigliare correttamente il nuovo Matcha Green Tea Latte con la descrizione e il prezzo che hai appena aggiunto. Ciò conferma che l'agente è basato sulle query direttamente nel tuo database Firestore live.
9. Esegui la pulizia
Per evitare addebiti continui al tuo account di fatturazione Google Cloud, elimina il servizio Cloud Run di cui è stato eseguito il deployment e il service account personalizzato.
Elimina il servizio Cloud Run:
gcloud run services delete coffee-barista --region $REGION --quiet
Elimina il service account personalizzato:
gcloud iam service-accounts delete barista-agent-sa@$PROJECT_ID.iam.gserviceaccount.com --quiet
(Facoltativo) Elimina il database Firestore (se creato):
gcloud firestore databases delete --database="coffee-menu" --quiet
(Facoltativo) Elimina l'intero progetto. ⚠️ ESEGUI QUESTA OPERAZIONE SOLO SE HAI CREATO UN PROGETTO DEDICATO PER QUESTO LAB
gcloud projects delete $PROJECT_ID
10. Complimenti
Complimenti! Hai creato e implementato un agente AI Barista RAG (Retrieval-Augmented Generation) utilizzando ADK e Cloud Run di Google.
Cosa hai imparato
- Costruire semplici strumenti RAG in Python.
- Utilizzando l'ADK
LlmAgenteInMemoryRunner. - Creazione di esperienze di chat con stato in Streamlit.
- Deployment di Streamlit in Cloud Run utilizzando build basate sull'origine.