How to Give Your AI Agent Long-Term Memory
LLM context windows forget everything between sessions. Here's how to implement persistent memory for AI agents using vector databases, Redis, and SQLite.
Builder of AI agents, crypto trading bots, and open-source automation tools. Sharing practical guides on how to build, deploy, and profit from AI and DeFi technology.
The biggest limitation of LLM-based agents is amnesia. Every new conversation starts fresh. For an AI agent to be genuinely useful, it needs to remember user preferences, past decisions, and domain knowledge.
Here's how to implement it properly.
Why Agents Need Memory
Imagine a crypto trading agent that:
- Has to re-learn your risk tolerance every session
- Forgets the trades it placed last week
- Can't learn from its past mistakes
Without memory, agents are glorified chatbots. With memory, they become genuine assistants.
The Four Types of Agent Memory
1. Working Memory: Current conversation context. Managed by the LLM's context window.
2. Episodic Memory: Records of past events. "What did the user ask about last Tuesday?"
3. Semantic Memory: General knowledge. "What is a moving average crossover strategy?"
4. Procedural Memory: How to do things. "The user prefers concise bullet-point answers."
Implementing Episodic Memory with ChromaDB
import chromadb
from openai import OpenAI
from datetime import datetime
import uuid
client = OpenAI()
chroma = chromadb.PersistentClient(path="./agent_memory") # Persistent to disk
collection = chroma.get_or_create_collection("episodes")
def embed(text: str) -> list[float]:
"""Create embedding for text."""
return client.embeddings.create(
model="text-embedding-3-small",
input=text
).data[0].embedding
def save_memory(content: str, memory_type: str = "general", metadata: dict = {}):
"""Save a memory to the vector store."""
memory_id = str(uuid.uuid4())
meta = {
"type": memory_type,
"timestamp": datetime.now().isoformat(),
**metadata
}
collection.add(
documents=[content],
embeddings=[embed(content)],
metadatas=[meta],
ids=[memory_id]
)
return memory_id
def recall(query: str, n: int = 5, memory_type: str = None) -> list[dict]:
"""Retrieve relevant memories."""
where = {"type": memory_type} if memory_type else None
results = collection.query(
query_embeddings=[embed(query)],
n_results=n,
where=where
)
memories = []
for i, doc in enumerate(results['documents'][0]):
memories.append({
"content": doc,
"relevance_score": 1 - results['distances'][0][i],
"metadata": results['metadatas'][0][i]
})
return memories
# Save memories
save_memory("User's risk tolerance is moderate โ max 5% per trade", "preference")
save_memory("User prefers Binance over other exchanges", "preference")
save_memory("User asked about EMA crossover strategies on 2025-03-01", "episode")
save_memory("BTC bot executed a buy at $65,000 on 2025-03-05", "trade_history")
# Recall relevant memories
query = "What exchange does the user prefer for trading?"
memories = recall(query, n=3)
for m in memories:
print(f"[{m['relevance_score']:.2f}] {m['content']}")
Injecting Memory into Agent Prompts
def build_system_prompt(user_query: str) -> str:
"""Build context-aware system prompt by injecting relevant memories."""
relevant_memories = recall(user_query, n=5)
memory_context = ""
if relevant_memories:
memory_context = "\n\n## Relevant Context from Memory:\n"
for mem in relevant_memories:
memory_context += f"- {mem['content']}\n"
return f"""You are a personal AI trading assistant.
You have access to the user's history and preferences.
{memory_context}
Use this context to provide personalized, relevant responses.
If the user asks something you've helped with before, reference that history."""
# Use in conversation
query = "Should I buy ETH now?"
system = build_system_prompt(query)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": query}
]
)
# Save this interaction
save_memory(f"User asked: {query}. Agent said: {response.choices[0].message.content[:200]}", "episode")
print(response.choices[0].message.content)
Procedural Memory with SQLite
For structured preferences and rules:
import sqlite3
from contextlib import contextmanager
@contextmanager
def db():
conn = sqlite3.connect("agent_prefs.db")
conn.row_factory = sqlite3.Row
try:
yield conn
conn.commit()
finally:
conn.close()
def setup_db():
with db() as conn:
conn.executescript("""
CREATE TABLE IF NOT EXISTS preferences (
key TEXT PRIMARY KEY,
value TEXT,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS rules (
id INTEGER PRIMARY KEY AUTOINCREMENT,
rule TEXT NOT NULL,
category TEXT,
active INTEGER DEFAULT 1,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
""")
def set_preference(key: str, value: str):
with db() as conn:
conn.execute(
"INSERT OR REPLACE INTO preferences (key, value, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP)",
(key, value)
)
def get_preference(key: str, default: str = None) -> str:
with db() as conn:
row = conn.execute("SELECT value FROM preferences WHERE key = ?", (key,)).fetchone()
return row['value'] if row else default
def add_rule(rule: str, category: str):
with db() as conn:
conn.execute("INSERT INTO rules (rule, category) VALUES (?, ?)", (rule, category))
def get_rules(category: str = None) -> list[str]:
with db() as conn:
if category:
rows = conn.execute("SELECT rule FROM rules WHERE category = ? AND active = 1", (category,)).fetchall()
else:
rows = conn.execute("SELECT rule FROM rules WHERE active = 1").fetchall()
return [r['rule'] for r in rows]
setup_db()
# Store user preferences
set_preference("risk_tolerance", "moderate")
set_preference("preferred_exchange", "Binance")
set_preference("base_currency", "USDT")
set_preference("max_trade_size_usd", "500")
# Store trading rules
add_rule("Never risk more than 2% of capital per trade", "risk")
add_rule("Always use stop-loss orders", "risk")
add_rule("Don't trade in the first 30 minutes after major news", "timing")
rules = get_rules("risk")
print(f"Risk rules: {rules}")
Complete Memory-Enabled Agent
class MemoryAgent:
def __init__(self):
self.client = OpenAI()
self.chroma = chromadb.PersistentClient(path="./memory")
self.episodes = self.chroma.get_or_create_collection("episodes")
self.conversation: list[dict] = []
setup_db()
def chat(self, user_message: str) -> str:
# Get relevant memories
memories = recall(user_message, n=5)
rules = get_rules()
# Build context-aware system prompt
prefs = {
"risk": get_preference("risk_tolerance", "moderate"),
"exchange": get_preference("preferred_exchange", "Binance"),
"max_trade": get_preference("max_trade_size_usd", "100"),
}
system = f"""You are a personal AI crypto trading assistant with persistent memory.
User Preferences:
- Risk tolerance: {prefs['risk']}
- Preferred exchange: {prefs['exchange']}
- Max trade size: ${prefs['max_trade']}
Active Rules:
{chr(10).join(f'- {r}' for r in rules[:5])}
Relevant Past Context:
{chr(10).join(f'- {m["content"]}' for m in memories if m["relevance_score"] > 0.7)}
Always use user preferences and past context when giving advice."""
# Add to conversation
self.conversation.append({"role": "user", "content": user_message})
response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "system", "content": system}] + self.conversation[-10:], # Last 10 turns
)
assistant_message = response.choices[0].message.content
self.conversation.append({"role": "assistant", "content": assistant_message})
# Save to long-term memory
save_memory(f"Q: {user_message} A: {assistant_message[:300]}", "episode")
# Extract and save new preferences mentioned
if "prefer" in user_message.lower() or "always" in user_message.lower():
save_memory(user_message, "preference")
return assistant_message
# Usage
agent = MemoryAgent()
print(agent.chat("My risk tolerance is low โ I only want to risk 1% max per trade"))
print(agent.chat("What's a good strategy for me?")) # Agent remembers the 1% risk limit
When to Use Each Memory Type
| Use Case | Memory Type | Storage | |----------|-------------|---------| | User preferences | Procedural | SQLite | | Past conversations | Episodic | ChromaDB | | Strategy knowledge | Semantic | ChromaDB | | Current session | Working | LLM context | | Trade history | Episodic | SQLite + ChromaDB |
With proper memory, your AI agent becomes exponentially more useful over time. It learns your patterns, respects your preferences, and builds genuine context about your goals โ the foundation of a truly autonomous assistant.
Related Articles
Agentic AI: The Next Evolution Beyond ChatGPT (Complete 2025 Guide)
9 min read
AI AgentsAutonomous vs Semi-Autonomous AI Agents: When to Choose Each
4 min read
AI AgentsOpenAI Assistants API vs Custom Agents: Full Comparison
4 min read
AI AgentsAI Agent Security: Protecting Your Bot From Attacks and Exploits
5 min read