Context variables et mémoire d'agent
Mis à jour le 29 juillet 2026
Context variables et mémoire d’agent
Un agent sans mémoire oublie tout entre chaque exécution : il redemande le nom du client à chaque message et repart de zéro à chaque tour. Deux mécanismes complémentaires corrigent cela. Les context variables injectent un état partagé dans l’agent et ses tools, tandis que la mémoire conversationnelle maintient le fil d’une conversation multi-tours.
Context variables : état partagé
Le RunContextWrapper est un objet typé qui circule entre l’agent, ses tools et ses guardrails. Concrètement, vous définissez une dataclass décrivant la session — identité, panier, préférences — et chaque tool la reçoit en premier paramètre. Dans l’exemple qui suit, ajouter_au_panier écrit dans cet objet et voir_panier le relit : les deux tools partagent le même panier sans qu’aucune donnée transite par le prompt.
from dataclasses import dataclass, field
from agents import Agent, Runner, RunContextWrapper, function_tool
@dataclass
class SessionUtilisateur:
user_id: str
nom: str
email: str
panier: list[dict] = field(default_factory=list)
preferences: dict = field(default_factory=dict)
@function_tool
def ajouter_au_panier(
ctx: RunContextWrapper[SessionUtilisateur],
produit: str,
quantite: int = 1,
) -> str:
"""Ajoute un produit au panier de l'utilisateur."""
ctx.context.panier.append({"produit": produit, "quantite": quantite})
total = len(ctx.context.panier)
return f"{produit} (x{quantite}) ajouté au panier. Total : {total} article(s)."
@function_tool
def voir_panier(ctx: RunContextWrapper[SessionUtilisateur]) -> str:
"""Affiche le contenu du panier."""
if not ctx.context.panier:
return "Votre panier est vide."
lignes = [f"- {item['produit']} x{item['quantite']}" for item in ctx.context.panier]
return f"Panier de {ctx.context.nom} :\n" + "\n".join(lignes)
agent = Agent(
name="Agent boutique",
instructions="Vous aidez les clients à faire leurs achats.",
tools=[ajouter_au_panier, voir_panier],
model="gpt-5.6-terra",
)
session = SessionUtilisateur(
user_id="usr_789",
nom="Marie Dupont",
email="[email protected]",
)
# Le contexte est partagé entre tous les tools
result = Runner.run_sync(agent, "Ajoutez un laptop et deux souris à mon panier", context=session)
print(result.final_output)
print(f"Panier après exécution : {session.panier}")
Le contexte est mutable : les tools peuvent le modifier, et les modifications persistent après l’exécution. C’est ce qui rend la dernière ligne intéressante — après le run_sync, l’objet session de votre application contient réellement les deux articles, prêts à être envoyés à votre système de commande.
Instructions dynamiques
Cet état ne sert pas qu’aux tools : il peut aussi façonner le comportement de l’agent. Les instructions peuvent être une fonction qui reçoit le contexte et fabrique le prompt système à la volée, avec le nom du client et sa langue de préférence.
def instructions_dynamiques(ctx: RunContextWrapper[SessionUtilisateur]) -> str:
prefs = ctx.context.preferences
langue = prefs.get("langue", "français")
return f"""Vous êtes un assistant commercial.
Le client s'appelle {ctx.context.nom}.
Son email est {ctx.context.email}.
Il a {len(ctx.context.panier)} article(s) dans son panier.
Communiquez en {langue}."""
agent = Agent(
name="Agent personnalisé",
instructions=instructions_dynamiques,
tools=[ajouter_au_panier, voir_panier],
model="gpt-5.6-terra",
)
Les instructions sont évaluées à chaque tour de la boucle agent, ce qui permet une personnalisation en temps réel : si un tool vient d’ajouter un article, le tour suivant en tient compte immédiatement dans le prompt système.
Mémoire conversationnelle multi-tours
Le contexte transporte des données, pas le dialogue lui-même. Pour maintenir une conversation sur plusieurs échanges, passez l’historique. Le principe tient en trois gestes : vous ajoutez le message de l’utilisateur, vous exécutez l’agent sur la liste complète, puis vous remplacez votre historique par celui que renvoie le résultat — messages, appels de tools et réponses compris.
from agents import Agent, Runner
agent = Agent(
name="Assistant",
instructions="Vous êtes un assistant qui se souvient de la conversation.",
model="gpt-5.6-terra",
)
historique = []
async def converser(message_utilisateur: str) -> str:
# Ajouter le message de l'utilisateur à l'historique
historique.append({"role": "user", "content": message_utilisateur})
# Exécuter l'agent avec l'historique complet
result = await Runner.run(agent, historique)
# Sauvegarder les nouveaux échanges pour le prochain tour
historique.clear()
historique.extend(result.to_input_list())
return result.final_output
# Simulation d'une conversation
async def demo():
print(await converser("Je m'appelle Thomas."))
print(await converser("Quel est mon prénom ?")) # L'agent se souvient
print(await converser("Recommandez-moi un bon restaurant à Paris."))
Cette mémoire vit en RAM. Elle disparaît au redéploiement de votre service, et elle grossit indéfiniment si la conversation dure : deux limites à garder en tête avant la mise en production.
Pattern : mémoire persistante avec base de données
Pour une mémoire qui survit aux redémarrages, stockez l’historique en base. L’approche présentée ici va un cran plus loin : au lieu de tout conserver, l’agent décide lui-même de ce qui mérite d’être retenu, via une paire de tools de sauvegarde et de récupération. Le client dit « je suis allergique aux arachides », l’agent appelle sauvegarder_note, et l’information reste disponible trois semaines plus tard.
import json
from agents import Agent, Runner, function_tool
@function_tool
async def sauvegarder_note(ctx: RunContextWrapper, cle: str, valeur: str) -> str:
"""Sauvegarde une information pour s'en souvenir plus tard."""
# En production : écriture en base de données
notes = ctx.context.notes
notes[cle] = valeur
return f"Note sauvegardée : {cle} = {valeur}"
@function_tool
async def recuperer_note(ctx: RunContextWrapper, cle: str) -> str:
"""Récupère une information sauvegardée précédemment."""
notes = ctx.context.notes
valeur = notes.get(cle)
if valeur:
return f"{cle} = {valeur}"
return f"Aucune note trouvée pour '{cle}'"
@dataclass
class ContexteMemoire:
user_id: str
notes: dict = field(default_factory=dict)
agent = Agent(
name="Assistant avec mémoire",
instructions="""Vous êtes un assistant avec une mémoire persistante.
Utilisez sauvegarder_note pour retenir des informations importantes
et recuperer_note pour les retrouver.""",
tools=[sauvegarder_note, recuperer_note],
model="gpt-5.6-terra",
)
Contexte vs. instructions : quand utiliser quoi
Ces quatre mécanismes se recouvrent partiellement, et l’erreur classique consiste à tout faire passer par les instructions. Le tableau ci-dessous résume l’affectation à retenir.
| Besoin | Solution |
|---|---|
| Données utilisateur (nom, rôle) | Context variables |
| Comportement de l’agent | Instructions (statiques ou dynamiques) |
| Historique de conversation | result.to_input_list() |
| Mémoire long terme | Tools + base de données |
| Configuration runtime | Context variables |
Points clés à retenir
RunContextWrappertransporte un état typé accessible par tous les tools- Le contexte est mutable : les tools peuvent le modifier pendant l’exécution
- Les instructions dynamiques (fonctions) s’adaptent au contexte à chaque tour
- L’historique conversationnel se maintient avec
result.to_input_list() - Pour une mémoire persistante, combinez des tools de sauvegarde avec une base de données