새 기능에 LLM을 붙이기로 하고 나면, 다들 비슷한 질문에서 멈춰요. "그래서 어떤 모델을 쓰지?" 보통은 제일 똑똑한 모델을 떠올리죠. 그런데 막상 붙여보면 응답이 느리거나, 한 달 청구서가 예상의 몇 배로 나오거나, 둘 다이기도 해요.
가장 성능 좋은 모델이 항상 가장 좋은 선택은 아니에요. 정확도, 응답 속도, 비용. 이 세 축이 서로 잡아당기거든요. 하나를 끌어올리면 다른 하나가 끌려 내려와요. 그래서 모델 선택은 "제일 좋은 거"를 고르는 문제가 아니라, "이 작업에 맞는 균형점"을 찾는 문제예요.
세 축은 서로 잡아당겨요
먼저 세 축이 어떻게 충돌하는지 짚어볼게요.
정확도는 모델이 원하는 출력을 얼마나 잘 만드는가예요. 보통은 크고 정교한 모델일수록 높아요. 하지만 늘 그렇진 않아요. 작업에 따라 소형 모델로 충분하거나, 오히려 군더더기 없이 더 깔끔한 경우도 있어요.
지연(Latency)은 요청을 보내고 응답을 받기까지 걸리는 시간이에요. 큰 모델은 답을 만드는 데 더 많은 연산이 들어서 느려요. 실시간 대화형 기능에서 응답이 2초만 넘어가도 사용자는 답답함을 느껴요. 챗봇이라면 이게 치명적이에요.
비용은 호출당 토큰 값이에요. 대형 모델은 소형 모델보다 토큰당 단가가 수십 배 차이 나기도 해요. 하루에 수천 번 호출되는 시스템이라면, 이 단가 차이가 그대로 월 운영비로 쌓여요. 프로토타입에선 안 보이다가, 트래픽이 늘면 갑자기 보이기 시작해요.
핵심은 이거예요. 세 축을 동시에 다 만족시킬 순 없어요. 그러니 이 작업에서 무엇을 양보할 수 있는지부터 정해야 해요.
작업 유형이 균형점을 정해요
같은 시스템 안에서도 작업마다 답이 달라요. 세 가지로 나눠볼게요.
구조화된 데이터 추출
청구서에서 금액과 날짜를 뽑거나, 들어온 이메일을 "문의 / 클레임 / 스팸"으로 분류하는 일이에요. 출력 형식이 정해져 있고, 깊은 판단보다 정확한 인식이 중요해요.
이런 작업은 소형 모델로 충분한 경우가 많아요. 프롬프트를 잘 설계하고 출력 형식을 엄격하게 고정하면, 굳이 비싼 모델이 필요 없어요. 비용을 아끼면서 속도까지 챙길 수 있어요. 여기서 대형 모델을 쓰는 건 택시 탈 거리를 헬기로 가는 셈이에요.
자유 형식 요약·초안 작성
고객 문의를 요약하거나, 회의록을 정리하거나, 보고서 초안을 잡는 일이에요. 출력의 품질이 중요하고 약간의 판단이 섞여요.
이 영역에선 모델 성능 차이가 실제로 체감돼요. 다만 "충분히 좋다"의 기준을 어디에 두느냐에 따라 선택이 달라져요. 결과를 사람이 검토하고 다듬는 구조라면, 중간 수준 모델로도 충분할 때가 많아요. 초안은 모델이 8할을 만들고 사람이 2할을 손보면 되니까요.
복잡한 추론
계약서에서 리스크 조항을 찾아내거나, 여러 단계를 거쳐야 하는 의사결정을 지원하는 일이에요. 여기선 대형 모델이 확실히 유리해요. 실시간성보다 정확도가 우선이고, 호출 빈도도 상대적으로 낮거든요. 한 번 틀리면 손실이 큰 작업이라, 비용보다 신뢰가 먼저예요.
실무에서 쓰는 세 가지 접근
이론을 알았으니, 실제로 비용과 속도를 잡는 방법을 볼게요.
작업을 분류해서 모델을 나눠요
한 시스템 안에서 모든 호출에 같은 모델을 쓸 이유가 없어요. 단순·반복 작업에는 소형 모델, 판단이 중요한 작업에는 대형 모델. 이렇게 라우팅하는 게 가장 효과가 커요. 예를 들면 이렇게 작업 유형에 따라 모델을 매핑해 둘 수 있어요.
# 작업 유형 → 모델 라우팅 설정 (예시)
routes:
extract: # 청구서·이메일 파싱
model: small
max_tokens: 512
temperature: 0
summarize: # 문의 요약, 회의록 정리
model: medium
max_tokens: 1024
temperature: 0.3
reason: # 계약서 리스크 분석
model: large
max_tokens: 4096
temperature: 0.2
fallback: medium # 분류 안 되는 요청작업 유형만 분기해도 전체 비용이 눈에 띄게 내려가요. 비싼 모델은 정말 필요한 호출에만 쓰이거든요.
응답을 캐싱해요
같거나 비슷한 입력이 반복되면, 응답을 저장해 두고 재사용하세요. 비용과 지연을 동시에 줄여줘요. 자주 묻는 질문이나 고정된 분류 작업에서 특히 효과적이에요. 입력을 정규화한 뒤 해시를 키로 쓰는 식이면 충분해요.
const cache = new Map<string, string>()
async function ask(prompt: string): Promise<string> {
const key = prompt.trim().toLowerCase()
const hit = cache.get(key)
if (hit) return hit // 캐시 적중: 호출 0, 지연 0
const answer = await callModel(prompt)
cache.set(key, answer)
return answer
}물론 실제 운영에서는 만료 시간(TTL)이나 캐시 크기 제한을 더해야 해요. 하지만 뼈대는 이렇게 단순해요. 반복 호출이 많은 시스템일수록 캐싱 한 줄의 효과가 커요.
모델보다 프롬프트를 먼저 손봐요
같은 모델이라도 프롬프트에 따라 출력 품질이 확 달라져요. 결과가 마음에 안 들 때, 곧장 더 비싼 모델로 올리기 전에 프롬프트부터 다듬어 보세요. 출력 형식을 더 명확히 지시하거나, 예시를 한두 개 넣는 것만으로 해결되는 경우가 많아요. 모델 업그레이드는 그다음이에요. 보통은 이게 가장 싸고 빠른 개선이거든요.
LLM 선택은 한 번 정하고 끝나는 결정이 아니에요. 모델은 빠르게 발전하고, 가격도 계속 바뀌어요. 작년에 비쌌던 성능이 올해는 절반 값에 풀리기도 해요. 그러니 실제 사용 패턴과 비용을 주기적으로 들여다보면서 조정하는 게, 길게 보면 가장 합리적인 운영이에요.