Créer des agents d'IA persistants avec ADK et Cloud SQL

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.

a98bbd65ddedd29c.jpeg

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) vers DatabaseSessionService pour 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 :

86307fac5da2f077.png

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).

ccc3214812750f1c.png

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.

54b615cd15f2a535.png

Après avoir attendu un moment, si le résultat suivant s'affiche dans la console, vous pouvez passer à l'étape suivante e576b4c13d595156.png.

Le script exécuté effectue les étapes suivantes :

  1. Vérifier que vous disposez d'un compte de facturation d'essai actif
  2. Recherchez un projet existant dans .env (le cas échéant).
  3. Créez un projet ou réutilisez-en un existant.
  4. Associer le compte de facturation d'essai à votre projet
  5. Enregistrer l'ID du projet dans .env
  6. 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.

9e11ee21cd23405f.png

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-micro est le niveau Cloud SQL le plus petit (et le moins cher), ce qui est suffisant pour cet atelier de programmation.
  • --root-password dé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.

b01e3fbd89f17332.png

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?

376ee6b189657e7a.png

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 :

cd9871699451867d.png

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

user:

Toutes les sessions de cet utilisateur

Oui

app:

Toutes les sessions, tous les utilisateurs

Oui

temp:

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 :

  1. place_order et get_order_summary utilisent des clés sans préfixe (current_order). Cet état est lié à la session en cours. Une nouvelle conversation commence par une commande vide.
  2. set_dietary_preference et get_dietary_preferences utilisent le préfixe user: (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_agent avec 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.

9051b46978c8017b.png

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

user

message

Un message que vous avez saisi dans le chat

cafe_concierge

message

Réponse textuelle de l'agent

cafe_concierge

tool_call

L'agent a décidé d'appeler un outil (nom de la fonction + arguments)

cafe_concierge

tool_response

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"]}

b528f4efd6a9f337.png

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.

5e06fb54f3f0d8d6.png

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_order n'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_preferences a le préfixe user:. 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.

57408cfae5f041ac.png

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.

764eb3885251307d.png

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.

82a5e05434cafe83.png

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.

9c139bf89becb748.png

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 ?

current_order

(aucun)

Session

Non

user:dietary_preferences

user:

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.db local 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.

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