본문 바로가기
AI2024년 7월 25일6분 읽기

LangChain 메모리 시스템 — 대화 맥락 유지 전략

YS
김영삼
조회 462

LLM 대화에서 메모리가 필요한 이유

LLM은 기본적으로 무상태(stateless)입니다. 매 API 호출마다 이전 대화를 기억하지 못하므로, 개발자가 직접 대화 이력을 관리하고 프롬프트에 포함해야 합니다.

메모리 유형 비교

메모리 타입방식토큰 사용적합한 경우
ConversationBufferMemory전체 대화 저장많음짧은 대화
ConversationBufferWindowMemory최근 K턴만중간일반 챗봇
ConversationSummaryMemory대화 요약적음긴 대화
ConversationSummaryBufferMemory요약 + 최근중간균형잡힌 선택
ConversationTokenBufferMemory토큰 수 기준제어 가능비용 최적화

ConversationBufferWindowMemory

from langchain.memory import ConversationBufferWindowMemory
from langchain.chains import ConversationChain
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4", temperature=0.7)

memory = ConversationBufferWindowMemory(
    k=10, return_messages=True, memory_key="history"
)

chain = ConversationChain(llm=llm, memory=memory, verbose=True)

response1 = chain.predict(input="안녕하세요, 저는 김영수입니다.")
response2 = chain.predict(input="제가 방금 이름을 알려드렸는데, 기억하시나요?")

ConversationSummaryBufferMemory

from langchain.memory import ConversationSummaryBufferMemory

memory = ConversationSummaryBufferMemory(
    llm=llm, max_token_limit=1000, return_messages=True, memory_key="history"
)

memory.save_context(
    {"input": "Python으로 웹 크롤러를 만들고 싶어요"},
    {"output": "BeautifulSoup이나 Scrapy를 추천드립니다..."}
)

print(memory.load_memory_variables({}))

Redis 기반 영속 메모리

from langchain_community.chat_message_histories import RedisChatMessageHistory
from langchain.memory import ConversationSummaryBufferMemory

def get_memory(session_id: str):
    message_history = RedisChatMessageHistory(
        session_id=session_id,
        url="redis://localhost:6379/0",
        ttl=86400
    )
    memory = ConversationSummaryBufferMemory(
        llm=ChatOpenAI(model="gpt-3.5-turbo"),
        max_token_limit=1000,
        chat_memory=message_history,
        return_messages=True,
        memory_key="history"
    )
    return memory

memory = get_memory("user-42-session-abc")
chain = ConversationChain(llm=llm, memory=memory)

LCEL 방식의 메모리 관리

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory

prompt = ChatPromptTemplate.from_messages([
    ("system", "당신은 도움이 되는 AI 어시스턴트입니다."),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{input}")
])

chain = prompt | llm

chain_with_history = RunnableWithMessageHistory(
    chain,
    get_session_history=lambda sid: RedisChatMessageHistory(
        session_id=sid, url="redis://localhost:6379/0"
    ),
    input_messages_key="input",
    history_messages_key="history"
)

response = chain_with_history.invoke(
    {"input": "안녕하세요!"},
    config={"configurable": {"session_id": "user-42"}}
)

토큰 최적화 전략

  • 대화 요약에는 gpt-3.5-turbo를, 실제 응답에는 gpt-4를 사용하면 비용을 줄일 수 있습니다.
  • max_token_limit은 전체 컨텍스트 윈도우의 30-40% 이하로 설정하세요.
  • 사용자별 세션에 TTL을 설정하여 오래된 대화를 자동으로 정리하세요.
  • Entity Memory를 결합하면, 사용자 이름/선호 등 핵심 정보를 별도로 추적할 수 있습니다.
  • 프로덕션에서는 ConversationSummaryBufferMemory가 가장 균형 잡힌 선택입니다.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록