1. Introduction

La première semaine, nous vous avons demandé qui dit quoi et qui fait quoi. La deuxième semaine, nous avons demandé qui décide de ce qui sera diffusé ensuite. La troisième semaine, nous vous avons demandé ce qu'une course laisse derrière elle. Cette semaine, la conversation se termine. La question est de savoir ce qui en ressort. Il s'avère que la nature de l'objet détermine où il va.
L'archive est l'endroit où la vallée se rend lorsqu'un problème est survenu. Une tour qui enregistre tout et Vesper, l'archiviste, au bureau du rez-de-chaussée. Votre lanterne s'éteint la nuit. Va demander.
Elle est agréable à côtoyer. Un mois plus tard, elle est également ravie de vous rencontrer.
Un enregistrement n'est pas un souvenir.
Cette phrase constitue l'intégralité de l'atelier. Vous allez gravir quatre niveaux, chacun correspondant à un étage de la tour :
rung | le sol | Ce dont il se souvient | ce qui le maintient |
1 | le bureau et le premier étage. | cette visite |
|
2 | au deuxième étage, dans votre tiroir. | ce visiteur | le préfixe |
3 | troisième étage, tour | ce qui a été dit | Memory Bank Vertex AI |
4 | le quatrième étage, la saison | toute la vallée | BigQuery |
Chaque échelon franchi est dû à la chute d'un élément de l'échelon inférieur.

Vous connaissez déjà les cinq façons d'oublier de l'archiviste, car chacune d'elles vous est arrivée lors d'un appel d'assistance :
ce qu'elle dit | ce qui n'a pas fonctionné ; | |
~~1~~ | ~~Pouvez-vous me redonner cette référence ?~~ | ~~Oubli dans une même conversation~~ : ce problème a été résolu au cours de la troisième semaine |
~~2~~ | ~~Je vous ai transféré. Veuillez recommencer depuis le début.~~ | ~~l'historique est mort avec le processus~~ — la semaine 3 a également corrigé ce problème |
3 | Bienvenue ! Que puis-je faire pour vous ? | à une personne ayant une demande ouverte le mois dernier |
4 | Pouvez-vous décrire les dommages ? | elle a regardé la lanterne la dernière fois |
5 | Nous n'avons jamais vu ça. | 31 personnes ont posé cette question cette saison |
La ligne 3 correspond à cette semaine. Il échoue de trois manières différentes : une nouvelle visite (chapitre 2), une phrase sans ligne sur le reçu (chapitre 3) et une archive qui n'existe que dans le processus (chapitre 4). Chaque manière correspond à un chapitre. La quatrième ligne est à vous : look() dans archive/agent.py, elle lit une marque sur une photo. La ligne 5 correspond au chapitre 5 et est facultative.
Vous n'avez pas besoin des semaines 1 à 3. Un agent est un modèle doté d'une instruction et de quelques outils. Pour le reste, cette semaine parle d'elle-même.
Vous allez écrire trois lignes, et chacune d'elles est un concept de mémoire :
la ligne | Qu'est-ce que c'est ? |
| L'état est écrit par le code, jamais par la conversation. |
| un préfixe est une durée de vie |
| la politique de rappel : le fichier n'est pas mémorisé |
Une ligne supplémentaire est déjà là pour vous : la règle d'écriture, await ctx.add_events_to_memory(...). Le chapitre 3 vous explique ce qu'elle fait avant que vous n'écriviez la ligne qui l'utilise.
Les deux autres niveaux ne sont pas des modifications : vous construisez une tour (un Agent Engine qui héberge Memory Bank) et le même code s'y connecte de lui-même, et vous chargez un entrepôt (BigQuery), y superposez un graphique et remettez au même agent deux requêtes régies : une par signification et une par connexion.
Chaque chapitre exécute la même boucle, que vous utiliserez sur vos propres agents : lire le code → écrire la ligne → l'observer dans la tour. Rien ne s'exécute en premier, rien n'est redémarré et rien n'est annulé avec Ctrl+C : chaque modification est prise en compte dans le message suivant, et la connexion à la tour est une ligne dans un fichier que l'archive relit à chaque requête. La tour est un dessin qui se redessine : elle lit les mêmes fichiers que vous modifiez et comporte trois boutons : 🌙 met fin à la journée, 🗓 démarre la prochaine visite et 🔥 vous oublie. Tout le reste se fait dans le code et le terminal.
Deux emplacements, et ils ne changent jamais de tâche : l'onglet 1 est le terminal, l'onglet 2 est l'archive. Le banc d'essai (adk web) n'apparaît qu'une seule fois, au chapitre 1, pour un aperçu de l'état brut de la session. Vous n'en aurez plus besoin ensuite. Chaque 👉 ci-dessous indique le type de contenu. 👉💻 correspond à l'onglet 1, 👉🖥 à l'onglet 2 et 👉🔬 à l'atelier. 👉📖 Ouvrir un fichier et le lire : rien à modifier. 👉✏️ C'est le type d'étape qui permet de modifier un fichier. Chaque fois qu'une étape vous demande de dire quelque chose à Vesper, le message exact se trouve dans le bloc juste en dessous. Copiez-le tel quel. De plus, une section dont l'en-tête se termine par — lecture seule ne nécessite aucune saisie, aucun collage ni aucun clic : le code qu'elle contient se trouve déjà dans le dépôt et est déjà en cours d'exécution. Il est imprimé pour que vous puissiez le lire.
La phrase au-dessus de la porte de Vesper est celle qui se trouve en haut. La phrase de cette semaine est la dernière de la quatrième semaine de la saison :
Les faits et les préférences appartiennent à des magasins différents.
2. 🧰 Configuration
- Quoi : pointez sur un projet ou collez une clé, installez et vérifiez que la chaîne d'outils est verte.
- Pourquoi : aucun élément n'est démarré ici. Chaque serveur démarre juste avant l'étape qui en a besoin. Ainsi, lorsqu'un écran s'ouvre, vous savez à quelle commande il appartient.
- Comment faire : un script pour créer le projet, un script pour installer et vous orienter vers Vertex AI, et un script de prévol pour lire votre code et vous indiquer où vous en êtes.
Tout ce qui se trouve dans cet atelier s'exécute dans Cloud Shell. Python, uv et gcloud y sont déjà installés. Gemini est accessible via Vertex AI à l'aide de vos propres identifiants. Cet atelier ne contient aucune clé API et vous n'avez rien à installer sur votre ordinateur portable.
Il y a une chose que cet atelier ne peut pas vous fournir : un projet Google Cloud avec la facturation activée. L'étape 1 vous permet d'obtenir un compte qui peut payer le projet. L'étape 4 transforme ce compte en projet ou reprend le projet Agent Valley que vous avez déjà créé au cours de la première, deuxième ou troisième semaine. Effectuez-les dans cet ordre : chaque étape après la quatrième lit le projet sur lequel l'étape 4 s'arrête.
1) Obtenir un compte avec facturation (~1 min)
🌐 Faites-le avant toute autre chose. Connectez-vous avec un compte Google pour lequel la facturation est activée. N'importe quel compte de ce type fonctionne. Si ce n'est pas le cas, démarrez un essai sans frais. Vous obtiendrez ainsi un compte de facturation, ce qui est tout ce dont vous avez besoin pour l'étape 4.
2 · Ouvrir Cloud Shell (environ 1 min)
🌐 Cliquez sur Activer Cloud Shell en haut de la console Google Cloud (icône en forme de terminal dans l'en-tête).

🌐 Cliquez sur Ouvrir l'éditeur (icône en forme de dossier ouvert avec un crayon). L'éditeur Cloud Shell s'affiche avec un explorateur de fichiers sur la gauche. C'est là que vous travaillerez chaque fois qu'une étape sera marquée 👉✏️.

🌐 Si vous êtes invité à autoriser l'accès à un moment donné, cliquez sur Autoriser pour continuer.
🌐 Ouvrez un terminal dans l'éditeur (c'est-à-dire l'onglet 1). Chaque étape 👉💻 s'y exécute, sauf indication contraire. L'onglet 2 correspond à l'archive. Vous l'ouvrez au chapitre 1, juste avant l'étape qui en a besoin. Si le terminal ne se trouve pas déjà en bas de l'écran, ouvrez-le en cliquant sur Affichage → Terminal :

🌐 Vérifiez avec quel compte vous êtes connecté. Il doit s'agir de celui de l'étape 1 :
gcloud auth list
3 · Obtenir l'atelier (environ 1 min)
💻 Clonez le dépôt. Il s'agit du dépôt Archive, et non de celui de la semaine 1, de la semaine 2 ou de la semaine 3 :
cd ~
git clone https://github.com/cuppibla/agent-valley-archive
cd agent-valley-archive
4 · Créez votre projet ou réutilisez celui d'une semaine précédente (environ 2 min)
💻 Un script trouve votre compte de facturation, y crée un projet et pointe Cloud Shell vers ce projet. Si vous avez effectué la semaine 1, la semaine 2 ou la semaine 3, le projet Agent Valley est trouvé en premier et il vous est proposé de le réutiliser. Répondez "Oui" et vous n'aurez pas à vous soucier d'un deuxième projet facturable :
cd ~/agent-valley-archive
./setup_project.sh
👀 Attendez-vous à un ✓ pour le compte de facturation qu'il a choisi, un ✓ pour le projet qu'il a créé ou réutilisé, et une fin comme celle-ci :
cd ~/agent-valley-archive
Project ready: agent-valley-4271
Next: ./setup_codelab.sh
agent-valley-4271 est l'ID de votre projet. Le vôtre sera différent. Quatre choses se passent :
facturation | prend le compte | |
project | recherche un projet Agent Valley que vous possédez déjà (semaine 1, 2 ou 3) et propose de le réutiliser. Sinon, il crée | |
sélectionne | écrit l'ID dans | |
waits | interroge jusqu'à ce que le projet soit réellement autorisé à diffuser des annonces, pendant deux minutes maximum. | |
🌐 Le même projet se trouve désormais dans la console. Son ID figure dans la fiche Informations sur le projet du tableau de bord :

5 : Installer et pointer vers Vertex AI (~3 min)
💻 Installez uv, exportez les trois variables qui envoient ADK à Vertex AI, puis exécutez la configuration :
cd ~/agent-valley-archive
curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.local/bin/env
export GOOGLE_GENAI_USE_VERTEXAI=TRUE
export GOOGLE_CLOUD_PROJECT=$(gcloud config get project)
export GOOGLE_CLOUD_LOCATION=global
./setup_codelab.sh
$(gcloud config get project) a quelque chose à renvoyer, car l'étape 4 l'a défini. C'est pourquoi l'étape 4 vient en premier.
setup_codelab.sh est idempotent et peut être réexécuté un nombre illimité de fois. Elle effectue cinq opérations, dans l'ordre :
api | lit l'étape 4 du projet sélectionné et active | |
uv env |
| |
site | exécute | |
.env | écrit les variables que lit l'atelier : | |
model check | effectue un véritable appel à Gemini. Ainsi, un projet de mauvaise qualité échoue lors de la configuration, et non plus tard dans un chapitre. | |
6 · Prouve que c'est vert (environ 1 min)
💻 Exécutez le vol d'essai : chaque coche correspond à une véritable vérification, et non à une supposition :
cd ~/agent-valley-archive
uv run python scripts/preflight.py
👀 Le test avant vol pose une question au modèle pour vérifier que vos identifiants fonctionnent, vérifie que les packages de l'archive sont en place, puis lit votre code et affiche la barre de progression de la semaine :
cd ~/agent-valley-archive
desk ▢ the slip · write_down writes nothing chapter 1 · EDIT ONE
floor 1 ✓ the file · SqliteSessionService chapter 1, read only
floor 2 ▢ the drawer · CASE = "case" chapter 2 · EDIT TWO
floor 3 ✓ what was said · closing time files the day chapter 3, read only
floor 3 ▢ the asking · recall never looks chapter 3 · EDIT THREE
floor 3 ▢ the tower · InMemoryMemoryService chapter 4 · built, not edited
floor 3 ✓ the rules · USER_PREFERENCES, LANTERN_CONTEXT chapter 4, read only
Trois sont déjà cochées. Ce sont ceux que vous ne faites que lire. Trois sont des lignes que vous écrivez, une est une tour que vous construisez. Exécutez à nouveau le test avant vol à tout moment de l'atelier. Il vous indiquera où vous en êtes, car il lit vos fichiers, et non une checklist.
3. Session, État, SqliteSessionService
- Quoi : écrivez une ligne, démarrez l'établi une fois et regardez le papier se remplir, puis faites de même dans la tour, puis lisez pourquoi il survit à la nuit.
- Pourquoi : la première chose à savoir sur la mémoire, c'est que rien n'est mémorisé en soi. Quelqu'un l'écrit.
- How : une ligne dans
agent.py, puis ne modifiez rien d'autre.
EDIT ONE
👉📖 Ouvrez archive/agent.py et recherchez write_down. Lisez jusqu'au 👉 :
case = dict(tool_context.state.get(CASE, {}))
if case.get(field):
return {"already_written": {field: case[field]}}
case[field] = value
# 👉 EDIT ONE — chapter 1. She heard you. Nothing was written. Delete the
# "# " in front of the next line, then save — the slip is session state,
# and state is written by code, never by the conversation:
# tool_context.state[CASE] = case
return {"written": {field: value}}
La fonction crée le reçu dans un dict local, puis le renvoie. Un dict local disparaît avec l'appel. Exécutez-le tel quel et Vesper vous entendra parfaitement : quatre appels write_down sont déclenchés, chacun répond "written", et l'état de la session reste vide, car rien ne l'a jamais atteint. Elle vous a entendu. Aucun texte n'a été saisi.
👉✏️ Toujours dans archive/agent.py, à l'intérieur de write_down : supprimez le # devant une ligne, c'est-à-dire le # et l'espace qui le suit. Avant :
case[field] = value
# 👉 EDIT ONE — chapter 1. She heard you. Nothing was written. Delete the
# "# " in front of the next line, then save — the slip is session state,
# and state is written by code, never by the conversation:
# tool_context.state[CASE] = case
return {"written": {field: value}}
Après :
case[field] = value
# 👉 EDIT ONE — chapter 1. She heard you. Nothing was written. Delete the
# "# " in front of the next line, then save — the slip is session state,
# and state is written by code, never by the conversation:
tool_context.state[CASE] = case
return {"written": {field: value}}
Économisez.
Le reçu se remplit
👉💻 Démarrez le workbench. C'est la seule fois que vous l'ouvrez dans l'atelier. Il s'agit de la seule fenêtre qui affiche l'état de la session sous forme de code JSON brut :
cd ~/agent-valley-archive
uv run adk web . --allow_origins="*"
👉🔬 Ouvrez l'atelier avec Aperçu sur le Web → Aperçu sur le port 8000 (le bouton "Aperçu sur le Web" est l'icône en forme d'œil au-dessus d'une fenêtre en haut à droite de Cloud Shell). Sélectionnez archive, puis cliquez sur État dans le panneau de gauche avant de saisir quoi que ce soit.
👀 Vide. Personne n'a encore rien dit.
👉🔬 Maintenant, dis ceci en un seul message :
Hi! My lantern keeps going out at night. My case number is k7f2, and there's a little q7 stamped on the base.
👀 Quatre chips write_down sont disponibles. Cliquez sur l'une d'elles et lisez le JSON : "written": {"no": "k7f2"}. Cliquez à nouveau sur État.

case {"no": "k7f2", "item": "lantern", "mark": "q7",
"symptom": "keeps going out at night"}
👀 Vide, puis plein, dans un même message. C'est ce dont elle se souvient, et cela n'est pas apparu tout seul. Vous avez écrit la ligne qui l'écrit. C'est tout le mécanisme : une fonction simple qui écrit dans tool_context.state et une instruction qui lui dit de l'utiliser chaque fois que le visiteur dit quelque chose qui correspond à une ligne sur le bulletin.
👉 🔬 Demandez-lui :
What's my case number?
👀 k7f2. Elle lit le reçu. Sans EDIT ONE, elle vous l'aurait demandé : ligne 1 de la liste d'assistance, dans une conversation.
Les deux gardes sont le reçu qui est un formulaire papier : quatre courtes lignes, chacune écrite une seule fois. Elles sont plus importantes qu'il n'y paraît. Sans eux, le modèle découvre qu'il peut verser toute la conversation dans symptom, et le chapitre 3 – dont le but est de montrer que le bordereau ne comporte pas de ligne pour cela – cesse discrètement d'être vrai. La forme d'un magasin est appliquée ou non par le code qui l'écrit.
Maintenant, allez à la tour.
👉💻 Vous avez terminé de travailler avec l'atelier. Vous pouvez le laisser en cours d'exécution ou fermer son onglet. Le reste de l'atelier se trouve dans l'archive. Ouvrez un deuxième onglet de terminal (onglet 2 : Archive) :
cd ~/agent-valley-archive
bash valley.sh
👉 🖥 Ouvrez l'archive en cliquant sur Aperçu sur le Web → Modifier le port, saisissez 3440, puis cliquez sur Modifier et prévisualiser. 3440 ne figure pas dans la liste rapide de l'aperçu Web (8080 est la valeur par défaut). Vous devez donc le définir manuellement cette fois-ci. Appuyez sur ▶ Démarrer, puis sur L'archive. Vous êtes à la porte. Choisissez le nom et l'espèce de la personne qui est venue vous voir, puis entrez.

👀 Un bâtiment. Vesper se trouve au bureau du rez-de-chaussée. C'est là que vous devez vous adresser à elle. Au-dessus d'elle : le premier, le deuxième et le troisième étage, ainsi qu'un grenier sombre. Les quatre barreaux correspondent aux quatre étages. Votre familier est assis au rez-de-chaussée, car c'est le seul étage que vous avez atteint. La colonne à côté du dessin indique ce que chaque étage contient actuellement : les quatre mêmes magasins que dans le tableau de l'introduction, dans le même ordre. Rien à droite n'est un bouton.
👉 🖥 Collez les quatre mêmes éléments dans la zone sous la conversation (ce message exact), puis appuyez sur Entrée :
Hi! My lantern keeps going out at night. My case number is k7f2, and there's a little q7 stamped on the base.

👀 Regardez le bureau. Le bulletin se remplit automatiquement, ligne par ligne, sur le dessin et en entier sous le bulletin à côté. Même outil, même état : la tour dessine simplement ce que write_down a écrit, et elle continuera à le faire pour le reste de l'atelier.
Elle se souvient de la nuit précédente : lecture seule
Ce que vous avez écrit et ce que c'est
la ligne | Qu'est-ce que c'est ? | où il se trouve |
| État de la session : écrit par le code, lu par l'instruction | le bureau · |
| le magasin de session : une visite dans un fichier, et non dans un processus. | premier étage · |
Ce palier correspond à une visite et n'expire pas à la fermeture. Elle ne survit pas à la prochaine visite.
4. État de l'utilisateur
- Quoi : revenez un mois plus tard, le reçu a disparu. Cinq personnages vous suivent.
- Pourquoi : une session correspond à une visite. La prochaine visite est une nouvelle session, qui n'a jamais vu la dernière.
- Comment : cinq caractères dans
state.py.


👉 🖥 Appuyez sur 🗓 un mois plus tard. Il s'agit d'une nouvelle session pour le même visiteur, comme Démarrer une nouvelle conversation l'était lors de la troisième semaine.
Bienvenue dans les archives. Que puis-je faire pour vous ?
👉 🖥 Regardez la tour. Au premier étage, un autre livre est posé. Le tiroir du deuxième étage est vide. Le papier sur le bureau est vierge.

👀 Pourquoi : le reçu est enregistré dans l'état de la session, et une session correspond à cette visite. Modifier les visites, modifier les sessions. Rien n'a été transféré, car aucune instruction n'a été donnée en ce sens. La dernière visite est toujours dans le fichier (il s'agit du premier livre du premier étage), mais le reçu a été écrit avec une clé qui n'est valable que pour une seule visite.
EDIT TWO
👉✏️ Ouvrez archive/state.py. Repérez le 👉. Avant :
# 👉 EDIT TWO — chapter 2. Five characters. A key with no prefix lives for one
# visit; `user:` follows the visitor into every visit after this.
CASE = "case"
Après :
CASE = "user:case"
Économisez. Pas de redémarrage : l'archive réimporte votre code à chaque message.
👉 🖥 Collez à nouveau les quatre mêmes éléments, à savoir ce message exact :
Hi! My lantern keeps going out at night. My case number is k7f2, and there's a little q7 stamped on the base.
👉 🖥 Appuyez ensuite à nouveau sur 🗓 un mois plus tard, le même bouton que précédemment.

👀 Le tiroir du deuxième étage porte votre nom. Les quatre champs se trouvent à l'intérieur. Le papier sur le bureau comporte les mêmes quatre lignes que celui que vous avez sorti du tiroir en entrant. Votre familier est passé à l'étage supérieur. Même clé, chaque visite, une seule valeur : c'est le préfixe qui fait son travail.
Le préfixe est une durée de vie.
préfixe | la durée de vie de l'annonce. | à quel étage ; |
(aucun) | cette visite | le bureau |
| chaque visite effectuée par ce visiteur. | au deuxième étage, dans votre tiroir |
| pour tous, pour toujours | une partie du quatrième étage |
| ce tour uniquement : ne monte jamais les escaliers | — |
Une table, quatre tiroirs. Ce chapitre en aborde un.
Elle te connaît maintenant
👉 🖥 Cette visite est toute nouvelle et vous n'y avez encore rien dit. Demandez-lui :
What did I bring in last time?
👀 J'ai noté que vous aviez apporté une lanterne, dossier k7f2. Il est marqué q7 et vous avez mentionné qu'il s'éteint la nuit. Chaque mot qui sort du tiroir, et non de la conversation : cette visite ne comporte qu'un seul message, et celui-ci n'a pas de nom. C'est le rôle de l'état au niveau de l'utilisateur : une clé user: est présente avant même que le visiteur ne dise un mot, à chaque visite.
Le tiroir contient les quatre lignes du reçu, et rien d'autre. Ce que vous dites qui n'est pas indiqué sur le reçu (ce que vous avez essayé, pourquoi cela vous intéresse, si vous en voulez un nouveau) n'est pas enregistré et disparaît un mois plus tard. Le tiroir chevauche le mois. Une phrase, en revanche, n'en a pas. Le chapitre 3 traite de ce sujet.
Ce que vous avez écrit et ce que c'est
la ligne | Qu'est-ce que c'est ? | où il se trouve |
| Un préfixe est une durée de vie : la même clé, limitée au visiteur au lieu de la visite | Étage 2 · État |
Cette marche est atteinte par un visiteur. Le tiroir vous suit, mais pas la conversation.
5. InMemoryMemoryService
- Quoi : lisez la ligne qui indique le jour, écrivez la ligne qui pose la question, puis indiquez une heure de clôture et posez une question.
- Pourquoi : le bulletin est un formulaire. Un formulaire comporte les lignes que vous lui avez fournies. Les gens ne parlent pas en lignes, et enregistrer ce qu'ils ont dit ne suffit pas à s'en souvenir.
- Comment : lisez
file, une ligne dansrecall, puis une 🌙, un 🗓 et une question.

Ce qu'elle fait en chemin : lecture seule
Le fichier n'est pas mémorisé
Cette ligne met la journée en veille. Il ne déduit rien. Une étagère pleine de cartes est aussi utile qu'une étagère vide si personne ne la regarde. Et comme le code est expédié, personne ne la regarde : recall, le nœud qui s'exécute avant Vesper sur chaque question, ne demande rien à la tour. Un stockage dont vous ne pouvez pas vous souvenir au bon moment n'est pas une mémoire, mais un journal. L'observation est l'autre moitié, et c'est à vous de l'écrire.
TROISIÈME ÉTAPE : LA DEMANDE
👉📖 Dans archive/agent.py, recherchez recall, la fonction juste au-dessus de file. Il s'agit d'un nœud de fonction simple qui s'exécute avant Vesper pour chaque question. Ce n'est pas le modèle qui décide quand chercher, ce qui signifie que les moments où il ne trouve rien sont également visibles. Lisez jusqu'au 👉 :
if query.strip():
try:
# 👉 EDIT THREE — chapter 3. Filed is not remembered: the cards are on
# the shelf and nobody is looking at them. Delete the "# " in front
# of the next line, then save:
# found = await ctx.search_memory(query)
pass
except ValueError:
# no memory service wired on this runner — degrade, do not crash
pass
👉✏️ Toujours dans archive/agent.py, à l'intérieur de recall : supprimez le # devant une ligne, ainsi que le # et l'espace qui le suit. Avant :
try:
# 👉 EDIT THREE — chapter 3. Filed is not remembered: the cards are on
# the shelf and nobody is looking at them. Delete the "# " in front
# of the next line, then save:
# found = await ctx.search_memory(query)
pass
except ValueError:
Après :
try:
# 👉 EDIT THREE — chapter 3. Filed is not remembered: the cards are on
# the shelf and nobody is looking at them. Delete the "# " in front
# of the next line, then save:
found = await ctx.search_memory(query)
pass
except ValueError:
Laissez pass à sa place. Il ne fait rien pour le moment, car found est déjà None au-dessus.
Économisez. Aucun redémarrage.
Deux lignes, deux règles, dont une que vous avez écrite. La règle d'écriture détermine ce qui est conservé et quand (heure de fermeture, toute la journée). La politique de rappel détermine quand et avec quoi effectuer la recherche (chaque question, la question elle-même). ADK vous fournit les verbes (add_events_to_memory, search_memory) et ne s'immisce pas dans la règle. C'est la bonne répartition, et c'est pourquoi vous deviez écrire la demande.
Heure de fermeture
👉🖥 Cite trois choses pour lesquelles le bordereau ne prévoit pas de ligne. Un ou trois messages :
I read by it at night, so night is exactly when I need it.
I've tried hanging it higher. No change.
I don't want a new one — it was a gift.

👉 🖥 Appuyez ensuite sur 🌙 C'est tout pour aujourd'hui.

👀 Regardez le bureau. Les trois choses que vous avez dites se détachent du papier et flottent dans les airs, puis atterrissent au troisième étage. Sous les fiches à côté de la tour, elles sont listées : une fiche pour chaque message que vous avez envoyé, marquée quote, vos phrases mot pour mot et dans ce processus au-dessus. La lampe sur le bureau reste allumée jusqu'à ce qu'ils aient atterri.
Un mois plus tard, elle sait
👉 🖥 Appuyez sur 🗓 un mois plus tard, puis posez la question suivante :
What have I already tried?
👀 Vous avez essayé de le suspendre plus haut, mais cela n'a pas aidé. Elle le sait. Le reçu ne comporte pas de ligne pour cela et n'en a jamais comporté. La caissière n'a donc pas pu répondre à cette question. recall a trouvé la carte, l'a inscrite dans ctx.state["recalled"] et a écrit cette instruction. Une ligne correspond à la différence.
Et tout se passe dans sa tête
Regardez sous les cartes à côté de la tour : dans ce processus. Pour le moment, la mémoire est InMemoryMemoryService, un dictionnaire dans bash valley.sh, et elle existe exactement aussi longtemps que ce processus. Ferme la tour ce soir et ouvre-la demain : les livres sont au premier étage, le tiroir au deuxième et le troisième est sombre. La demande est toujours présente dans le fichier. Ce que vous avez dit faisait partie du processus, et le processus a disparu.
La persistance n'est pas de la mémoire.
Il y a deux problèmes avec la troisième affirmation : elle est en cours et elle est exprimée avec vos propres mots (il s'agit d'une citation, pas d'un fait). Le chapitre suivant corrige les deux, sans aucun code.
Ce que vous lisez, ce que vous écrivez et ce que c'est
la ligne | Qu'est-ce que c'est ? | où il se trouve |
| la règle d'écriture : une journée entière, à l'heure de fermeture. | Troisième étage : le service de mémoire |
| la politique de rappel : chaque question, avant qu'elle ne réponde |
|
Cette étape consiste à identifier ce qui a été dit et à le conserver dans un dictionnaire au sein d'un processus, avec vos propres mots. Les deux moitiés de cette affirmation sont fausses, et le chapitre suivant corrige les deux sans aucun code.
6. MemoryBank
- Quoi : un script crée une Memory Bank. Les deux lignes que vous avez déjà commencent à y écrire des faits et à les relire.
- Pourquoi : un service de mémoire est un service. L'emplacement de l'archive est une décision de déploiement, et non une décision d'agent. Vous pouvez le modifier sans toucher à l'agent.
- Comment faire : exécutez
make_tower.py, dites trois phrases, appuyez sur 🌙, appuyez sur 🗓, posez une question. Ensuite, un aperçu en lecture seule de l'écriture et de la lecture.
Construire la tour
Le troisième étage du chapitre 3 était un dictionnaire Python à l'intérieur de bash valley.sh. Memory Bank est la version gérée de ce niveau. Elle réside sur une instance Agent Engine dans votre projet, conserve des faits extraits de la journée au lieu de vos phrases et les trouve par signification plutôt que par mots partagés. Vous n'avez pas besoin de déployer Vesper sur un Agent Engine pour l'utiliser. Une instance sans aucun déploiement héberge toujours une Memory Bank, et c'est ce que le script construit : une tour sans personne, dont le seul rôle est de conserver les cartes.
👉 💻 Dans l'onglet 1 (environ une minute) :
cd ~/agent-valley-archive
uv run python scripts/make_tower.py
👀 À quoi s'attendre ?
building the tower in YOUR_PROJECT / us-central1 — about a minute...
built, with the two topics in archive/topics.py configured on it.
resource: projects/.../locations/us-central1/reasoningEngines/6792...
AGENT_ENGINE written to .env
Next — nothing to restart. The Archive reads .env on every message:
look at floor three — under the cards it now says Memory Bank.
(adk web, if you use it: --memory_service_uri "agentengine://projects/.../reasoningEngines/6792...")
Un appel de SDK, agent_engines.create(), et une ligne écrite dans .env. L'archive relit ce fichier à chaque demande. Il n'y a donc rien à redémarrer.
La vidéo au service
👉🖥 Regardez le troisième étage : la tour se redessine d'elle-même en quelques secondes. Sous les cartes, il est désormais indiqué Memory Bank, et l'étagère est vide : les trois citations du chapitre 3 étaient en cours, et ce n'est pas le processus. Répète les trois phrases, en un ou trois messages :
I read by it at night, so night is exactly when I need it.
I've tried hanging it higher. No change.
I don't want a new one — it was a gift.
👉 🖥 Appuyez sur 🌙, c'est tout pour aujourd'hui. La fermeture prend environ huit secondes maintenant : la tour est en train de se rétracter. Ensuite, regarde au troisième étage.

👀 Les cartes ne sont pas vos phrases. Ils disent par exemple J'utilise ma lanterne pour lire la nuit, et c'est à ce moment-là qu'elle s'éteint et J'ai déjà essayé de suspendre ma lanterne plus haut, chacun marqué fact avec une date. Distillation : Ce qui a été saisi était une conversation. Ce qui est ressorti, ce sont des faits.
👉 🖥 Appuyez sur 🗓 un mois plus tard. Il s'agit d'une nouvelle visite. Par conséquent, tout ce que vous venez de dire n'est plus dans la conversation. Posez-lui cette question, qui ne partage aucun mot avec les cartes :
Should I just get a different lamp?
👀 Comme il s'agissait d'un cadeau, vous avez indiqué que vous ne souhaitiez pas remplacer votre lanterne et que vous aviez déjà essayé de la suspendre plus haut. Chaque mot de la carte était vrai, et seule la carte aurait pu lui dire : cette visite est un message ancien. Recherche de similarités : La tour correspond à la signification, et non aux mots : la question indique lampe et différent, tandis que la carte indique lanterne et remplacer. Et il est maintenant hors du processus : éteignez la tour ce soir et les cartes seront là demain, car elles se trouvent sur l'Agent Engine, et non dans bash valley.sh.
Écriture et lecture : lecture seule
Le droit à l'oubli

👉 🖥 Appuyez sur 🔥 Oublie-moi sous la zone de message.
👀 Trois étages sont éteints, mais pas un :
ce qu'il contient. | après 🔥 | |
troisième étage, les cartes | ce dont elle se souvient : les faits que la Banque de mémoire a extraits de vos visites. |
|
au deuxième étage, dans le tiroir |
| effacée |
le bureau, le reçu | la copie de la demande pour cette visite ; | effacée |
premier étage, les livres | les visites elles-mêmes : une session dans | inchangé : le nombre ne change pas |
Les livres sont l'enregistrement : ils indiquent qu'une visite a eu lieu, le jour où elle s'est déroulée et ce qui a été dit. Les fiches et le tiroir sont la mémoire : ce qu'elle a retenu de ces visites et ce qu'elle emporte avec elle pour la prochaine. Une demande d'oubli concerne la mémoire, c'est-à-dire les faits dérivés sur une personne et l'état qui les suit. La décision de conserver ou non l'enregistrement d'une visite est distincte et repose sur des raisons différentes (piste d'audit, historique d'assistance, etc.). Ce laboratoire le conserve à dessein pour que vous puissiez voir les deux se séparer sous vos yeux : l'enregistrement et la mémoire ne sont pas la même chose, et l'oubli de l'un n'affecte pas l'autre. Il s'agit de la phrase au-dessus de la porte de Vesper, vue de l'autre côté.
L'abstraction de mémoire ADK comporte add_events_to_memory et search_memory. Il n'y a pas de bouton de suppression. L'oubli est une action de gouvernance, et non une action d'agent. Il se trouve donc dans l'application – archive/tower.py, memories.delete sur le client brut – où le modèle ne peut pas l'atteindre par accident. Vous pouvez choisir si un agent peut oublier ou non, exactement comme vous choisissez s'il peut se souvenir de quelque chose.
Ce que vous avez créé et lu, et ce que c'est
la chose | Qu'est-ce que c'est ? | où il se trouve |
| le service de mémoire, en tant que service : une décision de déploiement, en dehors de l'agent | Vertex AI Memory Bank sur un Agent Engine |
| le même emplacement |
|
| ce qui peut être conservé, décidé au moment de l'écriture, et non dans la requête. |
|
🔥 → | L'oubli est une action d'application. L'API de mémoire de l'ADK ne comporte pas de fonction de suppression. |
|
Cette section reprend ce qui a été dit. Un jour passe, un fait ressort, distillé selon ce que les sujets permettent, et le livre au premier étage n'a jamais bougé.
7. GraphRAG
Facultatif.
- Quoi : un script charge le passé de la vallée dans BigQuery, génère des embeddings à l'intérieur de l'entrepôt et superpose un graphique aux tables sans déplacer une ligne. Ensuite, deux questions sont posées à Vesper, qui dispose de deux requêtes régies : une pour ce qui se ressemble et une pour ce qui est connecté.
- Pourquoi : "ressemble à" n'est pas la même chose que "est associé à". Un vecteur indique où chercher, un graphique indique ce qui est associé, et la réponse doit indiquer le chemin parcouru.
- Comment :
bash scripts/season.sh, une fois. Tout le reste de ce chapitre est en lecture seule.
La tour de Vesper est limitée à vous : (app_name, user_id). Les visites d'autres personnes ne font pas partie de sa mémoire, et une recherche plus approfondie ne changerait rien. Elles appartiennent à la vallée, qui les conserve dans un entrepôt. Trente et un visiteurs cette saison ont signalé qu'une lanterne Q7 s'éteignait la nuit, et l'un d'eux en a trouvé la cause. Ce chapitre charge cet entrepôt et y insère deux requêtes fixes.
RAG de graphiques
RAG signifie récupérer, puis générer : trouvez les bons enregistrements, transmettez-les au modèle et laissez-le répondre à partir de ces enregistrements. Le RAG simple récupère les résultats par similarité : il intègre la question et extrait les enregistrements les plus proches. Il trouve les éléments qui ressemblent à la question, et c'est là que s'est arrêtée la tour du chapitre 4. La génération augmentée par récupération (RAG) de graphiques ajoute une deuxième étape de récupération qui suit les arêtes (clés) qu'un entrepôt possède déjà, à partir de toute similitude trouvée, vers tout ce qui y est associé. Les deux étapes répondent à des questions différentes, et ce chapitre vous invite à vous poser les deux :
étape | la question à laquelle il répond ; | comment | dans ce chapitre |
similarité | Où dois-je regarder ? | intégrer la question, |
|
traversée | Qu'est-ce qui est connecté à cela ? |
|
|
de génération | Que dois-je dire au visiteur ? | le modèle, avec le chemin d'accès comme citation. | sa réponse |
Exécuter l'application
La saison est fournie sous forme de fichiers CSV bruts dans season/ (visiteurs, articles, demandes, corrections, saisons), comme le ferait un système d'assistance. Un seul script vous permet de les transférer jusqu'à l'entrepôt. C'est la seule chose que vous exécuterez dans ce chapitre.
👉💻 Dans l'onglet 1 (environ trois minutes ; chaque étape est imprimée au fur et à mesure, et le processus s'arrête à la première étape qui échoue) :
cd ~/agent-valley-archive
bash scripts/season.sh
👀 Lorsque le processus se termine, le quatrième étage de la tour s'allume et la légende à côté indique ouvert.
Ce qu'il a créé : lecture seule
Comment elle le lit : lecture seule
Demandez-lui
👉🖥 Le quatrième étage de la tour est ouvert. Posez-lui la question comme le ferait n'importe quel visiteur :
Has anyone else had a q7 lantern go out at night?

👀 Elle répond : trente et une autres personnes… la plupart ont dit que la flamme était basse et s'est éteinte au bout d'une heure… Marlow la loutre a constaté que les mèches n'étaient pas assez trempées. La dernière ligne de sa réponse est le chemin d'accès. Voici sa réponse. Lisez-la, mais ne la lui renvoyez pas :
mark q7 → 31 visits this season → 10 different things said → the wicks in the q7 batch were dipped too shallow — they drown in the oil and starve in an hour
Le chemin d'accès est la citation. Chaque saut est une arête du graphe, et une arête est une clé. N'importe qui peut donc le refaire et obtenir le même résultat (31). Personne ne peut revenir sur un score de similarité. Si elle indique, juste avant le chemin d'accès, que les lignes ont été renvoyées par trois jointures parce que le projet n'a pas de réservation de graphique, cela signifie que l'édition de votre projet refuse GRAPH_TABLE : les lignes et le chemin d'accès sont identiques.
👉 🖥 Maintenant, supprimez la marque et envoyez ceci :
Has anyone else had a lantern that keeps dying once the sun is down?
👀 Elle arrive au même trente et un, et au même chemin. Ce qui a changé, c'est le chemin : season_search a couru en premier, a trouvé cinq visiteurs qui semblaient identiques (chacun portant q7), a pris cette marque, puis a marché. "Similaire" n'est pas connecté, mais c'est là qu'il faut chercher.
Ce qui a été chargé et ce que c'est
la chose | Qu'est-ce que c'est ? | où il se trouve |
| un entrepôt : colonnes avec des noms et des types |
|
| Étape de similarité : où chercher |
|
| l'étape de parcours : ce qui est connecté ; les tableaux deviennent des nœuds et des flèches |
|
| la seule promenade qu'elle puisse faire ; le chemin est la citation |
|
Quelques dizaines de visiteurs ne justifient pas l'achat d'un entrepôt. Ce chapitre porte sur la forme de la requête, et non sur l'échelle. Agrandissez ce graphique mille fois et le MATCH ne changera pas d'un caractère.
8. Fermer
Trois lignes, une tour, un entrepôt : quatre étages. Aucun redémarrage n'a eu lieu.
le barreau | ce que vous avez fait ; | ce qu'il a acheté. |
ONE |
| une erreur qui existe : l'état est écrit par le code |
DEUX |
| un tiroir qui suit le visiteur ; |
la demande |
| ce qui a été dit, conservé |
TROIS |
| ce qui a été conservé, demandé ; ce qui a été classé n'est pas mémorisé |
la tour |
| une tour qui distille et survit à la nuit. |
les règles |
| uniquement ce qui doit être conservé. |
la saison |
| les visites des autres utilisateurs, par signification et par connexion. |
Éléments remplacés
ADK 2 | ce que vous écririez à la place. | ce que cela vous coûte |
| un dict à côté de la boucle de chat, que vous avez vous-même sérialisé sur le disque ; | le modèle ne peut pas le lire, et vous écrivez le CV et le verrouillage. |
le préfixe | un tableau des utilisateurs et une jointure à chaque tour. | décider où une clé doit être placée, à chaque fois |
| un cron qui génère des transcriptions et le modèle qui décide quand regarder. | il déverse, rien ne distille ; et vous ne voyez jamais les moments où il n'a pas regardé. |
| un magasin de vecteurs, une invite d'extraction, un job de consolidation et "ne retiens pas les anecdotes" dans l'invite. | trois services, et la règle tient jusqu'à ce que le modèle en décide autrement. |
| exporter, intégrer ailleurs, une base de données de graphiques, un job de synchronisation et le modèle écrivant du code SQL | Les données quittent l'entrepôt pour être comprises, et vous découvrez les jointures qu'il a devinées lorsqu'un client |
Trois questions, arrêtez-vous à la première réponse positive
- Est-ce que cela aura de l'importance demain ? Non → ne rien conserver. Il naît et meurt dans la conversation.
- Une fonction peut-elle vérifier cela ? Oui → le panneau. Le code l'écrit, chaque tour le lit, et aucune phrase ne peut le modifier.
- Sinon : la tour. Distillée à partir de ce qui a été dit, recherchée lorsqu'elle est demandée, révisée en fonction de ce qui est dit ensuite.
La phrase
Un enregistrement n'est pas un souvenir. Une mémoire est un enregistrement plus deux décisions : ce qu'il faut conserver et quand regarder. Le type de chose détermine à quel étage elle se trouve.
Les faits et les préférences appartiennent à des magasins différents.
👀 Chaque étage est éclairé. Votre familier est en haut de la liste. Le tampon "Archive" se trouve dans le passeport, et la semaine 5 ouvre le marché nocturne, où Nix anime la scène à voix haute, en temps réel, et tout ce que la tour sait vous accompagne.