AI Agents

Comment donner de la mémoire à un agent IA : patrons de persistance d'état en production

Alejandro Rioja
Alejandro Rioja
9 min de lecture
TL;DR

Les agents sans état — ceux qui oublient tout à la sortie du Worker — conviennent bien aux tâches ponctuelles. Dès qu'un agent doit se souvenir de ce qui s'est passé hier, reconnaître un client récurrent ou s'appuyer sur des résultats antérieurs, il vous faut de la mémoire. Il existe trois patrons : la mémoire de travail (contexte en vol, stockée dans KV pendant la durée d'une exécution), la mémoire épisodique (ce qui s'est passé et quand, un journal interrogeable) et la mémoire sémantique (ce que vous savez, récupéré par recherche vectorielle ou données structurées). Associez le bon patron au bon travail.

Newsletter gratuite

Chaque mercredi. 28 400+ opérateurs. Zéro superflu.

Table des matières

Mis à jour juin 2026.

TL;DR: Les agents sans état — ceux qui oublient tout à la sortie du Worker — conviennent bien aux tâches ponctuelles. Dès qu’un agent doit se souvenir de ce qui s’est passé hier, reconnaître un client récurrent ou s’appuyer sur des résultats antérieurs, il vous faut de la mémoire. Il existe trois patrons : la mémoire de travail (contexte en vol, stockée dans KV pendant la durée d’une exécution), la mémoire épisodique (ce qui s’est passé et quand, un journal interrogeable) et la mémoire sémantique (ce que vous savez, récupéré par recherche vectorielle ou données structurées). Associez le bon patron au bon travail.

[Lecture de l’opérateur] Je me suis heurté au mur de l’agent sans état plus d’une fois. L’agent de réponse sociale qui continuait à se présenter à des clients à qui il avait parlé 20 fois. L’agent de briefing quotidien qui signalait le même problème quatre jours de suite parce qu’il n’avait aucun souvenir de l’avoir signalé la veille. Ajouter le bon type de mémoire a résolu les deux. Voici ce que j’utilise.

Pourquoi les agents sans état continuent d’échouer

Un agent sans état commence chaque exécution avec uniquement ce que vous lui passez explicitement : le prompt système, le message utilisateur et les données récupérées au moment de l’invocation. Il n’a aucune conscience des exécutions précédentes, des utilisateurs précédents ou des décisions précédentes.

Pour une tâche de classification ponctuelle — lire un commentaire, retourner une catégorie — le mode sans état est correct. C’est rapide, bon marché et prévisible.

La zone de défaillance apparaît dès que vous avez besoin de continuité :

  • Un agent face aux clients qui ne reconnaît pas l’historique du client
  • Un agent de contenu qui recommande un article qu’il avait déjà recommandé la semaine dernière
  • Un agent de modération qui continue de réescalader un cas résolu
  • Un briefing quotidien qui affiche la même alerte obsolète indéfiniment

Tout cela est symptôme du même problème : l’agent n’a aucun moyen de transporter du contexte d’une exécution à l’autre.

Trois types de mémoire

Le cadre que je trouve utile en production :

  1. Mémoire de travail — ce que l’agent sait maintenant, pendant une seule exécution. Stockée dans KV ou en mémoire pendant la durée de l’invocation.
  2. Mémoire épisodique — ce qui s’est passé et quand. Un journal structuré que l’agent lit au début de chaque nouvelle exécution pour s’orienter.
  3. Mémoire sémantique — ce qu’il sait sur le monde, les clients ou une base de connaissances. Récupérée via des requêtes structurées ou une recherche vectorielle quand c’est pertinent.

Vous n’avez pas toujours besoin des trois. La plupart des agents que j’exploite ont besoin de travail + épisodique. La mémoire sémantique est la plus difficile à construire et ne mérite sa place que lorsque la base de connaissances est trop grande pour tenir dans la fenêtre de contexte.

Mémoire de travail : contexte en vol

La mémoire de travail est un état qui vit pendant la durée d’une exécution d’agent. La forme la plus simple consiste en des variables dans la portée de la fonction. La forme plus intéressante est une clé KV partagée que les sous-tâches d’une même exécution lisent et écrivent.

Mon agent de réponse sociale utilise la mémoire de travail pour accumuler du contexte lors du traitement d’un lot de commentaires dans un message de file d’attente. Il lit l’historique récent de chaque client depuis KV au début, ajoute du nouveau contexte au fur et à mesure, et réécrit à la fin.

typescript
// workers/social-reply.ts

async function processComment(
  comment: SocialCommentEvent,
  env: Env
): Promise<void> {
  // Charger l'historique récent de ce client depuis KV (mémoire de travail)
  const historyKey = `customer:${comment.userId}:history`;
  const rawHistory = await env.AGENT_KV.get(historyKey);
  const history: ConversationTurn[] = rawHistory
    ? JSON.parse(rawHistory)
    : [];

  // Construire un prompt système contextuel à partir de l'historique
  const systemPrompt = buildSystemPrompt(history);

  const response = await anthropic.messages.create({
    model: "claude-opus-4-8",
    max_tokens: 512,
    system: systemPrompt,
    messages: [{ role: "user", content: comment.text }],
  });

  const reply =
    response.content[0].type === "text" ? response.content[0].text : "";

  // Mettre à jour l'historique — garder les 10 derniers tours, TTL 30 jours
  const updatedHistory: ConversationTurn[] = [
    ...history.slice(-9),
    { role: "assistant", content: reply, timestamp: comment.timestamp },
  ];
  await env.AGENT_KV.put(historyKey, JSON.stringify(updatedHistory), {
    expirationTtl: 60 * 60 * 24 * 30,
  });

  await postReply(comment, reply, env);
}

Deux choses à noter. L’historique est limité à 10 tours — injectez une fenêtre glissante, ne le laissez pas croître sans limite. Et le TTL est de 30 jours : si un client reste silencieux pendant un mois, l’historique expire et l’agent repart de zéro. Les deux sont intentionnels.

Mémoire épisodique : ce qui s’est passé et quand

La mémoire épisodique est le journal de l’agent. Un enregistrement structuré des exécutions passées que l’agent lit au début de chaque nouvelle exécution pour éviter de se répéter.

Mon agent de briefing quotidien affichait les mêmes alertes obsolètes chaque jour parce que chaque exécution n’avait aucune conscience de ce qui avait déjà été signalé. La solution : un journal structuré d’alertes passées que l’agent lit avant de générer le briefing.

typescript
// workers/daily-brief.ts

interface AlertLogEntry {
  id: string;
  surfacedAt: string; // horodatage ISO
  resolvedAt?: string;
  summary: string;
}

async function buildDailyBrief(env: Env): Promise<void> {
  const [emails, calendar, tasks] = await Promise.all([
    fetchOvernightEmails(env),
    fetchTodayCalendar(env),
    fetchTopTasks(env),
  ]);

  // Charger la mémoire épisodique : ce qui a déjà été signalé
  const rawLog = await env.AGENT_KV.get("brief:alert-log");
  const alertLog: AlertLogEntry[] = rawLog ? JSON.parse(rawLog) : [];

  // Filtrer sur les alertes récentes et non résolues uniquement
  const sevenDaysAgo = new Date(
    Date.now() - 7 * 24 * 60 * 60 * 1000
  ).toISOString();
  const recentAlerts = alertLog.filter(
    (e) => e.surfacedAt > sevenDaysAgo && !e.resolvedAt
  );

  const brief = await synthesizeBrief(
    { emails, calendar, tasks, recentAlerts },
    env
  );

  // Mettre à jour le journal avec les nouvelles alertes signalées lors de cette exécution
  const newAlerts: AlertLogEntry[] = brief.newAlerts.map((a) => ({
    id: crypto.randomUUID(),
    surfacedAt: new Date().toISOString(),
    summary: a,
  }));

  const updatedLog = [...alertLog, ...newAlerts].slice(-100); // garder les 100 dernières
  await env.AGENT_KV.put("brief:alert-log", JSON.stringify(updatedLog));

  await writeToWorkspace(brief.content, env);
}

L’agent sait maintenant ce qu’il a déjà dit. Les alertes en double restent hors du briefing jusqu’à ce que le problème sous-jacent change. Quand je marque une alerte comme résolue, elle disparaît de la liste active.

Ce patron se généralise : tout agent qui produit des décisions, des signaux ou des recommandations bénéficie d’un journal. Le journal est bon marché (quelques Ko dans KV), le gain est élevé (plus de sorties redondantes).

Mémoire sémantique : ce que vous savez

La mémoire sémantique est la base de connaissances. Elle répond à « que sais-tu sur X ? » au moment de la requête, plutôt que de tout entasser dans le prompt système à l’avance.

La forme la plus simple est une recherche structurée dans KV ou une base de données. Mon agent de réservation Pickleland consulte les profils clients et les préférences de terrain avant de rédiger les confirmations :

typescript
// workers/booking-agent.ts

interface CustomerProfile {
  userId: string;
  preferredCourts: string[];
  experienceLevel: "beginner" | "intermediate" | "advanced";
  specialNotes: string;
}

async function draftConfirmation(
  booking: BookingEvent,
  env: Env
): Promise<string> {
  // Récupérer le profil client depuis KV (mémoire sémantique — connaissances factuelles)
  const profileKey = `customer:${booking.userId}:profile`;
  const rawProfile = await env.AGENT_KV.get(profileKey);
  const profile: CustomerProfile | null = rawProfile
    ? JSON.parse(rawProfile)
    : null;

  const systemPrompt = profile
    ? `Tu rédiges des confirmations de réservation personnalisées. Ce client préfère ${profile.preferredCourts.join(", ")}, est un joueur ${profile.experienceLevel}. ${profile.specialNotes}`
    : "Tu rédiges des confirmations de réservation pour une installation de pickleball.";

  const response = await anthropic.messages.create({
    model: "claude-haiku-4-5-20251001",
    max_tokens: 256,
    system: systemPrompt,
    messages: [
      {
        role: "user",
        content: `Rédige une confirmation pour : ${JSON.stringify(booking)}`,
      },
    ],
  });

  return response.content[0].type === "text" ? response.content[0].text : "";
}

Pour les bases de connaissances plus grandes — documentation produit, base de connaissances support, tout ce qui est trop grand pour tenir dans une fenêtre de contexte — vous avez besoin d’un stockage vectoriel. Le flux de travail est : intégrer la requête, récupérer les k fragments les plus pertinents, les injecter dans le contexte. Cloudflare Vectorize gère cela nativement si vous êtes déjà sur Workers. Pour les index plus grands, j’ai utilisé Upstash Vector. Le choix dépend de l’échelle, pas du principe.

La note honnête sur la mémoire sémantique : c’est la plus difficile des trois à construire et à maintenir. L’index doit rester à jour. La qualité de récupération varie. Commencez par des recherches structurées — KV, une table dans D1 — et n’atteignez la recherche vectorielle que lorsque l’approche structurée ne peut pas couvrir la surface de connaissance dont vous avez besoin.

Le cadre de décision mémoire

Avant d’ajouter de la mémoire à un agent, répondez à trois questions :

  1. L’agent doit-il se souvenir d’une exécution à l’autre ? Si chaque invocation est genuinement indépendante — une traduction, une classification, une génération ponctuelle — ignorez la mémoire. Sans état est plus simple et moins cher.

  2. L’agent se répète-t-il ou agit-il en ignorant son propre historique ? Si oui, ajoutez d’abord la mémoire épisodique. C’est la correction la moins coûteuse en effort et elle couvre la plupart des plaintes « l’agent continue à faire X ».

  3. L’agent traite-t-il chaque utilisateur ou entité de manière identique alors qu’il ne le devrait pas ? Si oui, ajoutez de la mémoire de travail (historique client, profil utilisateur) ou de la mémoire sémantique (un système de recherche ou de récupération).

L’erreur que je vois le plus souvent : quelqu’un ajoute une énorme base de connaissances (mémoire sémantique) à un agent qui échouait en réalité parce qu’il n’avait pas de mémoire épisodique — aucun journal de ce qu’il avait déjà fait. La complexité ne correspond pas au problème.

Ce que j’utilise vraiment en production

Sur 30+ agents :

  • Tous ont au moins une mémoire de travail — une forme d’état dans une exécution, même si c’est juste la fenêtre de contexte elle-même.
  • Environ la moitié ont une mémoire épisodique — un journal des exécutions passées, décisions ou signaux. Cela vaut presque toujours la peine d’être ajouté.
  • Trois ou quatre ont une vraie mémoire sémantique soutenue par un stockage vectoriel. Ce sont les agents qui répondent aux questions sur une grande base de connaissances dynamique.

Cloudflare KV est mon stockage par défaut pour la mémoire de travail et épisodique. C’est rapide, bon marché et intégré nativement dans Workers — pas de client supplémentaire, pas de credential séparée. La limite : KV est éventuellement cohérent et ne convient pas bien aux écritures à haute fréquence. Pour les agents qui écrivent de l’état plusieurs fois par seconde, j’utilise Durable Objects ou une base de données D1 à la place.

Pour la mémoire sémantique soutenue par des vecteurs, j’utilise Cloudflare Vectorize pour les index petits à moyens (moins de ~100K vecteurs) et Upstash Vector pour tout ce qui est plus grand. Les deux ont des clients JavaScript de première classe.

La conclusion de l’opérateur

Ajoutez de la mémoire à un agent uniquement quand le comportement sans état cause de vrais problèmes — sorties répétées, angles morts sur l’historique client, ignorance des décisions passées. Choisissez ensuite la bonne couche : mémoire de travail pour le contexte en cours d’exécution, épisodique pour ce qui s’est passé historiquement, sémantique pour ce que vous savez. Commencez par l’épisodique si vous n’êtes pas sûr — elle corrige le mode de défaillance le plus courant avec le moins de complexité. N’atteignez pas une base de données vectorielle tant que vous n’avez pas épuisé les recherches structurées. Le meilleur système de mémoire est le plus simple qui fait que l’agent se comporte correctement.


En lien : Le stack d’agents que j’utilise pour faire tourner 30+ agents en production · Agents déclenchés par événements vs planifiés · Comment je mesure si un agent IA fonctionne vraiment

Besoin d’aide pour concevoir la mémoire d’agents pour votre cas d’usage ? Contactez-moi — je conçois des systèmes d’agents en production pour des équipes opératrices.

Continuer à lire

Articles liés

Continuer à lire

Recevez le guide IA dans votre boîte mail

Chaque mercredi. 28 400+ opérateurs. Zéro superflu.

↵ pour voir tous les résultats esc esc pour fermer