Агентная ИИ с памятью: создание непрерывно обучающихся агентов с эпизодической и семантической памятью
'Практическое руководство по реализации эпизодической и семантической памяти для агентов, которые учатся и улучшаются между сессиями.'
Зачем нужна память
Память позволяет агенту связывать прошлые взаимодействия с будущими решениями. Вместо того чтобы рассматривать каждый пользовательский шаг как изолированный, агент с памятью сохраняет эпизоды (конкретные взаимодействия) и выделяет семантические паттерны (устойчивые предпочтения и стратегии действий). Это даёт систему, которая планирует, выполняет, пересматривает и рефлексирует между сессиями, делая ответы персонализированнее и автономнее со временем.
Проектирование эпизодической памяти
Эпизодическая память фиксирует конкретные ходы: состояние, действие, результат и метку времени. Ниже реализация, которая сохраняет эпизоды, строит простое встраивание и извлекает похожие прошлые опыты.
import numpy as np
from collections import defaultdict
import json
from datetime import datetime
import pickle
class EpisodicMemory:
def __init__(self, capacity=100):
self.capacity = capacity
self.episodes = []
def store(self, state, action, outcome, timestamp=None):
if timestamp is None:
timestamp = datetime.now().isoformat()
episode = {
'state': state,
'action': action,
'outcome': outcome,
'timestamp': timestamp,
'embedding': self._embed(state, action, outcome)
}
self.episodes.append(episode)
if len(self.episodes) > self.capacity:
self.episodes.pop(0)
def _embed(self, state, action, outcome):
text = f"{state} {action} {outcome}".lower()
return hash(text) % 10000
def retrieve_similar(self, query_state, k=3):
if not self.episodes:
return []
query_emb = self._embed(query_state, "", "")
scores = [(abs(ep['embedding'] - query_emb), ep) for ep in self.episodes]
scores.sort(key=lambda x: x[0])
return [ep for _, ep in scores[:k]]
def get_recent(self, n=5):
return self.episodes[-n:]Проектирование семантической памяти
Семантическая память суммирует шаблоны и предпочтения по эпизодам. Она отслеживает веса предпочтений, контекст-действие паттерны и базовые показатели успеха, чтобы агент мог выбирать действия, которые исторически срабатывали.
class SemanticMemory:
def __init__(self):
self.preferences = defaultdict(float)
self.patterns = defaultdict(list)
self.success_rates = defaultdict(lambda: {'success': 0, 'total': 0})
def update_preference(self, key, value, weight=1.0):
self.preferences[key] = 0.9 * self.preferences[key] + 0.1 * weight * value
def record_pattern(self, context, action, success):
pattern_key = f"{context}_{action}"
self.patterns[context].append((action, success))
self.success_rates[pattern_key]['total'] += 1
if success:
self.success_rates[pattern_key]['success'] += 1
def get_best_action(self, context):
if context not in self.patterns:
return None
action_scores = defaultdict(lambda: {'success': 0, 'total': 0})
for action, success in self.patterns[context]:
action_scores[action]['total'] += 1
if success:
action_scores[action]['success'] += 1
best_action = max(action_scores.items(), key=lambda x: x[1]['success'] / max(x[1]['total'], 1))
return best_action[0] if best_action[1]['total'] > 0 else None
def get_preference(self, key):
return self.preferences.get(key, 0.0)Восприятие и планирование
Агент с памятью должен распознавать намерение пользователя, обращаться к эпизодической памяти для контекста и использовать семантику для формирования плана. Ниже MemoryAgent объединяет восприятие, планирование и доступ к памяти.
class MemoryAgent:
def __init__(self):
self.episodic_memory = EpisodicMemory(capacity=50)
self.semantic_memory = SemanticMemory()
self.current_plan = []
self.session_count = 0
def perceive(self, user_input):
user_input = user_input.lower()
if any(word in user_input for word in ['recommend', 'suggest', 'what should']):
intent = 'recommendation'
elif any(word in user_input for word in ['remember', 'prefer', 'like', 'favorite']):
intent = 'preference_update'
elif any(word in user_input for word in ['do', 'complete', 'finish', 'task']):
intent = 'task_execution'
else:
intent = 'conversation'
return {'intent': intent, 'raw': user_input}
def plan(self, state):
intent = state['intent']
user_input = state['raw']
similar_episodes = self.episodic_memory.retrieve_similar(user_input, k=3)
plan = []
if intent == 'recommendation':
genre_prefs = {k: v for k, v in self.semantic_memory.preferences.items() if 'genre_' in k}
if genre_prefs:
best_genre = max(genre_prefs.items(), key=lambda x: x[1])[0]
plan.append(('recommend', best_genre.replace('genre_', '')))
else:
plan.append(('recommend', 'general'))
elif intent == 'preference_update':
genres = ['sci-fi', 'fantasy', 'mystery', 'romance', 'thriller']
detected_genre = next((g for g in genres if g in user_input), None)
if detected_genre:
plan.append(('update_preference', detected_genre))
elif intent == 'task_execution':
best_action = self.semantic_memory.get_best_action('task')
if best_action:
plan.append(('execute', best_action))
else:
plan.append(('execute', 'default'))
self.current_plan = plan
return planВыполнение, пересмотр и рефлексия
Агент выполняет действие, может пересмотреть план при негативной обратной связи и фиксирует опыт в эпизодической памяти, а паттерны — в семантической.
def act(self, action):
action_type, param = action
if action_type == 'recommend':
if param == 'general':
return f"Let me learn your preferences first! What genres do you enjoy?"
return f"Based on your preferences, I recommend exploring {param}!"
elif action_type == 'update_preference':
self.semantic_memory.update_preference(f'genre_{param}', 1.0, weight=1.0)
return f"Got it! I'll remember you enjoy {param}."
elif action_type == 'execute':
return f"Executing task with strategy: {param}"
return "Action completed"
def revise_plan(self, feedback):
if 'no' in feedback.lower() or 'wrong' in feedback.lower():
if self.current_plan:
action_type, param = self.current_plan[0]
if action_type == 'recommend':
genre_prefs = sorted(
[(k, v) for k, v in self.semantic_memory.preferences.items() if 'genre_' in k],
key=lambda x: x[1],
reverse=True
)
if len(genre_prefs) > 1:
new_genre = genre_prefs[1][0].replace('genre_', '')
self.current_plan = [('recommend', new_genre)]
return True
return False
def reflect(self, state, action, outcome, success):
self.episodic_memory.store(state['raw'], str(action), outcome)
self.semantic_memory.record_pattern(state['intent'], str(action), success)Запуск сессий и оценка памяти
Простой цикл показа демонстрирует, как цикл восприятие→план→действие→рефлексия повторяется по ходам и сессиям. Демонстрация ниже симулирует три сессии, оценивает использование памяти и выполняет тест извлечения.
def run_session(self, user_inputs):
self.session_count += 1
print(f"\n{'='*60}")
print(f"SESSION {self.session_count}")
print(f"{'='*60}\n")
results = []
for i, user_input in enumerate(user_inputs, 1):
print(f"Turn {i}")
print(f"User: {user_input}")
state = self.perceive(user_input)
plan = self.plan(state)
if not plan:
print("Agent: I'm not sure what to do with that.\n")
continue
response = self.act(plan[0])
print(f"Agent: {response}\n")
success = 'recommend' in plan[0][0] or 'update' in plan[0][0]
self.reflect(state, plan[0], response, success)
results.append({
'turn': i,
'input': user_input,
'intent': state['intent'],
'action': plan[0],
'response': response
})
return resultsdef evaluate_memory_usage(agent):
print("\n" + "="*60)
print("MEMORY ANALYSIS")
print("="*60 + "\n")
print(f"Episodic Memory:")
print(f" Total episodes stored: {len(agent.episodic_memory.episodes)}")
if agent.episodic_memory.episodes:
print(f" Oldest episode: {agent.episodic_memory.episodes[0]['timestamp']}")
print(f" Latest episode: {agent.episodic_memory.episodes[-1]['timestamp']}")
print(f"\nSemantic Memory:")
print(f" Learned preferences: {len(agent.semantic_memory.preferences)}")
for pref, value in sorted(agent.semantic_memory.preferences.items(), key=lambda x: x[1], reverse=True)[:5]:
print(f" {pref}: {value:.3f}")
print(f"\n Action patterns learned: {len(agent.semantic_memory.patterns)}")
print(f"\n Success rates by context-action:")
for key, stats in list(agent.semantic_memory.success_rates.items())[:5]:
if stats['total'] > 0:
rate = stats['success'] / stats['total']
print(f" {key}: {rate:.2%} ({stats['success']}/{stats['total']})")
def compare_sessions(results_history):
print("\n" + "="*60)
print("CROSS-SESSION ANALYSIS")
print("="*60 + "\n")
for i, results in enumerate(results_history, 1):
recommendation_quality = sum(1 for r in results if 'preferences' in r['response'].lower())
print(f"Session {i}:")
print(f" Turns: {len(results)}")
print(f" Personalized responses: {recommendation_quality}")def run_demo():
agent = MemoryAgent()
print("\n SCENARIO: Agent learns user preferences over multiple sessions")
session1_inputs = [
"Hi, I'm looking for something to read",
"I really like sci-fi books",
"Can you recommend something?",
]
results1 = agent.run_session(session1_inputs)
session2_inputs = [
"I'm bored, what should I read?",
"Actually, I also enjoy fantasy novels",
"Give me a recommendation",
]
results2 = agent.run_session(session2_inputs)
session3_inputs = [
"What do you suggest for tonight?",
"I'm in the mood for mystery too",
"Recommend something based on what you know about me",
]
results3 = agent.run_session(session3_inputs)
evaluate_memory_usage(agent)
compare_sessions([results1, results2, results3])
print("\n" + "="*60)
print("EPISODIC MEMORY RETRIEVAL TEST")
print("="*60 + "\n")
query = "recommend sci-fi"
similar = agent.episodic_memory.retrieve_similar(query, k=3)
print(f"Query: '{query}'")
print(f"Retrieved {len(similar)} similar episodes:\n")
for ep in similar:
print(f" State: {ep['state']}")
print(f" Action: {ep['action']}")
print(f" Outcome: {ep['outcome'][:50]}...")
print()
if __name__ == "__main__":
print("="*60)
print("MEMORY & LONG-TERM AUTONOMY IN AGENTIC SYSTEMS")
print("="*60)
run_demo()
print("\n Tutorial complete! Key takeaways:")
print(" • Episodic memory stores specific experiences")
print(" • Semantic memory generalizes patterns")
print(" • Agents improve recommendations over sessions")
print(" • Memory retrieval guides future decisions")Чему учит такой подход
Запуски и оценки показывают два эффекта: эпизодическое извлечение помогает агенту переиспользовать релевантные прошлые действия, а семантика направляет выбор стратегий, которые работали на практике. В сочетании они создают цикл, при котором агент постепенно становится лучше в персонализации и принятии решений.
Switch Language
Read this article in English