Memoripy

repository·master·Indexed 20 days ago

https://github.com/caspianmoon/memoripy

A Python library for managing context-aware AI memory using embeddings, concept graphs, and hierarchical clustering. It provides a MemoryManager to handle short-term and long-term memory retrieval via semantic search, spreading activation, and temporal decay. Supports multiple storage backends including JSONStorage, InMemoryStorage, and a DynamoDB adapter, with integration for model providers such as OpenAI, Ollama, and Azure OpenAI.

Tokens
2.9K
Snippets
9
Records
14
Agent score
71%

What's inside memoripy

  1. How Memoripy manages memory retrieval and relevance

    master

    Memoripy uses several mechanisms to ensure contextually relevant retrieval:

    1. Short-term vs Long-term Memory: Interactions are managed as short-term or long-term based on usage and relevance.
    2. Contextual Retrieval: Uses embeddings and concept extraction to find relevant past interactions.
    3. Graph-Based Associations: Builds a concept graph and uses spreading activation to find related memories even if they aren't direct semantic matches.
    4. Hierarchical Clustering: Groups similar memories into semantic clusters to improve retrieval accuracy.
    5. Decay and Reinforcement: Implements a temporal model where older, unused memories decay, while frequently accessed memories are reinforced, making them easier to retrieve.
  2. Run DynamoDB storage adapter locally with Docker

    master

    To test the DynamoDB adapter without an AWS account, use Docker Compose to spin up a local DynamoDB instance.

    1. Ensure Docker Compose is installed.
    2. From the examples/dynamo directory, run:
    docker compose up -d
    1. Configure your environment by copying the local.env file from the examples/dynamo directory to the repository root and renaming it to .env.
    2. Run the example application:
    python -m examples.dynamo.dynamo_example
    docker compose up -d
    python -m examples.dynamo.dynamo_example
  3. Initialize MemoryManager with models and storage

    master

    To use Memoripy, you must initialize a MemoryManager by providing a chat model, an embedding model, and a storage implementation.

    Supported storage options include:

    • JSONStorage(filepath): Persists interactions to a JSON file.
    • InMemoryStorage(): Keeps interactions in memory (volatile).

    Example initialization using OpenAI for chat and Ollama for embeddings:

    from memoripy import MemoryManager, JSONStorage
    from memoripy.implemented_models import OpenAIChatModel, OllamaEmbeddingModel
    
    api_key = "your-openai-key"
    chat_model_name = "gpt-4o-mini"
    embedding_model_name = "mxbai-embed-large"
    
    storage_option = JSONStorage("interaction_history.json")
    
    memory_manager = MemoryManager(
        OpenAIChatModel(api_key, chat_model_name),
        OllamaEmbeddingModel(embedding_model_name),
        storage=storage_option
    )
  4. Explore Memoripy usage examples

    master

    The examples/ directory contains various implementation patterns for using Memoripy with different model providers and storage backends. You can find specific examples for:

    • Azure OpenAI: Using Azure OpenAI for both chat and embedding models (azure_example.py).
    • OpenRouter & Ollama: Combining OpenRouter chat models with local Ollama embedding models (chatcompletions.py, openrouter.py).
    • OpenAI & Ollama: Combining OpenAI chat models with local Ollama embedding models (openai_example.py).
    • AWS DynamoDB: Using the Memoripy storage adapter to persist memory in AWS DynamoDB (dynamo/).
  5. Manage and retrieve context-aware memory with MemoryManager

    master

    The MemoryManager is the primary interface for managing AI memory. It handles the lifecycle of an interaction: retrieving context, generating responses, and storing new data.

    Key methods:

    • load_history(): Returns a tuple containing (short_term_memory, long_term_memory). Use this to get recent context.
    • retrieve_relevant_interactions(query, exclude_last_n=N): Searches past interactions using cosine similarity, decay factors, and spreading activation. Use exclude_last_n to avoid retrieving the immediate conversation history as 'relevant' past memory.
    • generate_response(prompt, last_interactions, relevant_interactions): Generates a response by combining the current prompt with both recent short-term context and retrieved long-term memories.
    • extract_concepts(text): Uses the configured model to extract semantic concepts from text.
    • get_embedding(text): Generates a vector embedding for the provided text.
    • add_interaction(prompt, response, embedding, concepts): Saves the new interaction, its embedding, and its extracted concepts into storage.
    # Example workflow
    # 1. Load recent context
    short_term, _ = memory_manager.load_history()
    last_interactions = short_term[-5:]
    
    # 2. Retrieve long-term relevant memories
    relevant_interactions = memory_manager.retrieve_relevant_interactions(new_prompt, exclude_last_n=5)
    
    # 3. Generate response
    response = memory_manager.generate_response(new_prompt, last_interactions, relevant_interactions)
    
    # 4. Prepare and store new interaction
    concepts = memory_manager.extract_concepts(f"{new_prompt} {response}")
    embedding = memory_manager.get_embedding(f"{new_prompt} {response}")
    memory_manager.add_interaction(new_prompt, response, embedding, concepts)
  6. Configure DynamoDB environment variables

    master

    Use the following environment variables to configure the connection and performance settings for the DynamoDB storage adapter:

    VariableDescription
    MEMORIPY_DYNAMO_HOSTThe URL of the DynamoDB instance (required for local development)
    MEMORIPY_DYNAMO_REGIONThe AWS region to connect to (default: us-east-1)
    MEMORIPY_DYNAMO_READ_CAPACITYRead capacity for the table (default: 1)
    MEMORIPY_DYNAMO_WRITE_CAPACITYWrite capacity for the table (default: 1)
  7. Configure storage options in Memoripy

    master

    Memoripy uses a storage abstraction to persist memory. You can choose between persistent file-based storage or volatile in-memory storage.

    • JSONStorage: Best for persistence. Requires a filename.
    • InMemoryStorage: Best for testing or ephemeral sessions. Data is lost when the process ends.
    • BaseStorage: The abstract base class you can implement to create custom storage backends.
    # Persistent JSON storage
    from memoripy import JSONStorage
    storage = JSONStorage("my_memory.json")
    
    # Volatile in-memory storage
    from memoripy import InMemoryStorage
    storage = InMemoryStorage()
  8. Initialize MemoryManager

    master

    The MemoryManager is the central orchestrator for managing conversational memory. It requires an OpenAI API key (if using OpenAI models), specifications for both chat and embedding models, and a storage backend.

    Supported model providers for chat_model and embedding_model include 'openai' and 'ollama'.

    from memory_manager import MemoryManager
    from json_storage import JSONStorage
    
    memory_manager = MemoryManager(
        api_key="your-key",
        chat_model="openai",
        chat_model_name="gpt-4o-mini",
        embedding_model="ollama",
        embedding_model_name="mxbai-embed-large",
        storage=JSONStorage("interaction_history.json")
    )
  9. Retrieve and manage conversational history

    master

    The MemoryManager provides methods to manage different layers of context:

    • load_history(): Returns a tuple containing (short_term_history, long_term_history). Short-term history is typically used for immediate conversational context.
    • retrieve_relevant_interactions(query, exclude_last_n=N): Performs a semantic search to find past interactions relevant to the provided query. Use exclude_last_n to prevent the most recent interactions (which are already in short-term memory) from being duplicated in the retrieved context.
    • generate_response(prompt, last_interactions, relevant_interactions): Generates an AI response by synthesizing the current prompt with both immediate short-term context and retrieved long-term relevant interactions.
    # Load recent context
    short_term, _ = memory_manager.load_history()
    last_interactions = short_term[-5:]
    
    # Retrieve semantic long-term context
    relevant_interactions = memory_manager.retrieve_relevant_interactions(new_prompt, exclude_last_n=5)
    
    # Generate response
    response = memory_manager.generate_response(new_prompt, last_interactions, relevant_interactions)