Skip to content

Episodic & Procedural Memory

Overview

Different types of information should be stored and retrieved differently.

  • Episodic: "What happened?" - Specific events
  • Procedural: "How do I do it?" - Skills and procedures

This file covers their differences, storage, and retrieval.


Episodic Memory: What Happened

Definition

Memory of specific events that occurred at specific times in specific contexts.

Examples:

  • "On Jan 15, I analyzed quarterly sales"
  • "The user mentioned they prefer concise responses"
  • "We discovered that customers want faster shipping"

Characteristics

Aspect Value
What Specific events/experiences
When Time-stamped
Where Context-rich
Why Learn from experience
Storage Vector DB (episodic store)
Retrieval Semantic similarity search
Retention Variable (important events kept longer)

Implementation

class EpisodicMemory:
 def __init__(self):
 self.vector_db = VectorStore()
 self.events = []

 def record_event(self, event: dict):
 """Record a specific event"""

 episode = {
 "timestamp": event['timestamp'],
 "description": event['description'],
 "context": event.get('context', {}),
 "outcome": event.get('outcome'),
 "emotional_valence": event.get('valence', 0), # -1 to 1
 "importance": event.get('importance', 0.5)
 }

 # Embed and store
 embedding = embed(episode['description'])

 self.vector_db.add(
 text=episode['description'],
 embedding=embedding,
 metadata={
 'timestamp': episode['timestamp'],
 'context': episode['context'],
 'outcome': episode['outcome'],
 'importance': episode['importance']
 }
)

 self.events.append(episode)

 def recall_similar(self, query: str, k: int = 5):
 """Recall similar past episodes"""

 query_embedding = embed(query)

 # Search by similarity
 similar = self.vector_db.search(query_embedding, k)

 # Return with timestamps (temporal context)
 return sorted(similar, key=lambda x: x['metadata']['timestamp'], reverse=True)

 def recall_recent(self, hours: int = 24):
 """Recall recent episodes"""

 cutoff = now() - timedelta(hours=hours)

 return [
 e for e in self.events
 if e['timestamp'] > cutoff
]

# Usage
episodic = EpisodicMemory()

# Record an event
episodic.record_event({
 'timestamp': now(),
 'description': 'Analyzed quarterly sales data from Q1',
 'context': {'user': 'alice', 'domain': 'sales'},
 'outcome': 'Found 15% growth trend',
 'importance': 0.9
})

# Later recall similar events
results = episodic.recall_similar("What analysis have we done on sales?")

Procedural Memory: How Do I Do It

Definition

Memory of skills, procedures, and strategies—how to do things.

Examples:

  • "To analyze data: 1) Load, 2) Explore, 3) Clean, 4) Analyze"
  • "When writing reports: Always include context and limitations"
  • "The most effective search strategy is to try multiple queries"

Characteristics

Aspect Value
What Skills, procedures, strategies
When Not time-specific
Where Domain-specific
Why Improve performance through practice
Storage Procedure DB, policy store
Retrieval Keyword/topic lookup
Retention Persistent (keep forever)
Updates Success rate tracking

Implementation

class ProceduralMemory:
 def __init__(self):
 self.procedures = {}
 self.success_rates = {}
 self.usage_counts = {}

 def learn_procedure(self, name: str, steps: List[str], domain: str = "general"):
 """Learn a new procedure"""

 self.procedures[name] = {
 "name": name,
 "steps": steps,
 "domain": domain,
 "learned_at": now(),
 "version": 1
 }

 self.success_rates[name] = 0.5 # Start neutral
 self.usage_counts[name] = 0

 def execute_procedure(self, name: str, **kwargs):
 """Execute a learned procedure"""

 if name not in self.procedures:
 raise ProcedureNotFound(f"Unknown procedure: {name}")

 procedure = self.procedures[name]

 try:
 # Execute steps
 for step in procedure['steps']:
 execute_step(step, **kwargs)

 # Record success
 self.record_success(name)
 return True

 except Exception as e:
 # Record failure
 self.record_failure(name)
 raise

 def record_success(self, procedure_name: str):
 """Update success rate when procedure succeeds"""

 current = self.success_rates.get(procedure_name, 0.5)

 # Update with exponential moving average
 self.success_rates[procedure_name] = 0.9 * current + 0.1 * 1.0
 self.usage_counts[procedure_name] += 1

 def record_failure(self, procedure_name: str):
 """Update success rate when procedure fails"""

 current = self.success_rates.get(procedure_name, 0.5)

 # Update with exponential moving average
 self.success_rates[procedure_name] = 0.9 * current + 0.1 * 0.0
 self.usage_counts[procedure_name] += 1

 def get_best_procedure(self, domain: str):
 """Get most successful procedure for domain"""

 domain_procedures = [
 (name, self.success_rates[name])
 for name, proc in self.procedures.items()
 if proc['domain'] == domain
]

 if not domain_procedures:
 return None

 # Return highest success rate
 best_name = max(domain_procedures, key=lambda x: x[1])[0]
 return self.procedures[best_name]

# Usage
procedural = ProceduralMemory()

# Learn a procedure
procedural.learn_procedure(
 name="analyze_sales_data",
 steps=[
 "Load data from database",
 "Explore dimensions and metrics",
 "Clean anomalies",
 "Calculate growth trends",
 "Identify patterns"
],
 domain="sales"
)

# Execute and track success
try:
 procedural.execute_procedure("analyze_sales_data", data=sales_df)
except Exception as e:
 print(f"Procedure failed: {e}")

Comparing Episodic vs Procedural

Use Cases

Scenario Which Memory
"What did we learn last time?" Episodic
"How did we solve this before?" Episodic (find similar case)
"How do I do task X?" Procedural
"What worked best for this domain?" Procedural (best procedure)
"When did we discover this?" Episodic (temporal)
"Why did that strategy work?" Both (combine)

Retrieval

Episodic:

# Find similar past events
recent_analyses = episodic.recall_similar("sales analysis", k=5)
# Returns

Procedural:

# Find how to do something
procedure = procedural.get_best_procedure("sales_analysis")
# Returns

Learning

Episodic:

# Learn from experience
# Just record what happened
episodic.record_event(...)
# Over time, patterns emerge from many episodes

Procedural:

# Learn through practice
# Try procedure, track success
try:
 procedural.execute_procedure(...)
 success = True # Update success rate
except:
 success = False # Update failure rate
# Success rate improves with practice

Integration: Combined Memory System

class IntegratedMemorySystem:
 def __init__(self):
 self.episodic = EpisodicMemory()
 self.procedural = ProceduralMemory()

 def learn_from_experience(self, task_name: str, outcome: dict):
 """Learn both episodic and procedural"""

 # Store what happened
 self.episodic.record_event({
 'timestamp': outcome['timestamp'],
 'description': f"Performed {task_name}",
 'outcome': outcome['result'],
 'importance': outcome['success']
 })

 # If new successful approach, learn procedure
 if outcome['success'] and outcome['is_novel_approach']:
 self.procedural.learn_procedure(
 name=outcome['procedure_name'],
 steps=outcome['steps'],
 domain=task_name.split('_')[0]
)

 # Track success for existing procedures
 if task_name in self.procedural.procedures:
 if outcome['success']:
 self.procedural.record_success(task_name)
 else:
 self.procedural.record_failure(task_name)

 def solve_new_problem(self, problem: dict):
 """Solve using both episodic and procedural"""

 # Step 1: Look for similar past problems (episodic)
 similar_past = self.episodic.recall_similar(problem['description'], k=3)

 # Step 2: Get best procedure for this domain (procedural)
 domain = problem['domain']
 best_procedure = self.procedural.get_best_procedure(domain)

 # Step 3: Combine insights
 if best_procedure:
 # Use proven procedure
 return self.procedural.execute_procedure(best_procedure['name'])
 elif similar_past:
 # Adapt solution from similar past case
 past_solution = similar_past[0]['outcome']
 return adapt_solution(past_solution, problem)
 else:
 # Fall back to general approach
 return solve_from_scratch(problem)

-

Competing for Storage: Which to Keep?

When storage is limited, which memories to keep?

Priority Matrix

 Low Success Rate High Success Rate
Old: Delete Keep (maybe compress)
Recent: Replace Keep
High Importance: Keep Keep
Low Importance: Delete Keep

Implementation

def prioritize_for_retention(memory, other_options):
 """Score memory for retention"""

 score = 0

 # Episodic factors
 if memory.type == 'episodic':
 score += memory['importance'] * 50

 # Older = lower priority
 age_days = (now() - memory['timestamp']).days
 score -= min(age_days / 30, 40) # Cap penalty

 # Frequently accessed = higher priority
 score += memory['access_count'] * 5

 # Procedural factors
 if memory.type == 'procedural':
 score += memory['success_rate'] * 50 # Very important
 score += memory['usage_count'] * 2
 score -= (memory.get('failure_count', 0) * 5)

 return score

Best Practices

1. Episodic: Keep Context

# Good
episode = {
 'what': 'Analyzed sales',
 'when': datetime.now(),
 'where': 'sales_dashboard',
 'who': 'alice',
 'why': 'Quarterly review',
 'outcome': 'Found 15% growth'
}

# Bad
episode = {'text': 'Analyzed sales'}

2. Procedural: Track Metrics

# Good
procedure['success_rate'] = 0.87
procedure['times_used'] = 15
procedure['last_success'] = datetime.now()

# Bad
procedure['steps'] = [...] # Don't know if it works

3. Combine for Better Decisions

# Good
best_procedure = procedural.get_best(domain)
similar_past = episodic.recall_similar(query)
decision = combine_insights(best_procedure, similar_past)

# Bad
decision = execute_procedure(best_procedure) # Ignore past context

Real-World Example

# A sales agent learns and improves

# Day 1
agent.analyze_sales(data) # Records event, learns procedure

# Day 2
agent.analyze_sales(data) # Uses learned procedure, tracks success

# Day 5
agent.analyze_sales(difficult_data)
 # Recalls similar past difficult cases (episodic)
 # Uses best procedure (procedural)
 # Adapts based on context
 # Records success

# Month 1
agent.analyze_sales(data) # Procedure highly successful

-

Key Takeaways

  1. Episodic: Store specific events with context
  2. Procedural: Store and improve skills/procedures
  3. Different storage: Episodic in vector DB, procedural in procedure DB
  4. Different retrieval: Episodic by similarity, procedural by domain
  5. Integration: Use both for better decisions
  6. Learning: Track success rates for procedures
  7. Retention: Keep both, prioritize high-value

-

Next Steps

-

Last Updated: August 9, 2026