Memory Persistence
QilbeeDB provides enterprise-grade memory persistence using RocksDB as the storage backend. All agent memories are automatically persisted to disk, ensuring durability across server restarts.
Overview#
Memory persistence in QilbeeDB is handled transparently by the server. When you store episodes through the Python SDK or HTTP API, they are automatically:
- Written to RocksDB - Stored in an efficient LSM-tree structure
- Protected by WAL - Write-ahead logging ensures durability
- Compressed with LZ4 - Reduces storage footprint
- Automatically recovered - Available immediately after server restart
┌─────────────────────────────────────────┐
│ Python SDK / HTTP API │
│ memory.store_episode(episode) │
└─────────────────────────────────────────┘
↓ Automatic Persistence
┌─────────────────────────────────────────┐
│ Memory Storage Layer │
│ • Episode serialization │
│ • Agent-scoped storage │
│ • Unique ID generation │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ RocksDB Backend │
│ • Write-Ahead Log (WAL) │
│ • LZ4 Compression │
│ • Automatic Recovery │
└─────────────────────────────────────────┘
Key Features#
Automatic Durability#
Episodes are persisted automatically when stored:
from qilbeedb import QilbeeDB
from qilbeedb.memory import Episode
db = QilbeeDB("http://localhost:7474")
db.login("admin", "password")
memory = db.agent_memory("my-agent")
# This episode is automatically persisted to disk
episode = Episode.conversation(
"my-agent",
"What is QilbeeDB?",
"QilbeeDB is a graph database with agent memory..."
)
episode_id = memory.store_episode(episode)
# Episode survives server restart
# No explicit save or flush required
Write-Ahead Logging (WAL)#
QilbeeDB uses RocksDB's write-ahead logging for durability:
- Crash Recovery: Episodes are recoverable even after unexpected shutdowns
- Transaction Safety: Writes are atomic and consistent
- Configurable Sync: Balance between performance and durability
Compression#
All stored episodes are compressed using LZ4:
- Fast Compression: Minimal overhead on write operations
- Reduced Storage: Typically 50-70% size reduction
- Transparent: No application changes required
Agent Isolation#
Episodes are stored in separate namespaces per agent:
# Each agent has isolated storage
sales_memory = db.agent_memory("sales-agent")
support_memory = db.agent_memory("support-agent")
# Episodes are stored separately
sales_memory.store_episode(Episode.conversation(
"sales-agent", "Pricing inquiry", "Our plans start at..."
))
support_memory.store_episode(Episode.conversation(
"support-agent", "How do I reset?", "Click forgot password..."
))
Server Configuration#
Memory persistence is configured on the server side. The Python SDK automatically benefits from these settings without any code changes.
Storage Path#
[storage]
data_path = "/var/lib/qilbeedb/data"
WAL Configuration#
[storage]
enable_wal = true # Enable write-ahead logging
sync_writes = true # Sync each write (safer, slower)
wal_sync_interval_ms = 1000 # Sync interval for async writes
Compression Settings#
[storage]
enable_compression = true
compression_type = "lz4" # Options: none, lz4, snappy, zstd
Using Persistence in Python#
Basic Usage#
from qilbeedb import QilbeeDB
from qilbeedb.memory import Episode
# Connect to QilbeeDB
db = QilbeeDB("http://localhost:7474")
db.login("admin", "password")
# Get memory manager for an agent
memory = db.agent_memory("customer-service-bot")
# Store episodes (automatically persisted)
episode = Episode.conversation(
"customer-service-bot",
"I need help with my order",
"I'd be happy to help! What's your order number?"
)
episode_id = memory.store_episode(episode)
print(f"Stored episode: {episode_id}")
# Episodes persist across sessions
# Restart your application or the server - data remains
Verifying Persistence#
# After server restart, episodes are still available
db = QilbeeDB("http://localhost:7474")
db.login("admin", "password")
memory = db.agent_memory("customer-service-bot")
# Get statistics to verify data persisted
stats = memory.get_statistics()
print(f"Total episodes: {stats.total_episodes}")
print(f"Average relevance: {stats.avg_relevance}")
# Retrieve recent episodes
recent = memory.get_recent_episodes(limit=10)
for ep in recent:
print(f"[{ep.episode_type}] {ep.content}")
Searching Persisted Episodes#
# Search through persisted episodes
results = memory.search_episodes("order number", limit=5)
for episode in results:
print(f"Found: {episode.content}")
Deleting Episodes#
# Delete a specific episode
deleted = memory.delete_episode(episode_id)
if deleted:
print("Episode permanently removed from storage")
# Clear all episodes for an agent
memory.clear()
print("All episodes cleared for this agent")
Best Practices#
1. Use Meaningful Agent IDs#
Agent IDs serve as storage namespaces. Use consistent, descriptive names:
# Good: Descriptive and consistent
memory = db.agent_memory("customer-support-v2")
memory = db.agent_memory("sales-assistant-prod")
# Avoid: Generic or inconsistent names
memory = db.agent_memory("agent1")
memory = db.agent_memory("test")
2. Handle Connection Errors#
Implement retry logic for robustness:
import time
from qilbeedb.exceptions import MemoryError
def store_with_retry(memory, episode, max_retries=3):
for attempt in range(max_retries):
try:
return memory.store_episode(episode)
except MemoryError as e:
if attempt == max_retries - 1:
raise
time.sleep(1 * (attempt + 1))
3. Monitor Storage Statistics#
Regularly check storage health:
stats = memory.get_statistics()
# Monitor episode count
if stats.total_episodes > 100000:
print("Warning: High episode count, consider consolidation")
# Check relevance distribution
if stats.avg_relevance < 0.3:
print("Many low-relevance episodes, consider forgetting")
4. Use Appropriate Episode Types#
Choose the right episode type for your data:
# Conversations: User interactions
Episode.conversation(agent_id, user_input, response)
# Observations: Environmental data
Episode.observation(agent_id, "CPU usage at 85%")
# Actions: Agent decisions and outcomes
Episode.action(agent_id, "Scaled to 4 instances", "Latency reduced")
Performance Considerations#
Write Performance#
- Episodes are written asynchronously by default
- WAL ensures durability without blocking
- LZ4 compression adds minimal overhead
Read Performance#
- Recent episodes are cached in memory
- RocksDB bloom filters speed up lookups
- Agent-scoped storage enables efficient queries
Storage Efficiency#
- LZ4 compression reduces disk usage
- Automatic compaction reclaims space
- Episode consolidation reduces redundancy
Troubleshooting#
Episodes Not Persisting#
- Check server logs for storage errors
- Verify disk space is available
- Ensure proper permissions on data directory
- Check WAL configuration
Slow Write Performance#
- Consider async WAL sync
- Check disk I/O utilization
- Review compression settings
- Monitor compaction status
Recovery After Crash#
- QilbeeDB automatically recovers from WAL
- Check server logs for recovery status
- Verify episode counts after restart
- Report any data loss issues