내가 드디어 AI API 비용을 (정신 건강을 해치지 않고) 해결한 방법
요약
OpenAI API 비용을 65% 절감하기 위해 구축한 캐싱 미들웨어 계층에 대한 기술적 경험담입니다. 프롬프트 해싱, Redis 기반 캐싱, 지능형 TTL 설정 및 요청 중복 제거 기술을 통해 비용과 지연 시간을 동시에 개선했습니다.
핵심 포인트
- 프롬프트 해싱을 통한 Redis 기반 캐싱 계층 구축
- 키워드 기반의 지능형 TTL(Time-to-Live) 설정으로 데이터 유효성 관리
- 뮤텍스를 활용한 요청 중복 제거로 불필요한 API 호출 방지
- API 비용 65% 절감 및 응답 지연 시간 대폭 개선
지난달, 나는 커피를 마시다 사레가 들릴 정도로 놀라운 OpenAI 청구서를 받았다. 무려 238달러였다. 활성 사용자가 겨우 50명뿐인 사이드 프로젝트에서 말이다. 나의 첫 생각은 이랬다. "어딘가에 메모리 누수 (memory leak)가 있는 게 분명해." 그래서 조사를 시작했다.
알고 보니 메모리 누수는 없었다. 그저 미숙한 통합 (integration) 때문이었다. 제안이 필요한 모든 사용자 액션이 매번 API를 새로 호출하고 있었다. 캐싱 (caching)도 없었고, 중복 제거 (deduplication)도 없었으며, 배치 처리 (batching)도 없었다. 그저 실행 후 잊어버리는 (fire-and-forget) 방식의 HTTP 호출뿐이었다. AI는 정확히 똑같은 질문에 반복해서 답변하고 있었고, 나는 매번 그 비용을 지불하고 있었다.
내가 처음 시도했던 것들 (실패한 방법들)
나는 간단하게 시작했다. 속도 제한기 (rate limiter)를 추가하는 것이었다. 사용자당 10초에 한 번의 요청만 허용했다. 덕분에 청구 금액을 약 15% 정도 줄일 수 있었지만, 사용자들은 지연 시간에 대해 불평했다. 그다음에는 프롬프트 (prompt)를 수동으로 배치 처리 (batching)하는 것을 시도했다. 여러 요청을 모아서 한꺼번에 보내는 방식이었다. 잠시 동안은 효과가 있었지만, 코드가 금방 지저분해졌다. 응답을 다시 올바른 사용자에게 매칭하는 작업은 악몽 같았다. 그리고 가장 최악인 점은, 여전히 엄청난 양의 중복 프롬프트가 발생했다는 것이다. 서로 다른 사용자들이 "파티를 위한 좋은 비건 저녁 식사는 뭐야?"라는 똑같은 질문을 할 때마다 각각 새로운 API 호출이 트리거되었다.
더 저렴한 모델로 교체하는 것도 고려했다. GPT-3.5 Turbo 대 GPT-4? 창의적인 작업에서는 품질 저하가 눈에 띄었다. 내 사용자들은 반발할 것이다. 그래서 나는 더 스마트한 접근 방식이 필요했다.
나를 구원한 기술
결국 내가 구축한 것은 다음과 같다: AI API 호출을 위한 캐싱 미들웨어 (caching middleware) 계층이다. 아이디어는 매우 단순하다:
- 프롬프트(시스템 메시지 및 temperature 포함)를 해싱 (hash)하여 고유한 키 (key)를 생성한다.
- Redis (또는 다른 빠른 키-값 저장소)에서 해당 키가 있는지 확인한다.
- 캐시 히트 (cache hit)라면 즉시 반환한다.
- 캐시 미스 (cache miss)라면, API 호출을 수행하고 응답을 저장한 뒤 반환한다.
하지만 진짜 승부수는 **지능형 시간 제한 (intelligent time-to-live, TTL)**을 도입했을 때 찾아왔습니다. 모든 프롬프트가 동일하게 캐싱 가능한 것은 아닙니다. "이 기사를 요약해줘"와 같은 프롬프트는 며칠 동안 유효할 수 있습니다. 반면 "오늘 도쿄 날씨는 어때?"와 같은 프롬프트는 TTL을 약 6시간 정도로 설정해야 합니다. 저는 간단한 휴리스틱 (heuristic)을 사용했습니다. 프롬프트에 시간 민감형 키워드("오늘", "이번 주", "최신")가 포함되어 있으면 짧은 TTL (1시간)을 사용하고, 그렇지 않으면 긴 TTL (7일)을 사용하는 방식입니다.
그리고 사용자 간에 동일한 프롬프트가 발생하는 경우에는 어떻게 할까요? 저는 뮤텍스 (mutex)를 이용한 요청 중복 제거 (request deduplication) 기능을 추가했습니다. 두 사용자가 밀리초(ms) 단위 내에 동일한 프롬프트를 호출하면, 첫 번째 사용자가 API 호출을 수행하고 두 번째 사용자는 대기했다가 그 결과를 재사용합니다. 중복 비용이 발생하지 않습니다.
코드 예시 (Flask + Redis)
import hashlib
import json
import redis
...
이 방법으로 첫 주 만에 API 비용을 65% 절감했습니다. 캐시된 응답의 지연 시간 (latency)은 약 2초에서 약 10ms로 떨어졌습니다. 사용자들도 만족했고, 저도 행복했습니다.
이 접근 방식이 실패하는 경우
캐싱은 만능 해결책 (silver bullet)이 아닙니다.
- 프롬프트가 거의 항상 고유한 경우 (예: 서로 다른 사용자 문서를 요약하는 경우): 캐시 히트 (cache hit)가 거의 발생하지 않을 것입니다. 이 경우에는 캐싱 대신 배치 (batching)나 스트리밍 (streaming)에 집중하세요.
- 동적 응답 (dynamic responses) (매번 약간의 무작위성을 원하는 창의적 글쓰기 등): 온도가 0보다 클 경우 동일한 프롬프트에 대해서도 다른 출력이 생성될 수 있으므로 캐싱의 효과가 떨어집니다. 저는 온도가 0인 경우(결정론적 모드, deterministic mode)에만 캐싱을 적용하고, 창의적인 작업에는 캐시를 우회하도록 설정하여 이 문제를 해결했습니다.
- 법적/컴플라이언스 (Legal/Compliance): 사용자의 프롬프트에 개인 식별 정보 (PII)나 민감한 데이터가 포함되어 있다면, Redis에 캐싱하는 것이 개인정보 보호 정책을 위반할 수 있습니다. 저장하기 전에 반드시 해싱 (hash)을 하거나, 그러한 요청에 대해서는 캐싱을 아예 피해야 합니다.
- 오래된 데이터 (Stale data): 모델이 업데이트되거나 외부 지식이 변경될 수 있습니다. 저는 수동 캐시 삭제 엔드포인트를 추가했으며, 어떤 경우에도 최대 TTL을 14일로 설정했습니다.
고려해 볼 만한 대안들
캐싱을 할 수 없는 상황이라면, 제가 실험했던 또 다른 접근 방식은 **프롬프트 배치 (prompt batching)**입니다. 요청당 한 번의 API 호출을 하는 대신, 짧은 시간(예: 200ms) 동안 여러 프롬프트를 모아서 하나의 배치 (batch)로 전송하는 방식입니다. OpenAI는 메시지 배열을 통해 /v1/chat/completions 엔드포인트에서 이 기능을 지원합니다. 여러분은 응답을 원래의 요청으로 다시 매핑하기만 하면 됩니다. 조금 더 까다롭긴 하지만, 트래픽이 높다면 비용을 대폭 절감할 수 있습니다.
그리고 전용 AI 프록시 서비스 (AI proxy services) (코드에서 링크한 것과 같은)도 있습니다. 이러한 서비스들은 캐싱 (caching), 배치 (batching), 속도 제한 (rate limiting), 그리고 모델 간의 폴백 (fallback)까지 기본적으로 처리해 줍니다. 저는 결국 하나의 서비스로 옮겼는데, Redis + 잠금 (locks) + TTL 휴리스틱 (heuristics)을 관리하는 것이 마치 부업처럼 느껴졌기 때문입니다. 하지만 작은 프로젝트라면 직접 구축해 보는 것도 훌륭한 학습 경험이 될 것입니다.
다음에 한다면 다르게 할 점
- 먼저 프로파일링하기 (Profile first) – 캐싱 전략을 구축하기 전에 프롬프트의 고유성 비율 (uniqueness rates)을 기록했어야 했습니다. 저는 중복이 많을 것이라고 가정했지만, 실제 데이터가 저를 안내해 주었을 것입니다.
- 첫날부터 전용 프록시 사용하기 – 만약 프로덕션 앱을 위해 이 작업을 다시 한다면, 이러한 문제들을 처리해 주는 서비스로 시작할 것입니다. 커스텀 캐싱을 구축하는 데 쓴 시간은 제품 기능 개발에 쓰일 수 있었을 것입니다.
- 관측 가능성 (observability) 추가하기 – 캐시 히트율 (cache hit ratio)과 비용 절감에 대한 메트릭 (metrics) 없이는 눈을 감고 비행하는 것과 같았습니다. 이제 저는 캐시 통계를 대시보드에 기록합니다.
진짜 교훈
AI API는 강력하지만, 이를 데이터베이스처럼 다룬다면 비용이 많이 듭니다. 모든 요청은 정당화되어야 합니다. 스스로에게 물어보세요. 모든 사용자에게 정말로 새로운 답변이 필요한가? 대개는 그렇지 않습니다.
저는 월 238달러에서 약 83달러로 비용을 줄였습니다. 캐시된 응답은 즉각적이기 때문에 제 앱은 더 빠릿하게 느껴집니다. 그리고 반복적인 작업에 돈을 낭비하고 있지 않다는 사실을 알기에 더 편안하게 잠들 수 있습니다.
여러분의 AI 비용 관리 방식은 무엇인가요? 여러분이 발견한 비결이 있다면 듣고 싶습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기