LLM 에이전트 메모리 시스템 설계: 단기 기억부터 장기 메모리까지
에이전트의 가장 큰 한계 중 하나는 기억입니다. 컨텍스트 윈도우가 꽉 차면 초기 대화를 잊어버리고, 세션이 끊기면 모든 것이 사라집니다. 실용적인 에이전트를 만들려면 메모리를 명시적으로 설계해야 합니다.
메모리의 4가지 유형
| 유형 | 특징 | 구현 방법 |
|---|---|---|
| 단기 메모리 | 현재 세션 내 대화 기록 | messages 배열 |
| 요약 메모리 | 긴 대화를 압축 요약 | Summarization + LLM |
| 의미 메모리 | 사실·지식 저장 | 벡터 DB |
| 절차 메모리 | 작업 수행 방법 기억 | Few-shot 예시 저장 |
단기 메모리: 슬라이딩 윈도우
from collections import deque
from openai import OpenAI
class ShortTermMemory:
def __init__(self, max_messages=20):
self.messages = deque(maxlen=max_messages)
self.system_prompt = "당신은 도움이 되는 AI 어시스턴트입니다."
def add(self, role, content):
self.messages.append({"role": role, "content": content})
def get_context(self):
return [{"role": "system", "content": self.system_prompt}] + list(self.messages)
client = OpenAI()
memory = ShortTermMemory(max_messages=10)
def chat(user_input):
memory.add("user", user_input)
response = client.chat.completions.create(
model="gpt-4o", messages=memory.get_context()
)
reply = response.choices[0].message.content
memory.add("assistant", reply)
return reply문제: 슬라이딩 윈도우는 오래된 중요 정보를 삭제합니다. 10번째 메시지에서 말한 사용자 이름을 30번째에서 잊어버립니다.
요약 메모리: 압축으로 컨텍스트 확장
대화가 길어지면 오래된 부분을 요약해서 저장합니다.
import anthropic
client = anthropic.Anthropic()
class SummaryMemory:
def __init__(self, window_size=10, summary_threshold=8):
self.recent_messages = []
self.summary = ""
self.window_size = window_size
self.summary_threshold = summary_threshold
def _summarize(self):
to_summarize = self.recent_messages[:self.summary_threshold]
existing = f"기존 요약: {self.summary}
" if self.summary else ""
conversation = "
".join(f"{m['role']}: {m['content']}" for m in to_summarize)
response = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=300,
messages=[{
"role": "user",
"content": f"{existing}다음 대화를 3-4문장으로 핵심만 요약하세요:
{conversation}"
}]
)
return response.content[0].text
def add(self, role, content):
self.recent_messages.append({"role": role, "content": content})
if len(self.recent_messages) > self.window_size:
self.summary = self._summarize()
self.recent_messages = self.recent_messages[self.summary_threshold:]
def get_context(self):
messages = []
if self.summary:
messages += [
{"role": "user", "content": f"[이전 대화 요약]
{self.summary}"},
{"role": "assistant", "content": "이전 대화 내용을 이해했습니다."}
]
return messages + self.recent_messages장기 메모리: 벡터 DB 기반
세션 간 정보를 유지하려면 외부 저장소가 필요합니다.
from openai import OpenAI
import json
from datetime import datetime
client = OpenAI()
class LongTermMemory:
def __init__(self, user_id, supabase_client):
self.user_id = user_id
self.sb = supabase_client
def _embed(self, text):
response = client.embeddings.create(
model="text-embedding-3-small", input=text
)
return response.data[0].embedding
def save(self, content, memory_type="fact"):
embedding = self._embed(content)
self.sb.table("agent_memories").insert({
"user_id": self.user_id,
"content": content,
"memory_type": memory_type,
"embedding": embedding,
"created_at": datetime.utcnow().isoformat()
}).execute()
def recall(self, query, top_k=3):
query_embedding = self._embed(query)
result = self.sb.rpc("match_memories", {
"query_embedding": query_embedding,
"user_id": self.user_id,
"match_count": top_k
}).execute()
return [r["content"] for r in (result.data or [])]메모리 계층 통합
class AgentWithMemory:
def __init__(self, user_id):
self.short_term = SummaryMemory(window_size=10)
self.long_term = LongTermMemory(user_id=user_id)
self.client = OpenAI()
def chat(self, user_input):
# 1. 장기 메모리에서 관련 기억 회상
relevant_memories = self.long_term.recall(user_input)
system_content = "당신은 도움이 되는 AI 어시스턴트입니다."
if relevant_memories:
system_content += "
[관련 기억]
" + "
".join(f"- {m}" for m in relevant_memories)
# 2. 단기 + 장기 컨텍스트 조합
messages = [{"role": "system", "content": system_content}]
messages.extend(self.short_term.get_context())
messages.append({"role": "user", "content": user_input})
response = self.client.chat.completions.create(model="gpt-4o", messages=messages)
reply = response.choices[0].message.content
self.short_term.add("user", user_input)
self.short_term.add("assistant", reply)
# 3. 중요 정보를 장기 메모리에 저장
self.long_term.extract_and_save(f"사용자: {user_input}
어시스턴트: {reply}")
return reply어떤 정보를 저장할 것인가
- 저장 O: 사용자 선호도, 프로젝트 이름·목표, 반복 패턴, 명시적 요청("기억해줘")
- 저장 X: 일회성 질문, 범용 사실(검색으로 대체 가능), 오류 메시지
다음 편에서는 구축한 에이전트의 평가와 디버깅 방법을 다룹니다.
이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.
댓글
불러오는 중...