GuideAvancé

Entity Memory : Retenir les entites mentionnees

29 mars 2026
20 min de lecture
Equipe Ailog

Guide complet pour implementer la memoire d'entites dans un systeme RAG : tracker les personnes, produits et concepts mentionnes dans la conversation.

Entity Memory : Retenir les entites mentionnees

L'Entity Memory extrait et stocke les entites cles mentionnees dans la conversation : personnes, produits, entreprises, lieux, dates, etc. Contrairement au Buffer ou Summary Memory qui gardent le texte brut, l'Entity Memory construit un "graphe de connaissances" dynamique enrichi au fil des echanges. Cela permet des references naturelles comme "il", "ce produit", "cette option".

Pourquoi l'Entity Memory ?

Le probleme des references aux entites

Dans une conversation naturelle, les utilisateurs font constamment reference a des entites mentionnees precedemment :

User: "Je cherche le Dell XPS 15"
AI: "Le Dell XPS 15 est un excellent laptop..."

User: "Quelle est sa garantie ?"        <- "sa" = Dell XPS 15
AI: "La garantie du Dell XPS 15..."

User: "Et compare a celui de Lenovo ?"  <- "celui" = quel produit Lenovo ?
AI: ???

Sans Entity Memory, le LLM doit deviner a quelle entite fait reference l'utilisateur.

L'architecture Entity Memory

┌─────────────────────────────────────────────────────────────┐
│                     ENTITY MEMORY                            │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌────────────────────────────────────────────────────┐     │
│  │ ENTITY STORE                                        │     │
│  ├────────────────────────────────────────────────────┤     │
│  │                                                     │     │
│  │ "Dell XPS 15" (PRODUCT)                            │     │
│  │   - Type: Laptop                                   │     │
│  │   - Prix: 1599 euros                               │     │
│  │   - Garantie: 2 ans                               │     │
│  │   - Mentions: 3                                    │     │
│  │                                                     │     │
│  │ "Lenovo ThinkPad X1" (PRODUCT)                     │     │
│  │   - Type: Laptop                                   │     │
│  │   - Prix: 1799 euros                               │     │
│  │   - Mentions: 1                                    │     │
│  │                                                     │     │
│  └────────────────────────────────────────────────────┘     │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Statistique cle : L'Entity Memory ameliore la pertinence des reponses de 40-60% pour les conversations avec des references frequentes aux memes objets.

Cas d'usage

DomaineEntites trackeesExemple de reference
E-commerceProduits, marques, categories"Ce produit", "le meme en noir"
SupportTickets, produits, problemes"Mon compte", "cette erreur"
RHCandidats, postes, entreprises"Cette politique", "le poste"
ImmobilierBiens, quartiers, acheteurs"Cet appartement", "le vendeur"

Implementation de base

Structure des entites

DEVELOPERpython
from typing import Dict, List, Optional from dataclasses import dataclass, field from datetime import datetime import json @dataclass class Entity: """Represente une entite extraite""" name: str type: str # PERSON, PRODUCT, ORGANIZATION, etc. attributes: Dict = field(default_factory=dict) mentions: int = 1 first_seen: datetime = field(default_factory=datetime.now) last_seen: datetime = field(default_factory=datetime.now) def update(self, new_attributes: Dict) -> None: """Met a jour les attributs de l'entite""" self.attributes.update(new_attributes) self.mentions += 1 self.last_seen = datetime.now() def to_dict(self) -> Dict: """Convertit en dictionnaire""" return { "name": self.name, "type": self.type, "attributes": self.attributes, "mentions": self.mentions }

Entity Memory complete

DEVELOPERpython
class EntityMemory: """ Memoire conversationnelle basee sur les entites """ def __init__(self, llm, entity_types: List[str] = None): self.llm = llm self.entity_types = entity_types or [ "PERSON", "PRODUCT", "ORGANIZATION", "LOCATION", "DATE", "MONEY", "CONCEPT" ] self.entities: Dict[str, Entity] = {} self.recent_messages: List[Dict] = [] def add_message(self, role: str, content: str) -> None: """Ajoute un message et extrait les entites""" self.recent_messages.append({ "role": role, "content": content, "timestamp": datetime.now().isoformat() }) # Extraire les entites du message entities = self._extract_entities(content) self._update_entity_store(entities) def _extract_entities(self, text: str) -> List[Dict]: """Extrait les entites d'un texte avec le LLM""" prompt = f"""Extrais les entites nommees de ce texte. Types d'entites a detecter: {', '.join(self.entity_types)} Texte: "{text}" Retourne un JSON array: [{{"name": "nom", "type": "TYPE", "attributes": {{}}}}, ...] Si aucune entite, retourne: [] JSON:""" response = self.llm.invoke(prompt) try: return json.loads(response) except json.JSONDecodeError: return [] def _update_entity_store(self, entities: List[Dict]) -> None: """Met a jour le store d'entites""" for entity_data in entities: name = entity_data.get("name", "").lower() if not name: continue if name in self.entities: self.entities[name].update(entity_data.get("attributes", {})) else: self.entities[name] = Entity( name=entity_data.get("name"), type=entity_data.get("type", "UNKNOWN"), attributes=entity_data.get("attributes", {}) ) def get_recent_entities(self, limit: int = 5) -> List[Entity]: """Recupere les entites les plus recemment mentionnees""" sorted_entities = sorted( self.entities.values(), key=lambda e: e.last_seen, reverse=True ) return sorted_entities[:limit] def resolve_reference(self, reference: str) -> Optional[str]: """Resout une reference comme 'il', 'ce produit'""" if not self.entities: return None entities_json = json.dumps([e.to_dict() for e in self.get_recent_entities(5)]) prompt = f"""Reference a resoudre: "{reference}" Entites connues: {entities_json} Quelle entite correspond a "{reference}"? Reponds uniquement avec le nom, ou "NONE" si aucune correspondance.""" result = self.llm.invoke(prompt).strip() return result if result != "NONE" else None def get_context(self) -> str: """Genere le contexte a injecter dans le prompt""" if not self.entities: return "" recent = self.get_recent_entities(5) entity_lines = [] for e in recent: attrs = ", ".join([f"{k}: {v}" for k, v in e.attributes.items()]) line = f"- {e.name} ({e.type})" if attrs: line += f": {attrs}" entity_lines.append(line) return "Entites en contexte:\n" + "\n".join(entity_lines) def clear(self) -> None: """Reinitialise la memoire""" self.entities = {} self.recent_messages = []

Integration avec RAG

DEVELOPERpython
class RAGWithEntityMemory: """Pipeline RAG avec Entity Memory""" def __init__(self, vector_store, llm): self.vector_store = vector_store self.llm = llm self.memory = EntityMemory(llm) def query(self, user_message: str) -> str: """Execute une requete RAG avec contexte d'entites""" # 1. Resoudre les references resolved_message = self._resolve_references(user_message) # 2. Extraire les entites self.memory.add_message("user", resolved_message) # 3. Recuperer les documents docs = self.vector_store.similarity_search(resolved_message, k=3) doc_context = "\n\n".join([d.page_content for d in docs]) # 4. Construire le prompt entity_context = self.memory.get_context() prompt = f"""{entity_context} Documents pertinents: {doc_context} Question: {user_message} Reponds en tenant compte des entites mentionnees.""" # 5. Generer la reponse response = self.llm.invoke(prompt) self.memory.add_message("assistant", response) return response def _resolve_references(self, text: str) -> str: """Resout les references pronominales""" references = ["il", "elle", "ce produit", "cela", "celui-ci"] for ref in references: if ref in text.lower(): resolved = self.memory.resolve_reference(ref) if resolved: text = text.replace(ref, resolved, 1) return text

Techniques avancees

Extraction avec relations

DEVELOPERpython
class RelationalEntityMemory(EntityMemory): """Entity Memory avec relations entre entites""" def __init__(self, llm, **kwargs): super().__init__(llm, **kwargs) self.relations: List[Dict] = [] def _extract_entities(self, text: str) -> List[Dict]: """Extrait entites ET relations""" prompt = f"""Analyse ce texte et extrait: 1. Les entites nommees 2. Les relations entre entites Types de relations: COMPARES_TO, PREFERS, OWNS, INTERESTED_IN Texte: "{text}" JSON: {{ "entities": [{{"name": "...", "type": "...", "attributes": {{}}}}], "relations": [{{"source": "e1", "relation": "TYPE", "target": "e2"}}] }}""" response = self.llm.invoke(prompt) try: data = json.loads(response) for rel in data.get("relations", []): self.relations.append(rel) return data.get("entities", []) except json.JSONDecodeError: return [] def get_related_entities(self, entity_name: str) -> List[Dict]: """Trouve les entites liees""" related = [] name_lower = entity_name.lower() for rel in self.relations: if rel["source"].lower() == name_lower: related.append({"entity": rel["target"], "relation": rel["relation"]}) elif rel["target"].lower() == name_lower: related.append({"entity": rel["source"], "relation": rel["relation"]}) return related

Persistence multi-session

DEVELOPERpython
from pathlib import Path class PersistentEntityMemory(EntityMemory): """Entity Memory avec sauvegarde persistante""" def __init__(self, llm, user_id: str, storage_dir: str = "./entity_store"): super().__init__(llm) self.user_id = user_id self.storage_path = Path(storage_dir) / f"{user_id}.json" self._load() def _load(self) -> None: """Charge les entites depuis le fichier""" if self.storage_path.exists(): with open(self.storage_path, "r") as f: data = json.load(f) for name, entity_data in data.get("entities", {}).items(): self.entities[name] = Entity( name=entity_data["name"], type=entity_data["type"], attributes=entity_data.get("attributes", {}), mentions=entity_data.get("mentions", 1) ) def save(self) -> None: """Sauvegarde les entites""" self.storage_path.parent.mkdir(exist_ok=True) data = { "user_id": self.user_id, "entities": {name: e.to_dict() for name, e in self.entities.items()} } with open(self.storage_path, "w") as f: json.dump(data, f, indent=2) def add_message(self, role: str, content: str) -> None: super().add_message(role, content) self.save()

Implementation avec LangChain

DEVELOPERpython
from langchain.memory import ConversationEntityMemory from langchain.chains import ConversationChain from langchain_openai import ChatOpenAI llm = ChatOpenAI(model="gpt-4", temperature=0.7) # Entity Memory native LangChain memory = ConversationEntityMemory(llm=llm, return_messages=True) conversation = ConversationChain(llm=llm, memory=memory, verbose=True) # Utilisation response = conversation.predict(input="Je cherche un Dell XPS 15") response = conversation.predict(input="Quel est son prix ?") # Inspecter les entites print(memory.entity_store)

Bonnes pratiques

1. Types d'entites par domaine

DEVELOPERpython
# E-commerce ECOMMERCE_TYPES = ["PRODUCT", "BRAND", "CATEGORY", "PRICE", "FEATURE"] # Support SUPPORT_TYPES = ["PRODUCT", "ISSUE", "SOLUTION", "TICKET_ID", "PERSON"] # RH HR_TYPES = ["PERSON", "POSITION", "COMPANY", "SKILL", "EDUCATION"]

2. Expiration des entites

DEVELOPERpython
from datetime import timedelta class ExpiringEntityMemory(EntityMemory): def __init__(self, llm, ttl_minutes: int = 30, **kwargs): super().__init__(llm, **kwargs) self.ttl = timedelta(minutes=ttl_minutes) def _cleanup_expired(self) -> None: now = datetime.now() expired = [name for name, e in self.entities.items() if now - e.last_seen > self.ttl] for name in expired: del self.entities[name] def get_context(self) -> str: self._cleanup_expired() return super().get_context()

3. Priorisation intelligente

DEVELOPERpython
def get_prioritized_entities(self, query: str, limit: int = 5) -> List[Entity]: """Retourne les entites les plus pertinentes pour une requete""" scored = [] for entity in self.entities.values(): score = 0 recency = (datetime.now() - entity.last_seen).total_seconds() score += max(0, 100 - recency / 60) score += entity.mentions * 10 if entity.name.lower() in query.lower(): score += 50 scored.append((entity, score)) scored.sort(key=lambda x: x[1], reverse=True) return [e for e, _ in scored[:limit]]

Quand utiliser Entity Memory ?

Cas ideaux

  • E-commerce : Suivi des produits compares
  • Support technique : Suivi du probleme et solutions
  • CRM/Ventes : Suivi des contacts et opportunites
  • Conseil : Retenir preferences et contraintes

Quand eviter

SituationAlternative
Conversations generiquesBuffer Memory
Latence critiqueBuffer simple
Conversations tres courtesBuffer Memory

Guides connexes

FAQ

Le Buffer Memory stocke les messages bruts de la conversation, tandis que l'Entity Memory extrait et structure les entites mentionnees (produits, personnes, concepts). L'Entity Memory permet de resoudre les references pronominales ("il", "ce produit") et de maintenir un contexte semantique plus riche.
Oui, l'extraction d'entites ajoute un appel LLM supplementaire par message. Comptez 200-500ms de latence additionnelle selon le modele utilise. Pour les cas critiques en latence, privilegiez un Buffer Memory simple ou utilisez des modeles NER dedies plus rapides.
Utilisez une normalisation des noms (lowercase, suppression d'accents) et stockez des attributs distinctifs. Pour les cas complexes, implementez une resolution de coreference avec le LLM qui prend en compte le contexte recent pour desambiguiser.
Cela depend du cas d'usage. Pour un e-commerce, persister les produits consultes ameliore l'experience. Pour un support technique, les entites d'une session precedente peuvent etre obsoletes. Definissez un TTL (time-to-live) adapte a votre domaine.
Oui, c'est meme recommande. Combinez Entity Memory avec Summary Memory pour les conversations longues : les entites fournissent le contexte structure, le resume fournit le fil narratif. LangChain propose des memoires combinees pour ce pattern. ---

Entity Memory avec Ailog

Avec Ailog, beneficiez d'une gestion d'entites native :

  • Extraction automatique des entites avec types configurables
  • Resolution de coreferences ("il", "celui-ci", etc.)
  • Persistence multi-session des entites utilisateur
  • Graphe de relations entre entites
  • Analytics sur les entites les plus mentionnees

Testez Ailog gratuitement et deployez un chatbot qui retient les entites importantes.

Tags

RAGmemoryentitiesNERtrackingcontexteLangChainLlamaIndex

Articles connexes

Ailog Assistant

Ici pour vous aider

Salut ! Pose-moi des questions sur Ailog et comment intégrer votre RAG dans vos projets !