Concepts de mémoire

La partie du magasin sémantique de la mémoire est construite à partir de quelques petits types. Apprenez ces quatre-là, et le reste de la section suit.

MemoryEntry

Un seul enregistrement de mémoire : un contenu, son auteur, et quand il a été créé.

use adk_memory::MemoryEntry;
use adk_core::Content;
use chrono::Utc;

let entry = MemoryEntry {
    content: Content::new("user").with_text("I prefer dark mode"),
    author: "user".to_string(),
    timestamp: Utc::now(),
};

Les entrĂ©es sont l’unitĂ© de stockage et l’unitĂ© de rappel — search renvoie les entrĂ©es les plus pertinentes pour une requĂȘte.

Le trait MemoryService

Chaque backend implĂ©mente un trait. Deux mĂ©thodes sont requises ; le reste a des implĂ©mentations par dĂ©faut qu’un backend peut remplacer :

#[async_trait]
pub trait MemoryService: Send + Sync {
    // Required
    async fn add_session(&self, app: &str, user: &str, session: &str,
                         entries: Vec<MemoryEntry>) -> Result<()>;
    async fn search(&self, req: SearchRequest) -> Result<SearchResponse>;

    // Optional (default: "not implemented")
    async fn delete_user(&self, app: &str, user: &str) -> Result<()>;          // GDPR
    async fn delete_session(&self, app: &str, user: &str, session: &str) -> Result<()>;
    async fn add_entry(&self, app: &str, user: &str, entry: MemoryEntry) -> Result<()>;
    async fn delete_entries(&self, app: &str, user: &str, query: &str) -> Result<u64>;
    // 
plus a health check
}
  • add_session ingĂšre la totalitĂ© des entrĂ©es d’une conversation terminĂ©e. Un Runner l’appelle pour vous lorsque la mĂ©moire est attachĂ©e.
  • search est le rappel. Les backends interprĂštent la requĂȘte diffĂ©remment — mots-clĂ©s, similaritĂ© d’embedding, ou notation de jetons de graphe — mais le contrat est le mĂȘme.

SearchRequest / SearchResponse

use adk_memory::SearchRequest;

let req = SearchRequest {
    app_name: "support".into(),
    user_id:  "alice".into(),
    query:    "contact preference".into(),
    ..Default::default()      // top_k, project scoping, etc.
};

let resp = memory.search(req).await?;   // resp.entries: Vec<MemoryEntry>

État de session vs mĂ©moire

Ce sont des outils diffĂ©rents — ne les confondez pas :

État de sessionMĂ©moire
DurĂ©e de vieUne conversationÀ travers les conversations
APIadk-session (SessionService, carte d’état)adk-memory (MemoryService)
ContientLa transcription en direct + l'Ă©tat temporaireDes faits durables dignes d'ĂȘtre rappelĂ©s plus tard
LectureToujours dans le contexteÀ la demande, via search_memory

Un flux typique : la conversation vit dans l’état de session ; lorsqu’elle se termine (ou Ă  chaque tour), les Ă©lĂ©ments saillants sont Ă©crits en mĂ©moire ; la session suivante recherche la mĂ©moire pour reconstituer le contexte. Voir Sessions & State.

Isolation : application, utilisateur et projet

La mĂ©moire est toujours indexĂ©e par (app_name, user_id), donc les utilisateurs ne voient jamais les mĂ©moires des autres. Vous pouvez dĂ©finir un troisiĂšme niveau — projet — au sein d’un utilisateur :

  • EntrĂ©es globales (project_id = None) — visibles dans tous les contextes.
  • EntrĂ©es de projet (project_id = Some(id)) — visibles uniquement dans ce projet.
  • Recherche de projet renvoie les entrĂ©es globales + les entrĂ©es de projet correspondantes ; la recherche globale ne renvoie que les entrĂ©es globales.
use adk_memory::{MemoryServiceAdapter, InMemoryMemoryService};
use std::sync::Arc;

let service = Arc::new(InMemoryMemoryService::new());

// store within a project
service.add_session_to_project("app", "user", "sess", "acme-project", entries).await?;

// an adapter scoped to that project
let adapter = MemoryServiceAdapter::new(service, "app", "user")
    .with_project_id("acme-project");

Utilisez les projets pour Ă©viter, par exemple, qu’un assistant professionnel et un assistant personnel d’un utilisateur partagent la mĂ©moire, tout en partageant les faits rĂ©ellement globaux.

Tous les backends n’implĂ©mentent pas la portĂ©e par projet

L’isolation par projet est une à€•à„à€·à€źà€€à€Ÿ du backend, pas quelque chose que le trait peut garantir. VĂ©rifiez avant de vous y fier :

if service.supports_project_scoping() {
    service.add_entry_to_project("app", "user", "acme-project", entry).await?;
} else {
    // Decide explicitly: refuse, or store globally on purpose.
}
BackendDélimitation du projet
InMemoryMemoryServiceOui
SqliteMemoryServiceOui
PostgresMemoryServiceOui
RedisMemoryServiceOui
MongoMemoryServiceOui
Neo4jMemoryServiceOui
GraphMemoryServiceNon — les mĂ©thodes du projet renvoient une erreur

Un backend sans prise en charge des projets Ă©choue l’appel plutĂŽt que d’écrire ou de supprimer silencieusement Ă  l’échelle globale. Étendre la portĂ©e d’une Ă©criture rendrait des donnĂ©es prĂ©vues pour un projet visibles par tout ce qui se trouve sous la mĂȘme application et le mĂȘme utilisateur, et Ă©tendre une suppression retirerait des entrĂ©es en dehors du projet nommĂ© — aucun de ces cas ne peut ĂȘtre dĂ©tectĂ© par l’appelant Ă  partir de la valeur de retour. MemoryServiceAdapter::supports_project_scoping indique ce que son backend prend en charge.

Effacement RGPD

delete_user(app, user) supprime tous les souvenirs d’un utilisateur (entrĂ©es et embeddings) sur l’ensemble des projets — le primitive du droit Ă  l’effacement. Les backends qui stockent de maniĂšre persistante l’implĂ©mentent ; appelez-le depuis votre chemin de suppression de compte.

memory.delete_user("support", "alice").await?;

Suivant : Backends →

Concepts de mémoire - Documentation ADK-Rust | ADK-Rust