What is Agent Memory?

AI agent memory is the persistent cognitive architecture that allows agents to accumulate knowledge, maintain contextual awareness, and adapt their behavior based on historical interactions and learned experiences.

  • Memory makes Agents: Reliable, Believable and Capable

What is Memory Management?

Memory management in agentic syustems refers to the systematic organization, persistence, and retrieval of different types of information that AI agents need to function effictively across interactions and sessions.

Core Components of Agent Memory Management

1. Generation

2. Storage

3. Retrieval

4. Integration

5. Updating

6. Deletion/Forgetting

Different Forms of Memory

Persona

  • Description: Stores agent identity information, including personality traits, roles, expertise domains, and communication styles.
  • Contents: Name, role, goals, background, and vector embeddings for semantic retrieval.
  • Usage: Provides consistent identity for agents across interactions and sessions.
  • Schema: Includes Persona_id, name, role, goals, background fields with embedding vectors

ToolBox

  • Description: Stores tool definitions, metadata, parameter schemas, and embeddings for function capabilities.
  • Contents: Tool names, descriptions, parameter specifications, and vector embeddings
  • Usage: Enables semantic discovery and execution of external functions by agents
  • Schema: Includes tool_id, name, function metadata, parameters, and embedding vectors.

Conversation Memory

  • Description: Stores historical exchanges between users and agents
  • Contents: Sequential turns with roles, content, timestamps, and conversation identifiers.
  • Usage: Provides context for ongoing conversations and enables coherent multi-turn interactions
  • Schema: Includes memory_id, conversation_id, role, content, timestamp fields

Workflow Memory

  • Description: Stores multi-step process information and state tracking
  • Contents: Workflow definitions, current state, transition history, and execution context
  • Usage: Supports complex, multi-stage operations that span multiple agent interactions
  • Schema: Includes workflow_id, stages, current_stage, history, and context information

Agent Memory

  • Description: Stores agent-specific state, decision patterns, and learned behaviors
  • Contents: Agent preferences, behavioral patterns, decision history, and adaptation parameters
  • Usage: Enables agents to maintain consistent behavior patterns and learn from past decisions
  • Schema: Includes agent_id, behavior_patterns, decision_history, preferences, adaptation_metrics

Episodic Memory

  • Description: Stores specific events and experiences as discrete episodes with temporal context
  • Contents: Event sequences, context information, outcomes, and temporal relationships
  • Usage: Enables agents to recall specific past events and learn from similar situations
  • Schema: Includes episode_id, timestamp, context, actions, outcomes, emotional_state

Long-term Memory

  • Description: Stores persistent knowledge, patterns, and insights that transcend individual sessions
  • Contents: Accumulated knowledge, learned patterns, strategic insights, and domain expertise
  • Usage: Provides foundational knowledge base that persists across agent lifecycles
  • Schema: Includes memory_id, knowledge_type, content, confidence_score, last_updated

Entity Memory

  • Description: Stores information about specific entities (people, objects, concepts) encountered by the agent
  • Contents: Entity attributes, relationships, interaction history, and contextual associations
  • Usage: Enables agents to maintain detailed knowledge about recurring entities and their properties
  • Schema: Includes entity_id, entity_type, attributes, relationships, interaction_history

Memory Implementation in LangGraph

1. Checkpointing for Conversation Memory

LangGraph provides built-in checkpointing mechanisms for maintaining conversation state:

from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.graph import StateGraph, END
from typing import TypedDict
 
class ConversationState(TypedDict):
    messages: list
    user_id: str
    conversation_id: str
    context: dict
 
# Initialize memory with SQLite checkpointer
memory = SqliteSaver.from_conn_string(":memory:")
 
def conversation_node(state: ConversationState):
    # Process conversation with memory context
    return {"messages": updated_messages}
 
# Build graph with memory
workflow = StateGraph(ConversationState)
workflow.add_node("conversation", conversation_node)
workflow.set_entry_point("conversation")
workflow.add_edge("conversation", END)
 
# Compile with memory checkpointing
app = workflow.compile(checkpointer=memory)
 
# Use with thread_id for conversation continuity
config = {"configurable": {"thread_id": "user_123_conversation"}}
result = app.invoke(input_data, config=config)

2. Custom Memory Storage Implementation

import sqlite3
import json
from datetime import datetime
from typing import Dict, List, Optional
 
class AgentMemoryManager:
    def __init__(self, db_path: str):
        self.db_path = db_path
        self.init_database()
    
    def init_database(self):
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # Conversation memory table
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS conversation_memory (
                id INTEGER PRIMARY KEY,
                conversation_id TEXT,
                role TEXT,
                content TEXT,
                timestamp DATETIME,
                metadata JSON
            )
        ''')
        
        # Entity memory table
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS entity_memory (
                id INTEGER PRIMARY KEY,
                entity_id TEXT UNIQUE,
                entity_type TEXT,
                attributes JSON,
                last_updated DATETIME
            )
        ''')
        
        # Episodic memory table
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS episodic_memory (
                id INTEGER PRIMARY KEY,
                episode_id TEXT UNIQUE,
                context JSON,
                actions JSON,
                outcomes JSON,
                timestamp DATETIME
            )
        ''')
        
        conn.commit()
        conn.close()
    
    def store_conversation(self, conversation_id: str, role: str, 
                          content: str, metadata: Dict = None):
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute('''
            INSERT INTO conversation_memory 
            (conversation_id, role, content, timestamp, metadata)
            VALUES (?, ?, ?, ?, ?)
        ''', (conversation_id, role, content, datetime.now(), 
              json.dumps(metadata or {})))
        
        conn.commit()
        conn.close()
    
    def retrieve_conversation_history(self, conversation_id: str, 
                                    limit: int = 50) -> List[Dict]:
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute('''
            SELECT role, content, timestamp, metadata 
            FROM conversation_memory 
            WHERE conversation_id = ? 
            ORDER BY timestamp DESC 
            LIMIT ?
        ''', (conversation_id, limit))
        
        results = cursor.fetchall()
        conn.close()
        
        return [{
            'role': row[0],
            'content': row[1],
            'timestamp': row[2],
            'metadata': json.loads(row[3])
        } for row in results]

3. Vector-Based Semantic Memory

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_core.documents import Document
 
class SemanticMemoryManager:
    def __init__(self, persist_directory: str):
        self.embeddings = OpenAIEmbeddings()
        self.vectorstore = Chroma(
            persist_directory=persist_directory,
            embedding_function=self.embeddings
        )
    
    def store_memory(self, content: str, memory_type: str, 
                    metadata: Dict = None):
        doc = Document(
            page_content=content,
            metadata={
                "memory_type": memory_type,
                "timestamp": datetime.now().isoformat(),
                **(metadata or {})
            }
        )
        self.vectorstore.add_documents([doc])
    
    def retrieve_relevant_memories(self, query: str, 
                                 memory_type: str = None,
                                 k: int = 5) -> List[Document]:
        filter_dict = {"memory_type": memory_type} if memory_type else None
        return self.vectorstore.similarity_search(
            query, k=k, filter=filter_dict
        )

Memory Integration Patterns

1. Memory-Augmented Agent Node

def memory_augmented_agent_node(state: AgentState):
    memory_manager = state["memory_manager"]
    query = state["current_query"]
    
    # Retrieve relevant memories
    conversation_history = memory_manager.retrieve_conversation_history(
        state["conversation_id"]
    )
    
    relevant_memories = memory_manager.retrieve_relevant_memories(
        query, memory_type="episodic"
    )
    
    # Augment context with memories
    context = {
        "conversation_history": conversation_history,
        "relevant_experiences": relevant_memories,
        "current_query": query
    }
    
    # Process with memory context
    response = llm.invoke(context)
    
    # Store new memory
    memory_manager.store_conversation(
        state["conversation_id"], 
        "assistant", 
        response.content
    )
    
    return {"response": response, "updated_context": context}

2. Multi-Memory Retrieval

def multi_memory_retrieval_node(state: AgentState):
    query = state["query"]
    memory_managers = state["memory_managers"]
    
    # Retrieve from multiple memory types
    memories = {}
    
    # Conversation memory
    memories["conversation"] = memory_managers["conversation"].retrieve(
        state["conversation_id"]
    )
    
    # Entity memory
    memories["entities"] = memory_managers["entity"].retrieve_entities(
        query
    )
    
    # Episodic memory
    memories["episodes"] = memory_managers["episodic"].retrieve_similar_episodes(
        query
    )
    
    # Long-term knowledge
    memories["knowledge"] = memory_managers["knowledge"].retrieve_knowledge(
        query
    )
    
    return {"retrieved_memories": memories}

Memory Lifecycle Management

1. Memory Consolidation

def consolidate_memories(memory_manager: AgentMemoryManager):
    """Consolidate short-term memories into long-term storage"""
    
    # Retrieve recent episodic memories
    recent_episodes = memory_manager.get_recent_episodes(days=7)
    
    # Identify patterns and important events
    patterns = identify_patterns(recent_episodes)
    important_events = classify_importance(recent_episodes)
    
    # Store consolidated knowledge
    for pattern in patterns:
        memory_manager.store_long_term_knowledge(pattern)
    
    # Promote important episodes to long-term storage
    for event in important_events:
        memory_manager.promote_to_long_term(event)

2. Memory Cleanup and Forgetting

def cleanup_memories(memory_manager: AgentMemoryManager):
    """Remove outdated or irrelevant memories"""
    
    # Remove old conversation history (keep only recent)
    memory_manager.cleanup_conversations(keep_days=30)
    
    # Remove low-confidence episodic memories
    memory_manager.remove_low_confidence_episodes(threshold=0.3)
    
    # Compress similar entities
    memory_manager.merge_similar_entities(similarity_threshold=0.9)

Best Practices for Memory Management

1. Memory Hierarchy Design

  • Immediate Memory: Current conversation context
  • Short-term Memory: Recent interactions and temporary context
  • Long-term Memory: Persistent knowledge and patterns
  • Meta-Memory: Memory about memory (what the agent remembers)

2. Retrieval Strategies

  • Recency: Prioritize recent memories
  • Relevance: Use semantic similarity for retrieval
  • Importance: Weight memories by significance
  • Frequency: Consider how often memories are accessed

3. Privacy and Security

  • Data Encryption: Encrypt sensitive memory content
  • Access Control: Implement role-based memory access
  • Retention Policies: Automatic cleanup of personal data
  • Anonymization: Remove identifying information when possible

4. Performance Optimization

  • Indexing: Create efficient indexes for memory retrieval
  • Caching: Cache frequently accessed memories
  • Compression: Compress old memory data
  • Partitioning: Partition memories by user, time, or type

Advanced Memory Patterns

1. Hierarchical Memory

class HierarchicalMemory:
    def __init__(self):
        self.working_memory = {}
        self.short_term_memory = {}
        self.long_term_memory = {}
    
    def store(self, content, importance_level):
        if importance_level == "immediate":
            self.working_memory[content.id] = content
        elif importance_level == "session":
            self.short_term_memory[content.id] = content
        else:
            self.long_term_memory[content.id] = content

2. Associative Memory Networks

class AssociativeMemory:
    def __init__(self):
        self.memory_graph = nx.Graph()
    
    def add_memory(self, memory_id, content, associations):
        self.memory_graph.add_node(memory_id, content=content)
        for assoc_id, weight in associations:
            self.memory_graph.add_edge(memory_id, assoc_id, weight=weight)
    
    def retrieve_associated(self, memory_id, depth=2):
        return nx.ego_graph(self.memory_graph, memory_id, radius=depth)

This comprehensive memory management system enables agents to maintain context, learn from experiences, and provide more intelligent, personalized interactions across sessions.