비용과 지연을 줄이는 운영 전략
이 글에서는 Prompt Caching과 Token Budget을 이용해 LLM 서비스의 비용과 지연을 운영 지표로 관리하는 방법을 정리합니다.
LLM 비용은 서버 CPU 비용처럼 고정적으로 나오지 않습니다. 요청마다 input token, output token, 모델, 캐시 여부에 따라 달라집니다. 응답 지연도 마찬가지입니다. 같은 API라도 프롬프트 길이와 검색된 문서 수에 따라 크게 달라집니다.
그래서 LLM 서비스에서는 “프롬프트를 잘 쓰는 법”보다 “프롬프트를 운영 가능한 비용 단위로 관리하는 법”이 중요합니다.
분석 기준일: 2026-05-12
실습 기준 환경: OpenAI API, FastAPI, Redis, Prometheus
주요 참고자료: OpenAI Prompt Caching Docs, OpenAI Rate Limits Docs, OpenAI Cookbook
핵심 요약
- Token Budget은 요청 하나에 허용할 input/output token 한도다.
- Prompt Caching은 반복되는 prompt prefix의 비용과 지연을 줄이는 데 도움이 된다.
- 정적 내용은 prompt 앞쪽에, 동적 내용은 뒤쪽에 두는 방식이 캐시 효율에 유리하다.
- 비용 최적화는 감이 아니라 usage metric으로 해야 한다.
- prompt version별 비용과 품질을 함께 봐야 한다.
1. LLM 비용은 왜 예측하기 어려운가
일반 API는 요청 수와 서버 리소스를 보면 비용을 어느 정도 예측할 수 있습니다. 하지만 LLM은 요청의 길이가 비용을 만듭니다.
| 요소 | 비용 영향 |
|---|---|
| system prompt 길이 | 모든 요청에 반복 비용 발생 |
| 검색된 문서 수 | RAG input token 증가 |
| 대화 이력 | context 길이 증가 |
| 출력 길이 | output token 비용 증가 |
| 재시도 | 같은 비용 반복 발생 |
| 캐시 여부 | input 처리 비용/지연 감소 가능 |
따라서 토큰 사용량을 API 지표로 봐야 합니다.
2. Token Budget이란 무엇인가
Token Budget은 요청 하나에 허용할 토큰 예산입니다.
# 예시입니다.총 budget = system prompt + tool schema + retrieved context + user question + output reserve
예시:
| 영역 | 예산 |
|---|---|
| system prompt | 1,000 tokens |
| tool/schema instruction | 800 tokens |
| retrieved context | 4,000 tokens |
| conversation history | 1,000 tokens |
| user question | 300 tokens |
| output reserve | 1,200 tokens |
budget을 넘으면 검색 문서 수를 줄이거나, 오래된 대화 이력을 요약하거나, output max token을 제한해야 합니다.
3. Prompt Caching 기본 개념
Prompt Caching은 반복되는 prompt prefix를 provider가 재사용해 지연과 비용을 줄이는 방식입니다.
실무적으로 중요한 점은 “반복되는 부분이 앞쪽에 있어야 한다”는 것입니다.
# 예시입니다.좋은 구조:[고정 system prompt][고정 tool schema][고정 응답 규칙][동적 검색 문서][동적 사용자 질문] 나쁜 구조:[사용자 질문][검색 문서][고정 system prompt][tool schema]
고정 내용이 뒤쪽에 있으면 캐시 prefix 재사용 효과가 떨어질 수 있습니다.
4. 캐시 친화적인 Prompt Layout
추천 layout은 다음과 같습니다.
# 예시입니다.System:- 역할- 답변 정책- citation 규칙- 금지사항- schema 설명 Developer:- tool 사용 규칙- output validation 기준 Context:- retrieved chunks User:- question
변하지 않는 정책은 앞에 두고, 요청마다 달라지는 문서와 질문은 뒤에 둡니다.
5. RAG에서 token budget 나누기
RAG는 token budget 관리가 특히 중요합니다. 검색 결과를 많이 넣는다고 항상 답변이 좋아지지 않습니다. 오히려 관련 없는 chunk가 늘면 모델이 혼란스러워질 수 있습니다.
| 전략 | 설명 |
|---|---|
| Top-k 제한 | 검색 결과 개수 제한 |
| Chunk 압축 | 긴 chunk를 요약 후 입력 |
| Metadata filter | 권한, 문서 유형, 날짜로 후보 줄이기 |
| Reranking | 관련도 높은 문서만 남기기 |
| Output reserve | 답변에 필요한 token 공간 확보 |
6. 비용·지연 지표 설계
반드시 남길 metric:
# 예시입니다.llm_input_tokens_totalllm_output_tokens_totalllm_cached_input_tokens_totalllm_cost_estimated_totalllm_latency_ms_bucketllm_prompt_version_usage_totalllm_rate_limit_error_totalllm_retry_total
분석 기준:
| 질문 | 볼 지표 |
|---|---|
| 어떤 prompt version이 비싼가? | version별 token usage |
| 캐시가 효과 있는가? | cached token ratio |
| 지연이 어디서 생기는가? | latency p95/p99 |
| 재시도 비용이 큰가? | retry count, retry token |
7. Rate Limit과 Backoff
Rate limit은 단순히 더 높은 요금제를 쓰면 해결되는 문제가 아닙니다. burst traffic, retry storm, 대량 eval 실행이 함께 오면 제한에 걸릴 수 있습니다.
대응 원칙:
# 예시입니다.[ ] 요청 단위 rate limit[ ] 사용자/조직 단위 quota[ ] eval batch 별도 제한[ ] exponential backoff[ ] retry budget[ ] provider fallback
8. 실무 예제
프롬프트 호출 전 budget check:
# 예시 코드입니다.def enforce_token_budget(parts: dict, max_input_tokens: int): estimated = sum(estimate_tokens(value) for value in parts.values()) if estimated <= max_input_tokens: return parts parts["retrieved_context"] = trim_context(parts["retrieved_context"]) estimated = sum(estimate_tokens(value) for value in parts.values()) if estimated > max_input_tokens: raise ValueError("TOKEN_BUDGET_EXCEEDED") return parts
실제 서비스에서는 tokenizer 기반 추정과 provider usage 결과를 함께 기록해야 합니다.
9. 실무 체크리스트
# 예시입니다.[ ] 요청당 input/output token budget을 정했는가?[ ] prompt version별 token usage를 기록하는가?[ ] 정적 prompt prefix를 앞쪽에 배치했는가?[ ] RAG context top-k와 최대 token을 제한했는가?[ ] output reserve를 확보했는가?[ ] cached input token 비율을 측정하는가?[ ] rate limit 오류와 retry 비용을 기록하는가?[ ] eval 실행과 사용자 트래픽의 quota를 분리했는가?
실패 사례: 캐시는 켰지만 비용이 줄지 않은 경우
Prompt Caching을 적용했는데 비용과 지연이 거의 줄지 않는 경우가 있습니다. 대개 반복되는 prefix가 짧거나, 매 요청마다 system prompt 앞부분이 달라지거나, 검색 문서가 prompt의 앞쪽에 끼어들기 때문입니다. provider가 cache를 지원해도 prompt layout이 캐시에 맞지 않으면 효과가 작습니다.
또 하나의 실패는 평균 token만 보는 것입니다. LLM 비용은 p95와 p99 요청이 크게 흔듭니다. 대부분 요청은 짧지만 일부 요청이 긴 문서 20개를 넣고, 긴 답변까지 생성하면 월 비용 추정이 틀어집니다. token budget은 평균 최적화가 아니라 요청별 상한과 예외 처리를 정하는 운영 정책입니다.
구현 예시: prompt layout을 cache-friendly하게 나누기
[stable prefix]- product role- response policy- tool contract- safety and citation rules [semi-stable]- tenant policy version- prompt template version [dynamic suffix]- user question- retrieved chunks- conversation summary
정적인 정책은 앞쪽에 두고, 질문과 검색 결과는 뒤쪽에 둡니다. template version이 바뀌면 cache hit가 줄어드는 것을 정상 이벤트로 보고 metric에 남깁니다. dynamic suffix가 budget을 넘으면 retrieval top-k를 줄이거나 요약 context로 대체해야 합니다.
체크리스트 적용 결과
| 지표 | 수집 이유 | 대응 예 |
|---|---|---|
| input tokens | 요청 비용의 기본 단위 | retrieval chunk 수 제한 |
| cached input tokens | caching 효과 확인 | stable prefix 재배치 |
| output tokens | 답변 길이와 비용 관리 | answer policy와 max token 조정 |
| prompt version | 변경 전후 비교 | regression eval 연결 |
| p95 latency | 긴 요청 감지 | timeout과 fallback 설계 |
이 지표가 있으면 "프롬프트가 길어서 비싸다"가 아니라 "version 7에서 cached input 비율이 떨어졌고 retrieval suffix가 p95를 밀어 올렸다"처럼 원인을 말할 수 있습니다. 비용 최적화는 문장 감각보다 측정 가능한 budget 관리에 가깝습니다.
10. Q&A
Q1. Prompt Caching만으로 비용 문제가 해결되나요?
아닙니다. Prompt Caching은 반복 prefix에 유리합니다. RAG context나 사용자 질문처럼 매번 달라지는 부분은 token budget과 retrieval 품질 개선이 필요합니다.
Q2. system prompt를 길게 써도 괜찮나요?
반복되고 캐시가 잘 적용된다면 비용 부담이 줄 수 있습니다. 하지만 긴 system prompt는 유지보수와 품질 회귀 리스크를 만들기 때문에 versioning과 eval이 필요합니다.
Q3. output token도 캐시되나요?
Prompt Caching은 주로 입력 prefix 재사용과 관련됩니다. 출력 길이는 별도 max token과 답변 정책으로 관리해야 합니다.
11. 참고자료와 불확실성
참고자료
- OpenAI Prompt Caching: https://platform.openai.com/docs/guides/prompt-caching
- OpenAI Rate Limits: https://platform.openai.com/docs/guides/rate-limits
- OpenAI Cookbook — Prompt Caching: https://developers.openai.com/cookbook/examples/prompt_caching_201
불확실성
- 캐시 적용 조건, 지원 모델, 가격 정책은 시점에 따라 달라질 수 있습니다.
- token 추정은 실제 provider usage와 차이가 날 수 있습니다.

댓글
GitHub 계정으로 로그인하면 댓글을 남길 수 있습니다. 댓글은 GitHub Discussions를 통해 운영됩니다.