ryong.log|
AI로 학생의 성장을 피드백하기까지: TOPIA Growth 시스템 개발기 배너
2026년 6월 21일·읽는 데 약 7분

AI로 학생의 성장을 피드백하기까지: TOPIA Growth 시스템 개발기

관련 글

유료 라이브러리 PSPDFKit을 대신하여 동일한 기능을 내부 라이브러리로 배포해보자

2026. 3. 31.

OpenClaw로 hotfix 대응팀을 만들어봤습니다 (TOPIA Harness)

2026. 3. 6.

음성인식 기반 아동 영어 교육 서비스 RockieTalkie

2024. 12. 30.

문제상황

학부모가 아이를 학원에 보내면서 가장 궁금해하는 것은 무엇일까요? 학원의 목적에 따라 조금씩 다르겠지만, 결국에는 우리 아이가 얼마나 성장하고 있는지일 것입니다. 이는 학원에서 보는 시험 점수로 어느 정도 가늠할 수 있고, 전화 상담을 통해서도 충족할 수 있습니다.

TOPIA Live에는 크게 두 가지 피드백 프로세스가 있습니다. 과목별 담당 강사가 한 달마다 학생에 대한 피드백을 작성하는 Monthly Report, 그리고 매니저가 학부모에게 직접 전화 상담을 진행하는 구조입니다.

하지만 이 시스템에는 잠재적인 문제가 많이 내포되어 있습니다.

TOPIA Live는 학생의 클래스 이동과 클래스 내 강사 교체가 비교적 자유로운 구조입니다. 따라서 학생이 여러 학기 동안 TOPIA Live를 다니면 클래스와 강사가 바뀌는 일은 자연스럽게 발생합니다. 문제는 강사가 새로운 학생을 배정받았을 때, 이 학생이 어떤 학생인지, 어떤 흐름으로 성장해왔는지, 잘하는 점과 미흡한 점은 무엇인지 파악할 방법이 없었다는 점입니다. 시스템 밖에서 매니저들끼리 공유하는 데이터는 있었지만, 시스템 안에 녹여내지 못했기 때문에 강사들은 이를 확인할 수 없었습니다.

또한 현재 구조는 재원생 수가 늘어날수록 점점 견디기 어려워지는 구조였습니다. 기존에는 매니저가 강사도 관리하고 학생 상담까지 맡고 있었지만, 이제는 매니저가 강사만 관리하고 강사가 학생을 더 직접적으로 관리하는 방식으로 전환할 필요가 있었습니다. 이를 위해서는 학생 데이터가 투명하게 공유되어야 했습니다.

학부모와 학생이 학원을 다니는 동안 더 풍부한 피드백을 받고, 학원과 더 자주 소통할 수 있는 구조도 필요했습니다. 기존 방식에서도 아이에게 관심이 많은 학부모는 전화 상담을 요청해 충분한 피드백을 받을 수 있었습니다. 반면 개인적인 사정으로 전화 상담을 받기 어려운 학부모는 비교적 수동적인 피드백만 받을 수밖에 없었습니다.

이 문제들을 해결하기 위해 학생의 성장을 데이터로 추적하고, 사용자의 니즈에 맞는 여러 산출물로 피드백을 제공하는 서비스가 필요했습니다. 사람이 직접 수기로 작성하는 방식이 아니라 AI가 학생 데이터를 바탕으로 피드백을 작성하도록 하는 TOPIA Growth 프로젝트를 독자적으로 맡게 되었습니다.

문제 해결 방향

큰 흐름은 단순합니다. 운영 DB에 흩어져 있는 학생의 데이터를 모아 input으로 정리하고, 이 데이터를 기반으로 여러 가지 형태의 output을 발행하는 구조입니다.

Input에는 학생의 학습 데이터와 시스템 내 학생의 피드백에 관련된 데이터를 모두 수집하였습니다. 테스트 결과, 과제 수행, 첨삭 이력, 수업 참여 데이터처럼 output에 의미 있게 쓰일 수 있는 다양한 데이터를 관심사별로, 날짜별로 분리하여 담았습니다.

Zoom으로 진행되는 수업에서 내려오는 transcript 데이터는 원문에 가까운 형태로 보관하면서도, 필요한 경우 학생 발화, 수업 맥락, 참여 흐름을 분석할 수 있도록 가공된 형태로도 저장했습니다. 이렇게 정리한 데이터는 여러 Markdown 파일로 나누어 S3에 저장했습니다.

이후 output은 우선 두 가지 형태로 제공하기로 했습니다. 하나는 짧은 주기로 학부모와 소통하기 위한 Weekly Report이고, 다른 하나는 한 학기 동안의 성장 변화를 보여주는 Semester Report입니다.

Weekly Report는 한 주간의 데이터를 보고, 이전 4주 흐름과 비교해 이번 주에 무엇을 잘했고 어떤 부분을 개선하면 좋을지를 가볍게 전달하는 데 초점을 맞췄습니다.

Semester Report는 학생의 한 학기, 즉 약 3개월간의 데이터를 보고 이전 학기와 비교해 어떤 부분이 성장했는지를 보여줍니다. 데이터를 기반으로 Speaking, Vocabulary, Writing, Grammar, Listening, Reading으로 영역을 나누어 디테일하게 제공되었습니다.

TOPIA Growth는 한 번 만들고 끝나는 프로젝트가 아니었습니다. 서비스가 고도화될수록 참고해야 할 학생 데이터는 계속 추가되거나 변경될 것이고, 이를 바탕으로 만들어야 할 산출물의 종류도 늘어날 가능성이 높았습니다. 그래서 처음부터 특정 리포트 하나를 만드는 데 집중하기보다, 학생 데이터를 꾸준히 쌓고 그 데이터를 바탕으로 다양한 산출물을 만들 수 있는 구조를 만드는 데 집중했습니다.

왜 DB를 바로 조회하지 않고 S3에 파일로 두었나?

처음에는 리포트를 만들 때마다 DB를 조회하면 된다고 생각할 수 있습니다. 학생 데이터를 S3에 별도로 저장해둔 이유는 다음과 같습니다:

  1. 학생 수와 산출물의 종류가 늘어날수록 DB 조회량도 함께 늘어납니다. 리포트 하나를 만들 때마다 여러 테이블을 조회하고, 학생별로 같은 작업을 반복하면 운영 DB에 부담이 커질 수밖에 없습니다.
  2. 데이터가 항상 raw 형태로만 쓰이지 않기 때문입니다. Zoom transcript처럼 원문도 중요하지만, 리포트에 쓰기 위해서는 학생 발화나 수업 맥락을 기준으로 한 번 정리된 데이터가 필요합니다. 이처럼 가공된 데이터를 매번 새로 만들기보다는, 학생별 input 파일로 관리하는 편이 더 안정적이었습니다.
  3. 어떤 데이터를 기준으로 산출물을 만들었는지 통제할 수 있어야 했습니다. TOPIA Growth의 목적은 단순히 여러 리포트를 뽑는 것이 아니라 학생 데이터 관리 시스템을 만드는 것이기도 했습니다. 그래서 S3에 학생별 정본 데이터를 두고, 스케줄러와 배치를 통해 주기적으로 갱신하는 구조를 선택했습니다.

물론 S3에 파일로 저장하면 outdated 문제가 생길 수 있습니다. 그래서 데이터를 한 번 넣고 끝내는 방식이 아니라, 주기적으로 최신 데이터를 반영하는 배치 흐름을 함께 설계했습니다. 운영 DB는 원천 데이터의 위치로 두고, S3는 리포트와 분석이 참조하는 학생별 정리본으로 역할을 나눈 것입니다.

Weekly Report와 Semester Report는 어떻게 만들어지는가?

Weekly Report는 비교적 가볍고 빠른 피드백에 초점을 맞췄습니다. 한 주 동안 쌓인 학습 데이터를 기준으로, 최근 4주 흐름과 비교해 이번 주에 어떤 변화가 있었는지를 정리합니다. 학생이 잘한 점, 눈에 띄는 변화, 다음 주에 조금 더 신경 쓰면 좋은 부분을 학부모가 부담 없이 읽을 수 있는 형태로 전달하는 것이 목적이었습니다.

반면 Semester Report는 훨씬 더 깊은 분석이 필요했습니다. 한 학기, 즉 약 3개월 동안의 데이터를 바탕으로 학생이 어떤 영역에서 성장했는지를 설명해야 했기 때문입니다. 단순 요약으로는 부족했고, Speaking, Vocabulary, Writing, Grammar, Listening, Reading 각 영역을 따로 분석할 필요가 있었습니다.

그래서 Semester Report는 6개 영역의 전문성을 가진 Analyzer Agent들이 먼저 각자의 영역을 분석하는 구조로 만들었습니다. Speaking Agent는 발화와 발표, 수업 참여 데이터를 보고, Writing Agent는 첨삭과 작문 데이터를 봅니다. Vocabulary, Grammar, Listening, Reading도 각각 자신에게 필요한 데이터를 기준으로 성장 흐름과 근거를 정리합니다.

이후 각 Agent가 분석한 결과를 하나로 모아 Report Creator Agent에게 전달합니다. Report Creator Agent는 영역별 분석 결과와 학기 범위의 데이터를 바탕으로, 학부모가 읽을 수 있는 하나의 Semester Report를 작성합니다. 즉, Semester Report는 하나의 Agent가 모든 데이터를 보고 단번에 쓰는 방식이 아니라, 영역별 분석 Agent들이 먼저 근거를 만들고, 마지막에 리포트 작성 Agent가 이를 학부모용 글로 엮는 방식입니다.

이 구조 덕분에 각 영역의 분석 기준을 독립적으로 고도화할 수 있었습니다. 예를 들어 Speaking 분석 기준을 바꾸더라도 Writing이나 Vocabulary 영역에는 영향을 주지 않습니다. 앞으로 새로운 데이터가 추가되거나 리포트 형식이 바뀌더라도, 필요한 Agent와 산출물만 확장할 수 있는 구조가 되었습니다.

AI가 쓴 것 같은 티가 나지 않도록 다듬는 과정

리포트 산출물을 개발하는 과정에서 생각보다 시간이 오래 걸렸던 부분은 문체 관리였습니다. 같은 입력 데이터와 에이전트 스펙으로 여러 번 산출물을 만들다보니 AI 특유의 어색한 말투가 섞이거나 어울리지 않는 표현이 포함되는 경우가 있었습니다.

예를 들어 내부 시스템에서 쓰는 표현이 그대로 새어 나오는 경우가 있었습니다. 2026-W23.md, Analyzer Speaking 추세, evidence-parser, confidence: 낮음, 직접 측정 커버리지 같은 표현은 이를 개발한 개발자에게는 익숙할 지 몰라도, 학부모가 읽는 리포트에는 어울리지 않기 마련입니다. 이는 마치 리포트라기보다 분석 로그나 디버그 결과처럼 보이기도 해서 수정이 불가피했습니다.

수치를 다루는 방식도 문제였습니다. “Pronunciation 76.7에서 80.4로 상승”과 같이 데이터를 그대로 인용하는 모습도 보였습니다. 하지만 학부모가 궁금한 것은 수치만 나열한 결과보다 그 수치가 아이의 수업 태도나 성장 모습과 어떻게 연결되는지일 것입니다. 따라서 직접적인 수치 언급은 필요한 경우에만 자연스럽게 보조 근거로 쓰도록 조정했으며, 리포트 하단에 어떤 데이터를 참고했는지를 영역으로 분리했습니다.

위 문제들을 해결하기 위해 “잘 써라”는 식의 추상적인 지시 대신, 실제로 실패했던 케이스를 하나씩 모아 검수 규칙으로 정리했습니다. 내부 용어를 노출하지 말 것, 본문에 불릿이나 표를 남발하지 말 것, 결함을 부각하는 표현을 쓰지 말 것, 근거가 얇은 영역에서 성장했다고 단정하지 말 것 같은 규칙들이 여기에 포함되었습니다.

그리고 이 규칙들을 리포트 생성 프롬프트에만 넣는 데서 끝내지 않고, 생성된 결과물을 다시 검수하는 리뷰 에이전트를 프로세스에 넣어 사용했습니다. 리뷰 에이전트는 AI가 쓴 글처럼 보이는 패턴을 찾아내는 역할을 맡았습니다. 번역투, 과한 접속사, 반복되는 종결어미, 시스템 용어 노출, “루틴을 권해요” 같은 템플릿형 조언을 다시 확인하여 정확도를 높였습니다.

그 결과 이전보다 확연히 AI가 쓴 어색한 글의 티를 벗어나게 되었으며, 학습자로써 학부모/학생에게 데이터를 기반으로 한 사실을 자연스럽게 전달하는 리포트를 발행할 수 있게 되었습니다.

시스템 구조와 인프라 세팅

TOPIA Growth를 구성하는 요소는 크게 두 가지입니다. 학생 데이터와 리포트 생성 과정을 모니터링하는 admin, 그리고 학생 데이터를 추출하고 리포트를 생성하는 실제 작업을 담당하는 batch worker입니다.

개발 초기에는 Next.js 앱에 백엔드 기능을 붙여 처리하는 방식으로 작업을 진행했습니다. 가벼운 작업 단위에서는 별다른 문제가 발생하지 않았으나, 프로젝트가 고도화될수록 학생 데이터 추출, LLM을 통한 분석 작업들이 무거워지기 시작하여 기존 방식으로 운영하기에는 불안정하다고 판단을 하였습니다. 이에 무겁고 오래걸리는 작업들은 batch worker 방식으로 분리하고, admin과 batch worker를 모노레포 방식으로 관리하도록 리팩토링을 진행했습니다.

admin은 Next.js 기반의 어드민 페이지입니다. 이 곳에서는 학생별 데이터 상태, Weekly Report와 Semester Report 생성 여부, 배치 실행 로그와 실패 원인, LLM 사용량과 비용 등 작업에 필요한 모든 요소들을 한 번에 확인할 수 있는 기능을 제공합니다. 이 뿐만 아니라 Data Extraction, Weekly Report, Semester Report 같은 배치 작업을 수동으로 실행하거나 스케줄을 관리하는 기능도 제공합니다. 말 그대로 All-in-one 앱인 셈입니다.

반면 batch worker는 SQS 큐에 쌓인 작업을 가져와 실제 배치 작업을 수행합니다. 학생 데이터 추출, LLM 호출, 리포트 저장처럼 시간이 오래 걸리고 실패 가능성이 있는 작업은 모두 worker에서 처리되도록 분리했습니다. 작업은 학생 단위로 큐에 들어가고, worker는 이를 하나씩 가져와 실행한 뒤 성공 여부와 로그, LLM 사용량을 남기게 됩니다. 중간에 실패한 작업은 바로 사라지지 않고 재시도될 수 있도록 했고, 반복해서 실패하는 작업은 DLQ로 이동시켜 나중에 원인을 따로 확인할 수 있게 했습니다. 덕분에 특정 학생의 리포트 생성이 실패하더라도 전체 배치가 멈추지 않고, 실패한 작업만 추적해 다시 처리할 수 있었습니다.

스토리지는 S3와 DB의 역할을 나누어 사용했습니다. 학생별 input 데이터와 Semester Report처럼 한 번 생성되면 자주 바뀌지 않고, 화면에서 보여주는 방식도 비교적 고정된 무거운 결과물은 S3에 파일 형태로 저장했습니다. 반면 Weekly Report처럼 상대적으로 가볍고, 이후 서비스 안에서 여러 형태로 조합될 가능성이 있는 피드백 데이터는 DB에 저장했습니다. 주차별 피드백을 모아 보여주거나, 그래프 데이터와 함께 성장 흐름을 구성하는 식의 확장을 고려하면 파일보다 테이블로 관리하는 편이 더 유연하다고 판단했습니다.

배포는 AWS ECS 기반으로 구성했습니다. admin은 ECS 서비스로 항상 떠 있도록 두고, Internal ALB 뒤에 배치해 VPN 안에서만 접근할 수 있도록 했습니다. 반면 batch worker는 항상 떠 있는 서비스로 두지는 않았습니다. 작업이 없을 때도 리소스를 계속 쓰는 구조는 비효율적이기 때문에, SQS에 처리할 메시지가 쌓이면 admin이 ECS Fargate RunTask를 호출해 worker를 띄우는 방식으로 구성했습니다. worker는 큐에서 작업을 가져와 처리하고, 실행 결과와 로그는 DB에 남겼습니다.

로컬 테스트에서는 Ministack을 활용했습니다. 실제 AWS 리소스에 매번 붙지 않고도 S3, SQS 흐름을 로컬에서 검증할 수 있어 배치 개발 속도를 높일 수 있었습니다. 특히 학생 데이터를 S3에 쌓고, 큐 메시지를 통해 worker가 실행되는 흐름은 운영 환경과 비슷하게 재현해야 했기 때문에 로컬에서 이 과정을 반복해서 확인할 수 있는 환경이 중요했습니다.

CI/CD는 환경별 CodePipeline으로 구성했습니다. dev, staging, prod 브랜치를 기준으로 각각 파이프라인을 두고, CodeBuild에서 admin 이미지와 batch worker 이미지를 빌드한 뒤 ECR에 푸시합니다. 이후 admin 서비스는 ECS Deploy 단계에서 rolling update되고, batch worker는 새로 RunTask가 실행될 때 최신 ECR 이미지를 가져가도록 했습니다.

유저의 반응

설레는 마음으로 조회해본 유저의 반응은 흥미로웠습니다. 6월 8일부터 약 2주간의 반응은 아래와 같았습니다.

이벤트이벤트 수사용자 수평균 체류 시간
학생에게 제공된 리포트 접근 수1,73359910초
학생에게 제공된 리포트 반응 수594230
학부모에게 제공된 리포트 접근 수1,08543227초
학부모에게 제공된 리포트 반응 수514170
아티팩트좋아요싫어요코멘트
Weekly Report2981931
Semester Report1200

이벤트 수와 댓글 내용을 함께 보면, 수요가 폭발적이었다고 보기는 어려운게 사실입니다. 다만 학습 상태에 관심이 있는 학부모와 학생에게는 꾸준히 수요가 있을 가능성이 있는 반응이었습니다. 특히 첫 주 리포트는 별도 알림 없이 발행되었습니다. 기존에 비활성화되어 있던 메뉴가 프론트 업데이트를 통해 노출되었고, 유저는 서비스 안에서 직접 리포트를 발견해야 했습니다. 그럼에도 상당수 유저가 리포트에 진입했다는 점에서, 최소한 진입 UX가 크게 어색하지는 않았다고 볼 수 있었습니다.

Weekly Report에 남겨진 코멘트도 흥미로웠습니다. “생각보다 정확하다”, “더 자주 받아보고 싶다”, “무엇을 어떻게 보완하면 좋을지 궁금하다”와 같은 코멘트를 남겨주셨습니다. 리포트가 단순히 읽고 끝나는 알림이 아니라, 어쩌면 새로운 소통의 창구가 될 수도 있겠다는 생각이 드는 순간이었습니다. 반대로 실제 발화와 다른 내용이 있다는 코멘트도 있었습니다. 이 경우에는 데이터 불일치 문제를 확인한 뒤 빠르게 수정하고, 리포트를 다시 발행해드리는 조치로 대응했습니다.

둘째 주에는 카카오 알림톡 템플릿 신청이 진행 중이어서 SMS로 별도 알림을 보냈습니다. 다만 현재까지는 알림 유무에 따라 유입이 크게 달라졌다고 보기는 어려웠습니다. 이후 실제 카카오 알림톡까지 발송해보면서 SMS와 비교해 어떤 채널이 더 효과적인지 확인해볼 필요가 있을 것 같습니다.

Semester Report는 조금 다른 고민을 남겼습니다. 학부모 마이페이지에서 버튼을 누르고, 리포트 탭을 전환한 뒤, Semester Report까지 들어가 스크롤 최하단에 있는 반응이나 코멘트를 남기는 과정에는 어느 정도 뎁스가 있는 건 사실입니다. 그 점을 감안하더라도 반응은 기대보다 조용했습니다. 잘못된 데이터라는 불만이 많았다기보다, 무반응에 가까웠다는 점에서 개선이 필요해 보였습니다. 진입 동선의 문제인지, 내용의 매력이 부족한 것인지, 혹은 학기 리포트라는 형식 자체가 유저에게 아직 익숙하지 않은 것인지 더 확인해야 했습니다.

앞으로는 재방문 흐름을 더 중요하게 볼 계획입니다. 리포트가 매주 새로 발행되는데도 유저 수가 점진적으로 줄어든다면, 유저 입장에서는 내용이 비슷하게 느껴졌거나 기대만큼 새롭지 않았다는 뜻일 수 있습니다. 따라서 에이전트 프롬프트가 학생 데이터를 충분히 반영하고 있는지 다시 점검하고, 유저가 어떤 형태의 피드백을 원하는지 UX 안에서 자연스럽게 수집해 리포트 품질과 기능 개선에 반영할 계획입니다.

1차 회고

기존에 주로 하던 프론트엔드 작업과는 많이 다른 프로젝트였습니다. 이번에는 완성된 요구사항을 받아 구현하는 방식이 아니라, 아직 정리되지 않은 의도를 전달받고 기획부터 구현, 배포까지 책임지는 형태였으니까요. 처음 맡는 형태의 임무였던 만큼 어려운 점도 많았지만, 결과적으로 하나의 프로젝트를 끝까지 만들어냈다는 점에서 뿌듯함이 컸습니다.

다만 기획을 진행할수록 아쉬운 지점도 분명히 보였습니다. TOPIA Growth로 유저와 소통할 수 있는 방법은 생각보다 많았지만, 정작 활용할 수 있는 데이터는 기대만큼 풍부하지 않았습니다. 시험이나 과제에는 많은 학습 맥락이 담겨 있지만, 현재 DB에는 대부분 결과 점수 위주로만 적재되어 있는 형태입니다. 어떤 문제를 틀렸는지, 어떤 유형에 강한지, 어떤 사고 과정에서 막혔는지를 점수만으로 파악하기에는 한계가 있었습니다.

Zoom transcript도 마찬가지였습니다. 이 프로젝트를 진행하면서 급하게 파싱 배치를 만들고 DB에 적재하기 시작했기 때문에, 이전 학기까지 거슬러 올라가 학생이 어떤 흐름으로 성장했는지를 온전히 복원하기는 어려웠습니다. 결국 좋은 리포트를 만들기 위해서는 리포트 생성 로직뿐 아니라, 어떤 데이터를 남길 것인지부터 함께 설계해야 한다는 점을 느꼈습니다.

앞으로도 꾸준히 여러 방향으로 개선을 이어가며 실제 피드백을 계속 받아볼 예정입니다. 특정 형식에 너무 일찍 제한을 두기보다는, 다양한 표현 방식을 시도하고 반응을 보고, 실패하면 빠르게 고치는 식으로 짧은 주기의 개선을 반복해 보려고 합니다. 그 과정에서 얻은 내용은 이 글 하단에 계속 이어서 공유할 예정입니다.

TOPIA Growth Admin
학부모 마이페이지 내 Growth
학생 마이페이지 내 Growth
  • 문제상황
  • 문제 해결 방향
  • 왜 DB를 바로 조회하지 않고 S3에 파일로 두었나?
  • Weekly Report와 Semester Report는 어떻게 만들어지는가?
  • AI가 쓴 것 같은 티가 나지 않도록 다듬는 과정
  • 시스템 구조와 인프라 세팅
  • 유저의 반응
  • 1차 회고