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

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

최근 대화만 남기는 Window 메모리

상담 기록철이 두꺼워지면 상담원은 앞에서부터 다 읽지 않고 맨 뒤의 몇 장만 펼쳐 봅니다. 책상이 좁아서 펼칠 수 있는 장 수도 정해져 있습니다. Window 메모리가 이 방법입니다. 기록을 뒤에서부터 세어 정한 양(토큰 상한)만큼만 남기고 앞쪽은 보내지 않습니다. LangChain 에서는 trim_messages 함수가 이 일을 합니다.

대화 기록 모으기, 뒤에서부터 토큰 세기, 상한을 넘는 앞쪽 잘라 내기의 세 걸음을 이은 흐름도

세 상자는 trim_messages 가 하는 차례입니다. 기록 전체를 받아 맨 뒤 메시지부터 토큰을 더해 가다가, 합이 상한을 넘기 직전에 멈추고 그 앞쪽을 잘라 냅니다. 시스템 메시지는 따로 챙겨 늘 맨 앞에 남깁니다. 여기서 책상의 크기가 토큰 상한(max_tokens), 맨 뒤의 몇 장이 남는 메시지입니다. 비유와 다른 점은, 상담원은 앞쪽에 중요한 장이 있으면 찾아 펴 보지만 trim_messages 는 중요한지와 상관없이 오래된 것부터 자른다는 것입니다.

trim_messages 의 인자

인자뜻이 장의 값
max_tokens남길 토큰의 상한60 ~ 300
token_counter메시지 목록을 받아 토큰 수를 돌려주는 함수. len 을 주면 메시지 개수를 센다tiktoken 으로 센 함수
strategy"last" 는 뒤에서부터 남기고, "first" 는 앞에서부터 남긴다. strategy 는 "전략"이라는 뜻"last"
include_system맨 앞의 시스템 메시지를 늘 남길지True
start_on남긴 기록이 이 역할의 메시지로 시작하게 한다"human"

start_on="human" 은 남긴 기록이 답(ai)으로 시작하지 않게 합니다. 질문 없이 답부터 보이면 모델이 무엇에 대한 답인지 헷갈리기 때문입니다.

짧은 예시

token_counter=len 으로 주면 "토큰" 대신 "메시지 개수"를 셉니다. 메시지 7개의 기록을 상한 4개로 줄여 봅니다.

Python
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, trim_messages

history = [
    SystemMessage("너는 여행 비서다."),
    HumanMessage("제주도 가요."), AIMessage("며칠인가요?"),
    HumanMessage("2박 3일이요."), AIMessage("좋습니다."),
    HumanMessage("숙소는 바닷가로요."), AIMessage("함덕을 추천합니다."),
]

kept = trim_messages(
    history,
    max_tokens=4,            # 상한: 여기서는 메시지 4개
    token_counter=len,       # len: 메시지 개수를 센다
    strategy="last",         # 뒤에서부터 남긴다
    include_system=True,     # 시스템 메시지는 늘 남긴다
    start_on="human",        # 남긴 기록이 사람의 질문으로 시작하게 한다
)
for m in kept:
    print(m.type, "|", m.content)
출력
system | 너는 여행 비서다.
human | 숙소는 바닷가로요.
ai | 함덕을 추천합니다.

시스템 메시지를 포함해 상한 4개 안에서 뒤쪽이 남았습니다. 시스템 1개를 빼면 3개가 남는 자리인데, 뒤에서 셋째가 답("좋습니다.")이라 start_on="human" 때문에 그것까지 떼어 냈습니다. "제주도"와 "2박 3일"은 모델에게 가지 않습니다.

코드가 의미하는 것

이 코드는 책상에 펼칠 수 있는 장 수를 정하고 기록철의 뒤쪽부터 펼치는 일을 흉내 냅니다. 토큰 대신 메시지 개수로 세어 결과를 눈으로 따라가기 쉽게 했습니다.

코드하는 일챗봇에서 뜻하는 것
max_tokens=4남길 양의 상한을 정한다책상의 크기입니다. 실제 챗봇에서는 토큰으로 정합니다
token_counter=len메시지 개수로 센다세는 방법을 바꿔 끼울 수 있다는 뜻입니다. 실습 5에서는 tiktoken 으로 센 함수를 넘깁니다
strategy="last"뒤에서부터 남긴다최근 대화가 지금 질문과 가장 가깝다고 보는 선택입니다
include_system=True시스템 메시지를 늘 남긴다비서의 말투와 규칙은 잘라 내지 않는다는 뜻입니다
start_on="human"남긴 기록이 질문으로 시작하게 한다답만 덩그러니 남아 모델이 헷갈리지 않게 합니다

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

  • 상한이 4 인데 3개만 남았다. 뒤에서 셋째인 "좋습니다."가 답이라 start_on="human" 이 떼어 냈습니다. 상한은 "이만큼까지"이지 "꼭 이만큼"이 아닙니다.
  • 조건이 사라졌다. "제주도"와 "2박 3일"이 든 앞쪽 메시지가 모두 빠졌습니다. 이 기록만 받은 모델은 목적지를 모릅니다.

주의할 점

  • 1장 프로젝트의 "최근 4개만"이 Window 메모리입니다. 그때 열 번의 입력 토큰 합은 모두 보내기 1,786 토큰에서 906 토큰으로 줄었지만, 마지막 정리 질문에서 "2박 3일"과 "아이 둘"을 잃었습니다. 실습 5에서 상한을 바꿔 가며 다시 봅니다.
  • 실제 API 가 세는 토큰은 메시지마다 역할 표시 같은 몇 개가 더 붙습니다. tiktoken 으로 세는 token_counter 는 어림값이므로 상한에 여유를 둡니다.
← 이전 절4장 · 손님마다 기록 상자 나누기다음 절 →4장 · 앞부분을 요약하는 Summary 메모리