LangChain 챗봇4장 · 대화형 챗봇과 메모리 전략11 / 22← 이전목차다음 →MetaContents

4장. 대화형 챗봇과 메모리 전략

앞부분을 요약하는 Summary 메모리

상담 기록철이 열 장이 넘으면, 꼼꼼한 상담원은 앞의 여덟 장을 읽고 "제주도, 2박 3일, 어른 둘 아이 둘, 오전 출발 원함" 같은 요약 메모 한 장을 써서 철 맨 앞에 붙입니다. 다음 상담원은 요약 메모와 최근 두 장만 읽어도 손님 사정을 압니다. Summary 메모리가 이 방법입니다. 오래된 기록은 요약 체인으로 짧게 줄이고, 요약과 최근 기록을 함께 보냅니다.

앞부분 떼어 내기, 요약 체인으로 줄이기, 요약을 시스템 메시지로 붙이기, 최근 기록과 함께 보내기의 네 걸음을 이은 흐름도

네 상자 가운데 둘째 상자에서 모델을 한 번 더 부른다는 점이 Window 메모리와 다릅니다. 요약하는 모델이 따로 한 번 일하고, 그 요약을 "앞의 대화 요약: …" 이라는 시스템 메시지로 만들어 최근 기록 앞에 붙입니다. 여기서 요약 메모가 요약 체인의 결과, 철 맨 앞에 붙이는 일이 시스템 메시지로 넣는 일입니다. 비유와 다른 점은, 요약도 모델이 쓰는 글이라 중요한 숫자를 빠뜨리거나 바꿔 쓸 수 있다는 것입니다. 그래서 요약 프롬프트에 "숫자와 인원은 빠뜨리지 말라"고 적습니다.

요약에 꼭 남길 것

남길 것예빠지면 생기는 일
숫자2박 3일, 예산 150만 원일정이나 예산이 틀린 답
사람어른 둘, 아이 둘아이에게 맞지 않는 일정 추천
정한 것오전 출발, 동쪽 해안 숙소이미 정한 것을 다시 묻는다
바뀐 것둘째 날은 비 → 실내 일정옛 계획대로 안내한다

짧은 예시

요약하는 모델 자리에 가짜 모델을 두고, 요약 + 최근 2개 + 새 질문으로 보낼 메시지를 꾸며 봅니다.

Python
from langchain_core.language_models.fake_chat_models import FakeListChatModel
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate

old = [HumanMessage("제주도 가요."), AIMessage("며칠인가요?"), HumanMessage("2박 3일, 아이 둘이요."), AIMessage("동쪽 해안을 추천합니다.")]
recent = [HumanMessage("렌터카는 언제 빌려요?"), AIMessage("공항에서 바로 빌리세요.")]

# 요약 체인: 앞부분 대화를 받아 짧은 요약 글을 쓴다. 숫자와 인원을 지키라고 적는다
summary_prompt = ChatPromptTemplate.from_messages([
    ("system", "다음 대화를 두 문장 이내로 요약하라. 날짜, 박수, 인원 같은 숫자는 빠뜨리지 않는다."),
    ("human", "{dialog}"),
])
summarizer = FakeListChatModel(responses=["손님은 제주도 2박 3일, 아이 둘과 함께 간다. 동쪽 해안 일정을 추천받았다."])
summary_chain = summary_prompt | summarizer | StrOutputParser()

dialog = "\n".join(f"{m.type}: {m.content}" for m in old)   # 메시지를 "역할: 내용" 줄글로 바꾼다
summary = summary_chain.invoke({"dialog": dialog})

# 보낼 메시지: 시스템 지시 + 요약 + 최근 기록 + 새 질문
to_send = [SystemMessage("너는 여행 비서다."), SystemMessage("앞의 대화 요약: " + summary)] + recent + [HumanMessage("일정 정리해 주세요.")]
for m in to_send:
    print(m.type, "|", m.content)
출력
system | 너는 여행 비서다.
system | 앞의 대화 요약: 손님은 제주도 2박 3일, 아이 둘과 함께 간다. 동쪽 해안 일정을 추천받았다.
human | 렌터카는 언제 빌려요?
ai | 공항에서 바로 빌리세요.
human | 일정 정리해 주세요.

앞의 메시지 4개가 요약 한 줄로 바뀌었고, 그 요약이 둘째 시스템 메시지로 들어갔습니다. 최근 2개와 새 질문은 그대로입니다. 요약 안에 "2박 3일"과 "아이 둘"이 남아 있으므로 모델은 일정 정리 질문에 이 둘을 쓸 수 있습니다. 진짜 요약 모델로는 실습 6에서 해 봅니다.

코드가 의미하는 것

이 코드는 앞의 장들을 요약 메모 한 장으로 줄여 철 맨 앞에 붙이는 일을 흉내 냅니다. 요약을 쓰는 상담원 자리에는 가짜 모델을 앉혔습니다.

코드하는 일챗봇에서 뜻하는 것
summary_prompt | summarizer | StrOutputParser()요약 체인을 만든다3장의 체인 모양 그대로, 요약만 하는 상담원을 하나 더 둡니다. 진짜 모델이면 이 호출에도 토큰이 듭니다
요약 프롬프트의 "숫자는 빠뜨리지 않는다"요약이 지킬 것을 적는다요약에서 박수와 인원이 빠지면 뒤의 답도 빠뜨리므로 미리 못 박는 줄입니다
"\n".join(f"{m.type}: {m.content}" for m in old)메시지를 "역할: 내용" 줄글로 바꾼다요약 체인에는 앞부분 대화를 글 하나로 건넵니다
SystemMessage("앞의 대화 요약: " + summary)요약을 시스템 메시지로 만든다손님의 말이나 비서의 답이 아니라 참고 메모로 넣는다는 뜻입니다
[…] + recent + [HumanMessage(…)]시스템, 요약, 최근 기록, 새 질문을 잇는다모델이 받을 목록입니다. 앞의 대화는 원문 대신 요약으로만 갑니다

결과에서 읽을 것은 두 가지입니다.

  • 메시지 4개가 한 줄이 됐다. 둘째 줄 system | 앞의 대화 요약: … 하나가 앞의 메시지 네 개를 대신합니다.
  • 요약 안에 조건이 남았다. "2박 3일"과 "아이 둘"이 요약에 있어 일정 정리에 쓸 수 있습니다. 이 요약은 가짜 모델에 적어 둔 글이므로, 진짜 모델의 요약이 이 둘을 지키는지는 실습 6에서 봅니다.

주의할 점

  • 요약할 때마다 모델을 한 번 더 부르므로 요약 호출의 토큰과 시간도 듭니다. 대화가 짧을 때는 요약하지 않고, 기록이 상한을 넘을 때만 요약합니다.
  • 요약을 매번 처음부터 새로 쓰지 않고 "지난 요약 + 새로 밀려난 메시지"로 고쳐 쓰면 요약 호출의 입력이 짧아집니다. 프로젝트에서 이 방식을 씁니다.
← 이전 절4장 · 최근 대화만 남기는 Window 메모리다음 절 →4장 · 메모리 전략 고르기