본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 26. · 2 Views
Memory Systems 완벽 가이드 - LLM 에이전트의 기억력 설계
LLM 에이전트가 대화를 기억하고 학습하는 메모리 시스템의 모든 것을 다룹니다. 단기 메모리부터 벡터 DB 기반 장기 메모리, 에피소딕 메모리까지 실전 구현 방법을 배워봅니다.
목차
1. 단기 메모리 대화 히스토리
어느 날 김개발 씨가 챗봇 서비스를 만들고 있었습니다. 사용자가 "내 이름은 철수야"라고 말했는데, 다음 대화에서 "내 이름이 뭐였지?"라고 물으니 봇이 기억을 못했습니다.
선배 박시니어 씨가 코드를 보더니 말했습니다. "단기 메모리가 없네요.
대화 히스토리를 관리해야 해요."
단기 메모리는 LLM 에이전트가 현재 대화 세션 동안의 메시지를 기억하는 시스템입니다. 마치 사람이 방금 나눈 대화를 기억하는 것처럼, 에이전트도 이전 메시지들을 컨텍스트로 유지합니다.
이를 통해 자연스러운 연속 대화가 가능해집니다.
다음 코드를 살펴봅시다.
# 단기 메모리: 대화 히스토리 관리
class ConversationMemory:
def __init__(self, max_messages=10):
self.messages = [] # 메시지 리스트
self.max_messages = max_messages
def add_message(self, role, content):
# 새 메시지 추가
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):
# LLM에 전달할 컨텍스트 반환
return self.messages
김개발 씨는 입사 3개월 차 주니어 개발자입니다. 회사에서 고객 상담용 챗봇을 만드는 프로젝트를 맡았습니다.
첫 버전을 만들고 테스트를 해보니, 사용자가 이전에 한 말을 봇이 전혀 기억하지 못했습니다. 사용자가 "내 주문 번호는 1234야"라고 말했는데, 바로 다음에 "내 주문 상태 알려줘"라고 하면 봇이 "주문 번호를 알려주세요"라고 되묻는 황당한 상황이 발생했습니다.
그렇다면 단기 메모리란 정확히 무엇일까요? 쉽게 비유하자면, 단기 메모리는 마치 메모장에 방금 나눈 대화를 적어두는 것과 같습니다.
사람이 대화할 때 "아까 네가 그랬잖아"라고 말할 수 있는 이유는 뇌가 최근 대화 내용을 기억하고 있기 때문입니다. LLM 에이전트도 똑같이 최근 대화를 기억해야 자연스러운 대화가 가능합니다.
단기 메모리가 없던 시절에는 어땠을까요? 초기 챗봇들은 매 요청을 독립적으로 처리했습니다.
사용자가 무엇을 물어봤는지, 어떤 정보를 제공했는지 전혀 기억하지 못했습니다. 마치 기억상실증 걸린 사람과 대화하는 것 같았습니다.
사용자는 매번 모든 정보를 반복해서 말해야 했고, 이는 매우 불편한 경험이었습니다. 바로 이런 문제를 해결하기 위해 대화 히스토리 관리 시스템이 등장했습니다.
단기 메모리를 사용하면 이전 대화의 맥락을 유지할 수 있습니다. 또한 사용자가 대명사를 사용해도 무엇을 가리키는지 이해할 수 있습니다.
무엇보다 자연스러운 연속 대화가 가능해진다는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 __init__ 메서드에서 메시지 리스트를 초기화하고 최대 메시지 개수를 설정합니다. add_message 메서드는 새로운 메시지를 리스트에 추가하는데, 이 부분이 핵심입니다.
메시지가 최대 개수를 초과하면 가장 오래된 메시지부터 제거하여 메모리를 관리합니다. 마지막으로 get_context 메서드가 LLM에 전달할 전체 대화 히스토리를 반환합니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 여행 예약 챗봇을 개발한다고 가정해봅시다.
사용자가 "서울에서 부산 가는 기차표 찾아줘"라고 하면, 봇이 몇 가지 옵션을 보여줍니다. 사용자가 "두 번째 거로 할게"라고 하면, 단기 메모리 덕분에 봇은 방금 보여준 옵션 리스트를 기억하고 있어서 정확히 어떤 기차를 선택했는지 알 수 있습니다.
카카오톡, 네이버 클로바 같은 대화형 AI 서비스들이 모두 이런 패턴을 사용합니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 메시지 개수 제한을 두지 않는 것입니다. 대화가 길어지면 컨텍스트가 무한정 늘어나서 LLM의 토큰 제한을 초과하거나 응답 속도가 느려질 수 있습니다.
따라서 적절한 최대 개수를 설정하고, 오래된 메시지는 제거하는 로직을 반드시 구현해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다. "아, 그래서 메시지 리스트를 관리해야 하는 거군요!" 단기 메모리를 제대로 이해하면 더 자연스럽고 사용자 친화적인 대화형 AI를 만들 수 있습니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 일반적으로 최근 10-20개 메시지만 유지하면 충분합니다
- 시스템 메시지는 항상 첫 번째에 유지하여 역할 정의를 보존하세요
- 토큰 수를 계산하여 동적으로 메시지 개수를 조절하면 더 효율적입니다
2. 장기 메모리 벡터 DB
김개발 씨의 챗봇이 점점 인기를 얻으면서 문제가 생겼습니다. 사용자가 "지난주에 내가 물어본 그 레시피 다시 알려줘"라고 하는데, 단기 메모리에는 이미 그 내용이 사라진 지 오래였습니다.
박시니어 씨가 말했습니다. "이제 장기 메모리가 필요한 시점이네요.
벡터 DB를 써봅시다."
장기 메모리는 과거의 중요한 정보를 영구적으로 저장하고 필요할 때 검색하는 시스템입니다. 텍스트를 벡터로 변환하여 데이터베이스에 저장하고, 의미적 유사도를 기반으로 관련 정보를 찾아냅니다.
이를 통해 몇 주, 몇 달 전의 대화도 기억할 수 있습니다.
다음 코드를 살펴봅시다.
from sentence_transformers import SentenceTransformer
import chromadb
class LongTermMemory:
def __init__(self):
# 임베딩 모델 초기화
self.encoder = SentenceTransformer('all-MiniLM-L6-v2')
# ChromaDB 클라이언트 생성
self.client = chromadb.Client()
self.collection = self.client.create_collection("memories")
def save(self, text, metadata=None):
# 텍스트를 벡터로 변환하여 저장
embedding = self.encoder.encode(text).tolist()
self.collection.add(
embeddings=[embedding],
documents=[text],
metadatas=[metadata or {}],
ids=[f"mem_{len(self.collection.get()['ids'])}"]
)
def search(self, query, top_k=3):
# 유사한 기억 검색
query_embedding = self.encoder.encode(query).tolist()
results = self.collection.query(
query_embeddings=[query_embedding],
n_results=top_k
)
return results['documents'][0]
김개발 씨의 챗봇은 이제 하루에 수백 명의 사용자와 대화를 나눕니다. 그런데 문제가 생겼습니다.
단기 메모리는 최근 몇 개의 메시지만 기억하기 때문에, 사용자가 며칠 전에 나눈 대화를 언급하면 전혀 기억하지 못했습니다. 어떤 사용자는 "저번에 추천해준 파스타 레시피 다시 보여줘"라고 했는데, 봇은 "무슨 레시피를 말씀하시는 건가요?"라고 되물었습니다.
사용자는 실망했고, 김개발 씨는 고민에 빠졌습니다. 그렇다면 장기 메모리란 정확히 무엇일까요?
쉽게 비유하자면, 장기 메모리는 마치 도서관 시스템과 같습니다. 도서관에는 수많은 책이 있지만, 사서가 색인 카드를 보고 원하는 책을 빠르게 찾아줍니다.
벡터 DB도 마찬가지로 모든 과거 대화를 저장해두고, 필요할 때 의미적으로 관련된 내용을 찾아냅니다. 장기 메모리가 없던 시절에는 어땠을까요?
개발자들은 단순히 모든 대화를 텍스트 파일이나 일반 데이터베이스에 저장했습니다. 하지만 "파스타 레시피"를 찾으려면 정확히 그 단어가 포함된 문장만 검색할 수 있었습니다.
사용자가 "이탈리아 요리"라고 표현하면 찾지 못했습니다. 키워드가 정확히 일치해야만 했기 때문입니다.
바로 이런 문제를 해결하기 위해 벡터 데이터베이스가 등장했습니다. 벡터 DB를 사용하면 의미적으로 유사한 내용을 찾을 수 있습니다.
"파스타 레시피"와 "이탈리아 요리 만드는 법"을 같은 맥락으로 이해할 수 있습니다. 또한 수백만 개의 대화 중에서도 밀리초 단위로 관련 정보를 검색할 수 있습니다.
무엇보다 사용자별로 개인화된 기억을 관리할 수 있다는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 SentenceTransformer로 임베딩 모델을 로드합니다. 이 모델이 텍스트를 벡터로 변환하는 핵심입니다.
ChromaDB 클라이언트를 생성하고 컬렉션을 만들어 메모리 저장소를 준비합니다. save 메서드에서는 텍스트를 벡터로 변환한 후 메타데이터와 함께 저장합니다.
search 메서드는 쿼리를 벡터로 변환하고, 코사인 유사도를 계산하여 가장 관련성 높은 기억들을 반환합니다. 실제 현업에서는 어떤 식으로 활용할까요?
예를 들어 의료 상담 챗봇을 개발한다고 가정해봅시다. 환자가 한 달 전에 "두통이 있어요"라고 말했고, 오늘 "머리 아픈 증상이 또 생겼어요"라고 하면, 벡터 검색으로 과거 두통 관련 대화를 찾아냅니다.
봇은 "지난달에도 비슷한 증상을 말씀하셨네요. 그때와 비교해서 어떤가요?"라고 맥락 있는 대화를 이어갈 수 있습니다.
실제로 많은 AI 어시스턴트 서비스들이 이런 방식을 사용합니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 모든 대화를 무분별하게 저장하는 것입니다. "안녕하세요", "감사합니다" 같은 단순한 인사말까지 저장하면 DB가 불필요하게 커지고 검색 품질도 떨어집니다.
따라서 중요한 정보만 선별적으로 저장하는 로직을 구현해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 설명을 들은 김개발 씨는 눈이 반짝였습니다. "와, 이제 진짜 똑똑한 봇이 되겠네요!" 장기 메모리를 제대로 이해하면 사용자 경험이 완전히 달라집니다.
여러분도 오늘 배운 벡터 DB를 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - ChromaDB 외에도 Pinecone, Weaviate, Qdrant 등 다양한 벡터 DB가 있습니다
- 임베딩 모델은 사용 언어와 도메인에 맞게 선택하세요
- 메타데이터에 타임스탬프, 사용자 ID 등을 저장하면 검색 필터링에 유용합니다
3. Episodic Memory
김개발 씨의 챗봇이 한층 더 똑똑해졌지만, 여전히 아쉬운 점이 있었습니다. 사용자가 "우리 지난주 화요일에 무슨 얘기했지?"라고 물으면 시간 순서를 이해하지 못했습니다.
박시니어 씨가 설명했습니다. "에피소딕 메모리를 추가하면 시간적 맥락까지 기억할 수 있어요."
에피소딕 메모리는 특정 사건이나 경험을 시간 순서와 함께 기억하는 시스템입니다. 단순히 내용만 저장하는 것이 아니라, 언제 무슨 일이 있었는지를 에피소드 단위로 기록합니다.
마치 사람이 "작년 여름 제주도 여행"처럼 특정 경험을 기억하는 것과 같습니다.
다음 코드를 살펴봅시다.
from datetime import datetime
import json
class EpisodicMemory:
def __init__(self):
self.episodes = [] # 에피소드 리스트
def create_episode(self, event_type, content, context=None):
# 새로운 에피소드 생성
episode = {
"timestamp": datetime.now().isoformat(),
"event_type": event_type, # 예: "task_completed", "user_feedback"
"content": content,
"context": context or {},
"id": len(self.episodes)
}
self.episodes.append(episode)
return episode
def get_episodes_by_type(self, event_type):
# 특정 타입의 에피소드 검색
return [ep for ep in self.episodes if ep["event_type"] == event_type]
def get_recent_episodes(self, hours=24):
# 최근 N시간 내 에피소드 검색
cutoff = datetime.now().timestamp() - (hours * 3600)
return [ep for ep in self.episodes
if datetime.fromisoformat(ep["timestamp"]).timestamp() > cutoff]
김개발 씨의 챗봇은 이제 과거 대화도 잘 기억합니다. 하지만 새로운 문제가 생겼습니다.
사용자가 "지난주에 내가 부탁한 작업 진행 상황 알려줘"라고 하면, 봇은 작업 내용은 찾지만 언제 시작했는지, 중간에 무슨 일이 있었는지는 모릅니다. 한 사용자는 "우리 월요일에 오류 얘기했잖아.
그거 해결됐어?"라고 물었는데, 봇은 오류 내용은 찾았지만 그게 월요일 일인지, 해결됐는지 추적하지 못했습니다. 김개발 씨는 또 고민에 빠졌습니다.
그렇다면 에피소딕 메모리란 정확히 무엇일까요? 쉽게 비유하자면, 에피소딕 메모리는 마치 일기장과 같습니다.
일기장에는 날짜별로 무슨 일이 있었는지 기록됩니다. "3월 15일: 친구를 만나서 영화를 봤다.
재미있었다." 처럼 시간과 사건이 함께 저장됩니다. 에피소딕 메모리도 마찬가지로 특정 시점에 일어난 일을 하나의 에피소드로 묶어서 기억합니다.
에피소딕 메모리가 없던 시절에는 어땠을까요? AI 시스템은 정보를 평면적으로 저장했습니다.
"사용자가 버그를 신고했다"는 기록은 있지만, 그 후에 "개발자가 수정했다", "사용자가 확인했다"는 연속된 사건의 흐름을 추적하지 못했습니다. 마치 퍼즐 조각들은 있는데 어떤 순서로 맞춰야 할지 모르는 상황이었습니다.
바로 이런 문제를 해결하기 위해 에피소딕 메모리 시스템이 등장했습니다. 에피소딕 메모리를 사용하면 시간 순서대로 사건을 추적할 수 있습니다.
또한 특정 사건의 전후 맥락을 이해할 수 있습니다. 무엇보다 "언제, 무엇이, 왜" 일어났는지를 종합적으로 파악할 수 있다는 큰 이점이 있습니다.
위의 코드를 한 줄씩 살펴보겠습니다. 먼저 create_episode 메서드는 새로운 에피소드를 생성합니다.
타임스탬프를 자동으로 기록하는 부분이 핵심입니다. 이벤트 타입으로 사건을 분류하고, 컨텍스트에 추가 정보를 저장합니다.
get_episodes_by_type은 특정 종류의 사건만 필터링하고, get_recent_episodes는 시간 범위로 검색합니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 프로젝트 관리 AI 어시스턴트를 개발한다고 가정해봅시다. 팀원이 "버그 수정 작업 시작했어"라고 말하면 에피소드를 생성합니다.
나중에 "그 버그 작업 어떻게 됐지?"라고 물으면, 시간 순서대로 "작업 시작 → 코드 리뷰 완료 → 배포 대기" 같은 이벤트 흐름을 보여줄 수 있습니다. 노션, 먼데이닷컴 같은 협업 도구의 AI 기능들이 이런 방식을 활용합니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 너무 세세한 것까지 에피소드로 만드는 것입니다.
사용자가 버튼을 클릭할 때마다 에피소드를 만들면 쓸모없는 데이터가 쌓이고 의미 있는 사건을 찾기 어려워집니다. 따라서 중요한 이벤트만 에피소드로 기록하고, 적절한 granularity를 유지해야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 무릎을 쳤습니다.
"그래서 시간 축이 중요했던 거군요!" 에피소딕 메모리를 제대로 이해하면 AI가 단순히 정보를 기억하는 수준을 넘어, 경험을 이해하는 시스템을 만들 수 있습니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 이벤트 타입은 미리 정의된 enum을 사용하면 일관성 있게 관리할 수 있습니다
- 에피소드 간 연결 관계를 저장하면 더 풍부한 맥락을 표현할 수 있습니다
- 주기적으로 오래된 에피소드를 요약하여 저장 공간을 절약하세요
4. 실습 메모리 시스템 구축
이제 김개발 씨는 세 가지 메모리를 모두 배웠습니다. 하지만 막상 실제로 구현하려니 막막했습니다.
"이걸 어떻게 하나로 합치죠?" 박시니어 씨가 웃으며 말했습니다. "통합 메모리 시스템을 만들어봅시다.
각 메모리의 장점을 모두 활용하는 거예요."
통합 메모리 시스템은 단기, 장기, 에피소딕 메모리를 하나의 에이전트에 결합한 구조입니다. 현재 대화는 단기 메모리로, 중요한 정보는 장기 메모리로, 특별한 사건은 에피소딕 메모리로 저장합니다.
세 메모리가 유기적으로 협력하여 완전한 기억 시스템을 만듭니다.
다음 코드를 살펴봅시다.
class MemoryAgent:
def __init__(self):
self.short_term = ConversationMemory(max_messages=10)
self.long_term = LongTermMemory()
self.episodic = EpisodicMemory()
def process_message(self, user_message):
# 1. 단기 메모리에 추가
self.short_term.add_message("user", user_message)
# 2. 장기 메모리에서 관련 정보 검색
relevant_memories = self.long_term.search(user_message, top_k=3)
# 3. 현재 컨텍스트 구성
context = {
"recent_messages": self.short_term.get_context(),
"relevant_past": relevant_memories,
"recent_episodes": self.episodic.get_recent_episodes(hours=24)
}
# 4. LLM에 컨텍스트와 함께 요청
response = self.call_llm(user_message, context)
# 5. 응답을 단기 메모리에 추가
self.short_term.add_message("assistant", response)
return response
def save_important_info(self, info, event_type=None):
# 중요한 정보는 장기 메모리와 에피소드 모두에 저장
self.long_term.save(info)
if event_type:
self.episodic.create_episode(event_type, info)
김개발 씨는 드디어 실전에 들어갈 준비가 되었습니다. 단기 메모리, 장기 메모리, 에피소딕 메모리를 각각 구현해봤지만, 이제 이것들을 하나로 통합해야 합니다.
처음에는 복잡해 보였지만, 박시니어 씨의 설명을 들으니 생각보다 명확했습니다. "각 메모리는 서로 다른 역할을 한다고 생각하세요." 박시니어 씨가 화이트보드에 그림을 그리며 설명했습니다.
"단기 메모리는 지금 대화, 장기 메모리는 과거 지식, 에피소딕 메모리는 특별한 사건을 담당합니다." 그렇다면 통합 메모리 시스템이란 정확히 무엇일까요? 쉽게 비유하자면, 통합 메모리 시스템은 마치 사람의 뇌와 같습니다.
우리 뇌도 작업 기억, 장기 기억, 일화 기억이 따로 놀지 않고 협력합니다. 누군가 "어제 점심 뭐 먹었어?"라고 물으면, 에피소딕 메모리에서 어제 사건을 찾고, 장기 메모리에서 그 식당 정보를 가져오고, 단기 메모리로 대화를 이어갑니다.
AI도 똑같이 작동해야 합니다. 통합 메모리 없이 각각 따로 사용하면 어떤 문제가 생길까요?
단기 메모리만 쓰면 과거를 잊어버립니다. 장기 메모리만 쓰면 현재 대화의 흐름을 놓칩니다.
에피소딕 메모리만 쓰면 일반 지식을 활용하지 못합니다. 세 메모리를 따로따로 사용하는 건 마치 퍼즐 조각을 하나씩만 보는 것과 같습니다.
전체 그림이 보이지 않습니다. 바로 이런 문제를 해결하기 위해 통합 메모리 아키텍처가 필요합니다.
통합 시스템을 사용하면 현재와 과거를 모두 고려한 응답을 만들 수 있습니다. 또한 중요한 정보는 자동으로 여러 메모리에 저장되어 나중에 다양한 방식으로 활용됩니다.
무엇보다 사용자 입장에서는 정말 기억력 좋은 AI와 대화하는 경험을 할 수 있다는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 __init__에서 세 가지 메모리를 모두 초기화합니다. process_message가 핵심인데, 여기서 마법이 일어납니다.
사용자 메시지가 오면 먼저 단기 메모리에 추가합니다. 그다음 장기 메모리에서 관련된 과거 정보를 검색합니다.
최근 에피소드도 가져옵니다. 이 모든 것을 context로 묶어서 LLM에 전달하면, AI는 풍부한 맥락을 가지고 답변할 수 있습니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 개인 비서 AI를 개발한다고 가정해봅시다.
사용자가 "다음 주 회의 준비해줘"라고 하면, 단기 메모리에서 방금 전 대화를 확인하고, 장기 메모리에서 이전 회의들의 패턴을 분석하고, 에피소딕 메모리에서 지난주 회의에서 정해진 안건들을 찾아냅니다. 세 메모리의 정보를 종합해서 "지난번 회의에서 논의하기로 한 마케팅 전략 자료를 준비할까요?"라고 제안할 수 있습니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 모든 메모리를 항상 다 사용하는 것입니다.
간단한 인사말에도 장기 메모리 검색과 에피소드 조회를 하면 불필요한 연산 낭비입니다. 따라서 메시지의 중요도를 판단하고, 필요한 메모리만 선택적으로 활용하는 로직을 추가하는 게 좋습니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 코드를 본 김개발 씨는 감탄했습니다.
"이렇게 간단하게 통합할 수 있었네요!" 통합 메모리 시스템을 제대로 구현하면 진짜 똑똑한 AI 에이전트를 만들 수 있습니다. 여러분도 오늘 배운 패턴을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 메시지 중요도를 판단하는 분류기를 추가하면 효율성이 높아집니다
- 각 메모리의 결과에 가중치를 부여하여 컨텍스트를 구성하세요
- 메모리 간 동기화 로직을 추가하면 일관성을 유지할 수 있습니다
5. 실습 컨텍스트 관리
김개발 씨의 통합 메모리 시스템이 완성되었습니다. 그런데 테스트를 해보니 LLM이 "컨텍스트가 너무 길다"는 오류를 뱉었습니다.
박시니어 씨가 진단했습니다. "메모리는 많은데 컨텍스트 관리를 안 했네요.
토큰 제한 안에서 최적화해야 합니다."
컨텍스트 관리는 LLM의 토큰 제한 내에서 가장 중요한 정보만 선별하여 전달하는 기술입니다. 메모리에서 가져온 모든 정보를 다 넣을 수 없으므로, 우선순위를 정하고 요약하고 압축합니다.
효율적인 컨텍스트 관리가 곧 AI의 성능을 좌우합니다.
다음 코드를 살펴봅시다.
import tiktoken
class ContextManager:
def __init__(self, model="gpt-4", max_tokens=8000):
self.encoder = tiktoken.encoding_for_model(model)
self.max_tokens = max_tokens
def count_tokens(self, text):
# 텍스트의 토큰 수 계산
return len(self.encoder.encode(text))
def build_context(self, short_term, long_term, episodes):
context_parts = []
remaining_tokens = self.max_tokens
# 1. 시스템 메시지 (최우선)
system_msg = "You are a helpful AI assistant."
context_parts.append(system_msg)
remaining_tokens -= self.count_tokens(system_msg)
# 2. 최근 대화 (높은 우선순위)
for msg in reversed(short_term[-5:]):
msg_tokens = self.count_tokens(str(msg))
if remaining_tokens - msg_tokens < 1000:
break # 여유 공간 확보
context_parts.append(msg)
remaining_tokens -= msg_tokens
# 3. 관련 장기 메모리 (중간 우선순위)
for memory in long_term[:3]:
mem_tokens = self.count_tokens(memory)
if remaining_tokens - mem_tokens < 500:
break
context_parts.append(f"Past: {memory}")
remaining_tokens -= mem_tokens
return context_parts
김개발 씨는 신이 났습니다. 드디어 완벽한 메모리 시스템을 만들었으니까요.
그런데 실제로 사용자와 대화를 시작하자마자 오류가 발생했습니다. "Error: maximum context length exceeded." LLM이 처리할 수 있는 토큰 수를 초과했다는 메시지였습니다.
"왜 이런 일이 생기죠?" 김개발 씨가 당황하며 물었습니다. 박시니어 씨가 설명했습니다.
"메모리에서 너무 많은 정보를 가져와서 그래요. LLM은 한 번에 처리할 수 있는 양이 정해져 있거든요." 그렇다면 컨텍스트 관리란 정확히 무엇일까요?
쉽게 비유하자면, 컨텍스트 관리는 마치 여행 짐싸기와 같습니다. 비행기 수하물은 무게 제한이 있습니다.
가져가고 싶은 옷이 많아도 다 넣을 수 없으므로, 중요한 것부터 우선순위를 정해서 챙깁니다. LLM의 컨텍스트도 마찬가지로 용량이 제한되어 있으므로, 가장 중요한 정보만 선별해서 전달해야 합니다.
컨텍스트 관리를 하지 않으면 어떤 문제가 생길까요? 메모리에 있는 모든 정보를 다 LLM에 넣으려고 하면 토큰 제한을 초과합니다.
또는 오래된 덜 중요한 정보가 공간을 차지해서 정작 중요한 최근 대화가 잘리는 경우도 생깁니다. 비효율적으로 컨텍스트를 구성하면 응답 속도도 느려지고 비용도 많이 듭니다.
바로 이런 문제를 해결하기 위해 스마트한 컨텍스트 관리 전략이 필요합니다. 컨텍스트 관리를 잘하면 제한된 토큰으로 최대 효과를 낼 수 있습니다.
또한 중요한 정보만 전달하므로 LLM이 더 집중된 답변을 만들 수 있습니다. 무엇보다 비용을 절감하고 응답 속도를 높일 수 있다는 큰 이점이 있습니다.
위의 코드를 한 줄씩 살펴보겠습니다. 먼저 tiktoken 라이브러리로 토큰을 정확하게 계산합니다.
이게 핵심인데, 문자 수와 토큰 수는 다르기 때문입니다. build_context 메서드는 우선순위 전략을 구현합니다.
시스템 메시지를 가장 먼저 넣고, 최근 대화를 높은 우선순위로, 장기 메모리를 중간 우선순위로 배치합니다. 각 단계마다 남은 토큰을 계산하고, 여유 공간을 확보하여 안전하게 관리합니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 고객 지원 챗봇을 개발한다고 가정해봅시다.
고객이 긴 불만을 토로한 후 "환불해줘"라고 하면, 컨텍스트 관리자는 전체 불만 내용 중 핵심만 요약해서 LLM에 전달합니다. "고객이 3번 배송 지연, 2번 파손을 경험함.
환불 요청"처럼 압축된 정보로 처리하면, 토큰을 아끼면서도 정확한 답변을 만들 수 있습니다. 실제로 대규모 AI 서비스들은 정교한 컨텍스트 관리로 비용을 수십 퍼센트 절감합니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 단순히 글자 수로 자르는 것입니다.
문장 중간에서 잘리면 의미가 깨집니다. 토큰 수를 정확히 계산하고, 문장 단위로 자르고, 중요한 정보를 우선 배치하는 로직이 필요합니다.
또한 너무 공격적으로 압축하면 맥락을 잃을 수 있으므로 적절한 균형이 중요합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 컨텍스트 관리 코드를 적용하자 오류가 사라졌습니다. "이제 완벽하게 작동하네요!" 컨텍스트 관리를 제대로 이해하면 효율적이고 경제적인 AI 시스템을 만들 수 있습니다.
여러분도 오늘 배운 우선순위 전략을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 각 정보 타입에 우선순위 점수를 부여하여 동적으로 선택하세요
- 긴 텍스트는 요약 모델로 압축하면 더 많은 정보를 담을 수 있습니다
- 모델별 토큰 제한을 고려하여 max_tokens를 설정하세요 (GPT-4: 8K, Claude: 100K 등)
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Multi-Agent 아키텍처 완벽 가이드
여러 AI 에이전트가 협업하여 복잡한 문제를 해결하는 Multi-Agent 아키텍처를 초급자 눈높이에서 설명합니다. 역할 분업, 협업 패턴, 실전 구현까지 실무에 바로 적용할 수 있는 내용을 담았습니다.
Hierarchical Agents 완벽 가이드
AI 에이전트를 계층적으로 구성하여 복잡한 작업을 효율적으로 처리하는 방법을 배웁니다. Supervisor-Worker 패턴부터 실전 프로젝트 관리까지 단계별로 학습합니다.
Agent Communication 완벽 가이드
여러 AI 에이전트가 서로 소통하며 협력하는 방법을 배웁니다. 프로토콜, 메시지 포맷, 협업 패턴까지 실무에 필요한 모든 것을 다룹니다. 초급 개발자도 쉽게 이해할 수 있도록 실전 예제와 함께 설명합니다.
Tool-Augmented Agents 완벽 가이드
LLM에 도구를 연결하여 검색, API 호출, 계산 등 실제 작업을 수행하는 에이전트를 만드는 방법을 초급 개발자도 쉽게 이해할 수 있도록 설명합니다. 실무에서 바로 활용할 수 있는 멀티 툴 에이전트와 API 통합 예제를 포함합니다.
Tree of Thoughts 에이전트 완벽 가이드
AI 에이전트가 복잡한 문제를 해결할 때 여러 사고 경로를 탐색하고 평가하는 Tree of Thoughts 기법을 배웁니다. BFS/DFS 탐색 전략부터 가지치기, 백트래킹까지 실전 예제와 함께 쉽게 설명합니다.