🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

AI 에이전트 Memory Systems 설계 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 28. · 4 Views

AI 에이전트 Memory Systems 설계 완벽 가이드

AI 에이전트가 정보를 기억하고 활용하는 메모리 시스템의 핵심 개념을 다룹니다. 벡터 스토어의 한계부터 Knowledge Graph, Temporal KG까지 4가지 메모리 아키텍처를 실무 예제와 함께 설명합니다.


목차

  1. 박시니어의_메모리_실패담
  2. Context_Memory_Spectrum
  3. 벡터_스토어의_구조적_한계
  4. Knowledge_Graph와_Temporal_KG
  5. 네가지_아키텍처_비교
  6. 구현_가이드_실습

1. 박시니어의 메모리 실패담

박시니어 씨는 사내에서 AI 전문가로 통합니다. 그런 그가 어느 날 팀 회의에서 고개를 숙이며 고백했습니다.

"제가 만든 AI 어시스턴트가 같은 질문에 매번 다른 답을 내놓습니다. 벡터 스토어만 믿었던 제 불찰입니다."

벡터 스토어는 텍스트를 숫자 벡터로 변환하여 유사한 정보를 빠르게 찾아주는 저장소입니다. 마치 도서관에서 비슷한 주제의 책을 한 서가에 모아두는 것과 같습니다.

하지만 이 방식만으로는 정보 간의 관계나 시간 순서를 파악할 수 없어 AI가 맥락을 놓치는 문제가 발생합니다.

다음 코드를 살펴봅시다.

from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings

# 벡터 스토어 생성 - 단순 유사도 검색만 가능
embedding = OpenAIEmbeddings()
vectorstore = Chroma(embedding_function=embedding)

# 문서 저장 - 관계 정보는 사라집니다
docs = ["김과장이 프로젝트A를 담당", "프로젝트A가 3월에 완료"]
vectorstore.add_texts(docs)

# 검색 결과 - "김과장의 프로젝트 완료 시점"을 연결하지 못함
results = vectorstore.similarity_search("김과장 프로젝트 언제 완료?")
# 두 문서가 개별적으로 반환될 뿐, 관계는 알 수 없음

박시니어 씨는 회사에서 10년 차 시니어 개발자입니다. 최근 그는 사내 업무를 도와주는 AI 어시스턴트를 개발하는 프로젝트를 맡았습니다.

처음에는 모든 것이 순조로워 보였습니다. "벡터 스토어에 모든 회의록과 문서를 넣으면 되겠지." 박시니어 씨는 자신만만하게 시스템을 구축했습니다.

OpenAI의 임베딩 모델을 사용해 수천 개의 문서를 벡터로 변환하고, Chroma DB에 저장했습니다. 처음 며칠은 괜찮았습니다.

단순한 질문에는 제법 그럴듯한 답변을 내놓았습니다. "지난주 회의 내용 알려줘"라고 물으면 관련 회의록을 잘 찾아냈습니다.

하지만 문제는 복잡한 질문에서 시작되었습니다. "김과장이 담당하는 프로젝트A는 언제 완료되나요?"라는 질문에 AI는 엉뚱한 답을 내놓았습니다.

분명 "김과장이 프로젝트A를 담당한다"는 문서와 "프로젝트A가 3월에 완료된다"는 문서가 모두 저장되어 있었는데 말입니다. 벡터 스토어의 한계가 여기서 드러났습니다.

벡터 스토어는 텍스트를 고차원 숫자 벡터로 변환합니다. "사과"라는 단어는 [0.1, 0.3, 0.7, ...]과 같은 수백 개의 숫자로 표현됩니다.

비슷한 의미의 단어는 비슷한 벡터를 갖게 되어 유사도 검색이 가능해집니다. 쉽게 비유하자면, 벡터 스토어는 마치 도서관의 분류 시스템과 같습니다.

요리책은 요리책끼리, 역사책은 역사책끼리 모아둡니다. "파스타 레시피"를 찾으면 이탈리아 요리 섹션에서 관련 책을 찾아줍니다.

하지만 이 시스템에는 치명적인 맹점이 있습니다. "김과장"과 "프로젝트A"의 관계를 이해하지 못합니다.

두 정보가 유사도 검색으로 함께 나왔다 해도, AI는 이 둘이 어떻게 연결되는지 알 수 없습니다. 더 심각한 문제는 시간 정보의 손실입니다.

"프로젝트A가 3월에 시작되었다"와 "프로젝트A가 6월에 완료되었다"라는 두 문서가 있다면, 어느 것이 최신 정보인지 벡터만으로는 판단할 수 없습니다. 박시니어 씨는 뒤늦게 깨달았습니다.

벡터 스토어는 시작점일 뿐, 완성된 해답이 아니었던 것입니다. AI 에이전트가 진정으로 똑똑해지려면 정보를 저장하는 것을 넘어 정보 간의 관계를 이해해야 합니다.

이날의 실패는 박시니어 씨에게 중요한 교훈을 남겼습니다. 메모리 시스템을 설계할 때는 단순 검색을 넘어 관계와 시간까지 고려해야 한다는 것을 말입니다.

실전 팁

💡 - 벡터 스토어는 유사도 검색에는 강하지만 관계 추론에는 약합니다

  • 복잡한 질의가 필요하다면 벡터 스토어 외에 추가 저장소를 고려하세요
  • 시간 순서가 중요한 데이터는 별도의 타임스탬프 관리가 필요합니다

2. Context Memory Spectrum

김개발 씨가 박시니어 씨에게 물었습니다. "선배, 그러면 AI는 정보를 어떻게 기억해야 하나요?" 박시니어 씨는 화이트보드에 긴 선을 하나 그렸습니다.

"메모리에도 스펙트럼이 있어. 즉각 접근부터 영구 저장까지."

Context-Memory Spectrum은 AI 에이전트가 정보에 접근하는 속도와 지속성을 기준으로 메모리를 분류한 개념입니다. 마치 사람이 방금 들은 말은 바로 기억하지만, 어릴 적 추억은 천천히 떠올리는 것과 같습니다.

이 스펙트럼을 이해하면 상황에 맞는 최적의 메모리 전략을 선택할 수 있습니다.

다음 코드를 살펴봅시다.

class MemorySpectrum:
    """메모리 스펙트럼: 즉각 접근 -> 영구 저장"""

    def __init__(self):
        # 1. Immediate Context - 현재 대화 컨텍스트 (가장 빠름)
        self.immediate = []  # 현재 프롬프트 내용

        # 2. Working Memory - 작업 중 임시 저장
        self.working = {}    # 세션 동안 유지

        # 3. Short-term Memory - 최근 대화 기록
        self.short_term = [] # 몇 시간~며칠

        # 4. Long-term Memory - 영구 저장소
        self.long_term = {}  # 벡터 DB, KG 등

    def retrieve(self, query, urgency="normal"):
        # 긴급도에 따라 검색 범위 결정
        if urgency == "immediate":
            return self.immediate  # 0ms
        elif urgency == "fast":
            return self.working    # ~10ms
        return self.long_term      # ~100ms+

박시니어 씨가 화이트보드에 그린 선의 왼쪽 끝에는 "즉각"이라고, 오른쪽 끝에는 "영구"라고 적혀 있었습니다. 김개발 씨는 고개를 갸웃거렸습니다.

"사람의 기억을 생각해 봐." 박시니어 씨가 설명을 시작했습니다. "지금 내가 하는 말은 바로 이해하잖아?

하지만 초등학교 졸업식 날 뭘 먹었는지 떠올리려면 시간이 좀 걸리지." AI 에이전트의 메모리도 마찬가지입니다. Immediate Context는 현재 대화에서 바로 사용할 수 있는 정보입니다.

사용자가 방금 한 말, 시스템 프롬프트에 포함된 지시사항이 여기에 해당합니다. 접근 속도가 가장 빠르지만, 용량에 한계가 있습니다.

Working Memory는 현재 작업을 수행하는 동안 임시로 저장하는 공간입니다. 마치 계산기를 두드리면서 중간 결과를 메모지에 적어두는 것과 같습니다.

세션이 끝나면 사라지지만, 복잡한 작업을 수행하는 데 필수적입니다. Short-term Memory는 최근 며 시간에서 며칠 동안의 대화 기록을 보관합니다.

"아까 말했던 그 파일"이라고 했을 때 AI가 맥락을 파악할 수 있는 이유입니다. 적절한 시점에 정리하지 않으면 비용과 성능 문제가 생길 수 있습니다.

Long-term Memory는 영구적으로 저장되는 정보입니다. 벡터 스토어, Knowledge Graph, 데이터베이스가 여기에 속합니다.

접근 속도는 상대적으로 느리지만, 용량 제한이 거의 없습니다. 흥미로운 점은 이 스펙트럼이 트레이드오프 관계에 있다는 것입니다.

빠른 메모리는 용량이 작고, 큰 메모리는 느립니다. 컴퓨터의 CPU 캐시와 하드디스크 관계를 생각하면 이해하기 쉽습니다.

실무에서 자주 하는 실수는 모든 정보를 Long-term Memory에만 저장하는 것입니다. 박시니어 씨가 처음에 저질렀던 실수이기도 합니다.

매번 벡터 DB를 검색하면 응답 시간이 느려지고 비용도 증가합니다. 반대로 모든 것을 Immediate Context에 넣으려는 시도도 문제입니다.

LLM의 컨텍스트 윈도우는 제한되어 있어 모든 정보를 담을 수 없습니다. 넘치는 정보는 중요한 내용을 밀어내 오히려 성능을 저하시킵니다.

현명한 전략은 정보의 성격에 따라 적절한 메모리 계층에 배치하는 것입니다. 자주 참조하는 핵심 정보는 Working Memory에, 필요할 때만 꺼내는 정보는 Long-term Memory에 저장합니다.

김개발 씨가 물었습니다. "그럼 어떤 정보를 어디에 저장할지 어떻게 결정하나요?" 박시니어 씨가 웃으며 답했습니다.

"그건 다음 시간에 알려줄게. 우선 이 구조를 확실히 이해하는 게 먼저야."

실전 팁

💡 - 메모리 계층별 접근 시간을 측정하고 모니터링하세요

  • 자주 사용하는 정보는 상위 계층으로 캐싱하는 전략을 고려하세요
  • 컨텍스트 윈도우의 크기를 고려해 Immediate Context를 설계하세요

3. 벡터 스토어의 구조적 한계

김개발 씨가 직접 벡터 스토어를 테스트해 보았습니다. 간단한 문서 검색은 잘 되었지만, "A가 B의 상사이고, B가 C를 관리한다면 A와 C의 관계는?"이라는 질문에 AI는 우물쭈물했습니다.

"왜 이런 간단한 추론도 못 하는 거죠?"

벡터 스토어는 텍스트를 독립적인 벡터로 변환하기 때문에 관계 정보가 손실됩니다. "A는 B의 상사다"라는 문장에서 A, B, 그리고 상사 관계가 하나의 벡터로 뭉개집니다.

마치 가족사진을 픽셀 색상값의 평균으로만 저장하는 것과 같아서, 누가 누구의 부모인지 알 수 없게 됩니다.

다음 코드를 살펴봅시다.

# 관계 정보가 손실되는 과정 시뮬레이션
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('all-MiniLM-L6-v2')

# 관계가 포함된 문장들
sentences = [
    "김부장은 이과장의 상사입니다",
    "이과장은 박대리를 관리합니다",
    "김부장은 마케팅팀 소속입니다"
]

# 임베딩 변환 - 관계 구조는 사라짐
embeddings = model.encode(sentences)

# 문제: "김부장과 박대리의 관계?"
query = "김부장과 박대리의 관계는?"
query_emb = model.encode([query])

# 유사도 검색으로는 간접 관계를 추론할 수 없음
# 김부장 -> 이과장 -> 박대리 연결고리가 벡터에 없음

김개발 씨는 박시니어 씨의 조언대로 벡터 스토어의 한계를 직접 실험해 보기로 했습니다. 회사 조직도 정보를 벡터 DB에 저장하고, 여러 질문을 던져 보았습니다.

"김부장의 직속 부하는 누구야?"라는 질문에는 잘 답했습니다. 해당 정보가 문서에 그대로 있었기 때문입니다.

하지만 "김부장과 박대리 사이에 몇 단계가 있어?"라는 질문에는 제대로 답하지 못했습니다. 문제의 핵심은 임베딩의 본질에 있습니다.

임베딩은 텍스트의 의미를 고차원 벡터 공간의 한 점으로 표현합니다. "왕 - 남자 + 여자 = 여왕"과 같은 유명한 예시처럼, 단어의 의미적 관계를 잘 포착합니다.

하지만 이 방식에는 근본적인 한계가 있습니다. 문장 전체를 하나의 벡터로 압축하면서 구조 정보가 사라집니다.

"A가 B의 상사다"와 "B가 A의 상사다"는 비슷한 벡터를 갖게 될 수 있습니다. 순서와 방향이 중요한 관계 정보가 뭉개지는 것입니다.

마치 도시 지도를 저장한다고 생각해 봅시다. 벡터 스토어는 "서울역과 시청은 가깝다", "시청과 광화문은 가깝다"라는 정보를 저장합니다.

하지만 지하철 노선도처럼 "서울역 -> 시청 -> 광화문" 순서로 연결된다는 경로 정보는 저장하지 않습니다. 이것이 바로 그래프 구조가 필요한 이유입니다.

그래프는 노드(점)와 엣지(선)로 관계를 명시적으로 표현합니다. "김부장 --상사-- 이과장 --상사-- 박대리"처럼 관계의 방향과 종류를 보존합니다.

벡터 스토어의 또 다른 한계는 업데이트의 어려움입니다. "김부장이 이과장에게 업무를 인계했다"는 새 정보가 들어오면, 기존 벡터를 어떻게 수정해야 할까요?

단순히 새 문서를 추가하면 과거 정보와 충돌이 생깁니다. 김개발 씨는 깨달았습니다.

벡터 스토어는 검색 엔진으로는 훌륭하지만, 지식 표현에는 한계가 있다는 것을. 정보를 찾는 것과 정보를 이해하는 것은 다른 문제입니다.

박시니어 씨가 다가와 말했습니다. "이제 왜 Knowledge Graph가 필요한지 알겠지?

다음엔 그걸 배워보자."

실전 팁

💡 - 벡터 유사도 점수를 맹신하지 말고 결과를 검증하는 로직을 추가하세요

  • 관계 추론이 필요한 경우 그래프 데이터베이스 도입을 고려하세요
  • 벡터 검색 결과를 후처리하여 관계를 재구성하는 방법도 있습니다

4. Knowledge Graph와 Temporal KG

"그래프라..." 김개발 씨가 중얼거렸습니다. 대학 시절 자료구조 시간에 배운 그래프가 떠올랐습니다.

박시니어 씨가 새로운 다이어그램을 그리기 시작했습니다. "Knowledge Graph는 단순한 그래프가 아니야.

지식을 표현하는 특별한 방법이지."

**Knowledge Graph(KG)**는 엔티티(개체)와 관계를 그래프 구조로 표현하는 지식 저장소입니다. 마치 인물관계도처럼 누가 누구와 어떤 관계인지 명확히 보여줍니다.

Temporal KG는 여기에 시간 축을 추가하여 "언제" 그 관계가 유효했는지까지 기록합니다.

다음 코드를 살펴봅시다.

from neo4j import GraphDatabase
from datetime import datetime

class KnowledgeGraph:
    def __init__(self, uri, auth):
        self.driver = GraphDatabase.driver(uri, auth=auth)

    def add_relation(self, entity1, relation, entity2, valid_from=None):
        """관계를 명시적으로 저장 - 시간 정보 포함"""
        query = """
        MERGE (a:Entity {name: $e1})
        MERGE (b:Entity {name: $e2})
        CREATE (a)-[r:RELATION {type: $rel, valid_from: $time}]->(b)
        """
        with self.driver.session() as session:
            session.run(query, e1=entity1, e2=entity2,
                       rel=relation, time=valid_from or datetime.now())

    def find_path(self, from_entity, to_entity):
        """간접 관계 추론 - 경로 탐색"""
        query = """
        MATCH path = shortestPath(
            (a:Entity {name: $from})-[*]-(b:Entity {name: $to})
        )
        RETURN path
        """
        # 김부장 -> 이과장 -> 박대리 경로를 자동으로 찾음

박시니어 씨가 화이트보드에 동그라미와 화살표를 그리기 시작했습니다. 김개발 씨에게는 익숙한 모양이었습니다.

그래프 자료구조였습니다. "Knowledge Graph는 세 가지 요소로 이루어져 있어." 박시니어 씨가 설명했습니다.

"주어(Subject), 술어(Predicate), 목적어(Object). 이걸 트리플(Triple)이라고 불러." 예를 들어 "김부장은 이과장의 상사다"라는 문장은 (김부장, 상사, 이과장)이라는 트리플로 저장됩니다.

벡터 스토어와 달리 관계의 방향과 종류가 명확하게 보존됩니다. 김개발 씨가 물었습니다.

"그럼 아까 못 풀었던 문제도 풀 수 있나요?" 박시니어 씨가 고개를 끄덕였습니다. "물론이지.

(김부장, 상사, 이과장)과 (이과장, 상사, 박대리) 트리플이 있으면, 김부장에서 박대리까지의 경로를 탐색할 수 있어." 이것이 바로 **그래프 순회(Graph Traversal)**입니다. Neo4j 같은 그래프 데이터베이스는 이런 경로 탐색을 매우 효율적으로 수행합니다.

소셜 네트워크의 "친구의 친구" 기능이 바로 이 원리입니다. 하지만 기본 Knowledge Graph에도 한계가 있습니다.

"김부장이 작년까지 이과장의 상사였지만, 올해는 아니다"라는 상황을 어떻게 표현할까요? 단순히 관계를 삭제하면 과거 기록이 사라집니다.

이 문제를 해결하는 것이 Temporal Knowledge Graph입니다. 각 관계에 시간 정보를 추가합니다.

"(김부장, 상사, 이과장) [2020-01-01 ~ 2023-12-31]"처럼 관계가 유효한 기간을 명시합니다. Temporal KG를 사용하면 "2022년에 김부장의 부하는 누구였나요?"라는 시점 질의(Point-in-time Query)가 가능해집니다.

또한 "김부장의 조직이 어떻게 변화했나요?"라는 변화 추적도 할 수 있습니다. 마치 역사책과 같습니다.

단순한 Knowledge Graph가 현재의 스냅샷이라면, Temporal KG는 시간의 흐름이 담긴 연대기입니다. AI 에이전트가 과거를 회상하고 미래를 예측하는 데 필수적인 능력입니다.

박시니어 씨가 덧붙였습니다. "실무에서는 KG와 벡터 스토어를 함께 사용하는 경우가 많아.

벡터로 후보를 빠르게 검색하고, KG로 관계를 검증하는 거지." 김개발 씨의 눈이 반짝였습니다. 이론이 점점 실무로 연결되고 있었습니다.

실전 팁

💡 - Neo4j, Amazon Neptune 등의 그래프 DB를 학습해 두면 유용합니다

  • 트리플 설계 시 일관된 명명 규칙을 정하세요
  • Temporal KG 구현 시 시간대(timezone) 처리에 주의하세요

5. 네가지 아키텍처 비교

"자, 이제 전체 그림을 정리해 보자." 박시니어 씨가 큰 종이를 펼쳤습니다. 김개발 씨는 지금까지 배운 개념들이 어떻게 연결되는지 궁금했습니다.

"Working Memory, Short-term, KG, Temporal KG... 각각 언제 쓰는 건가요?"

AI 에이전트의 메모리 시스템은 크게 네 가지 아키텍처로 나눌 수 있습니다. Working Memory는 현재 작업용, Short-term Memory는 최근 맥락 유지용, Knowledge Graph는 관계 추론용, Temporal KG는 시간 기반 추론용입니다.

각 아키텍처는 고유한 강점과 적합한 사용 사례가 있습니다.

다음 코드를 살펴봅시다.

class MemoryArchitecture:
    """4가지 메모리 아키텍처 비교"""

    architectures = {
        "working": {
            "persistence": "세션 동안만",
            "access_speed": "1ms 이하",
            "capacity": "수 KB",
            "use_case": "현재 작업의 중간 결과 저장"
        },
        "short_term": {
            "persistence": "수 시간 ~ 수 일",
            "access_speed": "10-50ms",
            "capacity": "수 MB",
            "use_case": "최근 대화 맥락 유지"
        },
        "knowledge_graph": {
            "persistence": "영구",
            "access_speed": "50-200ms",
            "capacity": "수 GB",
            "use_case": "엔티티 간 관계 추론"
        },
        "temporal_kg": {
            "persistence": "영구 + 이력",
            "access_speed": "100-500ms",
            "capacity": "수십 GB",
            "use_case": "시간 기반 변화 추적"
        }
    }

    @classmethod
    def recommend(cls, need_relations, need_history, need_speed):
        if need_speed and not need_relations:
            return "short_term"
        if need_relations and need_history:
            return "temporal_kg"
        if need_relations:
            return "knowledge_graph"
        return "working"

박시니어 씨가 종이에 큰 표를 그렸습니다. 가로축에는 네 가지 아키텍처를, 세로축에는 비교 항목들을 적었습니다.

김개발 씨는 드디어 전체 그림이 보이기 시작했습니다. Working Memory는 가장 빠르지만 가장 휘발성이 강합니다.

현재 대화에서 AI가 중간 계산 결과를 저장하거나, 여러 단계의 추론을 수행할 때 사용합니다. 예를 들어 "1부터 10까지 더하면?"이라는 질문에 AI가 내부적으로 합계를 계산하는 동안 중간값을 저장하는 공간입니다.

Short-term Memory는 최근 대화의 맥락을 유지합니다. "아까 말한 그 파일"이라고 했을 때 AI가 이해할 수 있는 이유입니다.

보통 Redis나 인메모리 데이터베이스를 사용하여 구현합니다. 세션이 끝나면 정리되거나, 일정 시간이 지나면 만료됩니다.

Knowledge Graph는 영구적인 지식 저장소입니다. 엔티티 간의 관계를 명시적으로 저장하여 복잡한 추론이 가능합니다.

"우리 회사 CTO가 이전에 다녔던 회사의 창업자는 누구야?"와 같은 다단계 질문에 답할 수 있습니다. 단점은 구축과 유지보수에 많은 노력이 든다는 것입니다.

Temporal KG는 Knowledge Graph에 시간 차원을 추가한 것입니다. 관계의 변화를 추적할 수 있어 "작년 이맘때 우리 팀 구성은 어땠어?"라는 질문에 답할 수 있습니다.

가장 강력하지만 가장 복잡하고 저장 공간도 많이 필요합니다. 실무에서는 하이브리드 접근이 일반적입니다.

모든 것을 하나의 아키텍처로 해결하려 하지 않습니다. 빠른 응답이 필요한 부분은 Working Memory로, 관계 추론이 필요한 부분은 KG로 처리합니다.

중요한 것은 사용 사례를 먼저 정의하는 것입니다. "이 AI 에이전트가 답해야 할 질문은 무엇인가?"를 먼저 정하고, 그에 맞는 아키텍처를 선택해야 합니다.

기술 먼저가 아니라 문제 먼저입니다. 김개발 씨가 질문했습니다.

"그럼 저희 사내 AI 어시스턴트는 어떤 조합이 좋을까요?" 박시니어 씨가 미소 지었습니다. "좋은 질문이야.

우선 어떤 질문들에 답해야 하는지 목록을 만들어 보자." 마지막으로 박시니어 씨가 강조했습니다. "기억해.

가장 좋은 아키텍처는 '충분히 단순한' 아키텍처야. 필요 이상으로 복잡하게 만들지 마."

실전 팁

💡 - 먼저 요구사항을 명확히 정의하고 아키텍처를 선택하세요

  • 단순한 것부터 시작해서 필요할 때 복잡도를 높이세요
  • 각 아키텍처의 운영 비용도 고려하세요

6. 구현 가이드 실습

"이론은 충분해." 박시니어 씨가 노트북을 열었습니다. "이제 실제로 구현해 보자." 김개발 씨의 손이 키보드 위에서 떨렸습니다.

드디어 코드를 작성할 시간이었습니다.

메모리 시스템 구현의 핵심은 계층화된 저장소통합 검색 인터페이스입니다. 각 메모리 계층을 독립적으로 구현하되, 하나의 인터페이스로 접근할 수 있어야 합니다.

이 패턴을 Unified Memory Manager라고 부릅니다.

다음 코드를 살펴봅시다.

from typing import Dict, List, Optional
from datetime import datetime
import json

class UnifiedMemoryManager:
    """통합 메모리 관리자 - 모든 메모리 계층을 하나로"""

    def __init__(self):
        self.working = {}  # 현재 세션
        self.short_term = []  # 최근 대화 (리스트)
        self.kg_relations = []  # 관계 저장소
        self.temporal_log = []  # 시간 기록

    def store(self, key: str, value: any, layer: str = "working"):
        """계층별 저장"""
        if layer == "working":
            self.working[key] = value
        elif layer == "short_term":
            self.short_term.append({"key": key, "value": value,
                                   "time": datetime.now()})
        elif layer == "kg":
            # (subject, predicate, object) 형태로 저장
            self.kg_relations.append(value)

    def retrieve(self, query: str, layers: List[str] = None) -> Dict:
        """통합 검색 - 여러 계층에서 한 번에"""
        results = {}
        layers = layers or ["working", "short_term", "kg"]
        for layer in layers:
            results[layer] = self._search_layer(layer, query)
        return results

박시니어 씨가 화면을 공유했습니다. 에디터에는 깔끔하게 정리된 파이썬 코드가 있었습니다.

김개발 씨는 집중해서 코드를 읽기 시작했습니다. "먼저 전체 구조를 보자." 박시니어 씨가 설명을 시작했습니다.

"UnifiedMemoryManager 클래스가 모든 메모리 계층을 감싸고 있어. 외부에서는 이 클래스만 사용하면 돼." 이것이 Facade 패턴입니다.

복잡한 내부 구조를 단순한 인터페이스로 감춥니다. 사용자는 메모리가 내부적으로 어떻게 구성되어 있는지 알 필요 없이, store와 retrieve 메서드만 호출하면 됩니다.

store 메서드를 살펴보겠습니다. layer 파라미터에 따라 다른 저장소에 데이터를 저장합니다.

working 레이어는 딕셔너리로, short_term은 리스트로, kg는 트리플 형태로 저장합니다. 각 저장소의 특성에 맞게 데이터 구조가 다릅니다.

retrieve 메서드가 핵심입니다. 하나의 쿼리로 여러 계층을 동시에 검색합니다.

결과는 계층별로 분리되어 반환됩니다. 이렇게 하면 호출하는 측에서 어느 계층의 정보를 사용할지 결정할 수 있습니다.

실무에서는 이 기본 구조에 여러 기능을 추가합니다. 캐싱을 넣어 반복 검색을 빠르게 하고, **TTL(Time To Live)**을 설정해 오래된 데이터를 자동 삭제합니다.

우선순위를 두어 어느 계층의 결과를 먼저 사용할지 정합니다. 김개발 씨가 물었습니다.

"short_term에 계속 데이터가 쌓이면 메모리가 부족해지지 않나요?" 좋은 질문이었습니다. 박시니어 씨가 답했습니다.

"그래서 **정리 정책(Eviction Policy)**이 필요해. 오래된 항목을 삭제하거나, 중요도가 낮은 항목을 정리하는 거지." LRU(Least Recently Used), LFU(Least Frequently Used) 등의 알고리즘이 여기에 사용됩니다.

또는 일정 개수 이상이 되면 오래된 항목을 Long-term Memory로 이동시키는 방법도 있습니다. 마지막으로 테스트의 중요성을 강조했습니다.

메모리 시스템은 AI 에이전트의 핵심입니다. 잘못 구현하면 AI가 이상한 말을 하거나, 같은 질문에 다른 답을 하게 됩니다.

단위 테스트와 통합 테스트를 꼼꼼히 작성해야 합니다. 김개발 씨가 고개를 끄덕였습니다.

"이제 직접 구현해 볼 수 있을 것 같아요!" 박시니어 씨가 웃으며 말했습니다. "그래, 직접 해보는 게 최고야.

문제가 생기면 언제든 물어봐."

실전 팁

💡 - 먼저 간단한 버전을 구현하고 점진적으로 기능을 추가하세요

  • 메모리 사용량을 모니터링하는 로직을 처음부터 넣어두세요
  • 각 계층별로 독립적인 테스트를 작성하세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#AI Engineering#Memory Systems#Vector Store#Knowledge Graph#LLM Agent

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.