مقدمه: ماهی طلایی با حافظه ۳ ثانیهای
یه شوخی قدیمی هست که میگه حافظه ماهی طلایی ۳ ثانیهست. حالا تصور کن یه Agent هم همین حافظه رو داشته باشه. هر بار که باهاش حرف بزنی، همه چیز از اول! نه اسمت رو یادش میمونه، نه ترجیحاتت، نه حتی اینکه ۵ دقیقه پیش چی بهش گفتی.
واقعیت اینه که LLM ها ذاتاً بدون حافظه هستن. هر بار که API رو صدا میزنی، از صفر شروع میشه. اون “حافظهای” که توی ChatGPT یا Claude میبینی، توسط سیستمهای اطراف LLM ساخته شده — نه توسط خود LLM.
توی این اپیزود میخوایم بفهمیم سیستمهای حافظه Agent چطور کار میکنن و چطور میشه یه حافظه خوب برای Agent ساخت.
چرا حافظه مهمه؟
بدون حافظه:
- کاربر هر بار باید خودش رو معرفی کنه
- Agent نمیتونه از اشتباهات قبلیش درس بگیره
- هر مکالمه مستقل و بیارتباط با بقیهست
- تجربه کاربری افتضاح میشه
با حافظه:
- Agent میدونه تو کی هستی و چی دوست داری
- از تجربههای قبلی استفاده میکنه
- مکالمات به هم مرتبط میشن
- کیفیت پاسخها با زمان بهتر میشه
انواع حافظه
مثل مغز انسان، حافظه Agent هم انواع مختلف داره. بیا هر کدوم رو بررسی کنیم:
۱. حافظه کوتاهمدت (Short-term / Working Memory)
این همون تاریخچه مکالمه فعلی ه. وقتی داری با Agent حرف میزنی، پیامهای قبلی توی context window قرار میگیرن.
class ShortTermMemory:
def __init__(self, max_messages: int = 50):
self.messages = []
self.max_messages = max_messages
def add(self, role: str, content: str):
self.messages.append({
"role": role,
"content": content
})
# اگه از حد گذشت، قدیمیها رو حذف کن
if len(self.messages) > self.max_messages:
self.messages = self.messages[-self.max_messages:]
def get_context(self) -> list:
return self.messages.copy()
def clear(self):
self.messages = []
۲. حافظه بلندمدت (Long-term Memory)
اطلاعاتی که بین session ها باقی میمونه. مثل اسم کاربر، ترجیحاتش، تاریخچه سفارشاتش. این اطلاعات معمولاً توی دیتابیس ذخیره میشن.
import json
from datetime import datetime
class LongTermMemory:
def __init__(self, storage_path: str = "memory.json"):
self.storage_path = storage_path
self.data = self._load()
def _load(self) -> dict:
try:
with open(self.storage_path, 'r') as f:
return json.load(f)
except FileNotFoundError:
return {"facts": [], "preferences": {}, "history": []}
def _save(self):
with open(self.storage_path, 'w') as f:
json.dump(self.data, f, ensure_ascii=False, indent=2)
def store_fact(self, fact: str, source: str = "conversation"):
self.data["facts"].append({
"fact": fact,
"source": source,
"timestamp": datetime.now().isoformat()
})
self._save()
def store_preference(self, key: str, value: str):
self.data["preferences"][key] = value
self._save()
def recall_facts(self, query: str = None) -> list:
if query is None:
return self.data["facts"]
# جستجوی ساده
return [f for f in self.data["facts"]
if query.lower() in f["fact"].lower()]
def get_preference(self, key: str) -> str:
return self.data["preferences"].get(key)
۳. حافظه اپیزودیک (Episodic Memory)
حافظه اپیزودیک مثل خاطرات شخصیه. Agent یادش میمونه چه اتفاقاتی افتاده و از اونا درس میگیره.
مثال: “دفعه قبل که کاربر درباره پایتون سوال کرد، من یه مثال ساده زدم و خوشش اومد. پس این بار هم مثال ساده بزنم.”
class EpisodicMemory:
def __init__(self):
self.episodes = []
def record_episode(self, situation: str, action: str,
outcome: str, feedback: str = None):
self.episodes.append({
"situation": situation,
"action": action,
"outcome": outcome,
"feedback": feedback,
"timestamp": datetime.now().isoformat()
})
def recall_similar(self, current_situation: str) -> list:
"""پیدا کردن تجربههای مشابه"""
relevant = []
for ep in self.episodes:
# اینجا میشه از similarity search استفاده کرد
if self._is_similar(current_situation, ep["situation"]):
relevant.append(ep)
return relevant
def _is_similar(self, a: str, b: str) -> bool:
"""مقایسه ساده — در عمل از embedding استفاده میشه"""
common_words = set(a.lower().split()) & set(b.lower().split())
return len(common_words) > 3
۴. حافظه معنایی (Semantic Memory)
حافظه معنایی شامل دانش کلی و ساختاریافتهست. مثل یه دایرهالمعارف شخصی. تفاوتش با حافظه اپیزودیک اینه که به زمان و مکان خاصی گره نخورده.
مثال: “پایتون یه زبان برنامهنویسی سطح بالاست” (حافظه معنایی) در مقابل “دیروز به کاربر پایتون یاد دادم” (حافظه اپیزودیک).
Vector Database: قلب حافظه بلندمدت
برای پیادهسازی حافظه بلندمدت به شکل موثر، از Vector Database استفاده میشه. ایده سادهست:
- متن رو تبدیل به embedding (بردار عددی) کن
- بردار رو توی دیتابیس ذخیره کن
- وقتی چیزی رو میخوای پیدا کنی، سوالت رو هم embedding کن و مشابهترین بردارها رو پیدا کن
from openai import OpenAI
import numpy as np
client = OpenAI()
class VectorMemory:
def __init__(self):
self.memories = [] # لیست (text, embedding)
def _get_embedding(self, text: str) -> list:
"""تبدیل متن به بردار"""
response = client.embeddings.create(
model="text-embedding-3-small",
input=text
)
return response.data[0].embedding
def store(self, text: str, metadata: dict = None):
"""ذخیره یه خاطره"""
embedding = self._get_embedding(text)
self.memories.append({
"text": text,
"embedding": embedding,
"metadata": metadata or {}
})
def recall(self, query: str, top_k: int = 5) -> list:
"""یادآوری مرتبطترین خاطرات"""
query_embedding = self._get_embedding(query)
# محاسبه شباهت کسینوسی
scored = []
for mem in self.memories:
similarity = self._cosine_similarity(
query_embedding, mem["embedding"]
)
scored.append((similarity, mem["text"]))
# مرتبسازی بر اساس شباهت
scored.sort(reverse=True)
return [text for _, text in scored[:top_k]]
def _cosine_similarity(self, a: list, b: list) -> float:
a = np.array(a)
b = np.array(b)
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
مثال با ChromaDB
import chromadb
# ساخت دیتابیس
chroma_client = chromadb.Client()
collection = chroma_client.create_collection(name="agent_memory")
# ذخیره خاطرات
collection.add(
documents=[
"کاربر اسمش علی هست و برنامهنویس پایتون",
"کاربر ترجیح میده توضیحات با مثال عملی باشه",
"آخرین بار درباره FastAPI سوال کرد",
"کاربر تازهکار نیست، سطح متوسطه",
],
ids=["fact1", "fact2", "fact3", "fact4"]
)
# یادآوری
results = collection.query(
query_texts=["کاربر چه سطحی داره؟"],
n_results=2
)
print(results["documents"])
# [['کاربر تازهکار نیست، سطح متوسطه',
# 'کاربر ترجیح میده توضیحات با مثال عملی باشه']]
خلاصهسازی مکالمه (Conversation Summarization)
وقتی مکالمه طولانی میشه و از حد context window رد میشه، یه راهحل خوب خلاصهسازی ه. به جای حذف پیامهای قدیمی، خلاصشون میکنی:
class ConversationSummarizer:
def __init__(self, llm_client, max_messages: int = 20):
self.client = llm_client
self.max_messages = max_messages
self.messages = []
self.summary = ""
def add_message(self, role: str, content: str):
self.messages.append({"role": role, "content": content})
if len(self.messages) > self.max_messages:
self._summarize_old_messages()
def _summarize_old_messages(self):
"""خلاصهسازی پیامهای قدیمی"""
# نصف اول رو خلاصه کن
to_summarize = self.messages[:len(self.messages)//2]
to_keep = self.messages[len(self.messages)//2:]
summary_prompt = f"""خلاصه مکالمه قبلی:
{self.summary}
پیامهای جدید برای خلاصهسازی:
{self._format_messages(to_summarize)}
لطفاً یه خلاصه جامع از کل مکالمه تا اینجا بده.
نکات مهم، تصمیمات، و اطلاعات کلیدی رو حفظ کن."""
response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": summary_prompt}]
)
self.summary = response.choices[0].message.content
self.messages = to_keep
def get_context(self) -> list:
"""گرفتن context برای LLM"""
context = []
if self.summary:
context.append({
"role": "system",
"content": f"خلاصه مکالمه قبلی:\n{self.summary}"
})
context.extend(self.messages)
return context
def _format_messages(self, messages: list) -> str:
return "\n".join(
f"{m['role']}: {m['content']}" for m in messages
)
الگوهای عملی حافظه
الگوی ۱: حافظه سهلایه
یه معماری رایج برای حافظه Agent:
class ThreeLayerMemory:
def __init__(self):
# لایه ۱: Context فعلی (حافظه کاری)
self.working_memory = ShortTermMemory(max_messages=20)
# لایه ۲: خلاصه مکالمات (حافظه میانمدت)
self.conversation_summary = ""
# لایه ۳: دانش پایدار (حافظه بلندمدت)
self.long_term = VectorMemory()
def build_context(self, user_message: str) -> list:
"""ساختن context کامل برای LLM"""
# از حافظه بلندمدت، مرتبطترین اطلاعات رو بیار
relevant_memories = self.long_term.recall(
user_message, top_k=3
)
context = []
# خلاصه مکالمات قبلی
if self.conversation_summary:
context.append({
"role": "system",
"content": f"خلاصه تعاملات قبلی:\n"
f"{self.conversation_summary}"
})
# اطلاعات مرتبط از حافظه بلندمدت
if relevant_memories:
memories_text = "\n".join(
f"- {m}" for m in relevant_memories
)
context.append({
"role": "system",
"content": f"اطلاعات مرتبط:\n{memories_text}"
})
# مکالمه فعلی
context.extend(self.working_memory.get_context())
return context
الگوی ۲: استخراج خودکار اطلاعات
Agent میتونه خودش از مکالمه اطلاعات مهم رو استخراج و ذخیره کنه:
def extract_and_store(self, conversation: list):
"""استخراج خودکار اطلاعات مهم از مکالمه"""
extraction_prompt = """از مکالمه زیر، اطلاعات مهم رو استخراج کن.
فقط اطلاعات واقعی و مهم رو بنویس، نه نظرات.
فرمت: هر اطلاعات در یک خط.
مکالمه:
{conversation}
اطلاعات استخراجشده:"""
response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "user",
"content": extraction_prompt.format(
conversation=self._format_messages(conversation)
)
}]
)
facts = response.choices[0].message.content.strip().split("\n")
for fact in facts:
fact = fact.strip("- ").strip()
if fact:
self.long_term.store(fact)
مشکلات و چالشها
مشکل ۱: حافظههای متناقض
کاربر ممکنه توی مکالمات مختلف چیزهای متناقض بگه. مثلاً یه بار بگه “من برنامهنویس جاواام” و بعداً بگه “من فقط پایتون بلدم”. باید سیستمی داشته باشی که اطلاعات جدیدتر رو اولویت بده.
مشکل ۲: حریم خصوصی
حافظه بلندمدت یعنی ذخیره اطلاعات کاربر. این موضوع حریم خصوصی داره. باید به کاربر اجازه بدی حافظه رو ببینه و پاک کنه.
مشکل ۳: مقیاسپذیری
وقتی حافظه بزرگ میشه، جستجو کندتر میشه. Vector database ها اینجا کمک میکنن، ولی باید معماری درستی داشته باشی.
مشکل ۴: نویز
همه چیز توی مکالمه مهم نیست. Agent باید بتونه تشخیص بده چه چیزی ارزش ذخیرهسازی داره.
ترکیب حافظه با Agent
بیا ببینیم یه Agent کامل با حافظه چطوری کار میکنه:
class MemoryAgent:
def __init__(self):
self.memory = ThreeLayerMemory()
self.client = OpenAI()
def chat(self, user_message: str) -> str:
# ذخیره پیام کاربر
self.memory.working_memory.add("user", user_message)
# ساختن context با حافظه
context = self.memory.build_context(user_message)
# ارسال به LLM
response = self.client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system",
"content": "تو یه دستیار هوشمند فارسیزبان هستی "
"که حافظه داره."},
*context,
],
)
reply = response.choices[0].message.content
# ذخیره پاسخ
self.memory.working_memory.add("assistant", reply)
# استخراج اطلاعات مهم برای حافظه بلندمدت
self._maybe_extract_info(user_message, reply)
return reply
def _maybe_extract_info(self, user_msg: str, assistant_msg: str):
"""تشخیص و ذخیره اطلاعات مهم"""
# هر ۵ پیام، اطلاعات مهم رو استخراج کن
msgs = self.memory.working_memory.messages
if len(msgs) % 10 == 0:
self.memory.extract_and_store(msgs[-10:])
# استفاده
agent = MemoryAgent()
agent.chat("سلام، من رضا هستم")
agent.chat("من دولوپر فرانتاند هستم")
# ... چند روز بعد ...
agent.chat("سلام")
# Agent: "سلام رضا! خوبی؟ بازم سوال فرانتاندی داری؟"
جمعبندی
- حافظه کوتاهمدت: تاریخچه مکالمه فعلی — ساده ولی محدود به context window
- حافظه بلندمدت: ذخیره در Vector DB — پایدار و قابل جستجو
- حافظه اپیزودیک: خاطرات و تجربهها — برای یادگیری از گذشته
- حافظه معنایی: دانش ساختاریافته — مثل دایرهالمعارف شخصی
- خلاصهسازی: راهحل مشکل context window محدود
اپیزود بعدی درباره Planning ه — وقتی Agent قبل از عمل فکر میکنه و برنامهریزی میکنه. یکی از جذابترین بخشهای ساخت Agent!
نظرات
هنوز نظری ثبت نشده. اولین نفر باشید!
نظر خود را بنویسید