Gemini 2.5 Flash API 비용 최적화 실전 가이드 — 실험으로 확인한 99% 절감 전략
Gemini 2.5 Flash API를 직접 실험해서 발견한 비용 최적화 기법 4가지. Thinking 토큰 비활성화, Context Caching, Flash-Lite 선택 기준, Batch API까지 — 실제 측정값으로 설명합니다.
직접 API를 호출해봤더니 예상과 다른 결과가 나왔다.
“15% of 240은 얼마야?” 라는 단순한 질문을 Gemini 2.5 Flash에 보냈다. 응답은 “36” — 총 2개 토큰. 그런데 청구서에는 305개 토큰이 찍혀 있었다. 그 차이 대부분이 내가 보낸 것도, 받은 것도 아닌 Thinking(추론) 토큰이었다.
비용 계산을 해봤다. 입력+출력: $0.000010. Thinking: $0.001067. 총 비용의 99.1%가 내가 쓰지도 않은 토큰에서 나왔다.
이게 내가 이 글을 쓰게 된 이유다. Gemini 2.5 Flash는 강력한 모델이지만, 아무 설정 없이 쓰면 예상보다 훨씬 많은 비용이 나온다. 오늘은 내가 실제로 실험하면서 확인한 비용 최적화 전략 4가지를 공유한다.
환경 정보: macOS Darwin 24.6.0, Python 3.12.8, google-genai 1.72.0.
시작 전: Gemini 2.5 Flash 요금 구조 이해
최적화하기 전에 무엇이 돈을 쓰는지부터 파악해야 한다. Gemini 2.5 Flash의 요금 구조(2026년 5월 기준)는 세 종류다.
| 토큰 유형 | 가격 (1M 토큰당) |
|---|---|
| 입력(Input) | $0.30 |
| 출력(Output) | $2.50 |
| Thinking | $3.50 |
| 캐시 읽기(Cache Read) | $0.075 |
한 가지 더: gemini-2.5-flash-lite는 입력 $0.10, 출력 $0.40이다. 언뜻 훨씬 저렴해 보이지만, 항상 그런 건 아니다. 이 부분은 Step 3에서 실험 결과와 함께 설명하겠다.
세팅부터 하자. LLM API 가격 비교 2026에서도 확인할 수 있지만, 오늘은 Gemini 2.5 Flash에 집중한다.
pip install google-genai
from google import genai
from google.genai import types
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
Step 1: Thinking 토큰을 통제하라 — 단순 작업에서 99% 절감
Gemini 2.5 Flash는 기본값으로 Thinking(추론) 모드가 활성화된다. 복잡한 문제를 더 잘 풀기 위해 내부적으로 추론 과정을 거치는데, 이 과정이 전부 청구된다.
솔직히 처음엔 이게 이렇게 클 줄 몰랐다. 직접 측정해보니 단순 수학 문제 하나에 305개의 Thinking 토큰이 소비됐다. 응답 토큰은 2개인데.
# Thinking 활성화 (기본값) — 같은 질문
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="What is 15% of 240? Just give the number.",
config=types.GenerateContentConfig(
thinking_config=types.ThinkingConfig(thinking_budget=1024)
)
)
usage = response.usage_metadata
print(f"Input: {usage.prompt_token_count}") # 18
print(f"Output: {usage.candidates_token_count}") # 2
print(f"Thinking: {usage.thoughts_token_count}") # 305
print(f"Cost: ~$0.001078") # 99%가 Thinking
# Thinking 비활성화 (budget=0)
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="What is 15% of 240? Just give the number.",
config=types.GenerateContentConfig(
thinking_config=types.ThinkingConfig(thinking_budget=0)
)
)
usage = response.usage_metadata
print(f"Input: {usage.prompt_token_count}") # 18
print(f"Output: {usage.candidates_token_count}") # 2
print(f"Thinking: 0")
print(f"Cost: ~$0.000010") # 99% 절감
실제 측정 결과:

| 설정 | 비용 | 응답 시간 |
|---|---|---|
| Thinking ON (budget=1024) | $0.001078 | 2.36s |
| Thinking OFF (budget=0) | $0.000010 | 0.80s |
| 절감 | 99.1% | 66% 단축 |
단, Thinking이 필요한 경우는 있다. 다음 기준으로 판단하자:
- Thinking OFF: 분류, 데이터 추출, 단순 변환, JSON 파싱, 고정 답변이 있는 질문
- Thinking ON: 코드 디버깅, 수학적 추론, 다단계 논리, 창의적 글쓰기
- Thinking budget 조정:
thinking_budget을 128〜512로 낮춰 복잡도에 맞게 제한 가능
# 실용적인 wrapper: 작업 유형별로 thinking 설정 분리
def call_gemini(prompt: str, task_type: str = "simple") -> str:
thinking_budget = 0 if task_type == "simple" else 1024
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=prompt,
config=types.GenerateContentConfig(
thinking_config=types.ThinkingConfig(thinking_budget=thinking_budget)
)
)
return response.text
나는 이 패턴을 프로덕션에서 쓴다면 가장 먼저 적용할 것이다. 비용 절감폭이 가장 크고 코드 변경도 한 줄이다.
Step 2: Context Caching으로 반복 컨텍스트 비용 제거
챗봇이나 RAG 시스템을 만들 때 매 요청마다 긴 시스템 프롬프트나 문서를 함께 보내는 경우가 많다. Context Caching은 이 부분을 서버에 저장해두고 캐시 읽기 요금(입력의 25%)만 내는 방식이다.
실험 중 중요한 제약을 발견했다. Context Caching을 시도했더니 이런 에러가 났다:
400 INVALID_ARGUMENT: Cached content is too small.
total_token_count=524, min_total_token_count=1024
최소 1024 토큰 이상의 컨텍스트에만 사용 가능하다. 짧은 시스템 프롬프트에는 적용이 안 된다. 설계 단계에서 캐싱을 고려한다면 시스템 프롬프트를 충분히 풍부하게 만들거나, 관련 문서를 함께 포함시켜야 한다.
# Context Cache 생성 (캐시할 내용이 1024+ 토큰이어야 함)
cache = client.caches.create(
model="gemini-2.5-flash",
config={
"contents": [
types.Content(
role="user",
parts=[types.Part(text=LONG_SYSTEM_PROMPT)] # 1024+ tokens
)
],
"ttl": "3600s", # 1시간 유지
}
)
# 캐시를 활용한 요청
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="사용자 질문",
config=types.GenerateContentConfig(cached_content=cache.name)
)
# 캐시 삭제 (TTL 전에 수동 삭제 가능)
client.caches.delete(cache.name)
캐시 읽기 요금은 $0.075/1M 토큰 — 일반 입력($0.30)의 25%다. 같은 컨텍스트를 10번 이상 재사용한다면 충분히 이득이다.
Context Caching이 효과적인 시나리오:
- 긴 시스템 프롬프트(1000+ 토큰)를 매 요청마다 전송하는 챗봇
- RAG에서 검색된 문서를 여러 질문에 걸쳐 재사용할 때
- 코드베이스나 매뉴얼 전체를 컨텍스트로 쓰는 코딩 어시스턴트
Claude API의 Prompt Caching과 개념은 같지만 구현 세부사항이 다르다. Anthropic은 캐시 마커를 명시적으로 지정하는 반면, Gemini는 캐시 객체를 별도로 생성하는 방식이다.
Step 3: Flash vs Flash-Lite — 항상 Lite가 싸지 않다
가격표만 보면 Flash-Lite가 압도적으로 저렴해 보인다. 입력이 3배 싸고 출력이 6배 싸다. 하지만 내 실험 결과는 달랐다.
같은 3가지 작업(분류, 코드 생성, 데이터 추출)을 두 모델에서 실행한 결과:
| 모델 | 총 비용 | 총 시간 |
|---|---|---|
| gemini-2.5-flash | $0.000176 | 6.16s |
| gemini-2.5-flash-lite | $0.000224 | 4.57s |
Flash-Lite가 27% 더 비쌌다. 왜 그랬을까?
코드 생성 작업에서 Flash는 요약된 답변(20 토큰)을 냈지만 Flash-Lite는 max_output_tokens=500 한도까지 상세한 코드를 생성했다. 출력 토큰이 많아지면 Flash-Lite의 이점이 사라진다.
# 출력 길이 제한: max_output_tokens는 항상 설정할 것
response = client.models.generate_content(
model="gemini-2.5-flash-lite",
contents=prompt,
config=types.GenerateContentConfig(
max_output_tokens=200, # 명시적 상한
temperature=0.0, # 결정론적 응답
)
)
선택 가이드:
| 작업 유형 | 추천 모델 | 이유 |
|---|---|---|
| 감정 분류, 태깅 | Flash-Lite | 출력 1〜5 토큰, 단순 |
| JSON 추출 | Flash-Lite | 구조화된 짧은 출력 |
| 코드 생성 | Flash | 긴 출력에서 단가 역전 |
| 복잡한 추론 | Flash | Thinking 품질 차이 |
| 고볼륨 배치 처리 | Batch API + 결정 | 50% 할인 적용 후 재계산 |
솔직히 이걸 모르고 Flash-Lite를 “항상 저렴하다”고 가정하면 실제 청구서에서 당황할 수 있다. 본인 워크로드의 평균 출력 토큰을 먼저 측정하는 게 순서다.
이런 작업별 모델 선택은 이종 LLM 아키텍처 비용 최적화에서 다루는 멀티 모델 라우팅 패턴과 연결된다.
Step 4: Batch API로 비긴급 작업 50% 할인
실시간 응답이 필요 없는 작업이 있다면 Batch API를 쓸 수 있다. Google은 배치 처리에 50% 할인을 제공한다 — Anthropic Message Batches API와 같은 맥락이다.
Anthropic Message Batches API 실전 가이드에서 배치 처리 패턴을 자세히 다뤘는데, Gemini도 동일한 원리다.
Gemini Batch API 사용 예시:
# 여러 요청을 파일로 저장 후 배치 제출
import json
# 배치 요청 파일 생성
requests = [
{"key": f"req_{i}", "request": {"contents": [{"parts": [{"text": prompt}]}]}}
for i, prompt in enumerate(prompts_list)
]
with open("batch_requests.jsonl", "w") as f:
for req in requests:
f.write(json.dumps(req) + "\n")
# 배치 작업 생성
batch_job = client.batches.create(
model="gemini-2.5-flash",
src="gs://your-bucket/batch_requests.jsonl", # GCS 경로 필요
config={"dest": "gs://your-bucket/results/"},
)
print(f"Batch job created: {batch_job.name}")
print(f"Status: {batch_job.state}")
# 완료까지 최대 24시간 소요
배치가 적합한 작업:
- 대량 문서 요약 (야간 배치)
- 콘텐츠 분류/태깅 파이프라인
- 데이터셋 레이블링
- 정기 리포트 생성
배치가 부적합한 작업:
- 사용자 인터페이스에서 실시간 응답이 필요한 경우
- 이전 응답에 따라 다음 프롬프트가 바뀌는 대화형 흐름
Step 5: max_output_tokens로 비용 상한 설정
가장 간단하지만 자주 빠뜨리는 방법이다. 출력 토큰에 상한을 두면 예상치 못한 과도한 응답을 방지할 수 있다.
config = types.GenerateContentConfig(
max_output_tokens=500, # 최대 출력 제한
temperature=0.0, # 결정론적 (재시도 줄이기)
stop_sequences=["---"], # 명확한 종료 지점
)
이것만으로도 Flash-Lite가 Flash보다 비싸진 내 실험 상황(코드 생성에서 500토큰 소비)을 방지할 수 있다.
프롬프트에서도 출력 길이를 직접 지시하는 것이 효과적이다:
"JSON으로만 응답하세요. 100 토큰 이하로 유지하세요."
"한 문장으로 요약하세요."
"예/아니오 중 하나만 답하세요."
Step 6: 사용량 로깅 — 최적화의 전제 조건
비용을 최적화하기 전에 먼저 어디서 비용이 나오는지 알아야 한다. usage_metadata를 모든 응답에서 수집하는 간단한 래퍼를 만들면 된다.
import time, logging, json
from dataclasses import dataclass, asdict
from google import genai
from google.genai import types
@dataclass
class CallRecord:
model: str
task_type: str
input_tokens: int
output_tokens: int
thinking_tokens: int
cost_usd: float
latency_ms: int
PRICING = {
"gemini-2.5-flash": {"input": 0.30, "output": 2.50, "thinking": 3.50},
"gemini-2.5-flash-lite": {"input": 0.10, "output": 0.40, "thinking": 0.0},
}
def tracked_generate(client, model: str, prompt: str, task_type: str, **kwargs) -> str:
start = time.time()
response = client.models.generate_content(
model=model, contents=prompt, **kwargs
)
elapsed_ms = int((time.time() - start) * 1000)
u = response.usage_metadata
p = PRICING.get(model, PRICING["gemini-2.5-flash"])
thinking = getattr(u, "thoughts_token_count", None) or 0
cost = (
(u.prompt_token_count / 1e6) * p["input"]
+ (u.candidates_token_count / 1e6) * p["output"]
+ (thinking / 1e6) * p["thinking"]
)
record = CallRecord(
model=model,
task_type=task_type,
input_tokens=u.prompt_token_count,
output_tokens=u.candidates_token_count,
thinking_tokens=thinking,
cost_usd=cost,
latency_ms=elapsed_ms,
)
logging.info(json.dumps(asdict(record))) # 로그 수집기로 전송
return response.text
# 사용 예시
result = tracked_generate(
client=client,
model="gemini-2.5-flash",
prompt="Classify this email as spam or not: ...",
task_type="classification",
config=types.GenerateContentConfig(
thinking_config=types.ThinkingConfig(thinking_budget=0)
)
)
이 패턴으로 몇 가지를 주기적으로 모니터링하면 된다:
- thinking_tokens / total_tokens 비율: 전체 비용에서 Thinking이 차지하는 비율 추적
- 작업 유형별 평균 비용: 어떤 task_type이 돈을 가장 많이 쓰는지 파악
- 모델별 출력 토큰 분포: Flash-Lite가 Flash보다 더 길게 응답하는 작업 타입 식별
프로덕션에서 Thinking 토큰 비율이 50%를 넘으면 그 작업에는 thinking_budget=0을 먼저 시도해볼 만하다.
실험에서 발견한 것들
이 글을 쓰면서 생각보다 흥미로운 사실들을 발견했다.
첫째, Thinking 토큰은 예측하기 어렵다. 같은 모델에 비슷한 질문을 해도 Thinking 토큰 수가 크게 달라진다. “15% of 240”에 305개가 소비됐지만, 다른 단순 질문에는 훨씬 적게 쓰일 수 있다. 이걸 정확히 제어하려면 thinking_budget으로 상한을 명시해야 한다.
둘째, Context Caching의 1024 토큰 최소 요건은 생각보다 설계에 영향을 준다. 짧은 시스템 프롬프트를 쓰는 앱이라면 캐싱을 위해 프롬프트를 의도적으로 풍부하게 만들어야 할 수도 있다. 문서화, 예시, 규칙을 상세히 쓰는 것이 비용을 아끼는 역설적인 상황이 된다.
셋째, Flash-Lite가 Flash보다 비싼 상황이 실제로 존재한다. 이건 단가 차이가 입력/출력 비율에 따라 역전될 수 있다는 뜻이다. 특히 출력이 긴 코드 생성이나 장문 요약에서는 반드시 실제 측정을 해보자.
아쉬운 점도 있다. Context Caching의 GCS 의존성(배치 API도 마찬가지)은 간단한 앱에서 진입 장벽이 된다. Anthropic의 캐싱 방식(HTTP 헤더 하나로 활성화)이 이 면에서는 더 간단하다.
비용 최적화 결정 매트릭스
정리하면 이렇다.
작업 유형 결정 흐름:
1. 출력이 짧은가? (< 50 토큰)
YES → Flash-Lite + thinking_budget=0
NO → Flash + thinking_budget 평가
2. 같은 컨텍스트를 10번 이상 재사용하는가?
YES + 컨텍스트 >= 1024 토큰 → Context Caching 추가
NO → 개별 호출
3. 실시간 응답이 필요한가?
NO → Batch API (50% 할인)
YES → 위 설정 유지
4. 복잡한 추론이 필요한가?
NO → thinking_budget=0 (단순 작업: 99% 절감)
YES → thinking_budget 128~1024 범위에서 조정
Gemini 2.5 Flash는 충분히 강력한 모델이다. 하지만 기본값으로 쓰면 Thinking 토큰이 조용히 비용의 대부분을 가져간다. 이 가이드의 핵심은 결국 하나다: 측정하고, 통제하라.
비용을 측정하지 않고 최적화하는 건 GPS 없이 운전하는 것과 같다. usage_metadata를 매 응답마다 로깅하고, Thinking 토큰이 전체의 몇 %를 차지하는지 확인하는 것에서 시작하면 된다.
이 글에서 다룬 최적화를 모두 적용한다고 해서 항상 최대 절감을 달성하는 건 아니다. 각 기법은 특정 조건에서 효과가 있다. Thinking OFF는 단순 작업에서 압도적이고, Context Caching은 1024+ 토큰의 반복 컨텍스트가 있을 때만 유효하며, Flash-Lite는 출력이 짧은 작업에서만 실제로 저렴하다. 본인 워크로드를 먼저 측정하고, 그 다음 적합한 기법을 선택하는 순서가 맞다.
google-genai SDK는 이 글을 작성하는 시점에 1.72.0이었다. API와 요금 구조는 변경될 수 있으니 Google AI Studio 가격 페이지에서 최신 정보를 확인하자.
다른 언어로 읽기
- 🇰🇷 한국어 (현재 페이지)
- 🇯🇵 日本語
- 🇺🇸 English
- 🇨🇳 中文
글이 도움이 되셨나요?
더 나은 콘텐츠를 작성하는 데 힘이 됩니다. 커피 한 잔으로 응원해주세요.