# Implementing Persistent User Memory Across Agent Sessions in AWorld

> Implement persistent user memory across agent sessions. Leverage MemoryFactory with in-memory or PostgreSQL storage for lasting context in your AI agents.

- Repository: [Bojie Li/ai-agent-book](https://github.com/bojieli/ai-agent-book)
- Tags: how-to-guide
- Published: 2026-08-18

---

**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`](https://github.com/bojieli/ai-agent-book/blob/main/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.

```python
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`](https://github.com/bojieli/ai-agent-book/blob/main/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`).

```python
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`](https://github.com/bojieli/ai-agent-book/blob/main/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.

```python
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`](https://github.com/bojieli/ai-agent-book/blob/main/main.py)) registers the instance globally.

```python
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).

```python

# 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.

```python

# 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`](https://github.com/bojieli/ai-agent-book/blob/main/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:

```bash
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`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/AWorld/tests/memory/utils.py) show factory initialization patterns for test isolation.

```python

# 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`](https://github.com/bojieli/ai-agent-book/blob/main/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.