헤비유저 비중의 분모는 학생 수가 아니었다
AI Tutor의 한 주 질문 보고서에 “헤비유저 비중 41%”라는 숫자가 있다면, 많이 질문한 학생이 전체 학생의 41%라는 뜻일까. 질문 분석 구현에서 이 값은 전체 질문 중 헤비유저가 만든 질문의 비중이었다. 계산을 코드로 옮기는 것만큼, 숫자의 단위와 분모를 고정하는 일이 중요했다.
질문 분석 파이프라인과 후속 기능의 구현 사례다. 제품 통합 전의 동작이며, 배포된 보고서의 정확성을 검증한 결과는 아니다.
computeOverview()는 입력 질문을 user_login별로 세고, 주간 질문 20건 이상을 heavy, 5건 이상을 middle, 나머지를 light로 나눈다. 각 구간에 학생 수와 질문 수를 함께 저장한다. 참여 학생 수도 질문을 한 고유 학생 수이며, 수강생 전체 인원이 아니다.
| 학생별 질문 수 | 구간 | 학생 수 | 질문 수 |
|---|---|---|---|
| 20 | heavy | 1명 | 20건 |
| 19, 5 | middle | 2명 | 24건 |
| 4, 1 | light | 2명 | 5건 |
이 입력에서 헤비유저의 인원 비율은 1/5, 즉 20%지만, 코드가 반환하는 heavy_user_ratio는 round(20 / 49 × 100)인 41이다. 이름만 보고 인원 비율로 읽으면 올바른 계산도 다른 사실로 전달된다.
같은 질문도 날짜를 자르는 기준에 따라 편중이 달라진다
기간 편중은 KST 날짜별 질문 수로 판정한다. 테스트에는 UTC 6월 1일 10시, 같은 날 16시, 다음 날 16시에 각각 3건을 둔다. UTC 날짜로 묶으면 하루에 6/9가 몰려 편중으로 분류되지만, KST로는 6월 1·2·3일에 3건씩 나뉜다. 교수자가 보는 주간 보고서의 날짜 경계와 집계 시간대를 맞춘 것이다.
주의 플래그도 모델의 판단에 맡기지 않았다. 상위 두 학생의 질문 비중이 50% 이상이면 쏠림, 총 질문이 30건 미만이면 작은 표본, 최다 하루의 질문 비중이 50% 이상이면 기간 편중이다. 다음은 반환 계산 중 일부이며, 학생·날짜별 집계는 생략했다.
heavy_user_ratio:
total > 0 ? Math.round((bands.heavy.questions / total) * 100) : 0,
cautions: {
concentration: total > 0 && top2 / total >= 0.5,
small_sample: total < 30,
period_skew: total > 0 && maxDay / total >= 0.5,
} 4/5건과 19/20건의 구간 경계, 29/30건의 표본 경계, 정확히 상위 두 명이 50%인 경우, KST 날짜 이동과 빈 입력을 검사하는 테스트가 있다. 빈 입력은 참여 학생과 비중을 0으로 반환하고 작은 표본 플래그는 켠다. 이 임계값들은 보고서의 제품 규칙이다. 통계적 유의성이나 학습 효과를 판정하는 기준은 아니다.
고정한 개요와 모델의 분석은 서로 다른 책임을 갖는다
후속 Step2는 Step1 분석 결과, 코드가 계산한 개요, 질문 목록을 별도 항목으로 받는다. 프롬프트는 참여 학생 수·헤비유저 비중·주의사항을 새로 계산하지 말고 그대로 인용하라고 지시한다. 코드가 재현 가능한 숫자를 정하고, 모델은 질문 내용에서 수업 보완 지점을 서술하는 역할을 맡는다.
모든 숫자를 한 번에 생성하면 입력은 간단해지지만 같은 정의의 수치를 반복해서 얻기 어렵다. 코드 집계에는 구간, 분모, 시간대를 유지할 책임이 생긴다. 또한 이 개요를 코드로 계산했다고 해서 Step1의 주제별 질문 수나 모델의 해석까지 모두 결정적으로 검증한 것은 아니다.
JSON 구조 검사와 개요의 경계 테스트는 다른 사실을 확인한다. 형식이 맞는 분석에도 근거가 약한 해석이 들어갈 수 있고, 입력에 정확한 숫자가 있어도 모델이 서술에서 잘못 인용할 수 있다. 이 구현의 경계는 개요의 계산과 전달이다. 이후 분석 도구로 주제별 건수를 세는 문제까지 같은 보장으로 넓힐 수는 없다.