커스텀 모델 파이프라인 구축 가이드
개요
왜 커스텀 모델 파이프라인이 필요한가
SaaS 기반 AI 코딩 도구(예: Kiro, GitHub Copilot)는 빠르게 시작할 수 있지만, 엔터프라이즈 환경에서는 근본적인 한계에 부딪힙니다.
| 제약 | SaaS (Kiro 등) | 자체 호스팅 파이프라인 |
|---|---|---|
| LoRA Fine-tuning | 불가능 | 도메인별 어댑터 학습 가능 |
| 데이터 주권 | 코드가 외부 전송 | VPC 내부에서 완결 |
| 모델 선택 | 제공 모델만 사용 | 오픈소스 모델 자유 선택 |
| 비용 제어 | 토큰 단가 고정 | SLM Cascade로 66% 절감 가능 |
| 고객별 최적화 | 범용 모델 공유 | Multi-LoRA로 고객별 특화 |
Base Model + LoRA 어댑터 패턴으로 하나의 GPU 위에 여러 도메인 전문 모델을 동시에 서빙합니다. 기본 모델 가중치를 공유하므로 GPU 메모리 효율이 극대화됩니다.
파이프라인 전체 흐름
학습 파이프라인에서 도메인 데이터를 QLoRA로 학습하고, 평가를 통과한 어댑터만 레지스트리에 등록합니다. 서빙 파이프라인에서는 vLLM Multi-LoRA로 여러 어댑터를 동시에 로드하고, Bifrost Cascade를 통해 SLM/LLM 간 비용 최적화 라우팅을 수행합니다.
- 운영 & 거버넌스 - 전체 운영 아키텍처
- 커스텀 모델 배포 가이드 - Kiro vs 자체 호스팅 비교 포함
LoRA 학습·배포 파이프라인 (도메인 특화)
이 섹션은 도메인 특화 전략에서 LoRA Fine-tuning과 Multi-LoRA 핫스왑 배포를 실제로 구현하는 방법을 다룹니다. 도메인 특화의 전략적 배경과 의사결정 기준은 도메인 특화 (LoRA + RAG)를 참조하세요.
LoRA Fine-tuning 파이프라인
QLoRA GPU 절감
QLoRA(Quantized LoRA)는 기본 모델을 INT4로 양자화한 상태에서 LoRA 어댑터만 학습하는 기법입니다. Full Fine-tuning 대비 GPU 요구사항을 극적으로 줄여줍니다.
| 모델 | Full Fine-tuning | LoRA (FP16) | QLoRA (INT4) |
|---|---|---|---|
| Llama-3.3-70B | H100x16+ (비현실적) | H100x2~4 | H100x1 |
| VRAM | ~840 GB (BF16+AdamW) | ~142-180 GB | ~40 GB |
| 학습 시간 | - | 5일 | 2-3일 |
| 비용 | - | $8,000 | $2,000 |
QLoRA는 학습 중 기본 모델 가중치를 INT4로 유지하므로, 극히 정밀한 수치 연산이 필요한 태스크(예: 금융 계산)에서는 LoRA(FP16) 대비 미세한 정확도 차이가 발생할 수 있습니다. 도메인 평가 단계에서 반드시 검증하세요.
학습 데이터 형식
학습 데이터는 JSONL 형식의 입력-출력 쌍으로 준비합니다.
{
"input": "COBOL: PERFORM CALC-INTEREST USING WS-PRINCIPAL WS-RATE.",
"output": "Java: @Transactional public BigDecimal calcInterest(BigDecimal principal, BigDecimal rate) { return principal.multiply(rate).setScale(2, RoundingMode.HALF_UP); }"
}
데이터 수집 전략:
| 소스 | 변환 방법 | 예상 데이터량 |
|---|---|---|
| 레거시 COBOL 코드 | COBOL → Java 변환 쌍 생성 | 10,000+ 모듈 |
| 사내 프레임워크 | 프레임워크 패턴 → 코드 쌍 | 5,000+ 패턴 |
| 코드 리뷰 히스토리 | 수정 전 → 수정 후 쌍 | 20,000+ 커밋 |
| 기술 문서 | 문서 → 구현 코드 쌍 | 3,000+ 페이지 |
데이터 양보다 품질이 중요합니다. 시니어 개발자가 검수한 1,000개의 고품질 쌍이, 자동 생성된 10,000개보다 효과적입니다. 최소 500개의 검수된 쌍에서 시작하세요.
학습 프레임워크
NeMo Framework (NVIDIA)
대규모 모델 학습에 최적화된 NVIDIA의 공식 프레임워크입니다. Multi-GPU, Multi-Node 분산 학습을 네이티브로 지원합니다.
python train_lora.py \
--config-path=conf \
--config-name=llama3_70b_lora \
model.data.train_ds.file_path=cobol_to_java.jsonl \
model.peft.lora_tuning.adapter_dim=16
adapter_dim(rank): 16이 일반적. 복잡한 도메인은 32~64까지 증가 가능adapter_dropout: 0.05 권장 (과적합 방지)target_modules: attention layer (q_proj,k_proj,v_proj,o_proj)
Unsloth (최대 2배 빠른 학습)
단일 노드에서 LoRA/QLoRA 학습 속도를 최대 2배 높이고 VRAM 사용량을 최대 70%까지 절감하는 오픈소스 라이브러리입니다 (Unsloth 자사 벤치마크 기준).
from unsloth import FastLanguageModel
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="meta-llama/Llama-3.3-70B-Instruct",
max_seq_length=4096,
load_in_4bit=True, # QLoRA: INT4 양자화
)
model = FastLanguageModel.get_peft_model(
model,
r=16, # LoRA rank
lora_alpha=32, # LoRA scaling factor
target_modules=["q_proj", "k_proj", "v_proj"],
)
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
max_seq_length=4096,
)
trainer.train()
| 프레임워크 | 장점 | 적합한 경우 |
|---|---|---|
| NeMo | Multi-Node 분산 학습, NVIDIA 공식 지원 | H100 클러스터 보유 시, 대규모 학습 |
| Unsloth | 2배 빠른 학습, 메모리 절감, 간편한 API | 단일 노드, 빠른 프로토타이핑 |
체크포인트 관리
학습된 LoRA 어댑터는 S3에 저장하고, MLflow로 버전을 관리합니다.
# 어댑터 저장 구조
s3://model-registry/
└── lora-adapters/
├── bank-ledger/
│ ├── v1.0/adapter_model.safetensors
│ ├── v1.1/adapter_model.safetensors
│ └── latest -> v1.1
├── stock-order/
│ └── v1.0/adapter_model.safetensors
└── insurance-contract/
└── v1.0/adapter_model.safetensors
MLflow에 학습 메트릭(loss, accuracy)과 어댑터 경로를 함께 기록하면, 어떤 데이터셋과 하이퍼파라미터 조합이 최적인지 추적할 수 있습니다.
Multi-LoRA 핫스왑 배포
아키텍처
vLLM의 Multi-LoRA 기능을 활용하면, 하나의 기본 모델 위에 여러 LoRA 어댑터를 동시에 로드하여 고객별 맞춤 서빙이 가능합니다.
기본 모델(예: 70B)은 한 번만 GPU 메모리에 로드됩니다. 각 LoRA 어댑터는 rank 16 기준 약 100-200MB 수준으로, 10개의 어댑터를 동시에 로드해도 추가 메모리는 2GB 미만입니다.
vLLM Multi-LoRA 설정
vllm serve meta-llama/Llama-3.3-70B-Instruct \
--enable-lora \
--lora-modules \
bank-ledger=/models/lora/bank \
stock-order=/models/lora/stock \
insurance-contract=/models/lora/insurance \
--max-lora-rank 16
주요 옵션:
| 옵션 | 설명 | 기본값 |
|---|---|---|
--enable-lora | Multi-LoRA 활성화 | false |
--lora-modules | 이름=경로 형태로 어댑터 등록 | - |
--max-lora-rank | 최대 LoRA rank | 16 |
--max-loras | 동시 로드 가능한 최대 어댑터 수 | 1 |
--max-cpu-loras | CPU 메모리에 캐시할 어댑터 수 | - |
vLLM은 요청 시점에 어댑터를 GPU 메모리로 로드합니다. --max-loras보다 많은 어댑터를 사용하면 스왑 지연 시간(수백ms)가 발생합니다. 자주 사용하는 어댑터 수에 맞게 --max-loras를 설정하세요.
요청 시 어댑터 지정
OpenAI 호환 API로 요청하며, extra_body에 LoRA 이름을 지정합니다.
response = client.chat.completions.create(
model="meta-llama/Llama-3.3-70B-Instruct",
messages=[{"role": "user", "content": "COBOL 원장 코드를 Java로 변환해줘"}],
extra_body={"lora_name": "bank-ledger"}
)
고객별 라우팅 (Bifrost + X-Customer-Domain 헤더)
kgateway의 HTTPRoute를 사용하여 HTTP 헤더 기반으로 고객별 LoRA 어댑터를 라우팅합니다.
# kgateway HTTPRoute - 고객별 LoRA 라우팅
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: lora-routing
spec:
rules:
- matches:
- headers:
- name: X-Customer-Domain
value: bank
backendRefs:
- name: vllm-svc
port: 8000
클라이언트(Aider/Cline) → X-Customer-Domain: bank 헤더 설정 → kgateway → Bifrost → vLLM (lora_name=bank-ledger 자동 매핑)
고객별 추론 추적 및 비용 청구
각 고객의 추론 요청을 LLM 트레이싱 시스템으로 추적하여 LoRA 어댑터별 성능을 모니터링하고 월별 비용을 청구합니다.
from langfuse import Langfuse
langfuse = Langfuse()
trace = langfuse.trace(
name="inference",
user_id="customer-bank-A",
metadata={
"lora": "bank-ledger",
"model": "glm-5-32b",
"domain": "ledger"
}
)
월별 비용 청구 예시:
| 고객 | 요청 수 | 토큰 수 | GPU 시간 | 비용 |
|---|---|---|---|---|
| A은행 | 100,000 | 500M | 50시간 | $2,500 |
| B증권 | 50,000 | 250M | 25시간 | $1,250 |
| C보험 | 30,000 | 150M | 15시간 | $750 |
구현 방법은 Agent 모니터링 및 LLM 트레이싱 배포를 참조하세요.
SLM Cascade Routing (비용 최적화)
Cascade 아키텍처
모든 요청을 대형 모델(LLM)로 보내는 것은 비용 낭비입니다. 요청의 70%는 소형 모델(SLM)로도 충분히 처리 가능합니다.
비용 분석
| SLM 단독 | LLM 단독 | Cascade (70:30) | |
|---|---|---|---|
| 월 비용 | $500 | $8,900 | $3,020 |
| 정확도 | 70% | 95% | 92% |
| 비용 절감 | - | - | 66% |
위 비용 분석 표(70:30 트래픽 가정)를 기준으로 Cascade 도입 시 월 $5,880(연간 $70,560)을 절감할 수 있습니다. 설정에 소요되는 시간은 1-2일 수준입니다. 실제 절감액은 트래픽 구성·복잡도 분포·품질 기준에 따라 달라집니다.
Bifrost Cascade Config
{
"providers": {
"openai": {
"keys": [
{
"name": "slm",
"value": "dummy",
"weight": 0.7,
"models": ["llama-8b"]
},
{
"name": "llm",
"value": "dummy",
"weight": 0.3,
"models": ["glm5"]
}
],
"network_config": {
"base_url": "http://glm5-serving:8000"
}
}
}
}
Bifrost는 2026-06-12 출시된 governance plugin v1.5.19부터 Complexity Router를 지원합니다. 요청을 SIMPLE/MEDIUM/COMPLEX/REASONING 티어로 자동 분류하고 complexity_tier CEL 변수로 라우팅 규칙에 사용할 수 있습니다. 다만 티어 분류만 자동이며 라우팅 규칙은 사용자가 명시적으로 작성해야 합니다. 상세 가이드: Bifrost Complexity Router
SLM 배포 YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-slm
namespace: agentic-serving
spec:
replicas: 1
selector:
matchLabels:
app: vllm-slm
template:
metadata:
labels:
app: vllm-slm
spec:
nodeSelector:
node.kubernetes.io/instance-type: g6.xlarge
containers:
- name: vllm
image: vllm/vllm-openai:latest
command: ["vllm", "serve"]
args:
- "meta-llama/Llama-3.1-8B-Instruct"
- "--served-model-name=llama-8b"
- "--tensor-parallel-size=1"
- "--max-model-len=32768"
- "--host=0.0.0.0"
- "--port=8000"
resources:
limits:
nvidia.com/gpu: 1
ports:
- containerPort: 8000
name: http
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
---
apiVersion: v1
kind: Service
metadata:
name: vllm-slm-svc
namespace: agentic-serving
spec:
selector:
app: vllm-slm
ports:
- port: 8000
targetPort: 8000
protocol: TCP
- GPU: NVIDIA L4 1개 (24GB VRAM)
- 비용: ~$0.805/hr (On-Demand), ~$0.19-0.49/hr (Spot, 지역별)
- 8B 모델 서빙에 충분한 사양
- 참조: 비용 Threshold 분석
평가 파이프라인
LoRA 어댑터 평가 매트릭스
학습된 어댑터는 배포 전 반드시 다중 평가를 통과해야 합니다.
| 평가 방법 | 목적 | 도구 | 자동화 |
|---|---|---|---|
| RAGAS | RAG 정확도 (faithfulness, relevancy) | ragas | CI/CD 통합 |
| SWE-bench | 코딩 퀄리티 (실제 이슈 해결력) | swe-bench | CI/CD 통합 |
| 도메인 전문가 리뷰 | 비즈니스 정합성 검증 | Langfuse Annotation | 수동 |
| Red-teaming | 보안/안전성 (prompt injection 등) | Garak | CI/CD 통합 |
어댑터 배포를 위한 최소 기준:
- RAGAS Faithfulness: >= 0.85
- SWE-bench Resolved: >= 30%
- 도메인 전문가 승인: 3명 중 2명 이상
- Garak 보안 테스트: 0 critical findings
LoRA A/B 테스트
새로운 어댑터 버전을 배포하기 전, LLM 트레이싱 시스템의 태그 기능을 활용한 A/B 테스트로 성능을 비교합니다. 요청 메타데이터에 lora 버전을 태그로 기록하면 대시보드에서 어댑터별 성능을 비교할 수 있습니다.
구현 예시는 Agent 모니터링 - A/B 테스트를 참조하세요.
A/B 테스트 비교 항목:
| 메트릭 | 측정 방법 | 의미 |
|---|---|---|
| 정확도 | SWE-bench / 도메인 테스트 | 코드 변환 정확성 |
| 지연 시간 | LLM 트레이싱 p50/p95 | 응답 속도 |
| 토큰 효율 | output_tokens / input_tokens | 답변 간결성 |
| 사용자 만족도 | Annotation Score | 실제 사용자 평가 |
Phase별 구축 로드맵
| Phase | 기간 | 구성 | 비용 (USD) | 주요 액션 |
|---|---|---|---|---|
| 1 | 즉시 | Base Model + Steering | $8,900/월 (GPU) | vLLM 배포, Bifrost + Langfuse 연동 |
| 2 | 1-2주 | + VectorRAG | +인프라 | Milvus 배포, 내부 문서 임베딩 |
| 3 | 2-4주 | + SLM Cascade | +$500/월 | SLM 배포, Bifrost cascade 설정 |
| 4 | 1-2개월 | + LoRA Fine-tuning | +$2K (1회) | 학습 데이터 수집 → QLoRA → 평가 → Multi-LoRA 배포 |
Phase 4까지 완료 시(가상 시나리오, 아래 전제에 따라 상이):
- COBOL→Java 전환: 10,000 모듈 x 1.5시간 절감 = 15,000시간 절감 (~$750K, 시간당 인건비 가정)
- LoRA 학습 비용: $2,000 (1회)
- 월 운영 비용 절감: $5,880 (Cascade 도입 효과)
- ROI: 약 375배 (절감액 ~$750K ÷ 1회 학습 비용 $2,000 기준)
참고 자료
공식 문서
| 자료 | 링크 |
|---|---|
| LoRA Paper (Hu et al., 2021) | arxiv.org/abs/2106.09685 |
| QLoRA Paper (Dettmers et al., 2023) | arxiv.org/abs/2305.14314 |
| vLLM Multi-LoRA | docs.vllm.ai/en/latest/features/lora/ |
| Unsloth Fast Training | github.com/unslothai/unsloth |
| NeMo Framework | docs.nvidia.com/nemo-framework |
| RAGAS Evaluation | docs.ragas.io |
| Bifrost AI Gateway | docs.getbifrost.ai |
| Agent 모니터링 | agent-monitoring.md |
| LLM 트레이싱 배포 | monitoring-observability-setup.md |
| 커스텀 모델 배포 가이드 | custom-model-deployment.md |
| MLOps 파이프라인 (Kubeflow·MLflow·ArgoCD) | mlops-pipeline-eks.md |
| Continuous Training Pipeline | continuous-training/index.md |