LLM API 비용을 60% 절감한 방법: 실제로 효과가 있었던 것들
요약
프로덕션 환경에서 LLM API 비용을 60% 절감할 수 있는 실질적인 전략을 다룹니다. 데이터 기반의 토큰 사용량 계측과 의미적 유사성을 활용한 시맨틱 캐싱(Semantic Caching)의 효과를 강조합니다.
핵심 포인트
- 비용 절감을 위해 먼저 요청 유형별 토큰 사용량을 정확히 계측해야 함
- 출력 토큰보다 반복되는 입력 토큰(시스템 프롬프트, 컨텍스트 등) 최적화가 더 중요함
- 시맨틱 캐싱을 통해 유사한 질문에 대한 중복 API 호출을 방지하여 큰 비용 절감 가능
- 캐싱 적용 시 작업 성격에 맞는 적절한 유사도 임계값 설정이 필수적임
대부분의 프로덕션 AI 프로젝트를 진행하다 보면, 어느 시점에 누군가가 월간 API 청구서를 보고 비용을 줄일 수 있는 방법이 있는지 묻게 됩니다. 대답은 언제나 '예'입니다. 하지만 구체적인 해결책은 실제로 어디에 돈을 쓰고 있는지에 따라 크게 달라집니다.
이 포스트에서는 저희에게 실질적인 변화를 가져다준 기술들을 영향력이 큰 순서대로 다룹니다. 이 중 일부는 돌이켜보면 당연한 것들이고, 몇 가지는 파악하는 데 생각보다 오랜 시간이 걸렸습니다.
돈이 실제로 어디에 쓰이는가
무엇인가를 최적화하기 전에, 무엇이 비용을 유발하는지 알아야 합니다. LLM API 가격 책정은 토큰 (token)을 기준으로 합니다. 입력 토큰 (input tokens)과 출력 토큰 (output tokens)으로 나뉘며, 보통 가격이 다르게 책정되는데 출력 토큰이 더 비쌉니다.
저희가 구축한 대부분의 프로덕션 시스템에서 비용 내역은 다음과 같은 양상을 보입니다. 입력 토큰의 상당 부분은 반복되는 컨텍스트(context)입니다. 즉, 매 요청마다 동일한 시스템 프롬프트 (system prompt), 동일한 검색된 문서 (retrieved documents), 동일한 몇 가지 퓨샷 예시 (few-shot examples)가 전송됩니다. 출력 토큰은 사람들이 예상하는 것보다 종종 더 적은데, 이는 대부분의 실제 작업이 긴 산문보다는 분류 (classification), 추출 (extraction), 또는 짧은 형태의 생성 (short-form generation)을 포함하기 때문입니다.
이것이 시사하는 바는, 가장 큰 이득은 출력을 압축하거나 단순히 모델을 교체하는 것이 아니라, 중복된 입력 토큰을 줄이는 것에서 온다는 점입니다.
저희는 프로덕션 환경의 모든 LLM 호출을 계측하여 요청 유형별 토큰 수를 기록합니다. 이것이 없다면 여러분은 추측만 할 뿐입니다. 다음은 저희가 Django 프로젝트에서 사용하는 미들웨어 (middleware)입니다:
import time
import logging
from dataclasses import dataclass, field
...
일주일 치의 데이터를 확보하면, 어떤 호출 유형이 가장 많은 지출을 차지하는지 정확히 알 수 있습니다. 그 이후의 모든 최적화 노력은 직감이 아닌 이 데이터에서부터 시작되었습니다.
시맨틱 캐싱 (Semantic caching): 우리가 실행한 가장 레버리지가 높은 변화
가장 큰 비용 절감은 시맨틱 캐싱 (Semantic caching)에서 이루어졌습니다. 이는 LLM 응답을 정확한 문자열 일치 (exact string match)가 아닌, 의미적 유사성 (semantic similarity)을 기준으로 캐싱하는 방식입니다. 사용자들은 동일한 질문을 서로 다른 방식으로 던집니다. 시맨틱 캐싱이 없다면, 각기 다른 표현 방식마다 새로운 API 호출이 발생하게 됩니다.
원리는 다음과 같습니다: 입력된 쿼리를 임베딩 (embedding)하고, 유사도 임계값 (similarity threshold) 이상의 유사한 쿼리가 캐시 저장소에 있는지 검색한 뒤, 발견되면 캐싱된 응답을 반환합니다. 진정으로 새로운 요청에 대해서만 LLM을 호출합니다.
import hashlib
import json
from typing import Optional
...
실제로 고객 대상 쿼리 인터페이스의 경우, 트래픽이 발생한 후 첫 몇 주가 지나면 30% 이상의 캐시 히트율 (cache hit rate)을 보이는 것이 일반적입니다. 캐시 조회를 위한 임베딩 호출 비용은 전체 LLM 완료 (completion) 비용의 아주 작은 부분에 불과합니다.
주의할 점 한 가지는 유사도 임계값이 매우 중요하다는 것입니다. 0.95는 사실 관계를 다루는 쿼리에 대해 보수적이고 안전한 수치입니다. 창의적이거나 생성적인 작업의 경우, 캐싱은 대개 전혀 적절하지 않습니다. 사용자들이 서로의 생성된 콘텐츠를 받게 되는 상황은 원치 않기 때문입니다.
품질 저하 없는 프롬프트 압축 (Prompt compression)
시스템 프롬프트 (System prompts)는 시간이 지남에 따라 점점 커집니다. 예외 케이스를 처리하기 위한 지침을 추가하고, 예시를 추가하며, 모델이 하지 말아야 할 행동에 대한 설명을 추가합니다. 머지않아 200 토큰으로 시작했던 시스템 프롬프트가 1,500 토큰으로 늘어나게 되고, 호출할 때마다 모든 토큰에 대해 비용을 지불하게 됩니다.
우리는 여기서 두 가지를 수행합니다. 첫째, 분기별로 시스템 프롬프트의 중복성을 감사 (audit)합니다. 프롬프트에는 모델이 기본적으로 올바르게 처리하거나 유스케이스 (use case)가 진화함에 따라 더 이상 불필요해진 지침들이 포함되는 경우가 많습니다.
둘째, RAG 파이프라인 (RAG pipelines)의 경우, 검색된 컨텍스트 (retrieved context)를 공격적으로 압축합니다. 단순한 방식은 문서 청크 (document chunks) 전체를 검색해 옵니다. 하지만 실제로는 검색된 텍스트의 상당 부분이 특정 쿼리와 무관합니다. 우리는 다음과 같이 압축 단계를 추가합니다.
from openai import OpenAI
client = OpenAI()
...
이 방식은 압축 단계에 약간의 비용을 추가하지만, 메인 모델로 전송되는 컨텍스트의 감소량이 이를 충분히 상쇄하고도 남습니다. 일반적으로 RAG 컨텍스트 길이를 3~4배 정도 줄여줍니다.
모델 라우팅 (Model routing): 작업에 적합한 모델 매칭
모든 LLM 호출에 사용 가능한 가장 강력한 모델이 필요하지는 않습니다. 저희는 각 호출 유형을 해당 작업을 안정적으로 수행할 수 있는 가장 저렴한 모델에 할당하는 간단한 라우팅 레이어 (routing layer)를 유지하고 있습니다.
저희가 사용하는 카테고리는 다음과 같습니다:
- 분류 및 의도 탐지 (Classification and intent detection) — 이 영역에서는 작은 모델들이 큰 모델만큼 성능을 내며, 레이블 세트 (label set)가 잘 정의되어 있을 때는 종종 더 나은 성능을 보이기도 합니다. 저희는 이 작업에
gpt-4o-mini또는claude-haiku를 사용합니다. - 구조화된 문서에서의 정보 추출 (Extraction from structured documents) — 마찬가지입니다. 무엇을 찾고 있는지 알고 있고 문서 형식이 어느 정도 잘 갖춰져 있다면, 작은 모델로도 충분합니다.
- 복잡한 추론, 미묘한 생성, 다단계 계획 (Complex reasoning, nuanced generation, multi-step planning) — 이 영역이 바로 대형 모델의 비용 가치가 증명되는 곳입니다. 이러한 작업은 저렴한 모델로 라우팅하지 마십시오.
- 요약 (Summarisation) — 요구되는 품질에 따라 크게 달라집니다. 내부용 요약 (요약본, 관리자 뷰)의 경우 저렴한 모델로도 충분합니다. 제품을 대표하는 고객 대면용 요약의 경우, 더 우수한 모델을 사용하십시오.
from enum import Enum
from dataclasses import dataclass
...
여기서 핵심적인 원칙은 더 저렴한 옵션을 선택하기 전에 두 가지 모델 계층 (model tiers) 모두를 사용하여 각 작업 유형을 벤치마크 (benchmark) 하는 것입니다. "괜찮아 보인다"는 기준은 충분하지 않습니다. 저희는 각 호출 유형을 50~100개의 실제 운영 사례 (production examples)에 대해 실행하고, 출력을 평가하며, 품질이 허용 가능한 오차 범위 내에 있을 때만 더 저렴한 모델로 라우팅합니다.
시도했지만 효과가 없었던 것들
공격적인 출력 길이 제한 (Aggressive output length constraints). 출력 비용을 줄이기 위해 생성 작업에서 max_tokens를 낮게 설정하는 것을 시도했습니다. 약간의 비용은 절감되었지만 출력이 나빠졌습니다. 모델이 일관성을 해치는 방식으로 텍스트를 잘라버리기 때문입니다. 출력 토큰 비용은 대개 문제가 아닙니다. 여기서 품질을 희생하지 마십시오.
요청 배치 처리 (Batching requests). 배치 API (batch API)는 일부 제공업체에서 비용을 약 50% 절감해주지만, 몇 분에서 몇 시간의 지연 시간 (latency)을 발생시킵니다. 사용자 대면 서비스의 경우, 그 트레이드오프 (tradeoff)는 가치가 없습니다. 지연 시간이 중요하지 않은 오프라인 처리 작업에는 적합합니다.
벤치마크 성능만을 기준으로 제공업체를 완전히 교체하는 것. 우리는 토큰당 비용이 더 저렴한 대안 제공업체들을 평가하는 데 시간을 보냈습니다. 어떤 작업에서는 괜찮았지만, 다른 작업에서는 품질 저하가 유의미하게 나타나 제품에 영향을 미쳤습니다. 벤치마크는 특정 데이터와 특정 작업에서 모델이 어떻게 작동하는지 알려주지 않습니다. 오직 여러분의 실제 워크로드(workload)로 테스트해야만 알 수 있습니다.
솔직한 요약
60%의 비용 절감은 매우 극적으로 들립니다. 실제로 이는 세 가지 요소가 함께 적용되어 얻은 결과였습니다: 시맨틱 캐싱 (semantic caching, 가장 큰 영향), 더 스마트한 모델 라우팅 (model routing, 두 번째로 큰 영향), 그리고 프롬프트/컨텍스트 압축 (prompt/context compression, 규모는 작지만 유의미함). 이 중 그 어떤 것도 근본적인 구조를 재설계할 필요를 요구하지 않았습니다.
이 모든 것의 전제 조건은 인스트루멘테이션 (instrumentation, 계측)이었습니다. 측정할 수 없는 것은 최적화할 수 없습니다. 모든 호출을 로그로 남기고, 호출 유형별 토큰 수를 기록하며, 어디에 집중할지 결정하기 전에 데이터를 살펴보세요. 비싸다고 느껴지는 호출이 실제로는 비싼 호출이 아닌 경우가 많습니다.
한 가지 더 말할 가치가 있는 점은, 조기 최적화(premature optimization)를 하지 말라는 것입니다. 만약 LLM 지출이 월 300달러이고 천천히 증가하고 있다면, 시맨틱 캐싱을 구현하기 위한 엔지니어링 시간은 아직 그만한 가치가 없습니다. 수치가 정당화될 때 실행하세요. 그리고 그 시점이 언제인지 알 수 있도록 인스트루멘테이션이 이미 갖춰져 있는지 확인하십시오.
_[Lycore는 기업을 위한 프로덕션 AI 시스템(RAG 파이프라인, AI 에이전트, LLM 통합, 확장성과 신뢰성을 위해 구축된 맞춤형 AI 애플리케이션)을 구축합니다. 여러분의 유스케이스(use case)에 대해 논의하고 싶다면 문의해 주세요.](https://www.lycore.com/ai-development-services/)]
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기