작은 로컬 모델 다루기
그리고 클라우드 모델과 임대 GPU를 쓸 때 걸리는 것
품앗이가 사무실 서버의 작은 GPU, GPU 없는 현장 서버, 임대 GPU, 클라우드 모델을 함께 쓰며 잰 기록을 다른 조직이 다시 쓸 수 있게 옮긴 글입니다. 모델과 도구 이름은 다시 해 볼 수 있도록 공개된 이름 그대로 적었습니다. 묶음 전체는 조직 AI 만들기에서 볼 수 있습니다.
요지
작은 로컬 모델에게는 지능을 기대하지 말고 골라내는 일만 시킵니다. 사진은 비전 모델보다 OCR이 먼저이고, 음성 엔진은 설치가 아니라 실제로 알아들을 수 있는 소리가 나는지로 판정합니다. 클라우드 모델과 임대 GPU에는 그 나름의 규칙이 있습니다. 출력 상한에 생각하는 토큰이 섞이고, 주제 자체로 막히기도 하고, 쉬는 GPU는 회수당합니다. 어느 모델에 무엇을 보낼지는 데이터 주권의 잣대를 한결같이 대서 정합니다.
1. 지능을 기대하지 말고 「골라내기」만 시킨다
6GB GPU에서 도는 7~8B 로컬 모델에게는 「만들어 내라」 대신 「골라내라」고 시킵니다. 환각은 생성에서 나오고, 주어진 것 가운데 고르는 일은 지어낼 여지가 거의 없기 때문입니다. 시킬 일과 시키지 않을 일, 그리고 같은 입력에도 결과가 흔들린다는 실측은 반복되는 일은 로컬 AI로 4절에 있습니다. 여기서는 그 위에 보탤 것만 적습니다.
- JSON 스키마 같은 정해진 형식은 추출과 분류에만 씌웁니다. 7
13B 모델에 스키마를 강제하면 형식은 지켜도 뜻의 정확도가 515% 떨어진다는 연구가 있습니다. 다만 우리가 복사에 가까운 추출 8건으로 잰 실측에서는 떨어지지 않았는데, 표본이 작아 확신할 수는 없습니다. - 정규식과 모델을 둘 다 돌려 결과를 합칩니다. 기록에 따르면 모델이 놓친 1건을 정규식이 잡았습니다.
- 모델이 자기 답에 확신이 낮으면 상위 모델로 넘깁니다.
- 그 실측의 성적은 지어낸 항목 0/38건, 찾아낸 비율 94%였습니다. 그러니 「전부 잡았다」고 말하면 안 됩니다.
- 검산하는 코드도 함정이 될 수 있습니다. 완전 일치만 보는 대조는 백틱이나 가운뎃점 때문에 멀쩡한 결과를 환각으로 오판했으니, 구두점을 걷어 낸 뒤에 대조합니다.
이름을 사람처럼 붙이지 않는 것도 기록에 남은 원칙입니다. 사람 이름을 주면 인격을 기대하게 되고, 그러면 판단이나 요약을 시키고 싶어집니다. 작은 모델의 값어치는 토큰을 아끼는 데 있지 않고, 그동안 아까워서 안 시키던 일을 시킬 수 있게 되는 데 있습니다.
기록에는 운용하면서 밟은 함정도 세 가지 남아 있습니다.
- 쓰레기를 넣고 모델더러 가려내라 하지 않습니다. 임계값 없이 자료를 긁어 왔더니 모델이 고른 13건 가운데 9건이 내려받기 0회인 습작이었습니다. 거르는 일은 수집하는 코드의 몫이라, 최소 내려받기 수나 별 수 같은 임계값을 코드에 넣고 설명이 빈 항목도 코드가 뺍니다.
- 컨텍스트 길이는 그 기계에서 재 봅니다. 기록에는 6GB GPU에서 컨텍스트를 8192로 올렸다가 런타임이 죽은 일이 있고, 몇 달 뒤 다른 버전과 설정에서는 같은 길이가 돌았습니다. 한계는 버전과 설정마다 다르니 넘기면 느려지는 것이 아니라 멈출 수도 있다고 보고 실제로 재 봅니다.
- GPU를 쓰고 있다고 믿지 말고 확인합니다. 한 서버에서는 부팅 직후 GPU를 찾는 과정이 제한 시간을 넘겨 실패하는 바람에, 모델이 내내 CPU로 돌고 있었습니다. 같은 7.8B 모델이 같은 지시문을 GPU에서 47초에, CPU에서 462초에 처리했습니다. 실행 기록에서 어느 장치로 돌았는지 찍어 봅니다.
오래된 GPU는 시한부라는 것도 기록이 짚은 점입니다. 실행 기록에 「compute capability not in compiled architectures」 같은 줄이 찍히고 예전 CUDA 묶음으로 넘어가서 돌고 있다면, 그 묶음이 빠지는 날 그 GPU는 쓸 수 없게 됩니다. 모델 파일은 SSD에 두는데, 같은 4.8GB 모델을 처음 불러오는 데 하드디스크에서는 40초, SSD에서는 13초가 걸렸습니다. 쉬면 모델을 내리는 런타임이라면 가끔 도는 야간 작업은 매번 이 로딩을 치릅니다. 이런 측정을 할 때는 운영체제의 파일 캐시를 먼저 비웁니다. 비우지 않고 쟀을 때는 「별 차이 없다」는 틀린 숫자가 나왔습니다.
2. GPU 없는 서버에서 사진을 읽을 때는 OCR이 먼저다
GPU 없이 2코어에 램 19GB인 현장 서버에서 서류 사진 한 장을 읽혀 본 기록이 있습니다. 작은 비전 모델은 130~238초가 걸렸고, PaddleOCR 한국어 모델은 5초 만에 한글과 숫자를 정확히 읽었습니다. 읽은 글자를 1.2B 모델로 JSON에 정리하는 데 7초가 더 들었는데, 숫자는 맞았지만 이름과 날짜 칸은 놓쳤습니다.
그 과정에서 밟은 것들은 아래와 같습니다.
- oneDNN 관련 오류가 나면
enable_mkldnn=False를 줍니다. lang="korean"만으로는 한글이 비어 나와서, 한국어 인식 모델 이름을 직접 지정해야 했습니다.- 어떤 GGUF 모델은 런타임에서 시스템 메시지를 버립니다. 프롬프트 토큰 수가 21처럼 지나치게 작게 찍히면 지시문이 빠진 것이니, 지시문을 사용자 메시지에 합쳐 넣습니다. 그런 상태에서 잰 시간은 측정이 아닙니다.
- 9천 자짜리 지시문을 단 챗봇은 CPU에서 지시문을 읽는 데만 250~378초가 걸렸습니다. GPU 없는 서버에서는 지시문 길이가 벽입니다.
3. 음성: 설치 성공과 쓸 수 있음은 다르다
자체 호스팅할 한국어 음성 합성 엔진을 실제로 돌려 본 기록입니다.
| 엔진 | 결과 |
|---|---|
| MeloTTS | 일본어 형태소 분석기, Rust 컴파일, Java로 이어지는 의존성 때문에 설치 단계에서 막힘 |
| Piper | 공개 음성 저장소의 전 언어 폴더를 확인해 보니 한국어 음성이 아예 없음 |
| Coqui XTTS-v2 | 불러오기는 되지만 「안녕하세요」가 6.7초로 늘어지고, 긴 문장은 지어내거나 끊김 |
| facebook/mms-tts-kor | 채택. 의존성이 거의 없고, 16kHz로 바로 나오고, 속도가 자연스러움. 단, 여성 화자 한 명뿐 |
엔진 판정은 세 단계까지 갑니다. 실제 한국어 문장을 합성하고, 소리의 길이와 속도를 확인하고, 음성 인식으로 되받아 원문과 같은지 봅니다. 설치가 통과하고 모델이 올라와도 이 세 단계에서 떨어지는 엔진이 있었습니다.
음성 입출력을 붙이는 첫째 이유가 접근성일 수 있습니다. 앞을 잘 보기 어려운 사용자에게는 말로 묻고 답을 들어서 듣는 것이 사실상 유일한 길입니다. 기록에 남은 화면은 음성으로 물었을 때만 답을 자동으로 읽어 주고, 저시력 모드를 켜면 글씨와 버튼을 키우고 늘 읽어 주게 했습니다.
녹음을 글로 옮길 때는 faster-whisper large-v3를 묶음 처리와 무음 구간 거르기로 돌렸습니다. 녹음기를 끄지 않아 몇 시간 동안 무음과 딴소리가 녹음된 파일에서는 「이 영상은 제작진이…」 같은 엉뚱한 문장이 찍혔습니다. 시간대별 글자 수 분포와 앞뒤 문맥을 보고 실제 내용이 끝나는 지점을 잘라 냅니다.
4. 클라우드 모델을 쓸 때 걸리는 것
생각하는 모델은 출력 상한에 생각하는 토큰까지 포함합니다. 기록에 따르면 출력 상한을 500으로 줬더니 생각이 481토큰을 먹어 실제 출력은 15토큰이었고, JSON이 중간에 잘렸습니다. 채점, 분류, 추출에는 생각 기능을 끕니다. 「응답은 오는데 내용이 비거나 잘린다」면 끝난 이유와 생각 토큰 수부터 봅니다.
프롬프트에서 부딪친 일도 기록에 남아 있습니다.
- 「간결하게」와 「150
400자」를 함께 쓰면 서로 충돌해서, 모델은 「간결하게」만 따랐습니다. 글자 수 대신 「35문장으로 된 완성된 문단」처럼 형태로 지정합니다. - 예시로 준 답이 짧으면 모델은 지시보다 예시의 길이를 따라 합니다.
- 미리보기 버전 모델은 답 대신 자기 평가 체크리스트를 내놓기도 했습니다. 대량으로 만들 때는 안정 버전을 씁니다.
외국 클라우드 모델은 주제 자체로 막기도 합니다. 한 나라의 정치와 제재가 얽힌 주제의 자료를 검토하게 했더니 고유명사를 가려도 세 번 모두 「민감한 콘텐츠」로 거절됐고, 아무 주제나 넣은 대조 호출은 정상이었습니다. 문서를 쪼개거나 낱말을 바꿔 우회하지 않습니다. 그렇게 하면 검토하려던 뜻 자체가 사라집니다. 나라마다 모델은 그 나라 권력의 기본값을 갖고 있습니다. 다른 관점의 교차 검토가 필요하면 모델을 바꾸기보다 1차 자료와 현장 경험자의 검토로 합니다.
데이터 주권의 잣대는 한결같이 댑니다. 클라우드 API는 회사의 국적과 상관없이 모두 모델 회사가 데이터를 받는 같은 칸입니다.
| 단계 | 모양 |
|---|---|
| 완전 주권 | 우리 하드웨어에서 공개 가중치 모델을 돌리고, 외부 통신이 없음 |
| 부분 주권 | 임대한 서버에서 우리가 직접 모델을 돌림. 모델 회사에는 안 가지만 인프라 회사의 데이터센터 안에 있음 |
| 주권 없음 | 클라우드 API. 모델 회사가 데이터를 받음 |
민감한 데이터는 어느 외부 모델에도 보내지 않습니다. 특정 나라의 회사만 위험하다고 말하면서 자기가 쓰는 클라우드를 빼면 이중 잣대입니다. 어느 회사를 쓸지는 주권이 아니라 비용과 성능으로 고릅니다. 클라우드 모델은 제공 회사나 그 나라 정부의 결정으로 접근이 끊길 수 있지만, 공개 가중치 모델은 한 번 내려받으면 어느 정부도 끊을 수 없습니다.
5. 임대 GPU와 공공 GPU의 규칙
임대 GPU는 쉬고 있으면 회수됩니다. 기록에 따르면 업체 쪽 장비 점검으로 작업이 죽은 뒤 GPU 사용률 0%가 6시간 쌓이자 자원이 자동으로 회수됐고, 15시간이 지나서야 알았습니다. 모델을 메모리에 올려 두는 것만으로는 사용률이 오르지 않고, 호출할 때만 오릅니다. 막을 수 있었던 자리는 사용률 감시와 끊김 알림이었습니다. 새 세션에서 사용자 폴더에 설치한 패키지가 되살아나지 않는 환경이라면, 몇 번이고 다시 돌릴 수 있는 셋업 스크립트로 환경을 만듭니다.
공공 GPU 지원사업의 자원은 쓰는 목적이 정해져 있습니다. 기록에 남은 공고는 「상업적 AI 서비스 운영과 추론 용도로는 쓸 수 없고, 연구, 기술 검증, 모델 학습 목적으로만 쓴다」였습니다. 다른 모델을 올려 서비스하는 것은 목적 밖의 사용이고, 사용률이 평가 지표라서 오히려 채워야 하는 의무가 붙은 자원입니다. 경계는 「추론이 목적인가」이고, 학습에 딸린 검증용 추론은 허용됩니다.
일곱 줄로 줄이면
- 작은 모델에게는 골라내기만 시키고, 코드로 검산하고, 헷갈리면 위로 넘긴다.
- 쓰레기를 거르는 일은 모델이 아니라 수집 코드에 맡긴다.
- GPU로 돌고 있는지, 컨텍스트 한계가 어디인지는 그 기계에서 잰다.
- GPU 없는 서버의 사진 읽기는 OCR이 먼저다.
- 음성 엔진은 합성, 길이, 되받아 듣기까지 해 보고 판정한다.
- 민감한 데이터는 어느 나라의 클라우드에도 보내지 않는다.
- 임대 GPU는 사용률을 감시하고, 공공 GPU는 정해진 목적 안에서 쓴다.
도구 메모
- Ollama가 어느 장치로 돌았는지 확인: 실행 기록에서
inference compute줄을 찾아 CPU인지 CUDA인지 본다. - 리눅스에서 디스크 속도를 잴 때 관리자 권한으로 캐시 비우기:
sync; echo 3 > /proc/sys/vm/drop_caches - PaddleOCR 한국어:
PaddleOCR(..., enable_mkldnn=False, text_recognition_model_name="korean_PP-OCRv5_mobile_rec")
관련 노드
- 조직 AI 만들기
- 무엇을 만드는가: 데이터와 규칙
- 가중치에 넣을 것과 넣지 말 것
- 한국어 RAG 실전
- 반복되는 일은 로컬 AI로
- 로컬서버를 지킬 때
- 외산 클라우드 코딩 에이전트를 안전하게 격리해 쓰기
작성: 품앗이 · 2026-10-22 · 사무실 서버·현장 서버·임대 GPU 실측 기록 기준