k
korAI
고급 전체
🔥 고급2026-09-197~9분

에이전트 장기 메모리 설계: 벡터 DB + 요약 압축으로 컨텍스트 폭발 막기

대화가 수십 턴을 넘을 때 발생하는 컨텍스트 길이 폭발 문제를 계층형 메모리(작업 메모리·에피소드 메모리·의미 메모리)로 해결하고, 각 계층의 트레이드오프와 운영 함정을 구체적으로 설명한다.

long-term-memoryRAGagent-design

문제: 긴 대화는 비용과 품질을 동시에 망친다

200K 컨텍스트 윈도우가 있어도 무작정 쌓으면 안 된다. 100턴 대화(평균 500토큰/턴)는 50,000 토큰 = claude-opus-4-5 기준 약 $0.75/대화. 하루 1만 사용자라면 월 $225,000이 대화 기록에만 소진된다. 또한 컨텍스트가 길수록 모델이 중간 정보를 '잊는' Lost-in-the-Middle 현상이 심화된다.

계층형 메모리 아키텍처

계층 1 — 작업 메모리 (Working Memory) 최근 10~15턴만 원문 유지. 토큰 예산: 8,000~12,000. 이 범위를 넘으면 자동으로 계층 2로 압축 트리거.

계층 2 — 에피소드 메모리 (Episode Memory) 완료된 대화 블록을 LLM으로 요약 압축. 원문 500토큰 → 요약 80토큰 (압축률 약 84%). 요약 품질 검증: ROUGE-L ≥ 0.45를 자동 체크해 미달 시 재요약.

계층 3 — 의미 메모리 (Semantic Memory) 사용자 프로필, 선호, 도메인 사실을 벡터 DB(pgvector / Pinecone)에 임베딩 저장. 쿼리 시 코사인 유사도 상위 5개 청크만 컨텍스트에 주입. 청크 크기: 256토큰, 오버랩: 32토큰.

import anthropic
from typing import List

client = anthropic.Anthropic()

def compress_episode(turns: List[dict]) -> str:
    """10턴 대화를 ~80토큰 요약으로 압축"""
    conversation_text = "\n".join(
        f"{t['role'].upper()}: {t['content']}" for t in turns
    )
    response = client.messages.create(
        model="claude-haiku-4-5",  # 압축엔 저렴한 모델 사용
        max_tokens=120,
        messages=[{
            "role": "user",
            "content": (
                "다음 대화를 3문장 이내로 압축하라. "
                "사용자의 목표, 결정사항, 미해결 항목만 포함.\n\n"
                + conversation_text
            )
        }]
    )
    return response.content[0].text

def build_context(working_memory: List[dict],
                 episode_summaries: List[str],
                 semantic_chunks: List[str]) -> List[dict]:
    """3계층을 system + messages로 조립"""
    system = "[장기 기억]\n" + "\n".join(episode_summaries)
    if semantic_chunks:
        system += "\n\n[관련 지식]\n" + "\n".join(semantic_chunks)

    return {
        "system": system,          # 요약·사실 주입
        "messages": working_memory  # 최근 원문만
    }

# 사용 예
episode = compress_episode(old_turns)          # haiku로 저렴하게
ctx = build_context(
    working_memory=recent_turns[-12:],
    episode_summaries=[episode],
    semantic_chunks=vector_db.query(user_query, top_k=5)
)
resp = client.messages.create(
    model="claude-opus-4-5",
    max_tokens=1024,
    system=ctx["system"],
    messages=ctx["messages"]
)

실패 모드 & 운영 체크리스트

주요 실패 모드

  • 요약 시 중요 수치(날짜, 금액)가 탈락 → 요약 프롬프트에 "숫자·고유명사는 반드시 보존" 명시
  • 벡터 검색 청크가 컨텍스트와 중복 → 작업 메모리 내용과 중복 필터링 (MMR 알고리즘 사용)
  • 에피소드 경계를 고정 턴 수로만 나누면 문장 중간 절단 → 주제 전환 감지 후 압축

체크리스트

  • [ ] 압축 전후 토큰 수를 로그로 기록해 압축률 모니터링 (목표: 75% 이상)
  • [ ] 요약 모델은 haiku급 사용 — 압축 비용이 전체의 5% 미만 유지
  • [ ] 벡터 DB 청크 임베딩 버전 관리 (모델 업그레이드 시 재임베딩 필요)
  • [ ] 사용자별 메모리 격리 — tenant_id 필터 필수
  • [ ] 메모리 만료 정책 설정 (90일 미접근 에피소드 아카이브)