실무 Multi-Agent 오케스트레이션 17장 · 장기 기억 관리 3 / 7 ← 이전목차다음 → TechLead Cro

17장. 장기 기억 관리

기억의 세 층과 고객 프로필 — 대화가 끝나도 남는 것

한 줄 요약

우리 상담원의 기억은 세 층입니다. 최근 대화의 원문(단기), 같은 대화 안의 요약(중기), 그리고 대화가 끝난 뒤에도 파일로 남는 고객 프로필(장기)입니다. 층마다 저장하는 방식이 다릅니다.


1. 세 층

층 우리 코드에서 담긴 것 수명 사람으로 치면
단기 recent (16장의 history) 대화 원문 그대로 대화 안 방금 나눈 말
중기 summary 오래된 턴의 요약 대화 안 아까 한 이야기의 줄거리
장기 customer_profiles.json 대화에서 뽑은 사실 대화가 끝난 뒤에도 그 사람에 대해 아는 것

2. 층마다 모양이 다른 이유

단기는 원문이어야 합니다. 바로 앞의 말에 나온 "그거"를 해석하려면 세부가 필요합니다.

중기는 요약이면 됩니다. 열 턴 전의 대화에서 필요한 것은 문장 하나하나가 아니라 줄거리입니다.

장기는 정해진 틀에 담긴 사실이어야 합니다. 다음 방문에서 쓰려면 "선호: 이메일 연락"처럼 항목이 나뉘어 있어야 합니다. 대화 원문 뭉치는 다음 주에 꺼내 쓰기 어렵습니다.

그래서 프로필은 세 칸짜리 JSON으로 정했습니다.

{"선호": [], "진행중_이슈": [], "메모": []}
칸 담는 것 예
선호 이 고객이 바라는 응대 방식 문자보다 이메일 연락 선호
진행중_이슈 아직 끝나지 않은 일 운동화 260 사이즈 교환 진행 중
메모 그 밖에 알아 두면 좋은 것 오늘 교환 신청 예정

이 세 칸은 개발자가 정한 틀입니다. 칸에 무엇을 채울지는 모델이 대화를 읽고 고릅니다.


3. 저장 — 대화가 끝날 때 사실을 뽑는다

save_profile은 대화 전체(요약 + 최근 원문)를 모델에게 주고 프로필을 뽑게 합니다.

r = client.models.generate_content(
    model=MODEL,
    contents="다음 상담에서, 이 고객을 다시 응대할 때 유용한 사실만 JSON 으로 추출하라.\n"
             '형식: {"선호": [], "진행중_이슈": [], "메모": []}\n'
             "카드번호·계좌번호·비밀번호 등 민감정보는 절대 포함하지 마라.\n\n"
             + transcript,
    config=types.GenerateContentConfig(
        temperature=1.0, response_mime_type="application/json"),
)

response_mime_type="application/json"은 4장에서 쓴 JSON 응답 모드입니다. 프로필은 코드가 읽고 쓰는 데이터이므로 자유로운 문장이 아니라 JSON이어야 합니다.

뽑은 프로필은 고객 ID를 열쇠로 삼아 파일에 넣습니다.

profiles = {}
if PROFILE_PATH.exists():
    profiles = json.loads(PROFILE_PATH.read_text(encoding="utf-8"))
profiles[customer_id] = json.loads(r.text)
PROFILE_PATH.parent.mkdir(exist_ok=True)
PROFILE_PATH.write_text(json.dumps(profiles, ensure_ascii=False, indent=2),
                        encoding="utf-8")
줄 하는 일
PROFILE_PATH haru-market/memory_store/customer_profiles.json. 고객 여러 명의 프로필이 이 파일 하나에 들어갑니다
profiles[customer_id] = ... 이 고객의 프로필을 통째로 새것으로 바꿉니다. 다른 고객의 프로필은 그대로 둡니다
mkdir(exist_ok=True) memory_store 폴더가 없으면 만듭니다

두 번째 줄을 기억해 두세요. 같은 고객의 프로필을 다시 저장하면 앞의 내용에 보태는 것이 아니라 덮어씁니다. 「따라하기」에서 다시 실행할 때 이 동작을 확인합니다.


4. 복원 — 다음 방문 때 시스템 프롬프트에 넣는다

재방문한 고객의 프로필을 읽어 시스템 프롬프트 끝에 붙입니다.

profile = load_profile(cid)
profile_txt = json.dumps(profile, ensure_ascii=False)
system2 = (SYSTEM_BASE
           + "\n\n[이 고객에 대한 기억] 지난 상담에서 적어 둔 기록입니다. "
             "현재 처리 상태는 아니므로, 지난 상담 내용으로만 말하고 "
             "현재 상태는 확인 후 안내드린다고 답합니다.\n"
           + profile_txt)

모델에게 따로 "기억" 기능이 생긴 것이 아닙니다. 3장에서 배운 대로 글을 넣어 준 것입니다. 역할과 규칙 뒤에 "이 고객에 대해 알고 있는 것"이 한 덩어리 더 붙었을 뿐입니다.

프로필 앞에 붙인 한 문장을 봅니다. "지난 상담에서 적어 둔 기록입니다. 현재 처리 상태는 아니므로 …" 프로필은 적어 둔 날의 사실입니다. 일주일 뒤의 상태가 아닙니다. 그 성격을 함께 적어 주면 상담원은 지난 일은 지난 일로 말하고, 지금의 상태는 확인 후 안내하겠다고 답합니다.

일 누가
프로필의 틀(세 칸)을 정한다 개발자
대화에서 사실을 골라 칸에 채운다 모델
파일에 쓰고, 다음에 읽어 온다 우리 코드
읽어 온 프로필을 프롬프트의 어디에 넣을지 정한다 개발자
프로필을 읽고 응대에 반영한다 모델

핵심 정리

  • 기억은 단기(원문), 중기(요약), 장기(프로필) 세 층입니다.
  • 층마다 모양이 다릅니다. 가까운 것은 자세하게, 먼 것은 줄여서, 오래 둘 것은 틀에 맞춰 담습니다.
  • 프로필은 대화가 끝날 때 JSON 모드로 뽑아 고객 ID별로 파일에 저장합니다.
  • 같은 고객을 다시 저장하면 덮어씁니다.
  • 재방문 때는 프로필을 시스템 프롬프트에 붙여 넣습니다. 기억도 결국 프롬프트입니다.
← 이전 절요약 메모리 — 버리지 말고 줄여서 남긴다다음 절 →기억하면 안 되는 것과 기억의 근거
오명운 · macro@prag-ai.com