Guide · IA & agents
Mémoire d'agent qui survit au redémarrage
Avec l’Agents SDK OpenAI, une SQLiteSession sur fichier garde l’historique. Sans chemin, elle disparaît avec le processus.
La mémoire dont parle ce guide est l’historique de conversation, pas une base de connaissances. L’Agents SDK OpenAI peut la tenir à votre place avec une session. La page Sessions dit que le runner, avant chaque tour, recharge les items et les place devant la nouvelle entrée, puis enregistre après le tour ce qui vient d’être produit : texte utilisateur, réponse, appels d’outils.
Une SQLiteSession construite avec seulement un identifiant utilise une base en mémoire. Elle meurt avec le processus. Pour qu’un second lancement retrouve le premier, il faut un chemin de fichier, le même identifiant, et la même base. Les commandes ci-dessous n’ont pas été rejouées le 2026-10-18.
Architecture retenue
Le runner charge les items de la session avant le tour, appelle le modèle, puis ajoute les nouveaux items au même stockage. SQLiteSession fournit donc un historique client, pas une mémoire fiable au sens humain : le modèle peut oublier un détail présent, mal l’interpréter ou reprendre une information devenue fausse. La base est la preuve du stockage ; la réponse du modèle ne l’est pas.
Le fichier SQLite reste sur la machine, mais chaque tour chargé dans le contexte part vers l’API du modèle. « Stocké localement » ne veut donc pas dire « jamais transmis ». La page OpenAI sur les contrôles de données distingue les journaux de surveillance des abus de l’état applicatif et décrit les réglages de conservation disponibles. Vérifiez ceux de votre projet avant d’utiliser un historique réel.
Prérequis
pip install openai-agents, comme la page d’accueil du SDK l’écrit.OPENAI_API_KEYdans l’environnement du processus qui lance le script. La page d’accueil le demande pour l’exemple minimal.- Un répertoire où un fichier SQLite peut être créé, et que vous pouvez effacer après l’essai.
- Un fait que vous inventez pour le test, par exemple un nom de code. Ne mettez pas un secret, un token, ou une donnée client dans le prompt : la session l’enregistre.
Ne combinez pas, dans le même run, une session avec conversation_id, previous_response_id, ou auto_previous_response_id. La page Sessions l’interdit. Ces trois options sont une autre continuation, côté serveur OpenAI. Les empiler n’est pas « plus de mémoire ».
Étape 1 : écrire le fait, puis quitter
Le script ne fixe pas de modèle. L’agent sans argument model suit le défaut du SDK. Si un run échoue sur un modèle inconnu, réglez model d’après la documentation des modèles, plutôt que d’en essayer une liste.
import asyncio
import os
from agents import Agent, Runner, SQLiteSession
agent = Agent(
name="Carnet",
instructions=(
"Réponds en une phrase. "
"Si le fait demandé n’est pas dans l’historique de cette session, "
"dis que tu ne l’as pas. Ne le cherche pas ailleurs."
),
)
session = SQLiteSession("carnet-local", "carnet.db")
async def main() -> None:
code = os.environ.get("CODE_TEST", "NORD-17")
result = await Runner.run(
agent,
f"Retiens ce nom de code pour cette session : {code}. Répète-le.",
session=session,
)
print(result.final_output)
items = await session.get_items()
print(f"items {len(items)}")
asyncio.run(main())
Changez CODE_TEST si NORD-17 ne vous convient pas. Le premier lancement doit créer carnet.db dans le répertoire courant. get_items renvoie l’historique. Vous devez y retrouver le message utilisateur qui contient le nom de code. Le texte de l’assistant, lui, n’est pas le critère : le modèle peut mal répéter. L’item stocké, si.
Vérification : le processus s’est terminé, carnet.db est encore sur le disque, et un item contient le nom de code que vous avez envoyé.
Étape 2 : relancer un autre processus
Fermez le terminal ou, au minimum, ne réutilisez pas l’objet Python du premier run. Un objet encore vivant ne prouve pas que le fichier sert. Second script, même identifiant, même chemin :
import asyncio
from agents import Agent, Runner, SQLiteSession
agent = Agent(
name="Carnet",
instructions=(
"Réponds en une phrase. "
"Si le fait demandé n’est pas dans l’historique de cette session, "
"dis que tu ne l’as pas."
),
)
session = SQLiteSession("carnet-local", "carnet.db")
async def main() -> None:
items = await session.get_items()
print(f"items avant {len(items)}")
result = await Runner.run(
agent,
"Quel nom de code t’ai-je donné dans cette session ?",
session=session,
)
print(result.final_output)
asyncio.run(main())
Comparez la réponse au nom de code du premier lancement, et relisez les items. Si items avant vaut 0, le second processus n’a pas ouvert la même base. Causes fréquentes : autre répertoire courant, autre nom de fichier, autre session_id.
Runner.run_sync accepte aussi une session, d’après la page Sessions. Les méthodes get_items, add_items, pop_item et clear_session montrées sur cette page sont asynchrones. Ce brouillon reste en async pour pouvoir les attendre.
Vérification : le nombre d’items avant le second tour est supérieur à zéro, et la réponse contient le nom de code du premier message utilisateur. Si les items sont là et la réponse non, le stockage a marché et le tour suivant a mal relu. Ce n’est pas la même panne qu’une base vide.
Étape 3 : effacer, et constater le vide
clear_session retire les items de cet identifiant. Appelez-le, puis relancez la question. La réponse attendue est que le nom de code n’est plus dans l’historique. pop_item ne fait pas ça : il retire seulement le dernier item. Pour annuler un tour, la page retire d’abord la réponse de l’assistant, puis le message utilisateur. Un seul pop_item laisse la question en place.
Vous pouvez aussi borner ce qui est renvoyé au modèle sans effacer le fichier. SessionSettings(limit=N) ne récupère que les N items les plus récents, via RunConfig.session_settings. Le défaut documenté est limit=None, donc tout l’historique. Un plafond trop bas fait disparaître le premier tour du contexte, alors qu’il est encore dans la base. Pour ce test, ne mettez pas de plafond.
Vérification : après clear_session, get_items est vide pour carnet-local. Un autre identifiant dans le même fichier ne doit pas avoir été touché, si vous en aviez créé un.
Ce qui peut casser
Oublier le chemin de base est la panne la plus nette. SQLiteSession("carnet-local") correspond au défaut documenté :memory:. Le second processus repart de zéro, même avec le même identifiant.
Mélanger une session et conversation_id dans le même run est refusé par le contrat de la page. Prenez l’un ou l’autre. OpenAIConversationsSession stocke l’historique via l’API Conversations, côté OpenAI. Ce n’est pas le fichier local de ce guide. La page dit aussi de ne pas envelopper cette session avec OpenAIResponsesCompactionSession : les deux gèrent l’historique autrement.
Le fichier SQLite contient le texte des tours et les appels d’outils. SQLiteSession n’ajoute pas le chiffrement applicatif montré par EncryptedSession. Ce wrapper utilise Fernet, dérive une clé par session et peut ignorer les items après un TTL. Il exige tout de même une clé maîtresse aléatoire, conservée séparément de la base et réutilisée après un redémarrage. Ce brouillon ne le configure pas. En attendant, ne mettez pas de secret dans le prompt, protégez les droits du fichier et effacez carnet.db après l’essai.
Une session partagée entre workers n’est pas le cas de SQLite sur un fichier local. La page oriente vers Redis, SQLAlchemy ou d’autres backends pour ça. Un fichier SQLite ouvert par plusieurs processus peut se comporter mal. Ce guide suppose un processus à la fois.
Le rappel du nom de code ne prouve pas que l’agent « connaît » votre projet. Il prouve que l’item a été relu. Un fait absent de l’historique doit rester absent. Si le modèle le devine, la consigne n’a pas tenu, et le test est à refaire avec un code moins prévisible.
Comment vérifier
- Premier processus : un item contient votre nom de code, puis le processus quitte.
- Second processus, autre invocation : les items sont encore là, et la réponse les cite.
clear_session, puis une question : plus d’item, et pas de nom de code repris comme s’il était encore stocké.- Contrôle négatif, non rejoué ici : même identifiant sans chemin de fichier. Le second processus ne doit rien retrouver.
Aucune de ces commandes n’a été rejouée le 2026-10-18.
Sources
- OpenAI Agents SDK, sessions
- OpenAI Agents SDK, encrypted sessions
- OpenAI Agents SDK
- OpenAI, data controls in the API platform
Ces pages ont été relues le 2026-10-19. Elles documentent le défaut en mémoire, le chemin de fichier, l’interdiction de combiner une session avec conversation_id, previous_response_id ou auto_previous_response_id, les méthodes get_items / clear_session / pop_item, ainsi que le wrapper chiffré. Le modèle par défaut du SDK n’y est pas nommé. Ce brouillon ne le devine pas et les scripts n’ont pas été exécutés.