홍쌤의 인포클래스AI + X · 기술 블로그

← 목록

학교 서버 한 대로 운영하는 시나브로 AI: 모델 고르기, 하네스, 그리고 내 측정이 먼저 틀렸던 순간들

작성 2026.10.12 · 수정 2026.10.31 · 홍창민

학교 서버 한 대로 학생들이 쓰는 AI를 운영하고 있다. 이름은 시나브로 AI다.
모델을 고르고, 바꾸고, 시험하는 도구(하네스)를 만들고, 보안을 점검한 3주를 적는다.
여기서 "수업용 튜닝"은 가중치 미세조정이 아니다. 모델 선택, 추론 설정, 프롬프트, 검증 장치를 바꾼 것이다. 미세조정은 아직 하지 않았다.


왜 직접 돌리나

학생 질문을 외부 AI 서비스로 보내지 않기 위해서다. 학생이 무심코 붙여 넣은 이름, 연락처, 과제 파일이 학교 밖으로 나가지 않아야 한다. 그래서 모델도, 대화 기록도, 음성 인식도 학교 서버 한 대(DGX Spark 계열 GB10) 안에서 돌린다. 외부 연결은 Cloudflare 터널 하나뿐이다. 서비스는 전부 127.0.0.1에만 열어 둔다.

구성은 이렇다.

시나브로 AI 첫 화면

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일: 수업에 맞춘 기능, 그리고 더 빠른 모델을 포기한 날

이날은 수업에서 바로 쓸 것들을 붙였다.

같은 날 오후에는 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 저장소가 아님"이라고 적혀 있던 걸 그제야 고쳤다.

아직 못 한 것

결국 중요한 건 하나였다. 숫자가 좋아 보일수록 측정 방법부터 의심해야 한다. 0.667도, 1443도, 1,118도 모델보다 내 측정이 먼저 틀렸다.