1. Introduction
Dans cet atelier pratique, vous allez aller au-delà des chatbots de base sans état pour créer un concierge Smart Cafe, un agent d'IA optimisé par Gemini qui agit comme un barista sympathique. Il prend les commandes de café suivies dans l'état de la session, mémorise les préférences alimentaires à long terme dans l'état à portée utilisateur et conserve tout dans une base de données Cloud SQL PostgreSQL. À la fin, votre agent se souvient que vous êtes intolérant au lactose, même après avoir redémarré l'application et commencé une toute nouvelle conversation.
Voici l'architecture système que nous allons créer.

Prérequis
- Un compte Google Cloud avec un compte de facturation d'essai
- Connaître les bases de Python
- Aucune expérience préalable avec ADK, les agents d'IA ou Cloud SQL n'est requise.
Points abordés
- Créer un agent d'IA à l'aide de l'Agent Development Kit (ADK) de Google avec des outils personnalisés
- Définir des outils qui lisent et écrivent l'état de session via
ToolContext - Faire la distinction entre l'état de portée session et l'état de portée utilisateur (préfixe
user:) - Provisionner une instance Cloud SQL pour PostgreSQL et s'y connecter depuis Cloud Shell
- Migrer du stockage local (qui est la valeur par défaut lorsque vous utilisez la commande
adk web) versDatabaseSessionServicepour un stockage persistant avec une base de données dédiée - Vérifier que la mémoire de l'agent persiste lors des redémarrages de l'application et des sessions de conversation distinctes
Prérequis
- Un ordinateur qui fonctionne et une connexion Internet fiable.
- Un navigateur, tel que Chrome, pour accéder à la console Google Cloud
- Un esprit curieux et l'envie d'apprendre
2. Configurer votre environnement
Cette étape prépare votre environnement Cloud Shell et configure votre projet Google Cloud.
Ouvrir Cloud Shell
Ouvrez Cloud Shell dans votre navigateur. Cloud Shell fournit un environnement préconfiguré avec tous les outils dont vous avez besoin pour cet atelier de programmation. Cliquez sur Autoriser lorsque vous y êtes invité.
Votre interface doit ressembler à ceci :

Ce sera notre interface principale, avec l'IDE en haut et le terminal en bas.
Configurer votre répertoire de travail
Créez votre répertoire de travail. Tout le code que vous écrivez dans cet atelier de programmation se trouve ici, séparément du dépôt de référence :
# Create your working directory
mkdir -p ~/build-agent-adk-cloudsql
# Change cloudshell workspace and working directory into previously created dir
cloudshell workspace ~/build-agent-adk-cloudsql && cd ~/build-agent-adk-cloudsql
Pour générer votre terminal, recherchez View > Terminal (Afficher > Terminal).

Configurer votre projet Google Cloud et les variables d'environnement initiales
Téléchargez le script de configuration du projet dans votre répertoire de travail :
curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh
Exécutez le script. Il valide votre compte de facturation d'essai, crée un projet (ou en valide un existant), enregistre l'ID de votre projet dans un fichier .env du répertoire actuel et définit le projet actif dans le terminal.
bash setup_verify_trial_project.sh && source .env
Lorsque vous exécutez cette commande, un nom d'ID de projet suggéré s'affiche. Vous pouvez appuyer sur Enter pour continuer.

Après avoir attendu un moment, si le résultat suivant s'affiche dans la console, vous pouvez passer à l'étape suivante
.
Le script exécuté effectue les étapes suivantes :
- Vérifier que vous disposez d'un compte de facturation d'essai actif
- Recherchez un projet existant dans
.env(le cas échéant). - Créez un projet ou réutilisez-en un existant.
- Associer le compte de facturation d'essai à votre projet
- Enregistrer l'ID du projet dans .env
- Définir le projet comme projet gcloud actif
Vérifiez que le projet est correctement défini en examinant le texte jaune à côté de votre répertoire de travail dans l'invite du terminal Cloud Shell. L'ID de votre projet devrait s'afficher.

Activer les API requises
Activez les API Google Cloud nécessaires pour cet atelier de programmation :
gcloud services enable \
aiplatform.googleapis.com \
sqladmin.googleapis.com \
compute.googleapis.com
- API Vertex AI (
aiplatform.googleapis.com) : votre agent utilise les modèles Gemini via Vertex AI. - API Cloud SQL Admin (
sqladmin.googleapis.com) : vous provisionnez et gérez une instance PostgreSQL pour le stockage persistant. - API Compute Engine (
compute.googleapis.com) : requise pour créer des instances Cloud SQL.
Configurer la région des produits Gemini et Cloud
Avant de continuer, configurons également l'emplacement/la région nécessaires pour le produit avec lequel nous interagissons. Ajoutez la configuration suivante à notre fichier .env.
# This is for our Gemini endpoint
echo "GOOGLE_CLOUD_LOCATION=global" >> .env
# This is for our other Cloud products
echo "REGION=us-central1" >> .env
source .env
Passons à l'étape suivante.
3. Configurer Cloud SQL
Cette étape provisionne une instance Cloud SQL PostgreSQL et fait passer votre agent du stockage en mémoire au stockage basé sur une base de données. La création de l'instance prend quelques minutes. Nous allons donc commencer par cette étape, puis nous pourrons continuer notre discussion sur le sujet suivant en attendant qu'elle soit terminée.
Démarrer la création de l'instance
Ajoutez le mot de passe de la base de données à votre fichier .env et rechargez-le. Nous utiliserons cafe-agent-pwd-2025 comme mot de passe.
echo "DB_PASSWORD=cafe-agent-pwd-2025" >> .env
source .env
Exécutez cette commande pour créer une instance Cloud SQL PostgreSQL. L'opération prend quelques minutes. Laissez-la s'exécuter et passez à la section suivante.
gcloud sql instances create cafe-concierge-db \
--database-version=POSTGRES_17 \
--edition=ENTERPRISE \
--region=${REGION} \
--availability-type=ZONAL \
--project=${GOOGLE_CLOUD_PROJECT} \
--tier=db-f1-micro \
--root-password=${DB_PASSWORD} \
--quiet &
Remarques concernant la commande ci-dessus :
db-f1-microest le niveau Cloud SQL le plus petit (et le moins cher), ce qui est suffisant pour cet atelier de programmation.--root-passworddéfinit le mot de passe de l'utilisateur postgres par défaut.- Le suffixe
&de la commande permet de l'exécuter en arrière-plan pour que vous puissiez continuer à travailler.
Le processus s'exécute en arrière-plan, mais la sortie de la console s'affiche parfois dans le terminal actuel. Ouvrons un nouvel onglet de terminal dans Cloud Shell (cliquez sur l'icône +) pour nous concentrer davantage.

Revenez à votre répertoire de travail et activez le projet à l'aide du script de configuration précédent.
cd ~/build-agent-adk-cloudsql
bash setup_verify_trial_project.sh && source .env
Passons ensuite à la section suivante.
4. Créer l'agent Cafe Concierge
Cette étape crée la structure du projet pour votre agent ADK et définit un concierge de café de base avec un outil de menu.
Initialiser le projet Python
Cet atelier de programmation utilise uv, un gestionnaire de packages Python rapide qui gère les environnements virtuels et les dépendances dans un seul outil. Il est préinstallé dans Cloud Shell.
Initialisez un projet Python et ajoutez l'ADK en tant que dépendance :
uv init
uv add google-adk==1.25.0 asyncpg
uv init crée un pyproject.toml et un environnement virtuel. La commande uv add installe la dépendance et l'enregistre dans pyproject.toml.
Initialiser la structure du projet d'agent
L'ADK s'attend à une structure de dossier spécifique : un répertoire nommé d'après votre agent contenant __init__.py, agent.py et .env à l'intérieur du répertoire de l'agent.
ADK dispose d'une commande intégrée pour vous aider à établir rapidement cette connexion. Exécutez la commande suivante :
uv run adk create cafe_concierge \
--model gemini-2.5-flash \
--project ${GOOGLE_CLOUD_PROJECT} \
--region ${GOOGLE_CLOUD_LOCATION}
Cette commande crée une structure d'agent avec gemini-2.5-flash comme cerveau. Votre répertoire devrait maintenant se présenter comme suit :
build-agent-adk-cloudsql/ ├── cafe_concierge/ │ ├── __init__.py │ ├── agent.py │ └── .env ├── pyproject.toml ├── .env ├── .venv/ └── ...
Écrire l'agent
Ouvrez cafe_concierge/agent.py dans l'éditeur Cloud Shell.
cloudshell edit cafe_concierge/agent.py
et remplacez le fichier par le code suivant.
# cafe_concierge/agent.py
from google.adk.agents import LlmAgent
from google.adk.tools import ToolContext
CAFE_MENU = {
"espresso": {
"price": 3.50,
"description": "Rich and bold single shot",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"latte": {
"price": 5.00,
"description": "Espresso with steamed milk",
"tags": ["gluten-free"],
},
"oat milk latte": {
"price": 5.50,
"description": "Espresso with steamed oat milk",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"cappuccino": {
"price": 4.50,
"description": "Espresso with equal parts steamed milk and foam",
"tags": ["gluten-free"],
},
"cold brew": {
"price": 4.00,
"description": "Slow-steeped for 12 hours, served over ice",
"tags": ["vegan", "dairy-free", "gluten-free"],
},
"matcha latte": {
"price": 5.50,
"description": "Ceremonial grade matcha with steamed milk",
"tags": ["gluten-free"],
},
"croissant": {
"price": 3.00,
"description": "Buttery, flaky French pastry",
"tags": [],
},
"banana bread": {
"price": 3.50,
"description": "Homemade with walnuts",
"tags": ["vegan"],
},
}
def get_menu() -> dict:
"""Returns the full cafe menu with prices, descriptions, and dietary tags.
Use this tool when the customer asks what's available, wants to see
the menu, or asks about specific items.
"""
return CAFE_MENU
root_agent = LlmAgent(
name="cafe_concierge",
model="gemini-2.5-flash",
instruction="""You are a friendly and knowledgeable barista at "The Cloud Cafe".
Your job:
- Help customers browse the menu and answer questions about items.
- Take coffee and food orders.
- Remember and respect dietary preferences.
Be conversational, warm, and concise. If a customer mentions a dietary
restriction, acknowledge it and suggest suitable options from the menu.
""",
tools=[get_menu],
)
Ce code définit un agent de base avec un outil : get_menu(). L'agent peut répondre aux questions sur le menu, mais ne peut pas encore suivre les commandes ni mémoriser les préférences.
Vérifier que l'agent s'exécute
Démarrez l'UI de développement d'ADK depuis votre répertoire de travail :
cd ~/build-agent-adk-cloudsql
uv run adk web
Ouvrez l'URL affichée dans le terminal (généralement http://localhost:8000) à l'aide de la fonctionnalité d'aperçu sur le Web de Cloud Shell. Sélectionnez cafe_concierge dans le menu déroulant de l'agent en haut à gauche.
Saisissez le texte suivant dans la barre de chat et vérifiez que l'agent répond avec des éléments de menu et des prix.
What's on the menu?

Arrêtez l'interface utilisateur de développement avec Ctrl+C avant de continuer.
5. Ajouter la gestion des commandes avec état
L'agent peut afficher le menu, mais il ne peut pas prendre de commandes ni se souvenir des préférences. Cette étape ajoute quatre outils qui utilisent le système d'état de l'ADK pour suivre les commandes dans une conversation et stocker les préférences alimentaires dans les conversations.
Comprendre les événements et l'état des sessions
Chaque conversation ADK se trouve dans un objet Session. Une session suit deux éléments distincts : les événements et l'état. Il est essentiel de comprendre la différence entre ces deux types de mémoire pour créer des agents qui se souviennent des bonnes choses de la bonne manière.
Les événements sont le journal chronologique de tout ce qui se passe dans une conversation. Chaque message utilisateur, chaque réponse de l'agent, chaque appel d'outil et sa valeur de retour sont enregistrés en tant qu'Event et ajoutés à la liste events de la session. Les événements sont immuables : une fois enregistrés, ils ne changent jamais. Considérez les événements comme la transcription complète d'une conversation.
L'état est un bloc-notes clé-valeur que l'agent lit et écrit pendant une conversation. Contrairement aux événements, l'état est mutable : les valeurs changent au fur et à mesure que la conversation évolue. L'état est l'endroit où l'agent stocke les données structurées dont il a besoin pour agir : la commande en cours, les préférences du client, un total en cours, etc. Considérez l'état comme des notes autocollantes que l'agent conserve à côté de la transcription.
Voici comment ils sont liés :

Les outils lisent et écrivent l'état via ToolContext, un objet que l'ADK injecte automatiquement dans toute fonction d'outil qui le déclare comme paramètre. Vous ne le créez pas vous-même. Grâce à tool_context.state, un outil peut lire et écrire le bloc-notes d'état de la session. ADK inspecte la signature de la fonction : les paramètres de type ToolContext sont injectés, et tous les autres paramètres sont renseignés par le LLM en fonction de la conversation.
Lorsqu'un outil écrit dans tool_context.state, ADK enregistre cette modification en tant que state_delta dans l'événement. SessionService applique ensuite le delta à l'état actuel de la session. Cela signifie que les changements d'état sont toujours traçables jusqu'à l'événement qui les a provoqués. Il en va de même pour d'autres formes de contexte, comme callback_context.
Comprendre les préfixes d'état
Les clés d'état utilisent des préfixes pour contrôler leur portée :
Préfixe | Portée | Survit au redémarrage ? (avec DB) |
(aucun) | Session actuelle uniquement | Oui |
| Toutes les sessions de cet utilisateur | Oui |
| Toutes les sessions, tous les utilisateurs | Oui |
| Appel actuel uniquement | Non |
Dans cet atelier de programmation, vous allez utiliser deux de ces préfixes : les clés sans préfixe pour les données à portée de session (la commande actuelle, qui ne concerne que cette conversation) et les clés user: pour les données à portée utilisateur (les préférences alimentaires, qui concernent toutes les conversations de cet utilisateur).
Ajouter les outils avec état
Ouvrez cafe_concierge/agent.py dans l'éditeur Cloud Shell.
cloudshell edit cafe_concierge/agent.py
Ajoutez ensuite les quatre fonctions suivantes au-dessus de la définition root_agent :
# cafe_concierge/agent.py (add below get_menu, above root_agent)
def place_order(tool_context: ToolContext, items: list[str]) -> dict:
"""Places an order for the specified menu items.
Use this tool when the customer confirms they want to order something.
Args:
tool_context: Provided automatically by ADK.
items: A list of menu item names the customer wants to order.
"""
valid_items = []
invalid_items = []
total = 0.0
for item in items:
item_lower = item.lower()
if item_lower in CAFE_MENU:
valid_items.append(item_lower)
total += CAFE_MENU[item_lower]["price"]
else:
invalid_items.append(item)
if not valid_items:
return {"error": f"None of these items are on our menu: {invalid_items}"}
order = {"items": valid_items, "total": round(total, 2)}
tool_context.state["current_order"] = order
result = {"order": order}
if invalid_items:
result["warning"] = f"These items are not on our menu: {invalid_items}"
return result
def get_order_summary(tool_context: ToolContext) -> dict:
"""Returns the current order summary for this session.
Use this tool when the customer asks about their current order,
wants to review what they ordered, or asks for the total.
Args:
tool_context: Provided automatically by ADK.
"""
order = tool_context.state.get("current_order")
if order:
return {"order": order}
return {"message": "No order has been placed yet in this session."}
def set_dietary_preference(tool_context: ToolContext, preference: str) -> dict:
"""Saves a dietary preference that persists across all conversations.
Use this tool when the customer mentions a dietary restriction or
preference (e.g., "I'm vegan", "I'm lactose intolerant",
"I have a nut allergy").
Args:
tool_context: Provided automatically by ADK.
preference: The dietary preference to save (e.g., "vegan",
"lactose intolerant", "nut allergy").
"""
existing = tool_context.state.get("user:dietary_preferences", [])
if not isinstance(existing, list):
existing = []
preference_lower = preference.lower().strip()
if preference_lower not in existing:
existing.append(preference_lower)
tool_context.state["user:dietary_preferences"] = existing
return {
"saved": preference_lower,
"all_preferences": existing,
}
def get_dietary_preferences(tool_context: ToolContext) -> dict:
"""Retrieves the customer's saved dietary preferences.
Use this tool when you need to check the customer's dietary
restrictions before making recommendations.
Args:
tool_context: Provided automatically by ADK.
"""
preferences = tool_context.state.get("user:dietary_preferences", [])
if preferences:
return {"preferences": preferences}
return {"message": "No dietary preferences saved yet."}
Deux points à noter :
place_orderetget_order_summaryutilisent des clés sans préfixe (current_order). Cet état est lié à la session en cours. Une nouvelle conversation commence par une commande vide.set_dietary_preferenceetget_dietary_preferencesutilisent le préfixeuser:(user:dietary_preferences). Cet état est partagé entre toutes les sessions du même utilisateur.
Mettre à jour l'agent avec de nouveaux outils et instructions
Remplacez la définition root_agent existante au bas du fichier par :
# cafe_concierge/agent.py (replace the existing root_agent)
root_agent = LlmAgent(
name="cafe_concierge",
model="gemini-2.5-flash",
instruction="""You are a friendly and knowledgeable barista at "The Cloud Cafe".
Your job:
- Help customers browse the menu and answer questions about items.
- Take coffee and food orders.
- Remember and respect dietary preferences.
The customer's saved dietary preferences are: {user:dietary_preferences?}
IMPORTANT RULES:
- When a customer mentions a dietary restriction, ALWAYS save it using the
set_dietary_preference tool before doing anything else.
- Before recommending items, check the customer's dietary preferences. If they
have preferences saved, only recommend items compatible with those
restrictions. Check the menu item tags to determine compatibility.
- When placing an order, confirm the items and total with the customer.
Be conversational, warm, and concise.
""",
tools=[
get_menu,
place_order,
get_order_summary,
set_dietary_preference,
get_dietary_preferences,
],
)
L'instruction utilise le modèle d'injection d'état {user:dietary_preferences?} pour injecter les préférences enregistrées de ce client directement dans la requête.
Vérifier le fichier complet
Votre fichier cafe_concierge/agent.py doit maintenant contenir les éléments suivants :
- Dictionnaire
CAFE_MENU - Cinq fonctions d'outil :
get_menu,place_order,get_order_summary,set_dietary_preference,get_dietary_preferences - Définition de
root_agentavec les cinq outils
6. Tester l'agent avec l'UI de développement ADK
Cette étape exécute l'agent et exerce toutes les fonctionnalités avec état : commande, suivi des préférences et mémoire intersession (dans le même processus). Vous examinerez également les panneaux "Événements" et "État" pour voir comment l'ADK suit la conversation en interne.
Démarrer l'UI de développement
cd ~/build-agent-adk-cloudsql
uv run adk web
Ouvrez l'aperçu sur le Web sur le port 8000 et sélectionnez cafe_concierge dans le menu déroulant.
Conversation 1 : Passer une commande et définir des préférences
Essayez ces requêtes dans l'ordre :
What's on the menu?
I'm lactose intolerant
What would you recommend?
I'll have an oat milk latte and a banana bread
What's my order?
Inspecter les événements de session
Tous les événements seront capturés et affichés dans l'interface utilisateur Web. Vous verrez que dans la zone de chat, il n'y a pas que votre requête et votre réponse, mais aussi tool_call et tool_response.

Une liste d'événements devrait s'afficher dans l'ordre. Chaque événement comporte un auteur (celui qui l'a produit) et un type (le type d'interaction qu'il représente) :
Auteur | Type | Ce que cela représente |
|
| Un message que vous avez saisi dans le chat |
|
| Réponse textuelle de l'agent |
|
| L'agent a décidé d'appeler un outil (nom de la fonction + arguments) |
|
| Valeur renvoyée par un appel d'outil |
Cliquez sur l'un des événements tool_call, par exemple l'appel set_dietary_preference. Vous devriez obtenir le résultat suivant :
- Nom de la fonction :
set_dietary_preference - Arguments :
{"preference": "lactose intolerant"}
Cliquez ensuite sur l'événement tool_response correspondant, juste en dessous. La valeur renvoyée devrait s'afficher :
- Réponse :
{"saved": "lactose intolerant", "all_preferences": ["lactose intolerant"]}

Recherchez le champ state_delta dans l'événement tool_response. Cela montre exactement quel état a changé à la suite de cet appel d'outil :
state_delta: {"user:dietary_preferences": ["lactose intolerant"]}
Chaque changement d'état est associé à un événement spécifique. C'est ainsi que l'ADK s'assure que le bloc-notes d'état reste synchronisé avec l'historique des conversations.
Inspecter l'état de la session
Cliquez sur l'onglet État. Contrairement au journal des événements (qui affiche l'historique complet), l'onglet "État" affiche un instantané de ce que l'agent sait actuellement, c'est-à-dire la valeur actuelle de chaque clé d'état.

Vous devriez voir deux entrées :
current_order—{"items": ["oat milk latte", "banana bread"], "total": 9.0}user:dietary_preferences—["lactose intolerant"]
Notez la différence dans les noms des clés :
current_ordern'a pas de préfixe, car elle est limitée à la session. Il n'existe que dans cette conversation et disparaît à la fin de la session.user:dietary_preferencesa le préfixeuser:. Il s'agit d'une dimension de portée utilisateur. Elle est partagée entre toutes les sessions de cet utilisateur.
Cette distinction est invisible dans le code (les deux utilisent tool_context.state), mais elle contrôle la portée des données. Vous verrez cela se produire lors du prochain test.
Conversation 2 : Valider l'état de l'utilisateur entre les sessions
Cliquez sur le bouton New Session (Nouvelle session) dans l'UI de développement pour démarrer une nouvelle conversation. Cela crée une session pour le même utilisateur.

Essayez ce prompt :
What do you recommend for me?
Consultez l'onglet État dans la nouvelle session. La touche user:dietary_preferences est conservée, mais current_order a disparu, car cet état était lié à la session précédente.

7. Respecter la limite de stockage local
L'agent mémorise les préférences entre les sessions, mais uniquement tant que le stockage local existe. Cette étape illustre la limite fondamentale du stockage local.
Redémarrez l'agent.
Vous avez arrêté l'UI de développement à la fin de l'étape précédente. Supprimons maintenant le stockage local et redémarrons-le pour simuler un environnement sans serveur qui est sans état :
cd ~/build-agent-adk-cloudsql
rm -f cafe_concierge/.adk/session.db
uv run adk web
Ouvrez ensuite l'aperçu sur le Web sur le port 8000 et sélectionnez cafe_concierge.
Tester la mémorisation des préférences
Type :
Do you remember my dietary preferences?
L'agent n'a aucun souvenir. Les préférences alimentaires, l'historique des commandes… tout a disparu.

Tout a été effacé lorsque nous avons supprimé le stockage local, ce qui se produisait généralement lorsque nous utilisions un environnement sans serveur. Le session.db stocke tous les états dans la mémoire du processus. Si vous le supprimez, tout sera effacé.
La solution : spécifiez DatabaseSessionService, qui, dans ce tutoriel, stockera toutes les données de session dans une base de données PostgreSQL dans Cloud SQL. Le code et les outils de l'agent restent exactement les mêmes. Seul le backend de stockage change.
Arrêtez l'interface utilisateur de développement avec Ctrl+C avant de continuer.
8. Revoir la configuration de la base de données
À ce stade, la création de notre instance de base de données devrait déjà être terminée. Pour le vérifier, exécutez la commande suivante :
gcloud sql instances describe cafe-concierge-db --format="value(state)"
Vous devriez obtenir le résultat suivant. Marquez-le comme terminé.
RUNNABLE
Créer la base de données
Créez une base de données dédiée pour les données de session de l'agent :
gcloud sql databases create agent_db --instance=cafe-concierge-db
Démarrer le proxy d'authentification Cloud SQL
Le proxy d'authentification Cloud SQL fournit une connexion sécurisée et authentifiée de Cloud Shell à votre instance Cloud SQL, sans avoir besoin d'ajouter des adresses IP à la liste blanche. Il est déjà préinstallé sur Cloud Shell.
cloud-sql-proxy ${GOOGLE_CLOUD_PROJECT}:${REGION}:cafe-concierge-db --port 5432 &
Le suffixe & de la commande permet au proxy de s'exécuter en arrière-plan. Vous devriez voir un résultat confirmant que le proxy est prêt, comme indiqué ci-dessous.
[your-project-id:your-region:cafe-concierge-db] Listening on 127.0.0.1:5432 The proxy has started successfully and is ready for new connections!
Vérifier la connexion
Testez votre capacité à vous connecter à la base de données via le proxy :
psql "host=127.0.0.1 port=5432 dbname=agent_db user=postgres password=$DB_PASSWORD" -c "SELECT 'Connection ok' AS status;"
Vous devriez obtenir le résultat suivant :
status --------------------- Connection ok (1 row)
9. Vérifier la mémoire persistante entre les sessions
Cette étape prouve que la mémoire de votre agent survit à la réinitialisation lorsque nous nous assurons que cafe_concierge/.adk/session_db (la base de données locale) est supprimée et s'étend sur les sessions de conversation.
Démarrer l'agent
Assurez-vous que le proxy d'authentification Cloud SQL est toujours en cours d'exécution (vérifiez avec les jobs). Si ce n'est pas le cas, redémarrez-le :
if ss -tlnp | grep -q ':5432 '; then
echo "Cloud SQL Auth Proxy is already running."
else
cloud-sql-proxy ${GOOGLE_CLOUD_PROJECT}:${REGION}:cafe-concierge-db --port 5432 &
fi
Ensuite, lançons l'UI de développement d'ADK en spécifiant la base de données comme service de session.
uv run adk web --session_service_uri postgresql+asyncpg://postgres:${DB_PASSWORD}@127.0.0.1:5432/agent_db
Ouvrez l'aperçu sur le Web sur le port 8000 et sélectionnez cafe_concierge.
Test 1 : Passer une commande et définir des préférences
Dans la première session, exécutez les invites suivantes :
Show me the menu
I'm vegan
What can I eat?
I'll have a cold brew and banana bread
Test 2 : Survivre à un redémarrage
Arrêtez l'interface utilisateur de développement avec Ctrl+C et assurez-vous que le session.db local est supprimé.
rm -f cafe_concierge/.adk/session.db
Ensuite, réexécutez le serveur de l'UI de développement.
uv run adk web --session_service_uri postgresql+asyncpg://postgres:${DB_PASSWORD}@127.0.0.1:5432/agent_db
Ouvrez l'aperçu sur le Web sur le port 8000, sélectionnez cafe_concierge, puis démarrez une nouvelle session. Posez ensuite
What are my dietary preferences?
L'agent répond en indiquant vos préférences enregistrées : végan. Les données ont survécu au redémarrage, car elles sont désormais stockées dans PostgreSQL et non dans le stockage local. Il en sera de même si nous créons une session, car l'état user: est conservé dans chaque nouvelle session de cet utilisateur.

Inspecter directement la base de données
Ouvrez un nouvel onglet de terminal dans Cloud Shell et interrogez la base de données pour afficher les données stockées :
psql "host=127.0.0.1 port=5432 dbname=agent_db user=postgres password=$DB_PASSWORD" -c "\dt"
Vous devriez voir des tableaux créés automatiquement par l'ADK pour stocker les sessions, les événements et l'état, comme dans cet exemple.
List of relations Schema | Name | Type | Owner --------+-----------------------+-------+---------- public | adk_internal_metadata | table | postgres public | app_states | table | postgres public | events | table | postgres public | sessions | table | postgres public | user_states | table | postgres (5 rows)
Résumé du comportement des états
Clé d'état | Préfixe | Portée | Partagé entre les sessions ? |
| (aucun) | Session | Non |
|
| Utilisateur | Oui |
10. Félicitations / Nettoyage
Félicitations ! Vous avez créé un agent d'IA persistant avec état à l'aide de l'ADK et de Cloud SQL.
Connaissances acquises
- Créer un agent ADK avec des outils personnalisés qui lisent et écrivent l'état de la session
- Différence entre l'état à portée de session (sans préfixe) et l'état à portée utilisateur (préfixe
user:) - Pourquoi le
session.dblocal par défaut de l'ADK ne convient qu'au développement : toutes les données sont perdues lors de la suppression (et faciles à supprimer, sans sauvegarde), ne convient pas au déploiement sans serveur qui est sans état - Provisionner une instance Cloud SQL PostgreSQL et s'y connecter avec le proxy d'authentification Cloud SQL
- Se connecter à DatabaseSessionService avec PostgreSQL sur Cloud SQL avec un minimum de modifications de code : mêmes outils, même agent, backend différent
- Comment l'état de portée utilisateur persiste-t-il dans différentes sessions de conversation ?
Nettoyage
Pour éviter que les ressources créées dans cet atelier de programmation ne soient facturées sur votre compte Google Cloud, nettoyez-les.
Option 1 : Supprimer le projet (recommandé)
Le moyen le plus simple d'effectuer un nettoyage consiste à supprimer le projet. Toutes les ressources associées au projet sont alors supprimées.
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
Option 2 : Supprimer des ressources individuelles
Si vous souhaitez conserver le projet, mais supprimer uniquement les ressources créées dans cet atelier de programmation :
gcloud sql instances delete cafe-concierge-db --quiet