Skip to main content

메모리 설계 베스트 프랙티스

1. TTL(Time-To-Live) 설정

오래된 메모리는 가치가 떨어지거나 오히려 해로울 수 있습니다. 3년 전 선호했던 제품을 지금도 추천하면 오히려 역효과입니다.
메모리 유형권장 TTL근거
대화 히스토리 (세부)30일세부 대화는 빠르게 가치 감소
사용자 선호90일선호는 비교적 안정적이나 변할 수 있음
학습된 도메인 지식1년정책/규정 변경 주기에 맞춤
에피소드 (성공 패턴)6개월도구/API 변경으로 오래된 패턴이 무효화될 수 있음

2. 메모리 요약(Consolidation)

주기적으로 세부 기억을 요약하여 저장 공간을 절약하고 검색 품질을 높입니다.
def consolidate_memories(user_id: str, days_old: int = 30):
    """30일 이상 된 세부 기억을 요약하여 압축"""
    old_memories = get_memories_older_than(user_id, days_old)

    if not old_memories:
        return

    # LLM으로 오래된 기억들을 요약
    summary = model.invoke(f"""
    다음은 사용자 {user_id}의 과거 대화 기록입니다.
    핵심 정보만 추출하여 간결하게 요약하세요:
    {format_memories(old_memories)}
    """)

    # 요약본 저장 + 원본 삭제
    store_memory(user_id, summary.content, {"memory_type": "consolidated"})
    delete_memories(old_memories)

3. 선택적 망각(Selective Forgetting)

모든 것을 기억하는 것이 능사가 아닙니다. 관련 없는 기억은 삭제하고, 특히 개인정보 삭제 요청(GDPR Right to Erasure) 에 대응할 수 있어야 합니다.
def forget_user_data(user_id: str):
    """GDPR 삭제 요청 대응: 특정 사용자의 모든 메모리 삭제"""
    # Vector Search에서 삭제
    index.delete(filter={"user_id": user_id})

    # Lakebase에서 삭제
    cursor.execute("DELETE FROM agent_memory WHERE user_id = %s", (user_id,))
    conn.commit()

    # MLflow 에피소드에서 태그 익명화
    anonymize_episodes(user_id)

4. 메모리 범위(Scoping)

메모리의 접근 범위를 명확히 구분해야 합니다:
범위접근 주체예시
Session-level현재 대화 세션만현재 대화의 맥락
User-level특정 사용자의 모든 세션사용자 선호, 과거 이력
Agent-level특정 Agent의 모든 사용자Agent가 학습한 도메인 지식
Global-level모든 Agent, 모든 사용자공통 정책, 회사 규정

5. 검색 전략: 복합 랭킹

메모리 검색 시 Vector similarity만으로는 부족합니다. 여러 신호를 결합하여 최적의 기억을 찾아야 합니다.
def recall_with_ranking(user_id: str, query: str, top_k: int = 5):
    """복합 랭킹으로 최적의 메모리 검색"""
    # 1단계: Vector similarity로 후보 검색 (넉넉하게)
    candidates = recall_memory(user_id, query, top_k=top_k * 3)

    # 2단계: 복합 점수 계산
    scored = []
    for mem in candidates:
        similarity_score = mem["score"]  # 의미적 유사도
        recency_score = calculate_recency_weight(mem["timestamp"])  # 최신성
        importance_score = mem.get("importance", 0.5)  # 메타데이터 중요도

        # 가중 합산
        final_score = (
            0.5 * similarity_score +
            0.3 * recency_score +
            0.2 * importance_score
        )
        scored.append((final_score, mem))

    # 3단계: 최종 순위로 반환
    scored.sort(key=lambda x: x[0], reverse=True)
    return [mem for _, mem in scored[:top_k]]

메모리 안티패턴

실무에서 흔히 발견되는 메모리 설계 실수와 해결 방법입니다:
안티패턴문제해결
무한 축적메모리가 무한히 커져 검색 성능 저하, 비용 증가TTL 설정 + 주기적 Consolidation
Privacy 위반개인정보(PII)가 메모리에 영구 저장PII 마스킹, 삭제 정책, GDPR 대응 로직
Context Pollution관련 없는 기억이 프롬프트에 포함되어 답변 품질 저하관련도 임계값 설정 (예: similarity > 0.7만 포함)
메모리 충돌서로 모순되는 기억이 공존 (예: “부서: 마케팅” vs “부서: 영업”)최신 기억 우선(timestamp), 충돌 감지 및 해결 로직
과도한 의존메모리 시스템 장애 시 Agent 전체가 멈춤메모리를 graceful degradation으로 설계 (없어도 기본 동작)
비용 폭발모든 대화를 벡터 임베딩하여 저장하면 스토리지/컴퓨팅 비용 급증중요한 정보만 선별 저장, 요약 후 저장
주의 Context Pollution은 가장 흔한 안티패턴 입니다. 관련 없는 과거 기억이 프롬프트에 포함되면 LLM이 혼란을 일으켜 오히려 메모리가 없는 것보다 나쁜 결과를 만들 수 있습니다. 반드시 관련도 임계값 을 설정하세요.

Databricks에서 Agent Memory 구축 가이드

실전에서 Databricks 플랫폼 위에 Agent Memory를 단계별로 구축하는 방법입니다.

Step 1. Session Memory — 기본 제공

ChatAgent의 messages 파라미터를 활용하면 별도 구현 없이 세션 내 메모리를 사용할 수 있습니다.
from databricks.agents import ChatAgent

class MyAgent(ChatAgent):
    def predict(self, messages, context=None):
        # messages에 이전 대화 히스토리가 자동 포함됨
        # → 별도 메모리 구현 불필요 (세션 내 한정)
        response = self.model.invoke(messages)
        return response

Step 2. User Profile Memory — Lakebase 활용

-- Lakebase에 사용자 프로필 테이블 생성
CREATE TABLE agent_memory (
    user_id     VARCHAR(255) NOT NULL,
    key         VARCHAR(255) NOT NULL,
    value       TEXT,
    created_at  TIMESTAMP DEFAULT NOW(),
    updated_at  TIMESTAMP DEFAULT NOW(),
    expires_at  TIMESTAMP,  -- TTL 지원
    PRIMARY KEY (user_id, key)
);

-- 인덱스 추가
CREATE INDEX idx_memory_user ON agent_memory(user_id);
CREATE INDEX idx_memory_expires ON agent_memory(expires_at);

Step 3. Semantic Memory — Vector Search 활용

-- Delta Table로 메모리 저장소 생성
CREATE TABLE catalog.schema.conversation_memory (
    id          STRING,
    user_id     STRING,
    content     STRING,
    timestamp   TIMESTAMP,
    memory_type STRING,
    importance  DOUBLE DEFAULT 0.5
);

-- Vector Search Index 생성
CREATE VECTOR SEARCH INDEX memory_index
ON catalog.schema.conversation_memory (content)
USING MODEL `databricks-gte-large-en`
WITH (endpoint_name = "memory_vs_endpoint");

Step 4. 하이브리드 통합 — System Prompt에 메모리 주입

모든 메모리를 통합하여 Agent의 System Prompt에 주입하는 최종 단계입니다.
def build_memory_enhanced_prompt(user_id: str, current_query: str) -> str:
    """모든 메모리 소스를 결합하여 풍부한 프롬프트 생성"""

    # 1. User Profile Memory (Lakebase)
    profile = get_user_preferences(user_id)
    profile_section = "[사용자 프로필]\n"
    for key, value in profile:
        profile_section += f"- {key}: {value}\n"

    # 2. Relevant History (Vector Search)
    relevant_memories = recall_with_ranking(user_id, current_query, top_k=3)
    history_section = "[관련 과거 대화]\n"
    for mem in relevant_memories:
        history_section += f"- ({mem['timestamp']}): {mem['text']}\n"

    # 3. Episodic Memory (MLflow)
    episodes = search_successful_episodes(current_query, top_k=2)
    episode_section = "[참고할 과거 경험]\n"
    for ep in episodes:
        episode_section += f"- {ep['task']}: {ep['approach']}{ep['outcome']}\n"

    # 통합 System Prompt
    system_prompt = f"""당신은 전문 업무 지원 Agent입니다.

{profile_section}
{history_section}
{episode_section}

위 메모리를 참고하여 사용자에게 개인화되고 맥락에 맞는 답변을 제공하세요.
새롭게 파악된 중요 정보는 메모리에 저장하세요."""

    return system_prompt

고객 FAQ

”메모리 없이 Agent를 운영할 수 있나요?”

단순 Q&A는 가능합니다.”오늘 날씨 알려줘”, “이 함수 사용법 알려줘” 같은 단발성 질문에는 메모리가 필요 없습니다. 하지만 다음 중 하나라도 해당되면 메모리가 필수입니다:
  • 사용자별 개인화 가 필요한 경우
  • 이전 대화의 맥락을 이어가야 하는 경우
  • Agent가 과거 경험으로부터 학습 해야 하는 경우
  • 멀티스텝 작업 에서 중간 결과를 추적해야 하는 경우

”메모리 구현에 어떤 DB를 써야 하나요?”

Databricks 환경이라면 Vector Search + Lakebase 조합을 권장 합니다.
  • Vector Search: 자연어 기반 의미 검색. “지난번 환불 관련 대화” 같은 퍼지 검색에 적합. Unity Catalog 통합으로 권한 관리 자동.
  • Lakebase (PostgreSQL): 구조화된 데이터 저장. 사용자 프로필, 설정값 등 정확한 조회에 적합. 서버리스로 관리 부담 최소.
  • 두 가지를 결합 하면 “이름이 뭐였지?” (구조화 조회)와 “비슷한 문제를 겪은 적 있나?” (의미 검색)를 모두 처리할 수 있습니다.

”메모리 데이터는 어떻게 보호하나요?”

세 가지 계층으로 보호합니다:
  1. 접근 제어: Unity Catalog ACL을 통해 메모리 테이블/인덱스에 대한 읽기/쓰기 권한을 세밀하게 관리합니다. Agent별, 팀별로 접근 가능한 메모리 범위를 제한할 수 있습니다.
  2. PII 마스킹: 메모리 저장 전에 개인정보(이름, 전화번호, 주민번호 등)를 자동 탐지하여 마스킹합니다. Databricks의 AI Functions(ai_mask())를 활용하면 편리합니다.
  3. TTL 기반 삭제: 보존 기한이 지난 메모리는 자동 삭제하여 불필요한 데이터 보유를 방지합니다. GDPR/PIPA 등 개인정보 보호법 준수에 필수적입니다.

”메모리가 많아지면 성능이 느려지지 않나요?”

적절히 설계하면 문제가 되지 않습니다. 핵심 전략은 다음과 같습니다:
  • TTL + Consolidation: 오래된 세부 기억은 요약하고, 만료된 기억은 삭제
  • 관련도 임계값: Vector Search에서 유사도가 낮은 결과는 필터링
  • 인덱싱 최적화: Lakebase에 적절한 인덱스 설정, Vector Search에 메타데이터 필터 활용
  • 비동기 저장: 메모리 저장은 응답 반환 후 비동기로 처리하여 사용자 체감 지연 최소화

다음: Multi-Agent 패턴 →