Fransys
Tous les cours
M6
45 min
Pédagogie complète

Memory tool API Anthropic (bêta 2026)

Memory tool API : conversation memory persistante au-delà de la session.

Devs construisant des assistants long terme

Pourquoi ce module

Anthropic propose le memory tool (memory_20250818, bêta) : une primitive qui laisse Claude lire et écrire des fichiers de mémoire entre les sessions, sans rebrancher le contexte à chaque fois.

⚠️ Point clé souvent mal compris. Le memory tool est client-side : Claude émet des commandes (view, create, str_replace, insert, delete, rename) sur un répertoire /memories, et c'est vous qui implémentez le backend de stockage (fichiers, base de données, chiffrement, scoping par utilisateur). Anthropic n'héberge pas cette mémoire — il n'existe pas de « Memory API » clé-valeur hébergée et chiffrée côté Anthropic. Pour une mémoire hébergée côté serveur, c'est une autre primitive : les memory stores des Managed Agents (montés en FUSE dans le conteneur de session, documents versionnés avec audit/redact — voir M13). Et ce n'est pas non plus le MEMORY.md de Claude Code (fichier local, scope projet).

Panneau /memory de Claude Code : mémoire utilisateur, projet et AGENTS.md importé
Côté Claude Code, /memory gère la mémoire fichier (client) : ~/.claude/CLAUDE.md (user), ./CLAUDE.md (projet, versionné), AGENTS.md importé. À distinguer du memory tool serveur étudié ici.

Dans ce module, les exemples utilisent un backend clé-valeur que vous hébergez vous-même, exposé soit via le memory tool natif, soit via vos propres tools custom — les deux approches sont valides. C'est votre responsabilité RGPD (chiffrement, droit à l'oubli, audit).

🧠 Le défaut, c'est l'oubli. Hors mémoire explicitement activée, Claude ne se souvient de rien d'une session à l'autre : chaque conversation repart de zéro. La fonctionnalité de mémoire de claude.ai est opt-in (à activer dans les réglages), et côté Claude Code l'auto memory dépend de autoMemoryEnabled (désactivable via CLAUDE_CODE_DISABLE_AUTO_MEMORY). Autrement dit, « Claude se rappelle de la semaine dernière » n'est vrai que si vous avez branché une des couches de persistance ci-dessous — sinon, c'est à vous de réinjecter le contexte.

Pour les équipes construisant des assistants long terme (chatbots SaaS, support client AI, CRM IA), la mémoire transforme l'UX : votre assistant se souvient de vos 3 derniers tickets, vos préférences produit, votre contexte de compte. Mais sans garde-fous, c'est RGPD-catastrophe. Vous allez apprendre à stocker, lire, mettre à jour et supprimer de la mémoire de manière compliant.

Prérequis : maîtriser les tool calls Claude (voir M1), avoir une clé API Anthropic, et connaître les basics de RGPD art. 17 (droit à l'oubli).

Objectifs pédagogiques

À l'issue de ce module, vous serez capable de :

  1. Distinguer les couches de mémoire : MEMORY.md (projet, Claude Code), memory tool client-side (backend à vous), memory stores Managed Agents (serveur), context window (session courante)
  2. Implémenter un cycle write/read/update/delete via tool calls TypeScript (memory tool natif ou tools custom)
  3. Concevoir un schéma de mémoire : quoi stocker (faits courts), quoi pas (transcripts entiers), comment versioner
  4. Exposer un opt-out RGPD complet : suppression du droit à l'oubli en 1 clic, audit trail, consentement préalable
  5. Debugger des mémoires divergentes (stale reads, concurrence, conflits d'updates)
  6. Évaluer ROI : quand la mémoire persistante vaut vraiment le coup vs context window ou logs externes

Plan détaillé

  1. Les trois couches : MEMORY.md vs mémoire vs context
  2. Anatomie mémoire : schema, scope, TTL
  3. Cycle complet : write / read / update / delete
  4. Use cases : chatbot, support N1, CRM IA
  5. Schéma de mémoire recommandé
  6. Concurrence et consistency
  7. RGPD et droit à l'oubli
  8. Audit trail et compliance
  9. Atelier : assistant support avec mémoire de tickets
  10. Pièges courants

Les trois couches : MEMORY.md vs mémoire vs context

MEMORY.md (Claude Code client)

  • Fichier .claude/MEMORY.md dans votre projet
  • Scope : projet entier
  • Persistance : fichier sur disque, versionné en Git
  • Lifecycle : existe tant que le projet existe
  • Format : Markdown libre
  • Use case : "Ce projet utilise Next.js, React Query, Tailwind"

Memory tool (memory_20250818, client-side, bêta)

  • Stockage : votre infrastructure — Claude appelle des commandes fichier (view/create/str_replace/insert/delete/rename), vous implémentez le backend
  • Scope : ce que vous décidez (utilisateur, tenant SaaS…) via vos chemins /memories/...
  • Persistance : selon votre backend ; survit aux sessions
  • Format : libre (le KV {key, value, ttl} montré plus bas est votre choix d'implémentation, pas un format imposé par Anthropic)
  • Chiffrement / RGPD : votre responsabilité (Anthropic ne stocke rien ici)
  • Use case : "Cet utilisateur a vu mes 3 derniers tickets" ou "Ses préférences de notification sont weekly"

Memory stores (Managed Agents, serveur Anthropic — voir M13)

  • Stockage : côté Anthropic, monté en FUSE dans le conteneur de session
  • Format : documents texte adressés par path, versionnés (audit + redact)
  • Use case : agents serveur persistants partageant une mémoire entre sessions

Context window (session courante)

  • Scope : conversation en cours
  • Persistance : none (réinitialise à chaque requête)
  • Use case : "Rappeler le contexte immédiat de la requête précédente"
Commande /context de Claude Code : grille d'occupation de la fenêtre de contexte par catégorie
/context rend visible la couche éphémère : ce qui occupe la fenêtre de la session courante (system prompt, outils, mémoire chargée, messages) et l'espace libre. Contrairement aux trois autres couches, elle se réinitialise à chaque requête — d'où l'intérêt d'une mémoire persistante (fichier ou backend) pour ce qui doit survivre.

Matrice comparative :

PropriétéMEMORY.mdmemory tool (client)memory stores (CMA)Context
Persistance✅ Git✅ Votre backend✅ Serveur Anthropic❌ None
Cross-session✅ Oui✅ Oui✅ Oui❌ Non
ScopeProjetAu choix (user…)Workspace/sessionConversation
FormatMarkdownLibre (vous)Documents versionnésText/tokens
Droits RGPDLocal (vous)Vous (backend & chiffrement)Anthropic (redact dispo)N/A

Voici une visualisation des trois couches et leurs interactions :

Chargement du schéma…

Architecture des 3 couches de mémoire IA
Serveur de données moderne avec rangées de LED bleues
Infrastructure de persistance : les serveurs qui stockent vos mémoires utilisateur

Anatomie : le memory tool natif + votre schéma backend

Superordinateur avec circuit imprimé bleu brillant
Mémoire persistante : stockage structuré de préférences et contextes utilisateur

1. Déclarer le memory tool natif

Côté requête, vous déclarez simplement le tool natif — Claude émet alors des commandes fichier (view, create, str_replace, insert, delete, rename) sur un répertoire /memories, que votre handler exécute :

const response = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 1024,
  tools: [{ type: "memory_20250818", name: "memory" }], // tool natif
  messages: [{ role: "user", content: "Retiens que je préfère les notifs le vendredi." }],
});
// → Claude renvoie un tool_use `memory` avec command="create", path="/memories/prefs.md", ...
// → VOUS écrivez le fichier (ou la ligne KV) dans VOTRE backend, puis renvoyez le tool_result.

Le SDK fournit un helper betaMemoryTool(handlers) (TS) / classe équivalente (Python) où vous branchez view/create/str_replace/insert/delete/rename sur le stockage de votre choix.

2. Le schéma de votre backend (exemple)

Le memory tool ne vous impose aucun format de données : à vous de modéliser ce que vous stockez. Un schéma clé-valeur courant pour un assistant multi-utilisateur :

{
  "key": "support_ticket_last_3",
  "value": {
    "tickets": [
      { "id": "T-2048", "date": "2026-04-28", "status": "resolved" },
      { "id": "T-2047", "date": "2026-04-15", "status": "resolved" },
      { "id": "T-2046", "date": "2026-03-30", "status": "open" }
    ]
  },
  "scope": "user",
  "ttl": 2592000
}

Champs (convention backend, pas imposés par Anthropic) :

  • key : identifiant unique par user (alphanumériques, tirets, underscores)
  • value : objet JSON quelconque (objets, arrays, strings, numbers)
  • scope : "user" (par utilisateur) ou "session" (par conversation — moins courant)
  • ttl : time-to-live en secondes. null = jamais expire. 2592000 = 30 jours.

Tailles limites (à fixer côté backend — bonnes pratiques) :

  • Clé : garder court (< 256 caractères)
  • Valeur : éviter les transcripts entiers ; viser des faits courts (< 10 K tokens)
  • Nettoyage : TTL + script d'archivage (sinon dérive infinie)

Cycle complet : write / read / update / delete

Le cycle CRUD de la mémoire suit cet ordre et ces dépendances :

Chargement du schéma…

Cycle CRUD de la mémoire

En TypeScript avec Anthropic SDK :

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

async function memoryDemo(userId: string) {
  // ========== WRITE ==========
  // Créer une nouvelle entrée mémoire
  const writeResponse = await client.messages.create({
    model: "claude-opus-4-8",
    max_tokens: 1024,
    system: `You have access to user memory. Write facts you learn to memory.`,
    tools: [
      {
        name: "memory_write",
        description: "Write a fact to the user's memory.",
        input_schema: {
          type: "object",
          properties: {
            key: {
              type: "string",
              description: "Memory key (e.g., 'user_preferences')",
            },
            value: {
              type: "object",
              description: "JSON value to store",
            },
            ttl: {
              type: "number",
              description: "Time-to-live in seconds (e.g., 2592000 for 30 days)",
            },
          },
          required: ["key", "value"],
        },
      },
    ],
    messages: [
      {
        role: "user",
        content: `Remember that I prefer email notifications on Fridays only, 
and my company is Acme Corp with 50 employees.`,
      },
    ],
  });

  console.log("Write response:", writeResponse.content);

  // ========== READ ==========
  // Lire une entrée mémoire
  const readResponse = await client.messages.create({
    model: "claude-opus-4-8",
    max_tokens: 1024,
    system: `You have access to user memory. Read and use stored facts to personalize responses.`,
    tools: [
      {
        name: "memory_read",
        description: "Read a fact from the user's memory.",
        input_schema: {
          type: "object",
          properties: {
            key: {
              type: "string",
              description: "Memory key to read",
            },
          },
          required: ["key"],
        },
      },
    ],
    messages: [
      {
        role: "user",
        content: `What are my notification preferences?`,
      },
    ],
  });

  console.log("Read response:", readResponse.content);

  // ========== UPDATE ==========
  // Mettre à jour une entrée (remplace complètement la valeur)
  const updateResponse = await client.messages.create({
    model: "claude-opus-4-8",
    max_tokens: 1024,
    tools: [
      {
        name: "memory_update",
        description: "Update an existing memory entry.",
        input_schema: {
          type: "object",
          properties: {
            key: {
              type: "string",
            },
            value: {
              type: "object",
            },
          },
          required: ["key", "value"],
        },
      },
    ],
    messages: [
      {
        role: "user",
        content: `Update my preferences: now I want daily notifications instead.`,
      },
    ],
  });

  console.log("Update response:", updateResponse.content);

  // ========== DELETE ==========
  // Supprimer une entrée (droit à l'oubli RGPD)
  const deleteResponse = await client.messages.create({
    model: "claude-opus-4-8",
    max_tokens: 1024,
    tools: [
      {
        name: "memory_delete",
        description: "Delete a memory entry (GDPR right to be forgotten).",
        input_schema: {
          type: "object",
          properties: {
            key: {
              type: "string",
            },
          },
          required: ["key"],
        },
      },
    ],
    messages: [
      {
        role: "user",
        content: `Delete all my personal preferences from memory (exercising my right to be forgotten).`,
      },
    ],
  });

  console.log("Delete response:", deleteResponse.content);
}

memoryDemo("user-12345");

Use cases : chatbot, support N1, CRM IA

Cas 1 : Chatbot SaaS client

Chaque client accède à votre chatbot. Au-delà de "Bonjour", votre assistant devrait :

  • Se souvenir du plan tarifaire du client (Enterprise vs Starter)
  • Connaître son industrie (répondre différemment à un SaaS vs un e-commerce)
  • Tracker les 3 dernières questions → éviter les répétitions
{
  "key": "client_profile_acme",
  "value": {
    "company": "Acme Corp",
    "plan": "Enterprise",
    "industry": "SaaS",
    "onboarding_step": 5,
    "recent_questions": ["How to customize dashboards?", "SSO setup?"]
  },
  "ttl": 7776000
}

Cas 2 : Support N1 avec mémoire de tickets

Agent support qui traite 100 tickets/jour. Pour chaque client, tracker :

  • Derniers 5 tickets ouverts et résolus
  • Status courant (waiting for client feedback, etc.)
  • Contexte persistant (c'est un client new, old, VIP, etc.)
{
  "key": "support_context_user_4521",
  "value": {
    "customer_type": "vip",
    "open_tickets": ["T-9821", "T-9820"],
    "last_resolution": "2026-04-28",
    "escalation_needed": false
  },
  "ttl": 2592000
}

Cas 3 : CRM IA

Agent accédant HubSpot qui enrichit les deals. Pour chaque prospect :

  • Dernier interaction timestamp
  • Angle de vente testé (n'essayer la même approche 2 fois)
  • Notes contexte non-structurées
{
  "key": "deal_context_12048",
  "value": {
    "prospect": "Acme Corp",
    "last_call": "2026-04-25",
    "tested_angles": ["cost savings", "time to value"],
    "next_angle": "compliance risk",
    "budget_range": "50K–100K USD"
  },
  "ttl": 5184000
}

Schéma de mémoire recommandé

Voici une structure scalable pour app multi-tenant :

memory_key_pattern: {namespace}_{resource_type}_{resource_id}

Exemples :
  - app_user_profile_u12345
  - support_ticket_context_t5678
  - crm_deal_metadata_d9012
  - feature_flag_cache_fflag_ab_test_v2

Anti-patterns :

  • ❌ Stocker des transcripts complets (100 K+ tokens)
  • ❌ Clés non-structurées (style "data", "stuff")
  • ❌ Valeurs gigantesques sans TTL (dérive infinie)
  • ❌ Pas de versioning (impossible d'upgrades le schéma)

Best practices :

  • ✅ Faits structurés, courts (< 10 K tokens)
  • ✅ TTL explicite (jamais null sauf raison solide)
  • ✅ Naming cohérent
  • ✅ Versioning clé : app_user_profile_v2_{id} si schema change
  • ✅ Cleanup script : archiver/supprimer memories > 180 jours

Concurrence et consistency

Deux users accèdent simultanément à la mémoire. Scénario : User A et B requêtent une mise à jour du même key au même temps.

Chargement du schéma…

Concurrence: dernier écrit remporte (last-write-wins)

Comportement par défaut d'un backend KV naïf : last-write-wins — l'update le plus récent écrase les précédents, pas de merge intelligent. (Comme c'est votre backend, c'est à vous d'ajouter de l'optimistic locking si besoin ; les memory stores CMA, eux, offrent un precondition content-sha256.)

Mitigation :

// UNSAFE : deux requêtes concurrentes overwrite-ing
const r1 = client.messages.create({ tools: [memory_update] });
const r2 = client.messages.create({ tools: [memory_update] });
await Promise.all([r1, r2]); // Risque : une overwrite l'autre

// SAFE : lire avant écrire (optimistic locking)
const currentValue = await memory_read("key");
const newValue = { ...currentValue, updated_field: "new" };
await memory_update("key", newValue); // Écrire la version complète

Pour haute concurrence (100+ writes/sec sur le même key) : ne pas faire transiter chaque write par le LLM. Écrire directement dans votre DB et ne synchroniser vers la mémoire de l'agent qu'en batch.

RGPD et droit à l'oubli

Article 17 RGPD : l'utilisateur peut demander la suppression complète de ses données. Avec la mémoire, c'est simple mais impératif :

async function completeUserDeletion(userId: string) {
  // 1. Lister tous les keys de cet user
  const allMemories = await listUserMemories(userId);

  // 2. Supprimer chaque key
  for (const memory of allMemories) {
    await client.messages.create({
      model: "claude-opus-4-8",
      max_tokens: 100,
      tools: [
        {
          name: "memory_delete",
          input_schema: {
            type: "object",
            properties: { key: { type: "string" } },
            required: ["key"],
          },
        },
      ],
      messages: [
        {
          role: "user",
          content: `Delete memory key: ${memory.key}`,
        },
      ],
    });
  }

  // 3. Log audit trail
  console.log(`[AUDIT] User ${userId} GDPR deletion completed at ${new Date()}`);
}

Consentement préalable : Avant de stocker la première mémoire pour un utilisateur, demander explicitement :

<dialog>
  <h2>Mémoire utilisateur</h2>
  <p>Nous allons mémoriser vos préférences, contexte et historique pour améliorer votre expérience.</p>
  <p>Vous pouvez demander la suppression complète à tout moment (droit à l'oubli RGPD).</p>
  <input type="checkbox" id="consent" /> J'accepte
  <button onclick="recordConsent()">Continuer</button>
</dialog>

Opt-out à tout moment :

// Dans l'UI utilisateur, exposer un bouton "Delete my memory"
async function userInitiatedDeletion() {
  await completeUserDeletion(currentUserId);
  showAlert("Votre mémoire a été supprimée. Données purgées en 24h.");
}

Audit trail et compliance

Chaque action mémoire doit être loggée pour compliance audit :

{
  "timestamp": "2026-04-28T14:32:10Z",
  "user_id": "u12345",
  "action": "memory_write",
  "key": "user_profile_v2_u12345",
  "result": "success",
  "value_size_tokens": 512,
  "ip_address": "192.168.1.1"
}

Logs à conserver : minimum 1 an (compliance audit, investigation fraude). Après purge data RGPD, logs restent anonymisés :

{
  "timestamp": "2026-04-28T14:32:10Z",
  "user_id": "REDACTED",
  "action": "memory_delete",
  "result": "success",
  "reason": "GDPR Article 17 - User request"
}

Atelier : assistant support avec mémoire de tickets (45 min)

Vous construisez un assistant support qui gère tickets clients et se souvient des contextes.

Livrable :

  1. Agent TypeScript qui utilise mémoire
  2. Schéma : support_context_{user_id} stockant derniers 3 tickets
  3. Quand utilisateur pose question :
    • Read memory → charger les 3 derniers tickets
    • Répondre en tenant compte du contexte passé
    • Write memory → mettre à jour status si ticket fermé
  4. Bouton "Droit à l'oubli" qui supprime TOUT
  5. Audit logs pour chaque opération mémoire

Critères de succès :

  • ✅ Read/write/delete working
  • ✅ Contexte réutilisé dans réponse
  • ✅ TTL défini (30 jours)
  • ✅ RGPD consentement visible
  • ✅ Audit logs sauvegardés

Pièges courants

PiègeSymptômeCure
Mémoire staleAgent cite contexte obsolèteRead avant chaque usage + TTL court
Explosion de tailleMemory key > 100 K tokensArchiver vieux entries, truncate arrays
Pas de versioningSchema change casse old memoriesClé avec version (_v2, _v3)
Oubli RGPDUser demande suppression ignoréeExposer bouton delete UI, audit logs
ConcurrenceDeux writes simultanés perdusLire avant écrire, pas Promise.all
Coût surpriseMemory reads incluent token costsCacher agressivement (context window)

Pour aller plus loin