AI API 비용 절감하기: 백엔드 엔지니어의 현장 노트
요약
백엔드 엔지니어가 실무에서 겪은 AI API 비용 과다 지출 문제를 해결하기 위한 전략을 다룹니다. 모든 작업에 고가의 모델을 사용하는 대신, 작업의 난이도에 따라 모델을 분리하는 계층적 라우팅 패턴을 제안합니다.
핵심 포인트
- 모든 프롬프트에 GPT-4o 같은 고가 모델을 사용하는 것은 비효율적임
- 워크로드별 라우팅 테이블을 구축하여 적절한 모델을 선택해야 함
- 저렴한 모델을 먼저 시도하고 실패 시 상위 모델로 격상하는 계층적 라우팅 적용
- 모델 선택 최적화만으로도 API 비용을 최대 90% 이상 절감 가능
AI API 비용 절감하기: 백엔드 엔지니어의 현장 노트
대시보드를 열고 "AI 서비스" 항목에 14,200달러가 찍힌 것을 보았던 그날 아침을 여전히 기억합니다. 당시 저는 10년 차 백엔드 엔지니어였고, 수많은 인프라 청구서를 봐왔습니다. 하지만 이 청구서는 저를 크게 웃게 만들었습니다. 거의 전적으로 피할 수 있었던 비용이었기 때문입니다.
첫 번째 LLM (Large Language Model) 기반 기능을 출시할 때 아무도 말해주지 않는 사실이 있습니다. 기본 설정(defaults)은 의도적으로 비싸게 되어 있다는 점입니다. 벤더(Vendors)들은 사용자가 이 모델들을 서로 대체 가능한 것으로 생각하기를 원하며, 따라서 사용자가 "이 단락을 요약해줘"부터 "이 축하 카드를 번역해줘"까지 모든 작업에 브랜드 인지도가 높은 모델을 사용하도록 유도합니다. 참고로(fwiw), 저도 무언가를 측정해 보기 전까지 6개월 동안 정확히 똑같은 실수를 저질렀습니다.
다음은 제가 몇몇 프로덕션(production) 시스템을 감사(auditing)한 후 얻게 된 플레이북(playbook)입니다. 특별한 것은 없습니다. 벤더 종속(vendor lock-in) 트릭도, "비밀" 가격 등급도 없습니다. 그저 새로운 클래스의 리소스에 적용된 백엔드 엔지니어링 위생(hygiene)일 뿐입니다. 제 생각에는(imo), 이것이 게임의 전부입니다.
90%의 지렛대: 모든 것에 GPT-4o를 사용하는 것을 멈춰라
모든 AI 청구서에서 가장 큰 항목은 모델 선택(model selection)이며, 대부분의 팀은 이를 결정할 필요가 없는 사항으로 취급합니다. 그들은 가장 익숙한 모델을 선택하고 모든 프롬프트(prompt)에 그것을 사용합니다. 저는 네 개의 회사가 이렇게 하는 것을 지켜보았습니다. 그들 모두는 호출의 70% 이상이 인사, FAQ 조회, 단순 분류와 같은 사소한 작업임에도 불구하고 이에 대해 프리미엄 요금을 지불하고 있었습니다.
해결책은 미묘하지 않습니다. 말 그대로 라우팅 테이블(routing table)을 만드는 것입니다. 제가 현재 거의 모든 프로젝트에 적용하는 테이블은 다음과 같습니다:
| 워크로드 (Workload) | 게으르게 행동한다면 | 사용해야 할 것 | 비용 차이 (Cost Delta) |
|---|---|---|---|
| 일상적인 채팅 | GPT-4o ($10/M out) | DeepSeek V4 Flash ($0.25/M) | 97.5% |
| ... |
저 퍼센트 수치들은 이론적인 것이 아닙니다. 공개된 요율에 따른 단순한 산술 계산입니다. 내부적으로 보면 "모델 선택"은 출력 비용에 대해 40배의 지렛대 역할을 하지만, 대부분의 사람들은 이를 전혀 건드리지 않습니다.
이 글에서 다른 것은 하지 않더라도, 이것만은 꼭 하십시오. 진심입니다.
계층적 라우팅 (Tiered Routing): "저렴한 모델 우선" 패턴
모든 프롬프트가 플래그십 모델(flagship model)을 사용할 가치가 없다는 점을 받아들였다면, 자연스럽게 다음 질문이 뒤따릅니다. "어떤 모델을 사용할지 어떻게 결정할 것인가?" 그 답은 아마도 RFC 7231이 승인할 만한 방식입니다. 즉, 저렴한 경로를 먼저 시도하고, 실패할 경우에만 상위 모델로 격상(escalate)하는 것입니다.
이는 CDN 폴백(fallback), 데이터베이스 읽기 복제본(read replicas), 또는 서킷 브레이커(circuit breakers)와 동일한 개념입니다. 백엔드 엔지니어들은 아주 오래전부터 계층적 라우팅 (Tiered Routing)을 수행해 왔습니다. 이를 LLM 호출에 적용하는 것은 지나온 시간을 되돌아보면 부끄러울 정도로 당연한 일입니다.
from openai import OpenAI
client = OpenAI(
...
실제 운영 환경에서 저는 이 패턴을 통해 고객 지원 챗봇의 비용을 월 420달러에서 28달러로 낮추는 것을 보았습니다. 단지 쿼리의 85%를 가장 저렴한 계층에서 처리하도록 두었을 뿐입니다. "품질 검사 (quality check)"가 거창할 필요도 없습니다. 대부분의 앱에서는 정규 표현식 (regex)이나 아주 작은 분류기 (classifier)만으로도 충분합니다. 완벽해지려는 것이 아닙니다. 바보 같은 짓을 하지 않으려는 것입니다.
캐싱 (Caching): 당신이 무시해 온 공짜 점심
캐싱 (Caching)은 백엔드 엔지니어들이 이미 어떻게 하는지 알고 있는 최적화 기술입니다. 이상한 점은 많은 팀이 LLM 호출에 대해서는 캐싱을 신경 쓰지 않는다는 것입니다. 왜냐하면 "모든 요청은 고유하다"라고 가정하기 때문입니다. 하지만 실제로 그런 경우는 거의 없습니다.
FAQ 질문, 문서 조회, "베를린 날씨 어때", 템플릿 완성 — 이 모든 것들은 반복됩니다. 아주 많이 말이죠. 솔직하게 측정해 본다면, 캐시 적중률 (cache-hit-rate)이 50~80%에 달하는 경우도 많습니다. 저는 한 번 "개인화된 비서"를 감사(audit)한 적이 있는데, 알고 보니 동일한 200개의 질문을 돌아가며 대답하고 있었습니다.
다음은 실제 코드베이스에서 가져와 수정한 최소 기능 제품 (MVP) 버전입니다:
import hashlib, json, time
cache = {}
...
단 20줄입니다. 트래픽에 조금이라도 중복이 있다면 하루 만에 본전을 뽑고도 남습니다. 접두사 기반(prefix-based) 또는 의미론적 캐싱 (semantic caching, 유사하지만 동일하지 않은 쿼리를 캐싱하는 것)을 위해서는 Redis나 벡터 스토어 (vector store)를 사용해야 하겠지만, 일단은 완전 일치(exact-match)부터 시작하십시오. 진심입니다. 대부분의 팀은 첫 번째 단계조차 밟지 못합니다.
프롬프트 압축 (Prompt Compression): 더 적게 지불하기
제가 처음 계산을 해봤을 때 진심으로 놀랐던 숫자가 하나 있습니다. 2,000-토큰 (token) 시스템 프롬프트 (system prompt)를 400-토큰으로 압축하면 DeepSeek V4 Flash에서 요청당 약 $0.024를 절약할 수 있습니다. 이를 하루 10,000번의 요청으로 곱하면 하루에 $240, 즉 연간 약 $87,600에 달하는 금액입니다. 단 한 번의 프롬프트 다듬기만으로 말이죠.
이것이 작동하는 이유는 부끄러울 정도로 단순합니다. 입력 토큰 (input tokens)에 대해 비용이 청구되는데, 대부분의 시스템 프롬프트는 비대해져 있기 때문입니다. 여기에는 상용구 (boilerplate), 폴백 지침 (fallback instructions), 성격 특성, 아무도 읽지 않는 예시들, 그리고 "당신은 유능한 어시스턴트입니다"라는 세 문단의 내용이 포함되어 있습니다. 이를 줄이십시오.
가장 게으른 방법은 말 그대로 텍스트를 그냥 삭제하는 것입니다. 그보다 약간 덜 게으른 방법은 컨텍스트 (context)를 전송하기 전에 저렴한 모델을 사용하여 자체적으로 요약하는 것입니다:
def compress_prompt(text, target_ratio=0.5):
if len(text) < 500:
return text # 왕복 비용을 들일 가치가 없음
...
이 패턴은 다른 모든 최적화 기법과 결합됩니다. 압축된 프롬프트는 더 저렴한 입력 토큰을 의미하며, 응답 시 출력 토큰 (output tokens)이 줄어들고 (모델이 반응해야 할 내용이 적어지기 때문), 캐시 점유율 (cache footprint)도 작아집니다. 이는 계속해서 최적화를 불러오는 최적화입니다. 제가 관찰한 현실적인 절감 범위는 요청당 15-30%이며, RAG (Retrieval-Augmented Generation) 컨텍스트가 무거운 경우에는 이보다 더 높은 쪽을 기대할 수 있습니다.
배치 처리 (Batching): 가장 오래된 기술 중 하나
백엔드 엔지니어들은 SQL이 등장하기 전부터 데이터베이스 삽입 (database inserts)을 배치 처리해 왔습니다. 동일한 원리가 LLM 호출에도 적용됩니다. 만약 10번의 요청을 보낼 예정이라면, 한 번에 보낼 수 있는지 확인하십시오.
여기서의 비용 절감은 주로 입력 토큰과 관련이 있습니다. 중복되는 컨텍스트를 가진 10번의 개별 호출은 동일한 시스템 프롬프트를 10번 다시 보내면서 엄청난 양의 토큰을 낭비합니다. 하나의 배치 호출은 해당 오버헤드 (overhead)를 정확히 한 번만 공유합니다.
# 이전: 3번의 호출, 3배의 시스템 프롬프트 토큰, 3번의 왕복 (round trips)
for q in questions:
client.chat.completions.create(
...
요청당 지연 시간 (latency)을 약간 포기하는 대신, 총비용을 10-20% 절감할 수 있으며 속도 제한 (rate limiter)에 걸리는 일도 멈출 수 있습니다. 1998년 이후 모든 인프라 RFC에 "배치 처리 (batch things)" 섹션이 포함되어 있는 데에는 다 이유가 있습니다.
스트리밍 (Streaming) + 조기 종료 (Early Termination)
이 내용은 제가 대부분 참고했던 원본 가이드에는 없었지만, 제 가이드에는 포함할 가치가 충분하다고 판단했습니다. 긴 출력을 생성하는 경우, 스트리밍 (stream)을 사용하고 다운스트림 소비자 (downstream consumers)가 필요한 정보를 얻었다는 첫 번째 신호가 나타나면 즉시 중단하십시오.
대부분의 채팅 UI는 점진적으로 렌더링됩니다. 만약 사용자가 600개 토큰의 응답 중 처음 80개 토큰 내에서 답을 얻었다면, 사용자가 읽지도 않을 나머지 520개 토큰에 대한 비용을 지불하고 있는 셈입니다. 배치 작업 (batch jobs)의 경우, 센티널 토큰 (sentinel token)을 사용하여 중단할 수 있습니다.
stream = client.chat.completions.create(
model="deepseek-v4-flash",
messages=messages,
...
이것 자체만으로는 비용 절감 효과가 아주 크지는 않지만 (약 5-10% 정도), 다른 모든 기법과 결합되어 시너지를 내며, 사용자가 실제로 중요하게 생각하는 지표인 체감 지연 시간 (perceived latency)을 개선해 줍니다.
관측 가능성 (Observability): 너무 늦기 전까지는 건너뛰게 되는 것
가장 재미없는 부분이라 마지막으로 남겨두었습니다. 하지만 성능 퇴보 (regression)를 방지할 수 있는 유일한 방법이기도 합니다. 이 글에서 다룬 다른 모든 기술은 그것이 제대로 작동하고 있는지 측정할 수 없다면 무용지물입니다.
요청당 세 가지 수치가 필요합니다:
- 어떤 모델을 호출했는가
- 입력/출력 토큰을 얼마나 사용했는가
- 캐시 (cache)에서 제공했는지, 압축 (compressed)했는지, 배치 (batched) 처리했는지 등
이것들을 로그 (log)로 남기고, 태그 (tag)를 달고, 대시보드 (dashboard)에 넣으십시오. 이것이 없다면 당신은 눈을 가리고 비행하는 것과 같으며, 다음에 청구서가 급증했을 때 그것이 누군가 프롬프트 (prompt)를 변경했기 때문인지, 아니면 누군가 일주일 동안 모든 트래픽을 GPT-4o로 재라우팅 (re-routed)했기 때문인지 알 방법이 없을 것입니다.
import logging
logger = logging.getLogger("llm-cost")
...
이 작업이 화려하다고 거짓말하지는 않겠습니다. 화려하지 않습니다. 하지만 RFC 8252도 관측 가능성 (observability)을 각주 정도로 취급하지 않았으며, 거기에는 타당한 이유가 있습니다. 보이지 않는 시스템은 최적화할 수 없기 때문입니다.
종합하기
중간 규모의 워크로드(workload)에 대한 대략적인 계산(back-of-the-envelope)을 예로 들어보겠습니다. 한 달에 100만 번의 LLM 호출을 수행하며, 평균적으로 입력 토큰(input tokens) 500개와 출력 토큰(output tokens) 300개를 사용한다고 가정해 봅시다.
| 전략 | 기본 비용 (Baseline Cost) | 최적화된 비용 (Optimized Cost) | 절감액 (Savings) |
|---|---|---|---|
| 기본: 모든 곳에 GPT-4o 사용 | $3,300 | — | — |
| ... |
이 수치들은 보수적인 편입니다. 저는 팀들이 이보다 더 큰 성과를 내는 것을 보았습니다.
최근 제가 라우팅(Routing)을 수행하는 방식에 대하여
하지만 이 글의 전체적인 논지는 어떤 게이트웨이(gateway)를 선택하느냐에 달려 있지 않습니다. 원하는 것을 무엇이든 선택하되, 쉬운 작업에는 저렴한 모델을 선택하십시오. 그것이 40배의 레버리지(lever)입니다. 그 외의 모든 것은 그 위에 얹는 미세 조정 (fine-tuning)일 뿐입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기