AI Agents

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.

A
AI Agents Hubยท2026-03-08ยท6 min readยท1,028 words

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