Agentic Design Pattern: Long Term Memory

Written by

in


    """
Pattern 027: Long-Term Memory

Description:
    The Long-Term Memory pattern enables agents to store and retrieve information
    across multiple sessions and conversations. Unlike short-term memory that exists
    only within a session, long-term memory persists indefinitely, allowing agents
    to remember user preferences, past interactions, learned facts, and accumulated
    knowledge over time.

Components:
    - Persistent Storage: Vector databases, traditional databases, file systems
    - Memory Indexing: Efficient retrieval mechanisms
    - Memory Types: Episodic (events), Semantic (facts), Procedural (skills)
    - Retrieval System: Similarity search, keyword matching
    - Memory Consolidation: Organizing and optimizing stored memories

Use Cases:
    - Personalized user experiences
    - Learning from past interactions
    - Knowledge accumulation
    - User preference tracking
    - Long-term relationship building

LangChain Implementation:
    Uses vector stores (Chroma, FAISS) for semantic memory storage,
    implements retrieval strategies, and combines with conversation
    context for personalized interactions.

Key Features:
    - Cross-session persistence
    - Semantic similarity search
    - Memory categorization
    - Efficient retrieval
    - Memory aging and importance
"""

import os
from typing import List, Dict, Any, Optional, Tuple
from dataclasses import dataclass, field
from enum import Enum
from datetime import datetime
import json
from pathlib import Path
from dotenv import load_dotenv

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

load_dotenv()


class MemoryType(Enum):
    """Types of long-term memories."""
    EPISODIC = "episodic"  # Specific events and experiences
    SEMANTIC = "semantic"  # Facts and knowledge
    PROCEDURAL = "procedural"  # Skills and procedures
    PREFERENCE = "preference"  # User preferences
    INTERACTION = "interaction"  # Past interactions


@dataclass
class Memory:
    """Represents a long-term memory."""
    id: str
    content: str
    memory_type: MemoryType
    timestamp: datetime
    importance: float = 1.0  # 0-1 scale
    metadata: Dict[str, Any] = field(default_factory=dict)
    access_count: int = 0
    last_accessed: Optional[datetime] = None
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            "id": self.id,
            "content": self.content,
            "memory_type": self.memory_type.value,
            "timestamp": self.timestamp.isoformat(),
            "importance": self.importance,
            "metadata": self.metadata,
            "access_count": self.access_count,
            "last_accessed": self.last_accessed.isoformat() if self.last_accessed else None
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Memory':
        """Create from dictionary."""
        return cls(
            id=data["id"],
            content=data["content"],
            memory_type=MemoryType(data["memory_type"]),
            timestamp=datetime.fromisoformat(data["timestamp"]),
            importance=data.get("importance", 1.0),
            metadata=data.get("metadata", {}),
            access_count=data.get("access_count", 0),
            last_accessed=datetime.fromisoformat(data["last_accessed"]) if data.get("last_accessed") else None
        )


class SimpleVectorStore:
    """
    Simple vector store for semantic memory storage (mock implementation).
    In production, would use Chroma, FAISS, or Pinecone.
    """
    
    def __init__(self):
        """Initialize vector store."""
        self.memories: List[Memory] = []
        self.embeddings_model = None  # Would use OpenAIEmbeddings() in production
    
    def add_memory(self, memory: Memory):
        """Add a memory to the store."""
        self.memories.append(memory)
    
    def search(
        self,
        query: str,
        memory_type: Optional[MemoryType] = None,
        k: int = 5
    ) -> List[Memory]:
        """
        Search for relevant memories.
        
        Args:
            query: Search query
            memory_type: Filter by memory type
            k: Number of results
            
        Returns:
            List of relevant memories
        """
        # Filter by type if specified
        candidates = self.memories
        if memory_type:
            candidates = [m for m in candidates if m.memory_type == memory_type]
        
        # Simple keyword matching (in production, would use vector similarity)
        query_lower = query.lower()
        scored_memories = []
        
        for memory in candidates:
            # Simple scoring based on keyword matches
            content_lower = memory.content.lower()
            score = 0.0
            
            for word in query_lower.split():
                if word in content_lower:
                    score += 1.0
            
            # Boost by importance and recency
            score *= memory.importance
            
            days_old = (datetime.now() - memory.timestamp).days
            recency_factor = 1.0 / (1.0 + days_old * 0.01)
            score *= recency_factor
            
            if score > 0:
                scored_memories.append((score, memory))
        
        # Sort by score and return top k
        scored_memories.sort(reverse=True, key=lambda x: x[0])
        results = [memory for _, memory in scored_memories[:k]]
        
        # Update access statistics
        for memory in results:
            memory.access_count += 1
            memory.last_accessed = datetime.now()
        
        return results
    
    def get_all_memories(self) -> List[Memory]:
        """Get all memories."""
        return self.memories.copy()
    
    def delete_memory(self, memory_id: str):
        """Delete a memory by ID."""
        self.memories = [m for m in self.memories if m.id != memory_id]


class PersistentMemoryStore:
    """
    Persistent storage for long-term memory (file-based mock).
    In production, would use proper database.
    """
    
    def __init__(self, storage_path: str = "memory_store.json"):
        """
        Initialize persistent store.
        
        Args:
            storage_path: Path to storage file
        """
        self.storage_path = Path(storage_path)
        self.vector_store = SimpleVectorStore()
        self._load()
    
    def _load(self):
        """Load memories from disk."""
        if self.storage_path.exists():
            try:
                with open(self.storage_path, 'r') as f:
                    data = json.load(f)
                    for memory_data in data:
                        memory = Memory.from_dict(memory_data)
                        self.vector_store.add_memory(memory)
            except Exception as e:
                print(f"Warning: Could not load memories: {e}")
    
    def _save(self):
        """Save memories to disk."""
        try:
            data = [m.to_dict() for m in self.vector_store.get_all_memories()]
            with open(self.storage_path, 'w') as f:
                json.dump(data, f, indent=2)
        except Exception as e:
            print(f"Warning: Could not save memories: {e}")
    
    def add_memory(self, memory: Memory):
        """Add and persist a memory."""
        self.vector_store.add_memory(memory)
        self._save()
    
    def search(
        self,
        query: str,
        memory_type: Optional[MemoryType] = None,
        k: int = 5
    ) -> List[Memory]:
        """Search for relevant memories."""
        return self.vector_store.search(query, memory_type, k)
    
    def get_all_memories(self) -> List[Memory]:
        """Get all stored memories."""
        return self.vector_store.get_all_memories()
    
    def clear(self):
        """Clear all memories."""
        self.vector_store.memories.clear()
        self._save()


class LongTermMemoryAgent:
    """
    Agent with long-term memory capabilities.
    """
    
    def __init__(
        self,
        user_id: str,
        storage_path: Optional[str] = None,
        model: str = "gpt-3.5-turbo"
    ):
        """
        Initialize agent with long-term memory.
        
        Args:
            user_id: Unique user identifier
            storage_path: Path to memory storage
            model: LLM model to use
        """
        self.user_id = user_id
        self.llm = ChatOpenAI(model=model, temperature=0.7)
        
        # Initialize memory store
        if storage_path is None:
            storage_path = f"memory_{user_id}.json"
        self.memory_store = PersistentMemoryStore(storage_path)
        
        self.interaction_count = 0
    
    def store_memory(
        self,
        content: str,
        memory_type: MemoryType,
        importance: float = 1.0,
        metadata: Optional[Dict] = None
    ):
        """
        Store a new memory.
        
        Args:
            content: Memory content
            memory_type: Type of memory
            importance: Importance score (0-1)
            metadata: Additional metadata
        """
        memory = Memory(
            id=f"{self.user_id}_{datetime.now().timestamp()}",
            content=content,
            memory_type=memory_type,
            timestamp=datetime.now(),
            importance=importance,
            metadata=metadata or {}
        )
        self.memory_store.add_memory(memory)
    
    def recall_memories(
        self,
        query: str,
        memory_type: Optional[MemoryType] = None,
        k: int = 5
    ) -> List[Memory]:
        """
        Recall relevant memories.
        
        Args:
            query: Query for memory retrieval
            memory_type: Filter by type
            k: Number of memories to retrieve
            
        Returns:
            List of relevant memories
        """
        return self.memory_store.search(query, memory_type, k)
    
    def chat(self, user_message: str) -> str:
        """
        Chat with memory-augmented responses.
        
        Args:
            user_message: User's message
            
        Returns:
            Agent's response
        """
        self.interaction_count += 1
        
        # Recall relevant memories
        relevant_memories = self.recall_memories(user_message, k=3)
        
        # Format memories for context
        memory_context = ""
        if relevant_memories:
            memory_lines = []
            for mem in relevant_memories:
                memory_lines.append(
                    f"[{mem.memory_type.value}] {mem.content} "
                    f"(from {mem.timestamp.strftime('%Y-%m-%d')})"
                )
            memory_context = "\n".join(memory_lines)
        
        # Create prompt with memory context
        prompt = ChatPromptTemplate.from_messages([
            ("system", """You are a helpful AI assistant with long-term memory.
Use the relevant memories to personalize your responses and maintain continuity
across conversations."""),
            ("user", """Relevant Memories:
{memory_context}

Current Message: {message}

Provide a helpful, personalized response:""")
        ])
        
        chain = prompt | self.llm | StrOutputParser()
        
        response = chain.invoke({
            "memory_context": memory_context if memory_context else "No relevant memories found.",
            "message": user_message
        })
        
        # Store this interaction
        self.store_memory(
            content=f"User: {user_message} | AI: {response}",
            memory_type=MemoryType.INTERACTION,
            importance=0.5
        )
        
        # Extract and store important information
        self._extract_and_store_info(user_message)
        
        return response.strip()
    
    def _extract_and_store_info(self, message: str):
        """Extract and store important information from message."""
        # Simple extraction logic (in production, would use NER or LLM)
        message_lower = message.lower()
        
        # Detect preferences
        if any(word in message_lower for word in ["like", "prefer", "favorite", "love"]):
            self.store_memory(
                content=message,
                memory_type=MemoryType.PREFERENCE,
                importance=0.8
            )
        
        # Detect facts
        if any(word in message_lower for word in ["my name is", "i am", "i work", "i live"]):
            self.store_memory(
                content=message,
                memory_type=MemoryType.SEMANTIC,
                importance=0.9
            )
    
    def get_memory_summary(self) -> Dict[str, Any]:
        """Get summary of stored memories."""
        all_memories = self.memory_store.get_all_memories()
        
        memory_by_type = {}
        for mem_type in MemoryType:
            memory_by_type[mem_type.value] = sum(
                1 for m in all_memories if m.memory_type == mem_type
            )
        
        total_accesses = sum(m.access_count for m in all_memories)
        
        return {
            "user_id": self.user_id,
            "total_memories": len(all_memories),
            "by_type": memory_by_type,
            "total_accesses": total_accesses,
            "interactions": self.interaction_count
        }


def demonstrate_long_term_memory():
    """Demonstrate the Long-Term Memory pattern."""
    
    print("=" * 80)
    print("LONG-TERM MEMORY PATTERN DEMONSTRATION")
    print("=" * 80)
    
    # Create agent for user
    user_id = "alice_demo"
    agent = LongTermMemoryAgent(user_id=user_id, storage_path=f"memory_{user_id}_demo.json")
    
    # Clear any existing memories
    agent.memory_store.clear()
    
    # Session 1: Initial interaction
    print("\n" + "=" * 80)
    print("SESSION 1: Initial Interaction")
    print("=" * 80)
    
    messages_session1 = [
        "Hi, my name is Alice and I'm a software engineer.",
        "I really love Python programming and machine learning.",
        "My favorite food is sushi."
    ]
    
    for msg in messages_session1:
        print(f"\nšŸ‘¤ User: {msg}")
        response = agent.chat(msg)
        print(f"šŸ¤– Agent: {response}")
    
    print("\nšŸ“Š Memory Summary after Session 1:")
    summary = agent.get_memory_summary()
    print(json.dumps(summary, indent=2))
    
    # Simulate new session (create new agent instance)
    print("\n\n" + "=" * 80)
    print("SESSION 2: Later Conversation (Testing Persistence)")
    print("=" * 80)
    print("(Simulating new session - creating fresh agent instance)")
    
    agent2 = LongTermMemoryAgent(user_id=user_id, storage_path=f"memory_{user_id}_demo.json")
    
    messages_session2 = [
        "What's my name?",
        "What do I do for work?",
        "What are my interests?",
        "What food do I like?"
    ]
    
    for msg in messages_session2:
        print(f"\nšŸ‘¤ User: {msg}")
        response = agent2.chat(msg)
        print(f"šŸ¤– Agent: {response}")
    
    print("\nšŸ“Š Memory Summary after Session 2:")
    summary2 = agent2.get_memory_summary()
    print(json.dumps(summary2, indent=2))
    
    # Session 3: Memory accumulation
    print("\n\n" + "=" * 80)
    print("SESSION 3: Adding More Memories")
    print("=" * 80)
    
    agent3 = LongTermMemoryAgent(user_id=user_id, storage_path=f"memory_{user_id}_demo.json")
    
    messages_session3 = [
        "I recently started learning about transformers.",
        "I'm working on a project about recommendation systems.",
        "Can you suggest something based on my interests?"
    ]
    
    for msg in messages_session3:
        print(f"\nšŸ‘¤ User: {msg}")
        response = agent3.chat(msg)
        print(f"šŸ¤– Agent: {response}")
    
    # Show memory details
    print("\n\n" + "=" * 80)
    print("STORED MEMORIES ANALYSIS")
    print("=" * 80)
    
    all_memories = agent3.memory_store.get_all_memories()
    
    print(f"\nTotal memories: {len(all_memories)}")
    
    for mem_type in MemoryType:
        type_memories = [m for m in all_memories if m.memory_type == mem_type]
        if type_memories:
            print(f"\n{mem_type.value.upper()} Memories ({len(type_memories)}):")
            for mem in type_memories[:3]:  # Show first 3
                print(f"  - {mem.content[:80]}...")
                print(f"    Importance: {mem.importance:.1f}, Accessed: {mem.access_count} times")
    
    # Clean up demo file
    try:
        os.remove(f"memory_{user_id}_demo.json")
    except:
        pass
    
    # Summary
    print("\n\n" + "=" * 80)
    print("PATTERN SUMMARY")
    print("=" * 80)
    print("""
The Long-Term Memory pattern demonstrates:

1. **Cross-Session Persistence**: Memories survive across sessions
2. **Memory Categorization**: Different types (episodic, semantic, preference)
3. **Semantic Retrieval**: Find relevant memories via similarity
4. **Memory Statistics**: Track access patterns and importance
5. **Personalization**: Use past memories for context-aware responses

Memory Types:

Episodic Memory:
- Stores specific events and experiences
- "When I visited Paris..."
- Time and context-stamped

Semantic Memory:
- Stores facts and knowledge
- "Paris is the capital of France"
- General information

Procedural Memory:
- Stores skills and procedures
- "How to make coffee"
- Step-by-step knowledge

Preference Memory:
- Stores user preferences
- "I prefer dark mode"
- Likes and dislikes

Interaction Memory:
- Stores past conversations
- Complete interaction history
- Enables continuity

Key Benefits:
- **Personalization**: Tailored responses based on history
- **Continuity**: Maintains context across sessions
- **Learning**: Accumulates knowledge over time
- **Relationship**: Builds long-term user relationships
- **Efficiency**: Doesn't repeat questions

Implementation Considerations:
- Vector databases for semantic search (Chroma, Pinecone, FAISS)
- Memory importance and decay
- Privacy and data retention
- Storage optimization
- Cross-device synchronization

Use Cases:
- Personal assistants with memory of user
- Educational tutors tracking student progress
- Healthcare agents remembering patient history
- Customer service with account context
- Long-term collaborative projects

This pattern transforms agents from stateless responders to
persistent entities with accumulated knowledge and relationships.
""")


if __name__ == "__main__":
    demonstrate_long_term_memory()

    

Agentic Design Pattern: Long Term Memory

Pattern 027: Long Term Memory – Line-by-Line Explanation

Overview

This document provides a detailed line-by-line explanation of the Long Term Memory pattern implementation.


Pattern Description

Pattern 027: Long-Term Memory

Description: The Long-Term Memory pattern enables agents to store and retrieve information across multiple sessions and conversations. Unlike short-term memory that exists only within a session, long-term memory persists indefinitely, allowing agents to remember user preferences, past interactions, learned facts, and accumulated knowledge over time.

Components: – Persistent Storage: Vector databases, traditional databases, file systems – Memory Indexing: Efficient retrieval mechanisms – Memory Types: Episodic (events), Semantic (facts), Procedural (skills) – Retrieval System: Similarity search, keyword matching – Memory Consolidation: Organizing and optimizing stored memories

Use Cases: – Personalized user experiences – Learning from past interactions – Knowledge accumulation – User preference tracking – Long-term relationship building

LangChain Implementation: Uses vector stores (Chroma, FAISS) for semantic memory storage, implements retrieval strategies, and combines with conversation context for personalized interactions.

Key Features: – Cross-session persistence – Semantic similarity search – Memory categorization – Efficient retrieval – Memory aging and importance


File Statistics

  • Total Lines: 586
  • Classes: 5
  • Functions: 1
  • Constants: 0

Module Documentation

"""
Pattern 027: Long-Term Memory

Description:
    The Long-Term Memory pattern enables agents to store and retrieve information
    across multiple sessions and conversations. Unlike short-term memory that exists
    only within a session, long-term memory persists indefinitely, allowing agents
    to remember user preferences, past interactions, learned facts, and accumulated
    knowledge over time.

Components:
    - Persistent Storage: Vector databases, traditional databases, file systems
    - Memory Indexing: Efficient retrieval mechanisms
    - Memory Types: Episodic (events), Semantic (facts), Procedural (skills)
    - Retrieval System: Similarity search, keyword matching
    - Memory Consolidation: Organizing and optimizing stored memories

Use Cases:
    - Personalized user experiences
    - Learning from past interactions
    - Knowledge accumulation
    - User preference tracking
    - Long-term relationship building

LangChain Implementation:
    Uses vector stores (Chroma, FAISS) for semantic memory storage,
    implements retrieval strategies, and combines with conversation
    context for personalized interactions.

Key Features:
    - Cross-session persistence
    - Semantic similarity search
    - Memory categorization
    - Efficient retrieval
    - Memory aging and importance
"""

Purpose: This module implements the Long Term Memory pattern, providing a structured approach to agent design and implementation.


Import Statements

Standard Library Imports

import dataclasses.dataclass
import dataclasses.field
import datetime.datetime
import enum.Enum
import json
import langchain_core.output_parsers.StrOutputParser
import langchain_core.prompts.ChatPromptTemplate
import os
import pathlib.Path
import typing.Any
import typing.Dict
import typing.List
import typing.Optional
import typing.Tuple

Purpose: Core Python functionality: – dataclasses.dataclass: Simplified class definitions with @dataclass – dataclasses.field: Simplified class definitions with @dataclass – datetime.datetime: Date and time handling – enum.Enum: Enumeration support – json: JSON serialization/deserialization – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – os: Environment variable access and system operations – pathlib.Path: Object-oriented filesystem paths – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Tuple: Type hints for better code documentation (List, Dict, Any, Optional)

LangChain Imports

from langchain_openai.ChatOpenAI
from langchain_openai.OpenAIEmbeddings

Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

Other Imports

from dotenv.load_dotenv

Purpose: Additional dependencies for specialized functionality.


Classes

Class: MemoryType

Lines 54-60

Inherits from: Enum

Purpose:

Types of long-term memories.

Class: Memory

Lines 64-100

Purpose:

Represents a long-term memory.

Methods:

to_dict(self)

Lines 75-86

Purpose:

Convert to dictionary.

Parameters:

Returns: <ast.Subscript object at 0x000001A06D64A3D0>

from_dict(cls, data)

Lines 89-100

Decorators: classmethod

Purpose:

Create from dictionary.

Parameters: – cls: Cls – data: Data

Returns: Memory


Class: SimpleVectorStore

Lines 103-180

Purpose:

Simple vector store for semantic memory storage (mock implementation).
In production, would use Chroma, FAISS, or Pinecone.

Methods:

__init__(self)

Lines 109-112

Purpose:

Initialize vector store.

Parameters:

add_memory(self, memory)

Lines 114-116

Purpose:

Add a memory to the store.

Parameters: – memory: Memory store for conversation history

search(self, query, memory_type, k)

Lines 118-172

Purpose:

Search for relevant memories.

Args:
    query: Search query
    memory_type: Filter by memory type
    k: Number of results

Returns:
    List of relevant memories

Parameters: – query: Input query or question – memory_type: Memory store for conversation history – k: K

Returns: <ast.Subscript object at 0x000001A06D6EA550>

get_all_memories(self)

Lines 174-176

Purpose:

Get all memories.

Parameters:

Returns: <ast.Subscript object at 0x000001A06D6E9950>

delete_memory(self, memory_id)

Lines 178-180

Purpose:

Delete a memory by ID.

Parameters: – memory_id: Memory store for conversation history


Class: PersistentMemoryStore

Lines 183-242

Purpose:

Persistent storage for long-term memory (file-based mock).
In production, would use proper database.

Methods:

__init__(self, storage_path)

Lines 189-198

Purpose:

Initialize persistent store.

Args:
    storage_path: Path to storage file

Parameters: – storage_path: Storage path

_load(self)

Lines 200-210

Purpose:

Load memories from disk.

Parameters:

_save(self)

Lines 212-219

Purpose:

Save memories to disk.

Parameters:

add_memory(self, memory)

Lines 221-224

Purpose:

Add and persist a memory.

Parameters: – memory: Memory store for conversation history

search(self, query, memory_type, k)

Lines 226-233

Purpose:

Search for relevant memories.

Parameters: – query: Input query or question – memory_type: Memory store for conversation history – k: K

Returns: <ast.Subscript object at 0x000001A06D70CD50>

get_all_memories(self)

Lines 235-237

Purpose:

Get all stored memories.

Parameters:

Returns: <ast.Subscript object at 0x000001A06D70E550>

clear(self)

Lines 239-242

Purpose:

Clear all memories.

Parameters:


Class: LongTermMemoryAgent

Lines 245-416

Purpose:

Agent with long-term memory capabilities.

Methods:

__init__(self, user_id, storage_path, model)

Lines 250-272

Purpose:

Initialize agent with long-term memory.

Args:
    user_id: Unique user identifier
    storage_path: Path to memory storage
    model: LLM model to use

Parameters: – user_id: User id – storage_path: Storage path – model: Language model instance

store_memory(self, content, memory_type, importance, metadata)

Lines 274-298

Purpose:

Store a new memory.

Args:
    content: Memory content
    memory_type: Type of memory
    importance: Importance score (0-1)
    metadata: Additional metadata

Parameters: – content: Content – memory_type: Memory store for conversation history – importance: Importance – metadata: Metadata

recall_memories(self, query, memory_type, k)

Lines 300-317

Purpose:

Recall relevant memories.

Args:
    query: Query for memory retrieval
    memory_type: Filter by type
    k: Number of memories to retrieve

Returns:
    List of relevant memories

Parameters: – query: Input query or question – memory_type: Memory store for conversation history – k: K

Returns: <ast.Subscript object at 0x000001A06D15B6D0>

chat(self, user_message)

Lines 319-375

Purpose:

Chat with memory-augmented responses.

Args:
    user_message: User's message

Returns:
    Agent's response

Parameters: – user_message: User message

Returns: str

_extract_and_store_info(self, message)

Lines 377-396

Purpose:

Extract and store important information from message.

Parameters: – message: Message

get_memory_summary(self)

Lines 398-416

Purpose:

Get summary of stored memories.

Parameters:

Returns: <ast.Subscript object at 0x000001A06D659D90>


Functions

demonstrate_long_term_memory()

Lines 419-581

Purpose:

Demonstrate the Long-Term Memory pattern.

Key Concepts Summary

Pattern Overview

The Long Term Memory pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

Core Components

  1. Agent Class: Main implementation of the pattern logic
  2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
  3. Tool Integration: Optional tools for extended functionality
  4. Memory Management: State handling across interactions
  5. Output Parsing: Structured response processing

When to Use

āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


Best Practices Demonstrated

1. Environment Configuration

  • āœ… Use .env files for API keys
  • āœ… Never hardcode credentials
  • āœ… Validate environment variables on startup

2. Error Handling

  • āœ… Graceful degradation on failures
  • āœ… Informative error messages
  • āœ… Logging for debugging

3. Prompt Engineering

  • āœ… Clear, specific instructions
  • āœ… Structured output formats
  • āœ… Few-shot examples when beneficial

4. Code Organization

  • āœ… Separation of concerns (class-based design)
  • āœ… Type hints for clarity
  • āœ… Docstrings for documentation

5. Performance Optimization

  • āœ… Appropriate temperature settings
  • āœ… Token budget management
  • āœ… Caching where applicable

LangChain Components Used

  • ChatOpenAI: OpenAI model interface
  • Chains: Sequential component composition

Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


Execution Flow

1. Initialize agent with configuration
   ↓
2. Load environment and dependencies
   ↓
3. Prepare prompt with input data
   ↓
4. Invoke LLM through LangChain
   ↓
5. Parse and validate response
   ↓
6. Return formatted result

Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


Performance Considerations

Computational Cost

  • LLM Calls: Primary cost factor (based on tokens)
  • Latency: Depends on model and input size
  • Memory: Minimal for most patterns

Optimization Strategies

  1. Prompt Optimization: Minimize tokens while maintaining clarity
  2. Caching: Cache repeated queries/responses
  3. Model Selection: Use smaller models when appropriate
  4. Batch Processing: Group similar requests
  5. Streaming: For long responses, stream tokens

Cost Estimates (Approximate)

  • GPT-3.5-turbo: ~$0.002 per request
  • GPT-4: ~$0.03 per request
  • GPT-4-turbo: ~$0.01 per request

Actual costs vary based on input/output token counts


Common Pitfalls to Avoid

1. Prompt Design Issues

āŒ Vague or ambiguous instructions
āœ… Clear, specific, testable prompts

2. Error Handling

āŒ Ignoring API errors or rate limits
āœ… Implement retry logic and graceful degradation

3. Token Management

āŒ Exceeding model token limits
āœ… Truncate inputs, chunk processing

4. Security

āŒ Exposing API keys in code
āœ… Use environment variables

5. Testing

āŒ Only testing happy paths
āœ… Test edge cases, failures, malformed inputs

6. Cost Management

āŒ Unmonitored API usage
āœ… Implement budgets, alerts, and monitoring


Further Improvements

Production Enhancements

  1. Monitoring: Add logging, metrics, tracing
  2. Validation: Input/output schema validation
  3. Rate Limiting: Implement request throttling
  4. Caching: Redis or in-memory cache for responses
  5. Async Support: Non-blocking operations for scalability

Feature Extensions

  1. Multi-Model Support: Switch between providers
  2. Fallback Models: Graceful degradation strategy
  3. Custom Tools: Domain-specific function calling
  4. Advanced Memory: Vector stores for long-term memory
  5. Evaluation: Automated testing and benchmarking

Code Quality

  1. Testing: Unit tests, integration tests
  2. Documentation: API docs, usage examples
  3. Type Safety: Stricter type hints
  4. Configuration: Externalized config files

Related Patterns

  • Pattern 026
  • Pattern 028

Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


Summary

The Long Term Memory pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


File: 027_long_term_memory.py
Total Lines: 586
Pattern Category: AI Agent Design Pattern #027


Generated from actual implementation code
For educational and reference purposes

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *