Mémoire
Mémoire sémantique à long terme pour les agents IA utilisant adk-memory.
Aperçu
Le système de mémoire fournit un stockage persistant et interrogeable pour les conversations d'agents. Contrairement à l'état de session (qui est éphémère), la mémoire persiste à travers les sessions et permet aux agents de rappeler le contexte pertinent des interactions passées.
Installation
[dependencies]
adk-memory = "0.2.0"
Concepts Clés
MemoryEntry
Un seul enregistrement de mémoire avec son contenu, son auteur et son horodatage :
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(),
};
Trait MemoryService
Le trait principal pour les backends de mémoire :
#[async_trait]
pub trait MemoryService: Send + Sync {
/// Store session memories for a user
async fn add_session(
&self,
app_name: &str,
user_id: &str,
session_id: &str,
entries: Vec<MemoryEntry>,
) -> Result<()>;
/// Search memories by query
async fn search(&self, req: SearchRequest) -> Result<SearchResponse>;
}
SearchRequest
Paramètres de requête pour la recherche de mémoire :
use adk_memory::SearchRequest;
let request = SearchRequest {
query: "user preferences".to_string(),
user_id: "user-123".to_string(),
app_name: "my_app".to_string(),
};
InMemoryMemoryService
Implémentation simple en mémoire pour le développement et les tests :
use adk_memory::{InMemoryMemoryService, MemoryService, MemoryEntry, SearchRequest};
use adk_core::Content;
use chrono::Utc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let memory = InMemoryMemoryService::new();
// Stocker les souvenirs d'une session
let entries = vec![
MemoryEntry {
content: Content::new("user").with_text("I like Rust programming"),
author: "user".to_string(),
timestamp: Utc::now(),
},
MemoryEntry {
content: Content::new("assistant").with_text("Rust is great for systems programming"),
author: "assistant".to_string(),
timestamp: Utc::now(),
},
];
memory.add_session("my_app", "user-123", "session-1", entries).await?;
// Rechercher des souvenirs
let request = SearchRequest {
query: "Rust".to_string(),
user_id: "user-123".to_string(),
app_name: "my_app".to_string(),
};
let response = memory.search(request).await?;
println!("Found {} memories", response.memories.len());
Ok(())
}
Isolation de la Mémoire
Les mémoires sont isolées par :
app_name: Différentes applications ont des espaces de mémoire séparésuser_id: Les mémoires de chaque utilisateur sont privées
// Mémoires de l'utilisateur A
memory.add_session("app", "user-a", "sess-1", entries_a).await?;
// Mémoires de l'utilisateur B (séparées)
memory.add_session("app", "user-b", "sess-1", entries_b).await?;
// La recherche ne renvoie que les mémoires de l'utilisateur A
let request = SearchRequest {
query: "topic".to_string(),
user_id: "user-a".to_string(),
app_name: "app".to_string(),
};
Comportement de Recherche
Le InMemoryMemoryService utilise la correspondance basée sur les mots :
- La requête est tokenisée en mots (minuscules)
- Le contenu de chaque mémoire est tokenisé
- Les mémoires contenant des mots correspondants sont renvoyées
// Requête : "rust programming"
// Correspond aux mémoires contenant "rust" OU "programming"
Backend de Memory personnalisé
Implémentez MemoryService pour un stockage personnalisé (par exemple, une base de données vectorielle) :
use adk_memory::{MemoryService, MemoryEntry, SearchRequest, SearchResponse};
use adk_core::Result;
use async_trait::async_trait;
pub struct VectorMemoryService {
// Your vector DB client
}
#[async_trait]
impl MemoryService for VectorMemoryService {
async fn add_session(
&self,
app_name: &str,
user_id: &str,
session_id: &str,
entries: Vec<MemoryEntry>,
) -> Result<()> {
// 1. Generate embeddings for each entry
// 2. Store in vector database with metadata
Ok(())
}
async fn search(&self, req: SearchRequest) -> Result<SearchResponse> {
// 1. Generate embedding for query
// 2. Perform similarity search
// 3. Return top-k results
Ok(SearchResponse { memories: vec![] })
}
}
Intégration avec les Agents
Memory s'intègre avec LlmAgentBuilder :
use adk_agent::LlmAgentBuilder;
use adk_memory::InMemoryMemoryService;
use std::sync::Arc;
let memory = Arc::new(InMemoryMemoryService::new());
let agent = LlmAgentBuilder::new("assistant")
.model(model)
.instruction("You are a helpful assistant with memory.")
.memory(memory)
.build()?;
Lorsque memory est configurée :
- Avant chaque tour, les
memoriespertinentes sont recherchées - Les
memoriescorrespondantes sont injectées dans le contexte - Après chaque
session, la conversation est stockée en tant quememories
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Agent Request │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Memory Search │
│ │
│ SearchRequest { query, user_id, app_name } │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ MemoryService │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌────────────┐ │ │
│ │ │ InMemory │ │ Vector DB │ │ Custom │ │ │
│ │ │ (dev/test) │ │ (Qdrant) │ │ Backend │ │ │
│ │ └─────────────┘ └─────────────┘ └────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ SearchResponse { memories: Vec<MemoryEntry> } │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Context Injection │
│ │
│ Relevant memories added to agent context │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Agent Execution │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Memory Storage │
│ │
│ Session conversation stored for future recall │
└─────────────────────────────────────────────────────────────┘
Bonnes Pratiques
| Pratique | Description |
|---|---|
| Utiliser une base de données vectorielle en production | InMemory est uniquement pour le développement/test |
| Délimiter par utilisateur | Toujours inclure l'user_id pour la confidentialité |
| Limiter les résultats | Limiter les mémoires retournées pour éviter le dépassement de contexte |
| Nettoyer les anciennes mémoires | Mettre en œuvre un TTL ou une archivage pour les données obsolètes |
| Intégrer stratégiquement | Stocker des résumés, pas des conversations brutes |
Comparaison avec les Sessions
| Caractéristique | État de la Session | Memory |
|---|---|---|
| Persistance | Durée de vie de la session | Permanent |
| Portée | Session unique | Inter-session |
| Recherche | Recherche par clé-valeur | Recherche sémantique |
| Cas d'utilisation | Contexte actuel | Rappel à long terme |
Précédent: ← Garde-fous | Suivant: Studio →