챗봇은 왜 방금 한 말을 잊어버릴까?
LLM이 이전 대화를 스스로 기억하지 않는 이유와 Spring AI Chat Memory가 Conversation ID로 과거 메시지를 다시 전달하는 원리·비용·보안 한계를 설명합니다.
Spring AI로 챗봇을 넘어 일하는 AI 만들기 4/9
Java·Spring 개발자가 LLM, RAG, Tool Calling, MCP를 공부하며 이해한 것들
이전 글 — AI는 같은 질문에도 왜 다른 답을 할까?
“내 이름은 민수야”라고 말한 뒤 “내 이름이 뭐였지?”라고 물었는데 챗봇이 모른다고 답합니다. 모델이 갑자기 기억을 잃은 것이 아닙니다. 두 번째 요청에 첫 번째 대화가 포함되지 않았기 때문입니다.
대부분의 LLM 호출은 이전 요청을 자동으로 기억하지 않습니다. 챗봇이 기억하는 것처럼 보이는 이유는 애플리케이션이 과거 Message를 저장했다가 다음 Prompt에 다시 포함하기 때문입니다.
이 글은 Spring AI 학습 흐름에 맞춰 2026년 3월 26일에 배치했습니다. 코드와 API 설명은 2026년 8월 14일의 공식 안정 버전 Spring AI 2.0.0을 기준으로 다시 확인했습니다. 실제 모델이나 데이터베이스를 실행해 성능을 측정한 기록은 아닙니다.
챗봇은 정말 기억력이 나쁜 걸까?
앞선 글에서는 LLM(Large Language Model, 대규모 언어 모델)이 다음 Token을 반복해서 선택해 답을 만든다는 사실을 살펴봤습니다. 이제 질문은 “그 선택에 이전 대화가 어떻게 들어가는가?”입니다.
LLM API는 일반적으로 현재 요청으로 전달된 Prompt(모델에 전달하는 전체 지시와 입력)와 Message(역할과 내용을 가진 대화 단위)를 바탕으로 답합니다. 첫 번째 요청이 끝났다는 이유만으로 그 내용이 두 번째 요청에 자동으로 붙지는 않습니다.
도서관 안내 직원을 떠올려 보겠습니다. 학생이 “제 이름은 민수예요. 자바 책을 찾고 있어요”라고 말하자 직원이 “민수 님, 자바 책은 3층에 있어요”라고 답합니다. 잠시 뒤 학생이 다시 와서 “제 이름이 뭐였죠?”라고 묻습니다.
새 질문만 받은 직원은 이름을 알 수 없습니다. 반대로 “사용자의 이름은 민수, 자바 책은 3층이라고 안내함”이라는 메모지도 함께 받으면 민수라고 답할 수 있습니다. 챗봇의 기억도 이 메모지와 비슷합니다.
안내 직원은 LLM, 현재 질문은 User Message입니다. 메모지는 Chat Memory, 메모지를 넣는 서랍은 ChatMemoryRepository, 알맞은 메모지를 꺼내 질문에 붙이는 직원은 MessageChatMemoryAdvisor에 해당합니다. 메모지 번호는 Conversation ID이고 직원이 한 번에 읽을 수 있는 종이 크기는 Context Window입니다.
이 비유가 실제 구현 전체를 표현하지는 않습니다. 하지만 모델이 대화를 영구 학습하는 것이 아니라 애플리케이션이 필요한 문맥을 다시 건넨다는 경계를 이해하는 데 도움이 됩니다.
HTTP 요청은 매번 새로 시작된다
Stateless(상태 비저장)는 요청 사이의 상태를 서버가 자동으로 이어서 갖지 않는 구조입니다. 사용자가 첫 번째 요청을 보낸 뒤 두 번째 요청을 보내면, 서버와 모델은 두 요청을 각각 독립된 일로 처리할 수 있습니다.
상태 비저장은 모델이 나쁘다는 뜻이 아닙니다. 요청 단위로 처리하기 쉽고, 여러 서버로 확장하기 유리하며, 올바르게 설계하면 사용자별 상태를 분리하기도 좋습니다.
대신 대화 맥락은 애플리케이션이 관리해야 합니다. 과거 메시지를 어디에 저장할지, 누구의 대화인지, 어느 범위까지 다시 전달할지 정해야 합니다.
Conversation Context(대화 문맥)는 현재 답변을 만들기 위해 모델에 실제로 전달되는 대화 정보입니다. 저장소에 대화가 존재해도 현재 Prompt에 들어오지 않았다면 모델은 그 내용을 사용할 수 없습니다.
기억이 없는 요청과 있는 요청
기억이 없으면 흐름은 짧습니다.
현재 질문 → LLM → 답변
Chat Memory(대화 기억)를 사용하면 애플리케이션 단계가 늘어납니다.
현재 질문 → Conversation ID → 과거 메시지 조회
→ 현재 Prompt에 결합 → LLM → 답변 → 새 메시지 저장
챗봇의 기억은 어디에서 생길까?
같은 두 질문을 기억 없이 보낼 때와 애플리케이션이 과거 메시지를 다시 붙여 보낼 때의 차이를 보여줍니다.
사용자 질문
내 이름이 뭐였지?Conversation ID
이전 대화를 불러오지 않음메시지 저장소현재 Prompt
현재 질문만 포함LLM
전달받은 Message만 읽음모델 응답
이름을 알 수 없어요.현재 단계: 첫 번째 요청에서 이름을 말합니다.
두 흐름 모두 모델의 가중치를 바꾸지 않습니다. Chat Memory는 Fine-tuning(미세 조정)도 아니고, 사용자의 말을 모델에 영구 학습시키는 기능도 아닙니다.
Spring AI의 ChatMemory는 무엇을 할까?
Spring AI의 ChatMemory는 어떤 메시지를 현재 기억으로 유지할지 관리하는 추상화입니다. 저장과 조회 자체는 ChatMemoryRepository라는 저장소 추상화가 맡습니다.
MessageChatMemoryAdvisor는 Conversation ID(서로 다른 대화를 구분하는 식별자)에 맞는 과거 메시지를 조회해 현재 Prompt의 Message 목록에 넣습니다. 모델 응답이 끝나면 새 User·Assistant Message도 기억에 반영합니다.
ChatClient는 이 Advisor 체인을 거쳐 모델을 호출합니다. Spring AI가 LLM 안에 새 기억 기관을 만드는 것이 아니라 애플리케이션 쪽의 대화 문맥 관리를 돕는 구조입니다.
Spring AI 2.0 코드로 연결하기
다음은 Spring AI 2.0.0 공식 문서의 현재 API를 따른 최소 예제입니다.
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.maxMessages(10)
.build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build()
)
.build();
String conversationId = "conversation-123";
String response = chatClient.prompt()
.user(userMessage)
.advisors(advisor -> advisor.param(
ChatMemory.CONVERSATION_ID,
conversationId
))
.call()
.content();
MessageWindowChatMemory는 최근 Message를 관리합니다. MessageChatMemoryAdvisor는 저장된 기억을 Prompt에 포함하고, ChatMemory.CONVERSATION_ID는 어떤 대화를 이어갈지 지정합니다.
같은 대화를 이어갈 때는 같은 Conversation ID를 사용하고, 다른 대화에는 다른 ID를 사용해야 합니다. Spring AI 2.0에서 모든 Memory Advisor는 이 값을 요구합니다. 누락하거나 null을 전달하면 실행 중 IllegalArgumentException이 발생하며 기본 Conversation ID는 없습니다.
따라서 1.x 예제에서 볼 수 있는 ChatMemory.DEFAULT_CONVERSATION_ID, Advisor builder의 .conversationId(...), 제거된 PromptChatMemoryAdvisor를 2.0 코드에 섞으면 안 됩니다. 2.0에서는 MessageChatMemoryAdvisor를 사용하고 호출할 때 ID를 전달합니다.
이 코드는 Spring AI 2.0.0 공식 문서 기반 예제입니다. 현재 환경에서 실제 모델과 연결해 응답을 측정하거나 Java 코드를 컴파일한 결과는 아닙니다. Spring AI 2.0.x는 Spring Boot 4.0.x·4.1.x 계열과의 공식 호환성을 확인해야 합니다.
MessageWindowChatMemory는 왜 창문일까?
MessageWindowChatMemory는 최근 메시지를 정해진 최대 수까지 유지하는 sliding window(이동 창) 방식입니다. 창문으로 보이는 범위만 지금 모델에게 보여준다고 생각하면 쉽습니다.
Spring AI 2.0.0의 공식 기본 최대값은 20개 Message입니다. 최대값을 넘으면 오래된 일반 메시지를 제거하되 System Message는 보존합니다. 2.0에서는 도구 호출처럼 여러 Message가 묶인 한 차례의 대화를 중간에서 자르지 않도록 완전한 turn 단위로 제거하므로, 실제 보관 수가 최대값보다 적을 수도 있습니다.
이해를 위해 최대 메시지를 네 개라고 가정해 보겠습니다. 이름, 자바 책, 스프링 책, 반납일에 관한 메시지가 창 안에 있고 새 질문이 들어오면 가장 오래된 일반 메시지가 창 밖으로 밀려날 수 있습니다. 이 숫자는 작동 원리를 설명하기 위한 가정이며 공식 기본값이나 권장 설정이 아닙니다.
창 밖으로 밀린 메시지는 현재 Prompt에 포함되지 않을 수 있습니다. 영속 저장소에 원본 기록이 남아 있더라도 어떤 정보를 다시 선택할지는 별도 정책입니다.
Context Window와 Memory는 무엇이 다를까?
Context Window(문맥 창)는 모델이 한 요청에서 처리할 수 있는 Token 범위입니다. Chat Memory는 애플리케이션이 다음 요청에 다시 전달할 대화 정보를 고르는 정책입니다.
| 구분 | Context Window | Chat Memory |
|---|---|---|
| 의미 | 모델이 한 요청에서 처리할 수 있는 Token 범위 | 애플리케이션이 저장하고 다시 전달할 관련 메시지 |
| 책임 | 모델 자체의 처리 한계 | 메시지 저장·선택·제거 정책 |
| 늘리는 방법 | 더 큰 문맥을 지원하는 모델 선택 등 | 최근 메시지, 요약, 중요 정보 선택 등 |
| 사라지지 않는 한계 | 한 요청에 넣을 수 있는 양은 유한함 | 저장량이 커도 Prompt에 모두 넣을 수 없음 |
데이터베이스에 대화를 아무리 많이 저장해도 한 번의 요청에 모두 넣을 수 있는 것은 아닙니다. 대화가 길어지면 최근 메시지만 유지하거나 오래된 내용을 요약하고, 중요한 정보만 선택하며, 장기 정보와 단기 대화를 분리할 수 있습니다.
Token 사용량도 함께 측정해야 합니다. Spring AI 2.0이 이런 전략을 모든 업무에 맞게 자동으로 완벽히 결정해 주지는 않습니다.
Chat Memory와 Chat History는 다르다
Chat History(대화 이력)는 사용자와 모델이 주고받은 전체 기록입니다. 고객 화면, 감사, 분쟁 처리처럼 완전한 기록이 필요한 목적에 쓰일 수 있습니다.
Chat Memory는 현재 모델 응답에 필요한 관련 정보입니다. 모든 과거 대화를 반드시 포함하지 않으며, Context Window와 현재 질문에 맞춰 일부가 제거되거나 요약될 수 있습니다.
Spring AI 공식 문서도 ChatMemory를 전체 이력 저장에 가장 적합한 도구로 보지 않습니다. 전체 기록이 필요하면 별도의 저장 설계를 두고, 모델에 보낼 기억과 감사용 이력을 분리해야 합니다.
금융 시스템에서는 Chat Memory의 오래된 메시지가 밀려났다고 해서 감사나 분쟁 처리를 위해 보존해야 할 전체 기록까지 함께 삭제돼서는 안 될 수 있습니다. 이는 금융 백엔드 관점에서 제시하는 설계 고려사항이며, 이 글이 실제 금융 챗봇 운영 경험을 주장하는 것은 아닙니다.
애플리케이션을 재시작하면 기억은 남을까?
InMemoryChatMemoryRepository는 프로세스 메모리의 ConcurrentHashMap에 메시지를 저장하는 기본 저장소입니다. 시작하기 간단하지만 프로세스가 종료되면 내용이 사라질 수 있어 단일 인스턴스의 학습 예제에 알맞습니다.
Persistent Storage(영속 저장소)는 애플리케이션 재시작 뒤에도 데이터를 유지하는 저장 방식입니다. Spring AI에는 ChatMemoryRepository 추상화와 JDBC를 사용하는 영속 구현이 있습니다.
영속화하면 재시작 문제는 줄일 수 있지만 Context Window 제한은 없어지지 않습니다. 보존 기간, 삭제 요청, 접근 권한, 암호화, 백업과 장애 복구를 새로 설계해야 합니다.
Conversation ID를 잘못 사용하면 어떻게 될까?
모든 사용자에게 같은 Conversation ID를 쓰면 서로의 대화가 섞일 수 있습니다. 클라이언트가 다른 사람의 ID를 임의로 보내거나, 로그아웃 뒤 예전 세션 ID를 재사용하거나, 멀티테넌트 환경에서 회사 경계를 놓치는 문제도 생길 수 있습니다.
ID는 인증된 사용자·세션·테넌트와 서버에서 연결하고 대화 소유권을 확인해야 합니다. 클라이언트가 보낸 값을 그대로 신뢰하지 않고 예측하기 어려운 식별자를 사용하며, 보존 기간과 삭제 기능도 마련해야 합니다.
Conversation ID 자체에 주민등록번호, 계좌번호, 이메일 같은 개인정보를 넣지 않습니다. 로그에 ID가 남는 범위도 필요한 수준으로 제한해야 합니다.
기억이 많을수록 좋을까?
과거 메시지가 늘면 입력 Token과 Context Window 사용량이 늘어납니다. 모델 호출 비용과 응답 지연이 증가할 수 있고, 오래된 잘못된 정보가 계속 답에 영향을 줄 수도 있습니다.
과거 대화에 들어온 Prompt Injection(모델의 지시를 바꾸려는 악의적 입력)의 영향이 다음 요청까지 이어질 위험도 있습니다. 개인정보 보관 범위 역시 넓어집니다.
좋은 기억은 많은 기억이 아니라 현재 질문에 필요한 기억입니다. 무엇을 저장할지뿐 아니라 무엇을 빼고 언제 지울지도 품질과 보안의 일부입니다.
대화 로그에는 무엇이 들어갈까?
Prompt와 Completion(모델이 생성한 응답)에는 계좌번호, 거래 정보, 고객 문의, 개인정보, 인증 정보와 내부 정책이 들어갈 수 있습니다.
Spring AI 2.0 Observability 문서는 Prompt와 Completion 데이터가 크고 민감할 수 있어 기본으로 내보내지 않는다고 설명합니다. ChatClient와 ChatModel의 Prompt·Completion logging 설정 기본값도 false입니다.
문제 분석에 유용하다는 이유만으로 로그를 모두 켜서는 안 됩니다. 금융 환경에서는 마스킹, 최소 수집, 접근 통제, 보존 기간과 삭제 정책을 먼저 정해야 합니다.
한 단계 더 깊게: 실제 요청 흐름
- 사용자가 Conversation ID와 질문을 보냅니다.
- MessageChatMemoryAdvisor가 ID에 맞는 기억을 조회합니다.
- 조회한 Message를 현재 Prompt에 추가합니다.
- ChatClient가 모델을 호출합니다.
- 모델은 현재 전달된 전체 Message를 바탕으로 답을 만듭니다.
- 새로운 User·Assistant Message를 저장합니다.
- 다음 요청에서 같은 과정이 반복됩니다.
이 과정에서 모델 자체의 가중치는 바뀌지 않습니다. Conversation ID가 다르면 별개의 대화로 처리됩니다. 저장소에 데이터가 있어도 현재 Prompt에 포함된 내용만 모델이 사용할 수 있으며, Message Window에서 제거된 정보는 전달되지 않을 수 있습니다.
자주 생기는 오해
챗봇은 대화할수록 나를 학습하나요?
Chat Memory는 모델 학습이 아닙니다. 애플리케이션이 이전 메시지를 다음 요청에 다시 포함하는 방식입니다.
데이터베이스에 저장하면 모델이 자동으로 기억하나요?
아닙니다. 저장한 메시지를 조회해 현재 Prompt에 넣어야 모델이 사용할 수 있습니다.
Context Window가 크면 Chat Memory가 필요 없나요?
더 많은 메시지를 한 번에 넣을 수는 있지만, 어떤 사용자의 어떤 대화를 선택하고 보존할지는 여전히 애플리케이션의 책임입니다.
In-memory 저장소도 재시작 후 유지되나요?
일반적으로 프로세스가 종료되면 메모리 내용도 사라집니다. 재시작 뒤 유지하려면 영속 저장소와 보존 정책이 필요합니다.
Conversation ID 하나를 모든 사용자에게 써도 되나요?
안 됩니다. 사용자나 테넌트의 대화가 섞일 수 있으므로 서버에서 소유권과 경계를 확인해야 합니다.
대화를 전부 넣으면 답변이 더 좋아지나요?
항상 그렇지 않습니다. 관련 없는 과거 정보는 Token·비용·지연을 늘리고 현재 질문을 흐리거나 보안 위험을 이어갈 수 있습니다.
기억의 주인은 모델이 아니라 애플리케이션이다
- LLM은 이전 요청을 스스로 기억하지 않으며, 애플리케이션이 과거 메시지를 다시 전달해야 합니다.
- Spring AI의 ChatMemory와 MessageChatMemoryAdvisor는 Conversation ID에 맞는 대화 문맥을 관리합니다.
- 기억에는 Context Window, 비용, 개인정보, 사용자 분리와 보존 정책이라는 한계가 있습니다.
다음 편의 제목은 AI는 왜 우리 회사 문서를 모를까?입니다.
대화 내용은 다시 전달하면 기억하게 만들 수 있다. 그렇다면 회사 규정과 내부 문서도 함께 넣어주면 알 수 있을까?