k
korAI
고급 전체
🔥 고급2026-07-236~8분

LLM 장기 메모리 설계: 벡터·요약·구조화 스토어의 조합 전략

단일 메모리 백엔드로는 정확도와 비용을 동시에 잡을 수 없다. 세 가지 메모리 레이어를 역할별로 분리하고 Claude API와 통합하는 운영 검증 설계를 공유한다.

memoryragproduction

왜 단일 메모리 백엔드는 실패하는가

벡터 DB 하나에 모든 대화를 때려 넣는 구조는 세 가지 실패 모드를 낳는다. 검색 오염: 오래된 사용자 선호가 최신 컨텍스트를 희석한다. 토큰 낭비: 유사도 상위 20개를 프롬프트에 붙이면 평균 1,800토큰이 추가되고 캐시 무효화가 빈번해진다. 업데이트 불가: 벡터 임베딩은 덮어쓰기가 사실상 불가능해 '사용자가 채식주의자로 바뀐' 사실을 반영하지 못한다.

3-레이어 메모리 아키텍처

L1 — 구조화 프로파일 (PostgreSQL/JSON): 사용자 선호, 인구통계, 명시적 사실. 쓰기 빈도 낮고 읽기 빈도 높음. 매 턴 시스템 프롬프트 앞단에 500토큰 이내로 삽입. prompt caching 고정 블록으로 활용하면 캐시 히트율 85%+ 유지 가능.

L2 — 요약 메모리 (Claude 요약 → 벡터 DB): 대화 10턴마다 claude-haiku로 핵심 사실 3~5개를 추출·임베딩 저장. 원본 대화 전체를 저장하는 것보다 임베딩 비용 60% 절감. 검색 시 top-k=3으로 제한해 프롬프트 오염 최소화.

L3 — 에피소드 로그 (Cold Storage): 원본 대화를 S3·GCS에 보관. 감사·파인튜닝 데이터 확보 목적. 실시간 경로에서 제외.

import anthropic
import json

client = anthropic.Anthropic()

def build_system_prompt(user_profile: dict, retrieved_summaries: list[str]) -> str:
    profile_block = json.dumps(user_profile, ensure_ascii=False)
    memory_block = "\n".join(f"- {s}" for s in retrieved_summaries)
    # L1은 앞에 고정 → prompt cache 최대 활용
    return (
        f"<user_profile>\n{profile_block}\n</user_profile>\n"
        f"<recent_memory>\n{memory_block}\n</recent_memory>\n"
        "You are a helpful assistant. Use the profile and memory above."
    )

def chat_with_memory(
    user_message: str,
    user_profile: dict,
    retrieved_summaries: list[str],
    history: list[dict],
) -> str:
    system = build_system_prompt(user_profile, retrieved_summaries)
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        system=system,
        messages=history + [{"role": "user", "content": user_message}],
    )
    return response.content[0].text

# 요약 생성 (10턴마다 비동기 호출)
def summarize_turns(turns: list[dict]) -> str:
    text = "\n".join(f"{t['role']}: {t['content']}" for t in turns)
    resp = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=256,
        messages=[{
            "role": "user",
            "content": f"다음 대화에서 사용자에 관한 핵심 사실 3~5개를 bullet으로 추출하라:\n{text}"
        }]
    )
    return resp.content[0].text

트레이드오프와 운영 체크리스트

트레이드오프: L2 요약 주기를 5턴으로 줄이면 정밀도는 올라가지만 haiku 호출 비용이 2배 증가한다. 10~15턴이 대부분 워크로드에서 최적점.

실패 모드: 요약 단계에서 hallucination이 발생하면 L1 프로파일과 충돌하는 '기억 모순'이 생긴다. 요약 결과를 사람이 검토 가능한 형태로 DB에 저장하고, 사용자 명시적 수정 API를 반드시 노출할 것.

운영 체크리스트

  • [ ] L1 프로파일 토큰 수 모니터링 (목표: 500토큰 이하)
  • [ ] L2 요약 주기 A/B 테스트 (5 / 10 / 15턴)
  • [ ] 벡터 검색 top-k 3~5로 고정, 임계 유사도 0.75 미만 결과 드롭
  • [ ] 요약 hallucination 감지: 원본 대화 대비 사실 일치율 주간 샘플링
  • [ ] Cold Storage 보관 주기 정책 수립 (GDPR 삭제 요청 대응)