Code › tail-villain

다시 이어지는 학습 세션

일회성 채팅처럼 보이던 study mode를 상태와 리포트를 가진 학습 세션으로 바꾼 기록

study mode에 다시 들어가면 대화가 처음부터 다시 시작됐다.

토픽을 고르고 코치를 선택하면 AI가 설명을 이어가며 질문을 던졌고, 사용자는 답변을 보낼 수 있었다. 그런데 잠깐 나갔다가 돌아오면 제품 안에는 그 세션이 어디까지 진행됐는지, 사용자가 어떤 부분을 이해했고 무엇이 아직 빈틈인지가 남아 있지 않았다.

면접 연습은 한 번의 질문과 답변으로 끝나지 않는다. study mode가 특정 토픽을 이해하도록 돕는 흐름이라면 이전 답변과 현재 수준, 다음에 확인할 내용을 기억해야 하는데, 그렇지 않으면 AI는 매번 친절한 첫 질문을 다시 만들지만 제품은 사용자가 실제로 어디까지 왔는지 알 수 없다.


대화 로그는 기본으로 남아야 한다. 사용자는 과거 답변을 다시 볼 수 있어야 하고 AI도 최근 대화를 참고해서 이어가야 하지만, 로그만으로는 학습 진행 상태를 표현하기 어려웠다. 무슨 말을 했는가와 그래서 학습이 어디까지 진행됐는가는 다른 정보이기 때문이다.

예를 들어 사용자가 캐시 일관성에 대해 답했다고 해보자. 대화 로그에는 답변 문장이 남는다. 그런데 그 답변이 기본 개념을 이해했다는 뜻인지, trade-off까지 설명했다는 뜻인지, 아니면 용어만 맞고 실제 사례는 약하다는 뜻인지는 따로 정리되어야 한다. 채팅 로그만 계속 쌓으면 나중에 AI가 다시 읽을 수는 있지만, 제품이 학습 진행도를 안정적으로 판단하기는 어렵다.

그래서 study mode에는 대화와 별개의 세션 상태가 필요했다. learner level, milestone state, current milestone, running summary, next focus, progress, confidence 같은 값들을 세션에 남기게 했는데, 목적은 사용자가 지금 어느 지점에 있고 다음 턴에서 무엇을 확인해야 하는지 제품이 기억하게 만드는 것이었다.


세션 상태를 따로 저장하기로 했다면, 사용자가 다시 들어올 때 그 상태가 붙어 있는 세션으로 보내야 했다. 진입할 때마다 새 세션을 만들면 상태를 저장해도 누적 효과가 사라진다. 같은 토픽과 같은 persona로 다시 들어온 사용자는 새 opening을 받는 대신 기존 active study session으로 돌아가야 했고, 그렇지 않으면 학습은 매번 “안녕하세요, 오늘은 이 주제를 공부해보겠습니다” 같은 출발점에서 다시 시작된다.

그래서 study session을 topicId, ownerId, personaKey 기준으로 다시 찾도록 했다. 같은 사용자가 같은 토픽을 같은 코치와 공부하는 중이면 기존 세션으로 보내고, 실제로 시작되지 않은 빈 실패 세션은 active session으로 취급하지 않았다. AI opening이 실패했는데 껍데기 세션만 남아 있으면, 다음 진입 때 사용자는 아무 내용 없는 세션으로 돌아갈 수 있기 때문이다.

같은 화면에서 같은 버튼을 눌러도, 새 세션을 만드는지 기존 세션을 이어가는지에 따라 기능의 성격이 달라진다. 매번 새 세션을 만들면 study mode는 대화 생성 기능에 머물고, 기존 세션을 이어가면 학습 상태가 누적되는 기능이 된다.


세션을 이어가는 흐름이 잡히자, 종료 시점에 무엇을 남길지도 같이 정해야 했다. 대화가 어느 정도 진행되면 사용자는 세션을 끝낼 수 있어야 하는데, 학습이 끝났다면 어떤 개념을 이해했고 어떤 빈틈이 남았으며 다음에 무엇을 보면 좋은지도 같이 남아야 했다. 그래야 세션 종료가 단순한 대화 중단이 아니라 다음 행동으로 이어진다.

그래서 study report에 summary, understood concepts, remaining gaps, recommended next steps, interview readiness 같은 값을 남기게 했고, completion endpoint도 추가했다. 이때 완벽한 평가 시스템을 만들려던 것은 아니었다. 지금 필요한 건 대화가 끝났다는 사실이 아니라 이 학습이 어떤 상태로 끝났는지를 남기는 최소한의 구조였다.

progress와 confidence를 나눈 것도 같은 이유였다. 사용자가 이미 보여준 이해는 쉽게 사라지면 안 되지만, 답변이 흔들리면 confidence는 내려갈 수 있다. 둘을 하나의 점수로 섞으면 AI가 한 턴의 약한 답변만 보고 전체 진행도를 뒤집을 수 있고, 사용자는 방금까지 쌓아온 학습이 사라진 것으로 받아들일 수 있다.


이 상태를 실제로 매 턴 갱신하려면 AI 응답 형식도 달라져야 했다. AI에게 좋은 설명만 요구하면 답변은 그럴듯하게 나온다. 하지만 study mode에서는 매 턴마다 reply와 함께 세션 상태를 갱신할 structured state도 필요했다. 그래서 프롬프트는 매 턴마다 답변뿐 아니라 상태 필드를 함께 반환하도록 바뀌었다.

상태를 너무 기계적으로 다루면 AI가 매번 비슷한 패턴으로 말한다. “좋아요, 지금 잘하고 있어요. 다음 질문입니다” 같은 안전한 코칭 문장이 반복되면 사용자는 공부를 하고 있다기보다 자동 응답을 받고 있다고 느끼기 때문에, 반복 표현을 줄이고 현재 답변에 맞는 다음 행동을 만들도록 프롬프트를 다듬었다.

프론트도 그 흐름에 맞춰 조정했다. 코치 말풍선에는 persona avatar를 붙이고, 사용자 메시지는 라벨을 덜어내서 일반적인 채팅처럼 읽히게 했다. 말풍선 폭과 padding도 줄였는데, 학습 세션은 오래 머무는 화면이라 여백과 정보량이 조금만 어긋나도 피로도가 커지기 때문이다.


이 작업을 하고 나니, study mode에서 AI 답변 하나를 잘 만드는 것은 시작점에 불과했다. 학습 제품이라면 사용자가 어디까지 왔는지, 무엇을 다시 봐야 하는지, 세션이 끝났을 때 무엇이 남는지를 제품이 알고 있어야 한다. 그렇지 않으면 대화는 남아도 학습은 흩어진다.

그날 만든 구조가 완성형은 아니었다. milestone 이름도 더 다듬어야 하고, 리포트 품질도 실제 사용을 보며 조정해야 한다. 그래도 적어도 한 가지는 정리됐다. study mode는 친절한 채팅창이 아니라, 사용자가 다시 돌아왔을 때 이전보다 조금 더 앞에서 이어갈 수 있는 학습 세션이어야 한다.