학교 서버 한 대로 학생들이 쓰는 AI를 운영하고 있다. 이름은 시나브로 AI다.
모델을 고르고, 바꾸고, 시험하는 도구(하네스)를 만들고, 보안을 점검한 3주를 적는다.
여기서 "수업용 튜닝"은 가중치 미세조정이 아니다. 모델 선택, 추론 설정, 프롬프트, 검증 장치를 바꾼 것이다. 미세조정은 아직 하지 않았다.
왜 직접 돌리나
학생 질문을 외부 AI 서비스로 보내지 않기 위해서다. 학생이 무심코 붙여 넣은 이름, 연락처, 과제 파일이 학교 밖으로 나가지 않아야 한다. 그래서 모델도, 대화 기록도, 음성 인식도 학교 서버 한 대(DGX Spark 계열 GB10) 안에서 돌린다. 외부 연결은 Cloudflare 터널 하나뿐이다. 서비스는 전부 127.0.0.1에만 열어 둔다.
구성은 이렇다.
- 로그인: Google 로그인 + 교사가 나눠 준 초대 코드, 또는 수업용 게스트 코드(8시간). 코드는 해시로만 저장한다.
- 게이트웨이: 사용량 한도는 하루 200요청, 50만 토큰이다. 학생 한 명당 동시 1건이고, 서버 전체는 동시 40건까지다.
- 그 뒤에 vLLM 모델 서버가 있다. 답변은 사후 검사를 거친다. 코드가 들어 있으면 네트워크가 막힌 격리 환경에서 실제로 돌려 본다.

9월 23일: 모델을 바꿨다
처음 운영 모델은 Qwen3.6 35B-A3B(MoE)였다. 추론(thinking)을 끄면 빨랐다. 40명이 동시에 물어도 첫 글자가 0.9초 안에 나왔다. 문제는 정확도였다. 짧은 정답 검사 11문항 중 엄격한 JSON 형식까지 맞춘 건 5개였고, 내용만 보면 7개였다. 계산 실수가 있었고, 파이썬 동작을 잘못 설명하기도 했다. 학생이 믿고 베끼기에는 위험했다.
같은 장비에서 세 모델을 직접 돌렸다. 공개 벤치마크 점수는 이 장비에서의 속도를 말해 주지 않으니까.
| 설정 | 1명 시작 | 40명 시작 | 40명 완료 | 정상 응답 |
|---|---|---|---|---|
| Qwen3.6 35B-A3B · 추론 끔 | 0.2초 | 0.9초 | 9.3초 | 40/40 |
| Qwen3.6 · 추론 켬 | 20.4초 | 92.1초 | 93.7초 | 38/40 |
| Muse Glimmer 30B · 짧은 추론 | 30.8초 | 39.7초 | 50.9초 | 40/40 |
| Qwen3.8 27B · 고정 MTP 3 | 5.4초 | 48.7초 | 55.3초 | 40/40 |
| Qwen3.8 27B · 부하에 따라 MTP 조절 | 6.2초 | 34.9초 | 52.6초 | 40/40 |
(95백분위, 한 번씩 잰 합성 부하라 순위로 읽으면 안 된다.)
Glimmer도 정답 11/11, 코드 24/24로 잘 풀었다. 그래도 Qwen3.8 27B를 골랐다. 사용자가 적을 때 훨씬 빨랐고 메모리도 덜 썼다. 정답 11/11, 코드 24/24였다.
수업용으로 손본 게 MTP(추측 디코딩) 설정이다. 혼자 쓸 때는 토큰 3개씩 미리 추측하면 빨라진다. 그런데 40명이 몰리면 그 추측이 오히려 GPU를 잡아먹는다. 그래서 동시 요청 수에 따라 바꿨다. 18명이면 3개, 916명이면 1개, 그보다 많으면 끈다. 이렇게 하니 40명 첫 응답이 48.7초에서 34.9초로 줄었다.
여기서 얻은 교훈은 하나다. 교실의 병목은 한 명의 속도가 아니라 40명이 동시에 엔터를 누르는 순간이다.
시도하고 접은 것도 있다. Glimmer의 DFlash 가속은 메모리 예산 45%에서 캐시 공간이 모자라 시작조차 못 했다. 배치를 줄여 다시 해도 같았다.
10월 1일: 보안 점검
기능을 더 붙이기 전에 코드를 처음부터 다시 읽었다. 고칠 곳 8건을 찾아 모두 고쳤고, 그중 3건은 위험이 높은 것이었다. 수업에서 본격적으로 쓰기 전에 찾아서 다행이었다. 자세한 내용은 적지 않는다.
10월 2일: 수업에 맞춘 기능, 그리고 더 빠른 모델을 포기한 날
이날은 수업에서 바로 쓸 것들을 붙였다.
- 퀴즈: 문항 수, 난이도, 유형을 고르면 문제를 낸다. 코드 결과를 예측하는 문항은 격리 환경에서 실제로 실행해 정답을 확인하고, 틀렸으면 자동으로 고친다. 다른 과목 정답은 자동 검증이 안 된다. 그래서 "교사 확인 필요"라고 화면에 표시한다.
- 발표자료와 보고서: 예전에는 답변을 줄 단위로 잘라 슬라이드에 붙였다. 지금은 모델이 JSON 개요를 짜고, 코드로 검사한 뒤, 별도 프로세스에서 PPTX·PDF·HWPX로 만든다. Cloudflare의 100초 응답 제한에 걸려서 생성 작업은 백그라운드로 돌렸다.
- 피코 배선도: 모델이 그리게 하지 않는다. 데이터시트 핀맵과 검증된 배선표로만 그린다. 센서 이름이 나오면 그 배선표를 프롬프트에 넣는다. 그래서 답변 속 핀 번호와 그림이 일치한다.
- 진로 탐색: 선택지를 2~4개 보여주고 탐구 과제를 낸다. 생활기록부 대필은 거절한다. 등급 컷을 단정하지 않는다. 위기 신호가 보이면 1388을 안내한다.
- 음성: Whisper를 서버 안에서 돌린다. 음성 파일은 저장하지 않는다.
같은 날 오후에는 Qwen3.8 Flash-Next를 시험했다. 이미지를 직접 빌드했는데, 레시피에 있던 hybrid 변환은 스냅샷 구조가 달라 실패해서 빼고 진행했다.
| 동시 요청 | 27B 전체 tok/s | Flash-Next 전체 tok/s |
|---|---|---|
| 1 | 23.5 | 25.5 |
| 8 | 120.3 | 75.6 |
| 16 | 186.3 | 114.6 |
| 25 | 188.9 | 108.2 |
혼자 쓸 때는 Flash-Next가 조금 빨랐다. 그런데 8명이 넘어가면 전체 처리량이 27B의 60% 정도로 떨어졌다. 124GiB짜리 가중치를 받아 이미지까지 빌드했지만 운영에는 넣지 않았다. 40명 수업에는 맞지 않는 모델이었다.
이날 정답 검사에서 가장 부끄러운 걸 발견했다.
| 질문 | 27B 답 | Flash-Next 답 | 내 채점기 |
|---|---|---|---|
| 훈민정음 반포 연도 | 1443 (틀림) | 1446 | 27B도 정답 처리 |
print(len(a), a is b, len(c)) 결과 |
4 True 4 (틀림) | 4 True 4 (틀림) | 둘 다 오답 처리 |
27B는 1443이라고 답하고 근거 문장에 "1446년에 반포"라고 썼다. 내 채점기는 답에 "1446"이라는 글자가 들어 있는지만 봤다. 그래서 정답으로 셌다. 모델보다 내 채점기가 먼저 틀렸다. 코드 문제는 두 모델 다 틀렸다. 그래서 코드는 말로 믿지 않고 실제로 돌려 본다는 원칙을 더 굳혔다.
하드웨어 계획도 하나 접었다. Spark 두 대를 묶어 큰 모델을 나눠 돌리려면 ConnectX-7 직결이 필요하다. 그런데 이 장비의 lspci에는 ConnectX-7이 보이지 않았다. 대신 두 대를 쓰게 되면 역할을 나누는 쪽으로 바꿨다. 한 대는 학생 대화, 한 대는 무거운 작업이다.
10월 9일: 하네스, 실패한 파서, 그리고 0.667
모델이나 설정을 바꿀 때마다 "느낌상 괜찮다"로 넘어가는 게 싫었다. 그래서 하네스를 만들었다. 핵심은 운영 코드와 같은 경로로 채점한다는 점이다. 발표자료 생성은 운영 서버가 실제로 쓰는 DECK_PROMPT와 clean_deck를 그대로 불러다 쓴다. 대체 경로 없이 통과해야 점수를 준다.
| 영역 | 문항 | 확인하는 것 |
|---|---|---|
| 코딩 | 3 | 생성한 코드를 실행해 assert 통과 |
| 발표자료 | 2 | 운영 파이프라인 그대로 개요 생성·검증 통과 |
| 환각 | 3 | 없는 책·논문·사람을 물으면 "모릅니다"라고 하는지 |
| 수업 적합성 | 2 | 눈높이에 맞는 간결한 설명, 숙제 대신 해 달라는 요청 거절 |
이날 tool calling을 켜려고 했다. 처음에는 hermes 파서를 썼는데 모델은 XML 형식으로 도구를 부르고 있었다. 형식이 안 맞아 도구 호출이 하나도 파싱되지 않았다. qwen3_xml 파서로 바꾸고 나서야 됐다.
그다음 하네스를 돌렸는데 환각 점수가 0.667이 나왔다. "가짜 교수님 논문" 질문 하나에 그럴듯하게 답을 지어냈다. 파서를 바꿔서 모델이 나빠진 줄 알았다. 그런데 같은 질문을 네 번 더 물으니 네 번 다 제대로 거절했다. 한 번 물어서 나온 결과가 샘플링 운이었던 것이다.
그래서 하네스를 고쳤다. 거절 판정은 세 번 물어 다수결로 정한다. 지금 기준선은 10개 항목 전부 1.0이고, 응답 속도는 25.5 tok/s다. 운영 설정은 문맥 32K, 동시 25개다. tool calling을 켜면서 9월 23일 설정(16K, 동시 40개)에서 바꿨다. 동시 수를 줄인 만큼 40명 수업에서 줄을 서는지는 아직 실제 수업으로 확인하지 못했다.
10월 11일: AI에게 얼마나 맡기고 있나
마지막으로 넣은 건 "인지적 외주 지수"다. 최근 질문 20개를 본다. "만들어줘, 답만, 복붙" 쪽인지 "내 풀이 봐줘, 왜, 힌트" 쪽인지 규칙으로 나눠 비율을 보여준다. 블랙박스 분류기를 쓰지 않은 건 학생이 왜 그 점수가 나왔는지 직접 볼 수 있어야 해서다. 기록은 학생 기기에만 남고 서버로 보내지 않는다.
같은 날 처음으로 git 저장소를 만들었다. 그동안은 날짜별 백업 폴더 14개로 버텼다. 점검 보고서에 "git 저장소가 아님"이라고 적혀 있던 걸 그제야 고쳤다.
아직 못 한 것
- 실제 40명 수업 한 시간 전체를 돌린 기록이 없다. 지금 숫자는 전부 서버 안에서 만든 합성 부하다.
- 퀴즈 정답 자동 검증은 코드 문항만 된다.
- 음성 에이전트를 설치했는데 이 PC에는 마이크가 없다. 지금은 무음만 듣고 있다.
- 미세조정은 하지 않았다. 교사가 승인한 질문·답변이 쌓이면, 같은 하네스를 통과하는 경우에만 바꿀 생각이다.
- 외부 검색에 학생 질문이 나간다는 안내 문구가 실제 동작과 다른 곳이 남아 있다.
결국 중요한 건 하나였다. 숫자가 좋아 보일수록 측정 방법부터 의심해야 한다. 0.667도, 1443도, 1,118도 모델보다 내 측정이 먼저 틀렸다.