모든 쿼리에 GPT-4를 쓰는 낭비
"날씨 알려줘"와 "복잡한 계약서 분석"에 같은 모델을 쓰는 것은 비효율적입니다. LLM 라우팅과 앙상블은 정확도는 유지하면서 비용을 30~70% 절감할 수 있습니다.
LLM 라우팅: 쿼리 복잡도 기반 분류
Python
from sklearn.linear_model import LogisticRegression
import numpy as np
class QueryRouter:
"""쿼리 복잡도를 분류해 적합한 모델로 라우팅"""
COMPLEXITY_LEVELS = {
"simple": "claude-haiku-4-5", # 단순 조회, FAQ
"medium": "claude-sonnet-4-6", # 일반 추론
"complex": "claude-opus-4-7", # 복잡한 분석, 코드
}
def __init__(self):
self.classifier = LogisticRegression()
# 특징: 토큰 수, 코드 포함 여부, 수치 복잡도, 도메인 키워드 수
self.feature_extractors = [
lambda q: len(q.split()),
lambda q: int(any(kw in q for kw in ["코드", "함수", "구현", "sql"])),
lambda q: q.count("?"),
lambda q: int(len(q) > 200),
]
def extract_features(self, query: str) -> np.ndarray:
return np.array([f(query) for f in self.feature_extractors]).reshape(1, -1)
def route(self, query: str) -> str:
if not hasattr(self.classifier, "classes_"):
return "medium" # 미학습 시 기본값
level = self.classifier.predict(self.extract_features(query))[0]
return self.COMPLEXITY_LEVELS[level]
async def query(self, user_input: str) -> str:
model = self.route(user_input)
return await llm_call(model, user_input)규칙 기반 라우팅 (빠르고 예측 가능)
Python
def simple_router(query: str) -> str:
tokens = len(query.split())
has_code = any(kw in query.lower() for kw in ["코드", "sql", "함수", "알고리즘"])
has_numbers = sum(c.isdigit() for c in query) > 5
is_long = tokens > 100
if has_code or (is_long and has_numbers):
return "claude-opus-4-7"
elif tokens > 30 or has_numbers:
return "claude-sonnet-4-6"
else:
return "claude-haiku-4-5"폴백 체인: 정확도 보장
빠른 모델이 실패하거나 신뢰도가 낮으면 더 강력한 모델로 승격합니다.
Python
async def escalating_query(query: str) -> dict:
models = [
("claude-haiku-4-5", 0.85), # (모델, 신뢰도 임계값)
("claude-sonnet-4-6", 0.90),
("claude-opus-4-7", None), # 최종 — 임계값 없음
]
for model, threshold in models:
response = await llm_call(model, query)
confidence = await estimate_confidence(response)
if threshold is None or confidence >= threshold:
return {
"answer": response,
"model_used": model,
"confidence": confidence
}
print(f"{model} 신뢰도 {confidence:.2f} < {threshold} → 상위 모델로 승격")앙상블: Mixture-of-Experts 경량 구현
Python
async def ensemble_query(query: str, models: list, weights: list = None) -> str:
responses = await asyncio.gather(*[llm_call(m, query) for m in models])
if weights is None:
weights = [1.0] * len(models)
# 응답을 임베딩으로 변환 후 가중 평균 클러스터링
embeddings = await asyncio.gather(*[embed(r) for r in responses])
centroid = np.average(embeddings, axis=0, weights=weights)
# 클러스터 중심에 가장 가까운 응답 선택
distances = [np.linalg.norm(e - centroid) for e in embeddings]
best_idx = np.argmin(distances)
return responses[best_idx]비용 대비 성능 측정 결과
실제 고객 서비스 챗봇 적용 결과 (월간 10만 건 기준):
| 전략 | 비용 | 정확도 | P95 지연 |
|---|---|---|---|
| 모두 Opus | $1,200 | 92% | 3.2s |
| 모두 Sonnet | $380 | 85% | 1.8s |
| 라우팅 (본문) | $340 | 91% | 2.1s |
| 폴백 체인 | $420 | 93% | 2.4s |
라우팅 전략이 단일 Opus 대비 72% 비용 절감, 정확도 1%p 차이로 최적점을 보여줍니다.
프로덕션 적용 시 주의사항
- 라우터 학습 데이터: 최소 500개 레이블된 쿼리 필요
- A/B 테스트: 라우터 도입 전후 품질 지표 비교 필수
- 폴백 로깅: 어떤 쿼리가 상위 모델로 승격되는지 추적
- 비용 모니터링: 라우터 오분류로 비용이 증가할 수 있음
이 3편 시리즈로 LLM 성능 향상의 핵심(RAG→파인튜닝→라우팅/앙상블)이 완성됩니다.
라우터가 잘못 보내는 요청 찾기: 측정과 조정
라우팅으로 비용을 줄였는데 사용자 불만이 늘었다면, 어려운 요청이 저가 모델로 잘못 분류되고 있을 가능성이 큽니다. 절감률은 라우터의 오분류율을 같이 봐야 의미가 있습니다.
원인
- 규칙 기반 라우터가 입력 길이·키워드만 보고 판단해, 짧지만 어려운 질문(계산, 다단계 추론)을 쉬운 요청으로 분류
- 분류기 학습 데이터가 오래돼 새 요청 유형을 모름
- 폴백 조건이 "API 오류"에만 걸려 있고, "품질 미달"에는 반응하지 않음
측정 방법
- 저가 모델로 처리된 요청에서 매일 일정 수를 무작위로 뽑아, 같은 입력을 상위 모델에도 보내고 두 답을 비교 채점합니다(사람 또는 별도 평가 모델).
- "상위 모델 답이 명확히 더 나은 비율"을 라우터 오분류율로 기록합니다.
- 사용자가 재질문·재생성을 누른 비율을 경로별로 나눠 봅니다.
SQL
SELECT route, count(*) AS n,
avg(CASE WHEN regenerated THEN 1 ELSE 0 END) AS regen_rate
FROM llm_requests WHERE created_at > now() - interval '7 days'
GROUP BY route;조정
- 오분류가 많은 유형을 찾아 규칙에 추가하거나, 분류기의 판단 확신도가 낮으면 상위 모델로 보내는 임계값을 둡니다.
- 출력 검증(JSON 스키마 실패, 답변 거절 문구 등)에 걸리면 상위 모델로 재요청하는 품질 기반 폴백을 추가합니다.
재발 방지
- 절감 비용과 오분류율, 재생성률을 한 대시보드에 두고, 오분류율이 기준을 넘으면 라우팅 비율을 자동으로 보수적으로 되돌립니다.
✦ ✦ ✦
출처·검증 안내
글마다 출처와 확인 범위가 다릅니다. 아래에 확인일·확인 범위·출처가 기록된 글만 그 범위에서 확인된 것입니다. 기록이 없는 글은 적용 전 사용 중인 버전의 공식 문서로 직접 확인하고, 오류는 이메일로 알려주세요. 편집 정책 · 이메일로 제보
이 글에는 사람이 확인한 날짜·범위 기록이 아직 없습니다.
주제 관련 공식 문서(자동 연결 · 문장별 근거 아님)OpenAI 공식 문서 ↗
이 글이 도움이 되었나요?
댓글
첫 번째 댓글을 남겨보세요.