로컬 LLM 벤치마크 CP949 오류 해결 및 자동 모델 추천 시스템 구축
로컬 LLM 벤치마크 CP949 오류 해결 및 자동 모델 추천 시스템 구축 경험을 공유합니다. 로컬 모델 연구 및 관리 기능을 강화하세요.
로컬 LLM 벤치마크 실행 중 CP949 인코딩 오류가 발생하거나, 모델 관리 기능이 부족해서 답답하셨나요? 이 글에서는 로컬 모델 연구 및 관리 기능을 강화하면서 겪었던 CP949 인코딩 오류를 해결하고, 자동 모델 추천 시스템을 구축한 경험을 공유하려 합니다.
시도와 함정
처음에는 어드민 페이지에서 간단하게 로컬 모델을 교체하고 벤치마킹할 수 있는 기능을 만들고 싶었습니다. 한국어 벤치마크 질문도 좀 더 다양하게 준비했고요.
// riel_agent/src/app/admin/tabs/LocalModelLabTab.tsx (일부 발췌)
import { Button, Select, Input } from '@mantine/core';
import { useState, useEffect } from 'react';
import {
getLocalModels,
switchLocalModel,
runBenchmark,
getBenchmarkResults,
} from '../../api/admin'; // 실제 API 호출 함수
function LocalModelLabTab() {
const [models, setModels] = useState<string[]>([]);
const [selectedModel, setSelectedModel] = useState<string>('');
const [benchmarkQuestions, setBenchmarkQuestions] = useState<string[]>([]);
const [benchmarkResults, setBenchmarkResults] = useState<any>(null);
useEffect(() => {
// 로컬 모델 목록 불러오기
getLocalModels().then(setModels);
// 한국어 벤치마크 질문 불러오기 (25개 확장)
// ...
}, []);
const handleModelChange = async (modelName: string) => {
await switchLocalModel(modelName); // 실제 모델 전환 API
setSelectedModel(modelName);
};
const handleRunBenchmark = async () => {
const results = await runBenchmark(selectedModel, benchmarkQuestions); // 실제 벤치마크 실행 API
setBenchmarkResults(results);
};
// ... UI 렌더링 ...
return (
<div>
<Select
label="로컬 모델 선택"
data={models}
value={selectedModel}
onChange={handleModelChange}
/>
<Button onClick={handleRunBenchmark}>벤치마크 실행</Button>
{/* 결과 표시 부분 */}
</div>
);
}
export default LocalModelLabTab;
모델 교체와 질문 확장은 어렵지 않게 성공했습니다. 문제는 벤치마크를 실행할 때였습니다. 특히 한국어 데이터로 벤치마킹을 시도하면 CP949 관련 인코딩 오류가 빈번하게 발생했습니다.
UnicodeEncodeError: 'cp949' codec can't encode characters in position 1-3: illegal multibyte sequence
이 오류 메시지를 보면서 처음에는 단순히 한국어 문자열 처리 문제라고 생각했습니다. 그래서 파이썬 파일의 인코딩 설정을 바꾸거나, 문자열을 utf-8로 명시적으로 인코딩/디코딩하는 시도를 해봤죠. 하지만 몇 시간 동안 삽질해도 문제는 해결되지 않았습니다.
# riel_backend/api/local_llm.py (초기 시도 중 일부)import json
def process_text_with_model(text: str, model_name: str) -> str: # ... 모델 호출 로직 ... # 여기서 CP949 오류 발생 # text = text.encode('utf-8').decode('cp949', errors='ignore') # 이런 시도들 # ... pass
원인
몇 시간의 삽질 끝에 문제의 근원을 파악했습니다. 문제는 단순히 파이썬 스크립트 자체의 인코딩 문제가 아니었습니다. 로컬 LLM 워커가 모델 응답을 처리하고 저장하는 과정에서, 특정 환경(특히 Windows)의 기본 인코딩인 CP949로 데이터를 강제로 변환하려는 시도가 있었던 것입니다.
# tools/local_llm_worker/worker.py (문제 발생 지점 추정)
def save_output(output_data: dict): # ... with open(output_file_path, 'w', encoding='cp949') as f: # <-- 여기서 문제 발생 json.dump(output_data, f, ensure_ascii=False) # ...
json.dump 함수는 ensure_ascii=False 옵션을 사용하면 유니코드 문자를 그대로 출력하지만, 파일 쓰기 시 encoding='cp949'로 지정되어 있으면 해당 인코딩으로 변환하려다 오류가 발생했습니다.
해결
해결책은 간단했습니다. 로컬 LLM 워커가 파일을 저장할 때, 명시적으로 utf-8 인코딩을 사용하도록 수정하는 것이었습니다.
# tools/local_llm_worker/worker.py (수정 후)import json
def save_output(output_data: dict): # ... with open(output_file_path, 'w', encoding='utf-8') as f: # <-- utf-8로 변경 json.dump(output_data, f, ensure_ascii=False, indent=4) # indent 추가로 가독성 향상 # ...
이와 함께, 자동으로 모델을 다운로드하고 벤치마킹하며 더 나은 모델을 추천하는 시스템을 구축했습니다.
# tools/local_llm_bench/auto_bench.py (자동 벤치마크 루프)import os import json import time from typing import List, Dict
필요한 함수 임포트 (예: download_model, run_single_benchmark, get_best_model)
from .utils import download_model, run_single_benchmark, get_best_model from ..local_llm_worker.worker import process_prompt # worker 모듈에서 프롬프트 처리 함수 임포트
def auto_benchmark_loop(model_dir: str, benchmark_prompts_path: str, num_iterations: int = 5): current_best_model = None candidate_models = ["model_a", "model_b", "model_c"] # 실제 모델 목록은 동적으로 가져옴
for i in range(num_iterations): print(f"Iteration {i+1}/{num_iterations}") # 1. 후보 모델 다운로드 (아직 없는 경우) for model_name in candidate_models: if not os.path.exists(os.path.join(model_dir, model_name)): print(f"Downloading {model_name}...") download_model(model_name, model_dir) # 실제 다운로드 함수 # 2. 현재 모델 벤치마킹 if current_best_model: print(f"Benchmarking current best model: {current_best_model}") results = run_single_benchmark(current_best_model, benchmark_prompts_path) # 결과 분석 및 저장 # ... # 3. 모든 후보 모델 벤치마킹 all_results: Dict[str, List[float]] = {} for model_name in candidate_models: print(f"Benchmarking candidate model: {model_name}") results = run_single_benchmark(model_name, benchmark_prompts_path) all_results[model_name] = results['scores'] # 예시: 점수 리스트 # 4. 최신 결과 기반으로 최적 모델 선택 new_best_model = get_best_model(all_results) # 실제 최적 모델 선택 로직 if new_best_model != current_best_model: print(f"New best model found: {new_best_model}. Updating...") current_best_model = new_best_model # 어드민 API 등을 통해 시스템에 최적 모델 알림 # switchLocalModel(current_best_model) # 예시 else: print("Current best model remains the best.") time.sleep(60 * 5) # 다음 루프까지 대기
if name == "main": MODEL_DIRECTORY = "/path/to/local/models" # 실제 경로 PROMPTS_FILE = "tools/local_llm_bench/prompts.json" auto_benchmark_loop(MODEL_DIRECTORY, PROMPTS_FILE, num_iterations=10)
이 과정에서 Gemma2:2b 모델이 기존에 사용하던 EXAONE 모델보다 훨씬 뛰어난 성능을 보인다는 것을 발견했습니다. 이 내용을 문서화하여 공유했습니다.
## Gemma2:2b 모델 성능 분석 (2026년 06월 15일 기준)최근 로컬 모델 벤치마크 자동화 시스템을 통해 다양한 모델들의 성능을 비교 분석했습니다. 특히, Gemma2:2b 모델이 기존에 사용하던 EXAONE 모델 대비 한국어 처리 능력 및 전반적인 응답 품질에서 상당한 우위를 보임을 확인했습니다.
주요 관찰 사항:
- 응답 속도: Gemma2:2b는 EXAONE 대비 유사한 응답 속도를 유지하면서도 더 나은 품질의 결과물을 생성했습니다.
- 한국어 이해도: 복잡하고 미묘한 뉘앙스를 가진 한국어 질문에 대해 Gemma2:2b가 훨씬 정확하고 자연스러운 답변을 제공했습니다.
- 창의적 생성: 주어진 프롬프트에 대한 창의적인 응답 생성 능력에서도 Gemma2:2b가 더 높은 점수를 기록했습니다.
이러한 결과는 향후 로컬 LLM 시스템 구축 시 Gemma2:2b 모델을 우선적으로 고려해야 함을 시사합니다.
결과
- 로컬 모델의 연구, 관리, 벤치마킹 기능이 대폭 강화되었습니다.
- 벤치마크 실행 중 발생하던
CP949인코딩 오류가 완전히 해결되어 시스템 안정성이 향상되었습니다. - Gemma2:2b 모델이 EXAONE보다 우수한 성능을 보임을 객관적인 데이터로 확인하고 문서화했습니다.
정리 — 같은 함정 안 빠지려면
- [ ] 로컬 환경에서 파일 입출력 시, 운영체제 기본 인코딩(
CP949on Windows)에 의존하지 말고 항상utf-8을 명시적으로 사용하세요. - [ ] 파이썬의
json.dump사용 시ensure_ascii=False옵션과 함께 파일 쓰기 시encoding='utf-8'을 지정하여 한글 깨짐 및 인코딩 오류를 방지하세요. - [ ] 로컬 LLM 모델 관리 및 벤치마킹 자동화 스크립트를 구축하여 모델 성능 개선 및 효율적인 운영을 도모하세요.
- [ ] 다양한 모델을 정기적으로 벤치마킹하고, 성능 우수 모델을 발견하면 즉시 문서화하고 시스템에 반영하는 프로세스를 만드세요.
- [ ]
UnicodeEncodeError: 'cp949' codec can't encode characters...와 같은 오류 발생 시, 코드 자체의 인코딩 문제뿐만 아니라 시스템 환경 및 파일 입출력 로직 전체를 점검하세요.
태그