Implementing Persistent User Memory Across Agent Sessions in AWorld

Store user preferences and context across multiple agent sessions using the MemoryFactory singleton with either ephemeral in-memory storage or a durable PostgreSQL backend.

The AWorld framework from the bojieli/ai-agent-book repository provides a production-ready memory subsystem that enables AI agents to maintain continuity across sessions. This article explains how to implement user memory persistence using the factory pattern, configuration-driven backends, and the unified MemoryBase API.

Architecture Overview

The memory system centers on three core abstractions defined in aworld/memory/main.py:

  • MemoryFactory – A singleton factory that manages the lifecycle of memory stores
  • MemoryBase – The abstract interface for all storage implementations
  • MemoryConfig – Configuration object selecting providers and embedding settings

The factory caches the initialized store in a module-level MEMORY_HOLDER dictionary, ensuring all components access the same instance throughout the process lifecycle.

Storage Backend Options

Ephemeral Storage with InMemoryMemoryStore

For development and testing, InMemoryMemoryStore provides zero-configuration storage that persists only for the process duration.

from aworld.memory.main import MemoryFactory, MemoryConfig

# Initialize with default in-memory store

config = MemoryConfig(provider="aworld")
MemoryFactory.init(config=config)

memory = MemoryFactory.instance()  # Returns cached InMemoryMemoryStore
  • Source: aworld/memory/main.py lines 55-79
  • Data structure: Python list holding MemoryItem objects
  • Use case: Unit tests, prototypes, single-session agents

Persistent Storage with PostgresMemoryStore

For production deployments requiring cross-session durability, PostgresMemoryStore writes memory items to PostgreSQL using SQLAlchemy ORM models (MemoryItemModel, MemoryHistoryModel).

from aworld.memory.db.postgres import PostgresMemoryStore

postgres_store = PostgresMemoryStore(
    db_url="postgresql://user:password@localhost:5432/aworld_db"
)
  • Source: aworld/memory/db/postgres.py lines 224-229
  • Table: aworld_memory_items with JSONB metadata columns
  • Use case: Multi-session user profiles, long-running agent deployments

Step-by-Step Implementation

Step 1: Configure Memory Provider

Create a MemoryConfig selecting your desired backend and embedding pipeline.

from aworld.memory.main import MemoryConfig
from aworld.memory.embeddings.openai import OpenAIEmbeddingConfig
from aworld.memory.vector_stores.faiss import FAISSVectorStoreConfig

config = MemoryConfig(
    provider="aworld",  # or "mem0" for external providers

    embedding_config=OpenAIEmbeddingConfig(
        model="text-embedding-3-small",
        api_key="sk-..."
    ),
    vector_store_config=FAISSVectorStoreConfig(
        index_path="./faiss_index"
    )
)

Step 2: Initialize the MemoryFactory Singleton

Call MemoryFactory.init with your store and configuration. This method (lines 158-166 in main.py) registers the instance globally.

from aworld.memory.main import MemoryFactory

# With persistent PostgreSQL backend

MemoryFactory.init(
    custom_memory_store=postgres_store,
    config=config
)

# With default in-memory backend

MemoryFactory.init(config=config)

Step 3: Access Memory in Agent Code

Retrieve the singleton anywhere in your codebase using MemoryFactory.instance() (lines 174-182).


# In your agent implementation

memory = MemoryFactory.instance()

# Store user information with metadata

from aworld.memory.models import MemoryHumanMessage, MessageMetadata

memory.add(
    MemoryHumanMessage(
        content="I prefer concise answers with code examples",
        metadata=MessageMetadata(
            user_id="user_456",
            session_id="sess_2024_001",
            timestamp=datetime.utcnow()
        )
    )
)

Step 4: Retrieve Memory in Subsequent Sessions

When the same user returns, query their historical preferences.


# New session, same factory initialization

MemoryFactory.init(custom_memory_store=postgres_store, config=config)
memory = MemoryFactory.instance()

# Retrieve all memories for this user

user_memories = memory.get_all(
    filters={"user_id": "user_456"}
)

# Or get most recent preference

latest = memory.get_first(
    filters={"user_id": "user_456"},
    order_by="timestamp",
    descending=True
)

Real-World Agent Integration

The LLMAgent class in aworld/agents/llm_agent.py demonstrates production usage. Agents access MemoryFactory.instance() during initialization and inject relevant memories into prompts.

Key integration patterns:

  • Session startup: Load user profile via memory.get_all(filters={"user_id": ...})
  • During execution: Append new observations with memory.add()
  • Session end: Optionally summarize and store compressed history

Memory Operations API

Both storage backends implement these MemoryBase methods:

Method Purpose Example
add(item) Store new memory item memory.add(MemoryHumanMessage(...))
get(filters) Retrieve matching items memory.get({"user_id": "123"})
get_first(filters) Single most recent match memory.get_first({"topic": "preferences"})
get_all(filters) Paginated result sets memory.get_all({"user_id": "123"}, limit=10)
delete(filters) Remove matching items memory.delete({"session_id": "old_sess"})
history(key) Temporal sequence for key memory.history("user_123:preferences")

Configuration Reference

Environment variables for PostgreSQL persistence:

export MEMORY_STORE_POSTGRES_DSN="postgresql://user:pass@host:port/db"
export MEMORY_STORE_POSTGRES_POOL_SIZE=10
export MEMORY_STORE_POSTGRES_MAX_OVERFLOW=20

Testing Your Implementation

The test utilities in chapter9/gaia-experience/AWorld/tests/memory/utils.py show factory initialization patterns for test isolation.


# Test-specific in-memory store

from tests.memory.utils import create_test_memory

def test_user_memory_persistence():
    memory = create_test_memory()
    memory.add(MemoryHumanMessage(content="test", metadata=...))
    assert len(memory.get_all()) == 1

Summary

  • Use MemoryFactory as the central singleton for managing memory store instances across your application
  • Choose InMemoryMemoryStore for ephemeral, single-process scenarios and PostgresMemoryStore** for durable, multi-session persistence
  • Initialize once with MemoryFactory.init() then access everywhere via MemoryFactory.instance()
  • Leverage MessageMetadata to tag items with user_id, session_id, and custom fields for precise retrieval
  • Maintain API compatibility—the same MemoryBase methods work regardless of backend, enabling seamless environment transitions

Frequently Asked Questions

How does MemoryFactory ensure the same store instance across sessions?

MemoryFactory.init() caches the initialized store in a module-level MEMORY_HOLDER dictionary keyed by configuration signature. Subsequent calls to MemoryFactory.instance() return this cached object. For process restarts, PostgresMemoryStore persists data externally, and re-initialization with the same database URL reconstructs the logical session continuity.

Can I migrate from in-memory to PostgreSQL storage without code changes?

Yes. The MemoryBase abstraction ensures identical method signatures across backends. Simply change your initialization code to pass a PostgresMemoryStore instance to MemoryFactory.init()—all agent code using memory.add(), memory.get(), and other methods continues working unchanged.

What metadata should I include for effective user memory retrieval?

Include at minimum user_id for cross-session identification and session_id for temporal grouping. Add domain-specific keys like topic, intent, or agent_version to enable filtered queries. The MessageMetadata class in aworld/memory/models.py supports arbitrary string-keyed fields for flexible indexing.

How do I handle memory growth and cleanup for long-lived users?

Implement retention policies using memory.delete() with date-range filters, or add a background job calling memory.history() to summarize older entries before archival. The PostgresMemoryStore includes MemoryHistoryModel for audit trails, allowing soft-deletion patterns while maintaining compliance records.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →