Jupyter Notebook에서 모델이 잘 돌아간다고 끝일까요? 아닙니다. 실제 사용자가 접속할 수 있게 서비스해야 하고, 트래픽이 몰려도 안정적으로 돌아가야 하고, 시간이 지나서 성능이 떨어지면 감지하고 대응해야 합니다. 전통적인 소프트웨어는 코드를 배포하면 끝이지만, AI 모델은 다릅니다 — 2주 전에 95% 정확도였던 모델이 2주 후에는 80%로 떨어질 수 있습니다. 이걸 “모델 드리프트”라고 부릅니다.
MLOps란? — DevOps와의 결정적 차이
MLOps는 Machine Learning Operations의 약자로 DevOps를 ML 영역으로 확장한 개념입니다. 전통 DevOps는 코드를 빌드, 테스트, 배포하는 파이프라인입니다. 핵심은 “코드가 결정론적”이라는 것입니다 — 같은 입력에 같은 출력이 나옵니다. 배포 후에도 동작이 변하지 않죠.
MLOps는 여기에 “데이터”와 “모델”이라는 두 가지 변수가 추가됩니다. 모델의 성능이 데이터에 의존하고, 모델이 확률적으로 작동하며, 모델의 성능이 시간에 따라 변합니다. 그래서 MLOps 파이프라인은 전통 DevOps에 세 가지를 추가합니다. 모델 버전 관리, 모델 레지스트리, 모델 모니터링입니다. DevOps는 “코드를 안정적으로 배포하는 것”이 목표이고, MLOps는 “모델이 시간이 지나도 성능을 유지하는 것”이 목표입니다. 배포가 끝이 아니라 시작인 것이죠.
MLOps가 특히 중요한 이유는 AI 모델의 성능 저하가 조용히 일어난다는 것입니다. 웹 서비스는 서버가 죽으면 500 에러가 뜨니까 바로 알 수 있습니다. 하지만 AI 모델은 응답은 계속하는데 품질이 서서히 떨어집니다. 사용자 불만이 쌓이기 전까지 아무도 모릅니다. 그래서 능동적인 모니터링이 필수입니다.
MLflow로 모델 버전 관리와 레지스트리 구축
MLflow는 가장 널리 쓰이는 오픈소스 MLOps 플랫폼입니다. 학습 실험을 추적하고 모델을 버전 관리하고 배포를 관리할 수 있습니다. 파인튜닝 코드에 MLflow 추적을 추가하면 하이퍼파라미터, 메트릭, 모델 아티팩트를 한눈에 볼 수 있습니다.
import mlflow
mlflow.set_tracking_uri("http://localhost:5000")
mlflow.set_experiment("vib-customer-support-finetuning")
with mlflow.start_run(run_name="qlora-llama3-8b-v1"):
mlflow.log_params({
"model": "meta-llama/Meta-Llama-3-8B",
"method": "QLoRA",
"lora_r": 16,
"epochs": 3,
"learning_rate": 2e-4,
})
trainer.train()
mlflow.log_metrics({
"train_loss": 0.34,
"eval_loss": 0.41,
"eval_accuracy": 0.89,
})
mlflow.transformers.log_model(
transformers_model=model,
artifact_path="model",
)
모델 레지스트리를 사용하면 학습된 모델을 staging 단계로 등록하고 검증을 거쳐 production으로 승격할 수 있습니다. “현재 프로덕션에 어떤 버전이 있는지”, “이전 버전은 무엇인지”를 추적할 수 있고, 문제가 발생하면 이전 버전으로 롤백하는 것도 한 줄이면 됩니다. 모델 레지스트리 없이 모델 파일을 폴더에 저장하면 3개월 후에 “model_v2_final_real_final.pth”가 뭔지 아무도 모르게 됩니다 — 이걸 방지하는 것입니다.
vLLM으로 고성능 LLM 추론 서버 구축
HuggingFace의 pipeline이나 generate로 추론할 수도 있지만 프로덕션에서는 성능이 부족합니다. 동시 사용자가 늘어나면 응답 시간이 급격히 느려집니다. vLLM은 PagedAttention이라는 기술로 GPU 메모리를 효율적으로 사용해서 일반 추론보다 3~5배 빠른 처리량을 보여줍니다.
pip install vllm
vllm serve meta-llama/Meta-Llama-3-8B \
--port 8000 \
--max-model-len 4096 \
--gpu-memory-utilization 0.9 \
--enable-lora \
--lora-modules vib-support=./lora-adapter
vLLM은 OpenAI 호환 API를 제공해서 기존 OpenAI 클라이언트 코드를 그대로 쓸 수 있습니다. 마이그레이션 비용을 크게 줄여주는 장점이 있습니다. 핵심 장점은 동시 처리입니다 — 일반 추론은 한 번에 하나의 요청만 처리하지만 vLLM은 여러 요청을 배치로 처리합니다. 10명의 사용자가 동시에 질문해도 개별 응답 시간이 크게 늘어나지 않습니다. 처리량 기준으로 단일 A100 GPU에서 초당 3000~5000 토큰을 생성합니다.
트러블슈팅 팁입니다. CUDA out of memory가 나면 gpu-memory-utilization을 0.7~0.8로 낮추세요. 응답이 느리면 max-model-len을 줄이세요 — 길이가 길수록 메모리를 많이 씁니다. LoRA 어댑터가 적용되지 않으면 모델명을 vib-support로 정확히 지정했는지 확인하세요. 원본 모델명을 쓰면 어댑터 없이 추론합니다.
모델 드리프트 탐지 — 데이터 분포 변화 감지
배포 후 가장 중요한 작업은 모니터링입니다. 운영 지표(응답 시간, 에러율, 처리량, GPU 사용량)와 ML 지표(예측 정확도, 입력 데이터 분포 변화, 출력 분포 변화)를 모두 추적해야 합니다. 그중 가장 중요한 것이 데이터 드리프트 탐지입니다.
데이터 드리프트는 입력 데이터의 분포가 학습 시점과 달라지는 현상입니다. 예를 들어 고객 지원 봇을 학습할 때는 “환불”, “배송” 관련 질문이 80%였는데, 3개월 후에는 “교환”, “A/S” 관련 질문이 60%가 될 수 있습니다. 입력 분포가 변하면 모델이 학습하지 않은 유형의 질문이 많아져서 응답 품질이 떨어집니다.
import numpy as np
from scipy.stats import ks_2samp
# 학습 시점 입력 길이 분포
train_lengths = np.array([len(q.split()) for q in train_questions])
# 최근 1주일 입력 길이 분포
recent_lengths = np.array([len(q.split()) for q in recent_questions])
# Kolmogorov-Smirnov 검정으로 분포 변화 감지
statistic, p_value = ks_2samp(train_lengths, recent_lengths)
if p_value < 0.05:
print("데이터 드리프트 감지! 모델 재학습 필요.")
p-value가 0.05 이하면 분포가 유의미하게 변했다는 뜻이고 모델 재학습을 고려해야 합니다. 하지만 모든 드리프트가 재학습을 필요로 하는 건 아닙니다. 프로모션 기간에 "할인" 관련 질문이 급증하는 건 정상이고 프로모션이 끝나면 원래 분포로 돌아옵니다. "일시적 변동인가, 영구적 변화인가"를 구분하는 게 드리프트 대응의 핵심입니다.
CI/CD 파이프라인에 AI 배포 자동화 통합
이 모든 과정을 CI/CD 파이프라인으로 자동화합니다. 데이터가 업데이트되거나 정기 재학습 주기가 되면 자동으로 학습, 검증, 배포가 이루어지는 구조입니다. GitHub Actions를 사용한 예시에서는 매주 월요일 새벽에 최신 데이터를 가져오고 모델을 학습하고 평가하고 이전 모델보다 성능이 좋으면 배포합니다.
배포 자동화의 핵심은 "성능이 좋을 때만 배포"라는 조건입니다. 무조건 배포하면 새 모델이 이전보다 성능이 떨어질 수 있습니다. evaluate 단계에서 기존 모델과 새 모델의 성능을 비교하고 기준치를 넘으면 배포하는 구조로 만들어야 합니다. 카나리 배포 전략을 쓰면 더 안전합니다 — 전체 트래픽의 10%만 새 모델로 보내고 에러율과 응답 품질을 모니터링한 뒤 점진적으로 늘리는 방식입니다.
처음부터 전체 파이프라인을 구축할 필요는 없습니다. 수동으로 시작해서 반복되는 작업을 하나씩 자동화하면 됩니다. 가장 먼저 자동화할 가치가 있는 건 모니터링입니다 — 문제를 모르면 대응을 못 하니까요. 그 다음은 모델 버전 관리, 그 다음은 재학습 자동화 순으로 확장하면 됩니다. MLOps는 도구가 아니라 문화입니다. "모델을 배포하고 나서도 계속 관리한다"는 마인드셋이 있어야 합니다.
재학습 파이프라인 — 드리프트 대응 자동화
드리프트가 감지되면 즉시 모델을 재학습해야 합니다. 최근 데이터를 수집하고 라벨링하고 파인튜닝을 다시 돌립니다. 그리고 새 모델을 staging에 올려서 A/B 테스트를 합니다. 기존 모델과 새 모델의 성능을 비교해서 새 모델이 더 좋으면 production으로 승격합니다. 이 전체 과정을 자동화하면 "재학습 파이프라인"이 완성됩니다.
재학습 파이프라인에서 중요한 건 롤백 전략입니다. 새 모델이 배포 후 예상과 다르게 성능이 떨어지면, 즉시 이전 버전으로 되돌릴 수 있어야 합니다. MLflow 모델 레지스트리가 있으면 롤백이 한 줄 코드로 가능합니다. 카나리 배포를 했다면 새 모델 트래픽 비율을 0%로 줄이기만 하면 됩니다. 이런 안전장치 없이 "무조건 최신 모델"으로 서비스하면, 재학습 후 성능 저하가 발생했을 때 복구하는 데 시간이 오래 걸립니다.
팀이 커지면 데이터 엔지니어, ML 엔지니어, DevOps가 각자의 역할을 나눠서 협업해야 합니다. 이때 MLflow 같은 도구가 중심이 되어 모든 팀이 같은 정보를 볼 수 있게 해줍니다. "이 모델이 어떤 데이터로 학습됐고, 언제 배포됐고, 현재 성능이 어떤지"를 모든 팀이 투명하게 공유하는 것이 MLOps 문화의 핵심입니다.
참고 자료
모델 배포 후 서버 운영이 궁금하다면 docker compose로 1분 만에 셀프 호스팅 서비스 띄우기를 읽어보세요. 이 글에서 사용한 MLflow의 공식 문서에서 더 자세한 사용법을 확인할 수 있습니다.



















