메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

Spring AI로 LLM에 대화 기억 기능 추가하기

 

챗봇을 만들어 본 분들이라면 이런 경험이 있으실 겁니다. 사용자가 한참 대화를 이어가다가 다시 질문을 던졌을 때, 챗봇이 앞선 맥락을 전혀 이해하지 못하고 전혀 다른 답을 내놓는 경우 말이죠. 

 

대규모 언어 모델LLM은 기본적으로 상태를 저장하지 않기 때문에, 이전 대화 내용을 기억하거나 그에 기반한 응답을 생성할 수 없습니다. 이러한 한계를 보완하기 위해 Spring AI는 대화 기억Chat Memory 기능을 제공합니다. 이 기능을 통해 LLM과의 여러 차례 대화에서 주고받은 내용을 저장하고, 이후 대화에서 이를 조회해 문맥을 유지할 수 있습니다.

 

 

그렇다면 대화 기억과 대화 기록에 대한 차이는 무엇일까요?

 

 

 

 

 

✅ 대화 기억과 대화 기록의 차이

 

• 대화 기억(Chat Memory)

현재 세션에서 LLM과 대화할 때 맥락context 유지하기 위해 사용하는 메시지들(UserMessage + AssistantMessage)입니다. 세션이 종료되면 없어지거나, 영구 저장할 수도 있습니다.

 

• 대화 기록(Chat History)

현재 세션뿐만 아니라, 과거 세션에서 주고받은 모든 메시지들(UserMessage + Assistant Message )을 말합니다. 과거의 대화 기억들이 꾸준히 저장된 것을 대화 기록입니다.

 

 

Spring AI가 제공하는 대화 기억Chat Memory은 현재 대화를 이어가기 위한 문맥을 관리하도록 설계 되었기 때문에 현재 대화와 관련된 메시지만을 목적으로 합니다. 따라서 전체 대화 기록을 관리하는 최적의 솔루션이 아닙니다. 전체 대화 기록을 유지해야 한다면, Spring Data 모듈JPA, JDBC을 이용 하는 방식을 고려해야 합니다.

 

Spring Ai는 대화 기억을 위해 기억 유형과 기억 저장소로 기능을 분리합니다. 기억 유형은 몇 개의 메시지를 저장할지, 어떤 기간 동안 저장할지, 전체 메시지 양을 얼마로 할지를 결정하고, 기억 저장소는 단지 메시지를 저장하고 조회하는 일만 하게 됩니다.

 

Spring AI는 ChatMemory 인터페이스를 통해 다양한 기억 유형을 구현할 수 있도록 지원합니다. 어떤 정보를 기억할지, 그리고 언제 기억을 삭제할지는 ChatMemory 인터페이스를 구현한 클래스 에 따라 달라집니다.

 

ChatMemory 인터페이스는 대화 기억을 관리하기 위해 기본 메소드들을 정의하고 있습니다. 대화 기억 추가add, 검색get, 삭제clear할 수 있는 다음 메소드들을 가지고 있습니다.

 

public interface ChatMemory {
    void add(String conversationId, List<Message> messages); 
    List<Message> get(String conversationId);
    void clear(String conversationId);
}

 

  • conversationId는 사용자 ID입니다. 로그인한 사용자 아이디를 사용해도 좋고, 웹 환경이라면 서버에서 생성 되는 세션 ID를 사용해도 좋습니다.
  • add ( ) 메소드는 사용자 ID와 함께 대화 기억을 저장합니다.
  • get()메소드는사용자ID로저장된대화기억을검색해서가져옵니다.
  • clear()는사용자ID로저장된대화기억을삭제합니다.

 

 

ChatMemory의 기본 구현체는 MessageWindowChatMemory입니다. 이 클래스는 지정된 메시지 최대 개수(메시지 윈도우)까지 메시지를 유지합니다. 메시지 수가 메시지 윈도우를 초과하면 오래된 메시지부터 제거합니다. 기본 메시지 윈도우 크기는 20개입니다.

 

메시지 윈도우를 변경하고 싶다면 다음과 같이 MessageWindowChatMemory를 명시적으로 빌드할 때, maxMessages ( )를 통해 설정하면 됩니다.

 

ChatMemory memory = MessageWindowChatMemory.builder() 
    .maxMessages(10)
    .build();

 

Spring AI는 ChatMemoryRepository 인터페이스를 통해 다양한 저장소에 대화 기억을 저장할 수 있습니다. 다음은 ChatMemoryRepository를 구현한 클래스들입니다.

 

  • InMemoryChatMemoryRepository: 컴퓨터 하드웨어 메모리에 저장합니다.
  • JdbcChatMemoryRepository: 관계형 데이터베이스를 저장합니다.
  • CassandraChatMemoryRepository: ApacheCassandra를 이용해서 시계열로 저장합니다.

 

 

Spring AI는 다른 저장소를 위한 구성이 없으면, 기본적으로 MessageWindowChatMemory를 이용해서 ChatMemory 빈을 자동 생성합니다. 그리고 대화 기억 저장소는 InMemoryChat MemoryRepository를 사용합니다. 자동 구성된 ChatMemory 빈은 사용자 ID별로 최대 20개의 메시지를 컴퓨터 메모리에 저장합니다. 이렇게 자동 구성된 ChatMemory 빈은 다음과 같이 필드로 주입하거나, 생성자 주입할 수 있습니다.

 

@Autowired
ChatMemory chatMemory;
또는
ClassName(ChatMemory chatMemory) {
}

 

 

 

 

 

✅ 대화 기억을 위한 Advisor

 

ChatMemory가 대화 기억을 제공하더라도, 이를 실제 프롬프트에 포함시키는 작업이 필요합니다. 이 역할을 담당자가 바로 Advisor입니다. Advisor는 LLM에게 프롬프트를 전송하기 전에 전처리 작업으로 ChatMemory로부터 받은 대화 기억을 시스템 텍스트 또는 메시지 묶음으로 프롬프트에 추가합니다.

 

그리고 LLM으로부터 응답이 오면, 후처리 작업으로 사용자의 질문UserMessage과 LLM의 응답AssistantMessage 을 ChatMemory를 이용해서 대화 기억 저장소에 저장합니다.

 

 

• MessageChatMemoryAdvisor

MessageChatMemoryAdvisor는 ChatMemory에서 받은 대화 기억을 사용자 메시지User Message 와 AI 메시지AssistantMessage들로 생성합니다. 그리고 이 메시지들을 프롬프트에 추가합니다.

 

다음은 MessageChatMemoryAdvisor를 빌드할 때 ChatMemory를 제공하는 코드입니다.

 

MessageChatMemoryAdvisor advisor = MessageChatMemoryAdvisor.builder(chatMemory).
build();

 

 

 

다음은 MessageChatMemoryAdvisor를 ChatClient의 기본 Advisor로 추가하는 코드입니다.

 

ChatClient chatClient = chatClientBuilder .defaultAdvisors(
    MessageChatMemoryAdvisor.builder(chatMemory).build() 
    )
.build();

 

 

 

• PromptChatMemoryAdvisor

PromptChatMemoryAdvisor는 ChatMemory로부터 받은 대화 기억을 텍스트 형태로 시스템 메시지에 포함시킵니다. 다음은 PromptChatMemoryAdvisor를 빌드할 때 ChatMemory를 제공하는 코드입니다.

 

PromptChatMemoryAdvisor advisor = PromptChatMemoryAdvisor.builder(chatMemory).build();

 

 

 

다음은 PromptChatMemoryAdvisor를 ChatClient의 기본 Advisor로 추가하는 코드입니다.

 

ChatClient chatClient = chatClientBuilder 
    .defaultAdvisors(
        PromptChatMemoryAdvisor.builder(chatMemory).build() 
    )
    .build();

 

 

이렇게 Spring AI의 ChatMemory와 Advisor를 활용하면 기본적으로 이전 대화를 기억하지 못하는 LLM에서도 자연스러운 대화 흐름을 구현할 수 있습니다.

 

 

 


 

위 콘텐츠는 『이것이 Spring AI다』의 내용을 재구성하여 작성되었습니다.

댓글

댓글 입력