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 storesMemoryBase– The abstract interface for all storage implementationsMemoryConfig– 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.pylines 55-79 - Data structure: Python list holding
MemoryItemobjects - 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.pylines 224-229 - Table:
aworld_memory_itemswith 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
MemoryFactoryas the central singleton for managing memory store instances across your application - Choose
InMemoryMemoryStorefor ephemeral, single-process scenarios andPostgresMemoryStore** for durable, multi-session persistence - Initialize once with
MemoryFactory.init()then access everywhere viaMemoryFactory.instance() - Leverage
MessageMetadatato tag items withuser_id,session_id, and custom fields for precise retrieval - Maintain API compatibility—the same
MemoryBasemethods 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →