티스토리 뷰
Python으로 공부하는 OpenAI 12편 — 비용은 기능보다 늦게 터지지만, 한 번 터지면 훨씬 아픕니다
octo54 2026. 4. 10. 12:34Python으로 공부하는 OpenAI 12편 — 비용은 기능보다 늦게 터지지만, 한 번 터지면 훨씬 아픕니다
OpenAI 기능은 처음 붙일 때 되게 재밌습니다.
채팅 붙고, RAG 붙고, 스트리밍 붙고, 출처까지 붙으면 꽤 근사해 보여요.
근데 서비스가 진짜 서비스가 되는 순간,
거의 반드시 부딪히는 문제가 하나 있습니다.
“이거 비용이 어디서 이렇게 많이 나가지?”
이 질문은 늘 늦게 옵니다.
처음엔 API 몇 번 호출하니까 체감이 잘 안 돼요.
근데 사용자 수가 조금만 늘어도 바로 보입니다.
- 히스토리를 너무 많이 보내고 있나?
- RAG chunk를 너무 많이 넣고 있나?
- 출력이 너무 길게 나오나?
- 캐시될 수 있는 프롬프트를 매번 바꾸고 있나?
- 로그는 많은데, 정작 어디서 새는지 모르나?
이번 글은 바로 그 얘기입니다.
기능 얘기보다 살짝 덜 화려하지만, 운영에서는 훨씬 중요할 수 있는 주제예요.
OpenAI 공식 문서도 비용과 토큰 관리를 별도 주제로 다루고 있고, Prompt Caching, Usage/Costs 추적, Pricing, Production best practices를 각각 안내합니다. Prompt Caching은 자동으로 동작하며 지연과 입력 비용을 크게 줄일 수 있고, Pricing 문서는 모델별 input, cached input, output 단가를 공개합니다. 또 Production best practices는 대기 시간의 큰 부분이 보통 출력 토큰 생성에서 발생한다고 설명합니다. (OpenAI Developers)
1. 비용은 결국 세 군데에서 크게 샙니다
처음엔 막연하게 “모델이 비싸다”라고 느끼기 쉬운데,
실제로는 보통 아래 세 군데가 핵심입니다.
1) 입력 토큰
프롬프트, 히스토리, RAG 문서 조각, 시스템 지침이 다 여기 들어갑니다.
2) 출력 토큰
모델이 길게 답할수록 비용과 지연이 커집니다.
3) 불필요한 반복
같은 instructions, 같은 prefix, 같은 문맥을 매번 다시 비싸게 처리하는 경우입니다.
OpenAI Pricing 문서는 모델별로 input / cached input / output 단가를 따로 제시하고 있고, Prompt Caching 가이드는 반복되는 prefix가 자동 캐시에 걸리면 입력 비용을 크게 줄일 수 있다고 설명합니다. Production best practices는 실제 체감 지연의 대부분이 출력 토큰 생성에서 생긴다고 짚습니다. (OpenAI Developers)
즉, 실무 감각으로 정리하면 이렇습니다.
비용은 입력 길이, 출력 길이, 반복 구조에서 터진다.
2. 제일 먼저 알아야 할 것: “좋은 기능”과 “싼 기능”은 다를 수 있습니다
이건 좀 씁쓸하지만 사실입니다.
예를 들어 아래 기능들은 사용자 경험은 좋아집니다.
- 긴 시스템 프롬프트
- 최근 대화 20턴 유지
- RAG top-k 10
- 답변 자세히 길게 쓰기
- 출처 chunk 여러 개 다 넣기
근데 비용 관점에서는 꽤 위험할 수 있어요.
왜냐하면:
- 입력이 길어지고
- 출력도 길어지고
- 캐시 이점이 깨지고
- 불필요한 잡음까지 모델에 먹이게 되기 때문입니다.
OpenAI Accuracy 가이드도 retrieval에서 너무 많은 irrelevant context가 오히려 품질을 해칠 수 있다고 설명하고, File Search는 결과 수를 줄이면 토큰 사용량과 지연을 낮출 수 있다고 안내합니다. (OpenAI Developers)
그래서 운영 단계에선 늘 이 균형을 봐야 합니다.
정확도에 도움이 되는 길이인가, 그냥 습관적으로 길어진 건가.
3. 로그를 안 남기면, 비용은 줄일 수가 없습니다
이건 정말 중요합니다.
많은 팀이 비용 얘기를 하면서도
정작 요청 단위로 뭘 얼마나 썼는지 안 남깁니다.
그럼 결국 이런 대화만 반복돼요.
- “요즘 비용 많이 오른 것 같은데?”
- “아마 RAG 때문 아닐까?”
- “스트리밍 때문에 그런가?”
- “모델 바꿔서 그런가?”
전부 추측입니다.
운영에서는 요청마다 최소한 이 정도는 남기는 게 좋습니다.
- 요청 시각
- endpoint 이름
- model 이름
- 사용자/세션 ID
- input token 수
- cached input token 수
- output token 수
- total token 수
- 응답 시간
- RAG 사용 여부
- 검색된 chunk 수
- 히스토리 턴 수
OpenAI Cookbook에는 Usage API와 Costs API로 usage 데이터를 조회하고 시각화하는 예제가 있고, API 레퍼런스와 배치 usage 구조 문서도 input_tokens, output_tokens, cached_tokens, total_tokens 같은 필드를 설명합니다. (OpenAI Developers)
4. 최소 비용 로그 테이블은 이렇게 시작하면 충분합니다
처음부터 거대한 관측 시스템 만들 필요는 없습니다.
이 정도만 있어도 꽤 쓸 만해요.
from dataclasses import dataclass
from datetime import datetime
@dataclass
class OpenAIUsageLog:
created_at: datetime
endpoint: str
model: str
session_id: str | None
input_tokens: int
cached_input_tokens: int
output_tokens: int
total_tokens: int
latency_ms: int
rag_enabled: bool
retrieved_chunk_count: int
recent_history_count: int
이걸 DB에 저장해도 좋고,
처음엔 JSON 로그로 남겨도 괜찮습니다.
핵심은 하나예요.
“요청 하나당 얼마를 썼는지”를 나중에 복기할 수 있어야 한다.
5. FastAPI에서 사용량 로그를 남기는 기본 예제
아래 예시는 서비스 계층에서 응답 후 usage를 추출해 로그 객체로 만드는 흐름입니다.
import time
from dataclasses import asdict
from datetime import datetime
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY")
def call_openai_with_usage_logging(
user_input: str,
session_id: str | None = None,
rag_enabled: bool = False,
retrieved_chunk_count: int = 0,
recent_history_count: int = 0,
):
started = time.perf_counter()
response = client.responses.create(
model="gpt-5.4-mini",
input=user_input,
instructions="한국어로 답하고, 너무 길게 쓰지 마세요."
)
elapsed_ms = int((time.perf_counter() - started) * 1000)
usage = getattr(response, "usage", None)
input_tokens = getattr(usage, "input_tokens", 0) if usage else 0
output_tokens = getattr(usage, "output_tokens", 0) if usage else 0
total_tokens = getattr(usage, "total_tokens", input_tokens + output_tokens) if usage else (input_tokens + output_tokens)
cached_input_tokens = 0
if usage and getattr(usage, "input_tokens_details", None):
cached_input_tokens = getattr(usage.input_tokens_details, "cached_tokens", 0)
log_row = {
"created_at": datetime.utcnow().isoformat(),
"endpoint": "/chat",
"model": "gpt-5.4-mini",
"session_id": session_id,
"input_tokens": input_tokens,
"cached_input_tokens": cached_input_tokens,
"output_tokens": output_tokens,
"total_tokens": total_tokens,
"latency_ms": elapsed_ms,
"rag_enabled": rag_enabled,
"retrieved_chunk_count": retrieved_chunk_count,
"recent_history_count": recent_history_count,
}
return {
"answer": response.output_text,
"usage_log": log_row,
}
OpenAI 관련 usage 구조는 공식 문서와 레퍼런스에서 input_tokens, output_tokens, total_tokens, 그리고 input_tokens_details.cached_tokens 같은 상세 필드를 설명합니다. Prompt Caching 문서도 cached input 개념을 공식적으로 다룹니다. (OpenAI Developers)
6. Prompt Caching은 생각보다 훨씬 중요합니다
이건 비용 최적화에서 진짜 큰 포인트예요.
OpenAI Prompt Caching 가이드는 이 기능이 모든 API 요청에서 자동으로 동작하고, 반복되는 prompt prefix에 대해 입력 비용을 크게 줄일 수 있다고 설명합니다. 문서에 따르면 지연은 최대 80%, 입력 비용은 최대 90%까지 줄어들 수 있습니다. 또 cookbook 예시는 캐시가 1024 토큰을 넘는 프롬프트에서 특히 의미 있게 작동한다고 설명합니다. (OpenAI Developers)
이게 무슨 뜻이냐면,
아래처럼 반복되는 부분이 많으면 유리하다는 뜻입니다.
- 같은 system prompt
- 같은 도구 정의
- 같은 앱 정책
- 같은 고정 prefix
- 자주 반복되는 instructions
반대로 캐시를 깨기 쉬운 패턴도 있어요.
- 매 요청마다 system prompt를 조금씩 바꿈
- 앞부분에 timestamp 같은 가변 문자열을 넣음
- 메시지 배열의 앞부분이 자주 바뀜
- 불필요하게 prefix 구조를 흔듦
OpenAI 블로그와 prompt caching 가이드는 정확히 identical prefix가 중요하다고 설명합니다. 즉, 캐시는 “비슷하면”이 아니라 “앞부분이 같을수록” 잘 먹습니다. (OpenAI Developers)
7. 운영에서 제일 먼저 줄여야 하는 건 보통 출력 길이입니다
이건 의외로 간과됩니다.
사람들은 히스토리와 RAG만 줄이려 하는데,
OpenAI Production best practices는 실제 대기 시간의 큰 부분이 출력 토큰 생성에서 생긴다고 설명합니다. Pricing도 output 단가가 input보다 더 높은 경우가 많습니다. (OpenAI Developers)
즉, 아래를 먼저 점검할 가치가 커요.
- 답변이 필요 이상으로 길지 않은가
- “친절하게”를 “장황하게”로 구현하고 있진 않은가
- 요약형 endpoint인데도 불필요한 부연설명이 붙지 않는가
- 기본 max output을 너무 크게 열어두지 않았는가
이건 정말 체감됩니다.
같은 기능이어도 출력 길이만 조금 줄여도 비용과 지연이 같이 좋아지는 경우가 많아요.
8. RAG에서는 무엇이 특히 비싸게 만드나
RAG가 붙으면 입력 토큰이 빠르게 늘어납니다.
주범은 보통 이 네 가지예요.
1) recent history가 너무 많음
이전 대화를 너무 많이 보냄
2) session summary가 너무 김
요약을 한다면서 또 장문의 요약을 넣음
3) retrieved chunks가 너무 많음
top-k를 크게 잡아 불필요한 chunk까지 다 넣음
4) chunk 자체가 너무 큼
관련 문장 한두 줄만 필요했는데 큰 덩어리를 넣음
OpenAI Accuracy 가이드는 retrieval에서 wrong context와 too much irrelevant context가 품질도 해치고 불필요한 잡음이 될 수 있다고 설명합니다. 결과 수 조절은 비용뿐 아니라 정확도 측면에서도 중요한 이유가 됩니다. (OpenAI Developers)
그래서 저는 보통 이렇게 점검합니다.
- 최근 히스토리 몇 턴인가
- summary 길이는 몇 자/몇 토큰인가
- top-k는 몇 개인가
- 실제로 모델에 넣은 검색 본문 총 길이는 얼마인가
9. Usage API와 Costs API는 운영 대시보드에 정말 유용합니다
OpenAI Cookbook에는 Usage API와 Costs API를 호출해서 usage 데이터를 가져오고, pandas와 matplotlib로 시각화하는 예제가 있습니다. 이 예제는 시간대별 usage, 모델별 usage, 비용 추이를 확인하는 흐름을 보여줍니다. (OpenAI Developers)
이런 식으로 보면 좋습니다.
- 하루 단위 총 토큰 사용량
- 모델별 사용량 비율
- endpoint별 비용
- RAG 사용 요청 vs 일반 요청 비교
- 캐시된 입력 토큰 비율
- 출력 토큰 평균 길이
즉, 애플리케이션 내부 로그와 OpenAI의 조직 단위 usage/cost 집계를 같이 봐야
“어디서 왜 비싸졌는지”가 더 잘 보입니다.
10. 비용 계산은 대충 하지 말고, 분리해서 봐야 합니다
모델 단가가 input, cached input, output으로 다를 수 있으니
계산도 나눠서 보는 게 좋습니다.
예를 들어 개념적으로는 이렇게 계산합니다.
def estimate_cost_usd(
input_tokens: int,
cached_input_tokens: int,
output_tokens: int,
input_price_per_1m: float,
cached_input_price_per_1m: float,
output_price_per_1m: float,
) -> float:
non_cached_input_tokens = max(input_tokens - cached_input_tokens, 0)
input_cost = (non_cached_input_tokens / 1_000_000) * input_price_per_1m
cached_input_cost = (cached_input_tokens / 1_000_000) * cached_input_price_per_1m
output_cost = (output_tokens / 1_000_000) * output_price_per_1m
return input_cost + cached_input_cost + output_cost
Pricing 문서는 모델별로 input, cached input, output 가격을 별도로 제공합니다. 예를 들어 일부 GPT-5.4 계열은 cached input 단가가 일반 input보다 훨씬 낮게 제시됩니다. 최신 수치는 가격표를 직접 확인해야 합니다. (OpenAI Developers)
이 분리를 해두면
“비용이 올랐는데 사실 입력보다 출력이 문제였구나”
혹은
“캐시가 잘 안 먹어서 input 비용이 뛰었구나”
같은 걸 훨씬 빨리 볼 수 있습니다.
11. 배치 작업은 Batch를 검토할 가치가 있습니다
실시간 응답이 아닌 작업이라면
예를 들어:
- 대량 문서 요약
- 블로그 초안 벌크 생성
- 임베딩 전처리
- 카테고리 분류 일괄 처리
이런 건 Batch 계열이 더 나을 수 있습니다.
Pricing 표에는 Batch 열이 따로 있고, Batch usage 구조도 input_tokens, cached_tokens, output_tokens 등을 제공합니다. 즉, 실시간 응답이 필요 없는 작업은 일반 실시간 호출과 분리해서 보는 게 좋습니다. (OpenAI Developers)
이건 운영에서 꽤 큽니다.
실시간과 비실시간을 안 나누면, 모든 작업을 비싼 방식으로 하게 될 수도 있거든요.
12. 지금 바로 적용하기 좋은 최적화 순서
주니어 개발자가 운영 단계에서 바로 적용하기 좋은 순서는 보통 이렇습니다.
1) usage 로그부터 남긴다
안 보이면 못 줄입니다.
2) 출력 길이부터 줄인다
가장 빠르게 체감되는 경우가 많습니다.
3) 고정 instructions를 안정화한다
Prompt Caching 이점을 살리기 좋습니다.
4) RAG top-k를 줄여본다
3~5 정도에서 실험하는 경우가 많습니다.
5) 히스토리를 최근 N턴 + 요약으로 정리한다
전체 대화를 다 보내지 않습니다.
6) 고비용 endpoint를 모델별로 재검토한다
무거운 모델이 꼭 필요한 endpoint인지 다시 봅니다.
이 순서는 기술적으로도, 운영적으로도 납득이 갑니다. Prompt Caching, Pricing, Production best practices, Accuracy 가이드가 각각 이 축들을 뒷받침합니다. (OpenAI Developers)
13. 자주 하는 실수들
실수 1. 비용 문제를 모델 교체로만 해결하려고 한다
가끔은 모델보다 프롬프트 구조가 더 큰 문제입니다.
실수 2. 캐시를 믿으면서 prefix를 계속 바꾼다
Prompt Caching은 앞부분이 안정적일수록 유리합니다. (OpenAI Developers)
실수 3. usage는 보는데 endpoint 단위로 안 본다
그럼 어디서 새는지 모릅니다.
실수 4. 출력 길이를 통제하지 않는다
생각보다 여기서 많이 샙니다. (OpenAI Developers)
실수 5. RAG는 좋아 보인다는 이유로 chunk를 너무 많이 넣는다
잡음과 비용이 같이 늘 수 있습니다. (OpenAI Developers)
14. 오늘 글의 핵심 요약
이번 글에서 꼭 가져가야 할 건 이것입니다.
OpenAI 비용 최적화는 “싼 모델 찾기”보다 먼저, 입력 구조·출력 길이·캐시·로그를 제대로 보는 데서 시작한다.
정리하면:
- Prompt Caching은 자동으로 동작하고, 반복 prefix가 많을수록 비용과 지연을 크게 줄일 수 있다. (OpenAI Developers)
- Pricing은 input, cached input, output 단가를 따로 본다. (OpenAI Developers)
- 실제 지연의 큰 부분은 보통 출력 생성에서 온다. (OpenAI Developers)
- Usage/Costs 추적은 요청 로그와 조직 집계를 함께 보는 게 좋다. (OpenAI Developers)
- RAG 비용은 히스토리, summary, chunk 크기, top-k에서 자주 불어난다. (OpenAI Developers)
기능은 잘 돌아가는데 돈이 새고 있다면,
대부분 문제는 이미 로그 안에 들어 있습니다.
다만 아직 안 보고 있을 뿐이에요.
다음 편 예고
다음 글에서는 여기서 한 단계 더 들어가겠습니다.
Python + FastAPI에서 OpenAI 기능을 백그라운드 작업과 비동기 큐로 분리하는 방법
이 주제로,
- 어떤 작업은 왜 즉시 응답으로 처리하면 안 되는지
- 긴 요약, 대량 처리, 문서 색인 작업을 어떻게 분리할지
- API 서버와 워커를 나누는 구조
- 운영 가능한 AI 백엔드 아키텍처
까지 이어가보겠습니다.
출처
- OpenAI Prompt Caching 가이드 — 자동 동작, 반복 prefix 재사용, 지연 최대 80%·입력 비용 최대 90% 절감 가능. (OpenAI Developers)
- OpenAI Prompt Caching cookbook — 1024+ 토큰 프롬프트와 캐시 실전 예시. (OpenAI Developers)
- OpenAI Pricing — 모델별 input / cached input / output 단가. (OpenAI Developers)
- OpenAI Production best practices — 대기 시간의 큰 부분은 출력 토큰 생성에서 발생. (OpenAI Developers)
- OpenAI Usage/Costs cookbook — Usage API와 Costs API로 사용량·비용 시각화 예시. (OpenAI Developers)
- OpenAI usage 구조 관련 API 문서 — input_tokens, cached_tokens, output_tokens, total_tokens 등 usage 필드. (OpenAI Developers)
Python, OpenAI, FastAPI, 토큰 비용, Prompt Caching, Usage API, Costs API, OpenAI Pricing, AI 백엔드 운영, RAG 비용 최적화, Responses API, OpenAI Python SDK, 비용 절감, 토큰 추적, 주니어 개발자
'study > Python으로 시작하는 OpenAI 개발 입문' 카테고리의 다른 글
- Total
- Today
- Yesterday
- CI/CD
- Next.js
- fastapi
- kotlin
- nextJS
- Python
- REACT
- 웹개발
- ai철학
- SEO최적화
- JWT
- LangChain
- Docker
- JAX
- NestJS
- 개발블로그
- 생성형AI
- llm
- seo 최적화 10개
- Redis
- PostgreSQL
- DevOps
- Express
- 쿠버네티스
- Prisma
- 백엔드개발
- flax
- 딥러닝
- node.js
- rag
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |

