OpenAI·Gemini API 키 안전하게 관리하고 토큰 비용 계산하는 법 (Python 완벽 가이드)
OpenAI와 Gemini API 키를 발급받았는데, 소스 코드에 그냥 붙여넣으면 안 된다는 건 알겠는데 그럼 어떻게 해야 할까요? 잘못 관리된 API 키 하나가 GitHub에 올라가는 순간 수백만 원짜리 청구서가 날아올 수 있습니다. 이 글에서는 Python 프로젝트에서 API 키를 안전하게 저장·로드하는 방법부터, 토큰 비용을 미리 계산해서 예상치 못한 요금 폭탄을 막는 실전 기법까지 단계별로 알려드립니다.
목차
- 🔑 API 키를 하드코딩하면 왜 위험한가
- 📦 .env 파일과 python-dotenv로 키 관리하기
- 🖥️ 환경 변수(OS Environment Variable)로 관리하기
- 🛡️ .gitignore 설정으로 키 유출 원천 차단
- ⚙️ OpenAI·Gemini 키 로드 및 연결 검증 코드
- 💰 토큰 비용 계산: 요금 폭탄 막는 법
- 🔒 실무에서 쓰는 고급 보안 패턴
- ✅ 마무리 요약
🔑 API 키를 하드코딩하면 왜 위험한가
API 키는 비밀번호와 같습니다. 소스 코드 안에 직접 쓰면 아래와 같은 경로로 유출됩니다.
- GitHub 공개 저장소 업로드: 실수로 public repo에 push하면 수 분 내에 봇이 스캔해 키를 탈취합니다.
- 코드 공유·스크린샷: 질문 게시판에 코드를 붙여넣을 때 키가 함께 노출됩니다.
- 로그 파일 유출: 에러 로그에 환경 변수 전체가 찍히는 경우도 있습니다.
OpenAI와 Google 모두 유출된 키를 감지하면 즉시 비활성화하지만, 그 전에 이미 수천 달러의 요청이 발생할 수 있습니다. 예방이 유일한 답입니다.
📦 .env 파일과 python-dotenv로 키 관리하기
가장 널리 쓰이는 방법은 .env 파일에 키를 저장하고, python-dotenv 라이브러리로 불러오는 것입니다. 프로젝트 루트에 .env 파일을 만들고 절대 Git에 올리지 않는 것이 핵심입니다.
라이브러리 설치
# 터미널에서 실행
pip install python-dotenv openai google-generativeai tiktoken
.env 파일 작성
프로젝트 루트 폴더에 .env 파일을 생성합니다. 파일명 앞에 점(.)이 붙는 것에 주의하세요.
# .env 파일 (절대 GitHub에 올리지 마세요!)
OPENAI_API_KEY=sk-proj-여기에_실제_키를_붙여넣으세요
GEMINI_API_KEY=AIza여기에_실제_키를_붙여넣으세요
📸 스크린샷 지시: VS Code에서 프로젝트 루트에 .env 파일이 생성된 파일 탐색기 화면. .env 파일이 목록에 보이고, 내용에 API 키 변수가 작성된 상태.
파일명: 20250101_1.png
Python에서 .env 불러오기
🔽 [Click to expand] dotenv 로드 기본 코드
import os
from dotenv import load_dotenv
# 프로젝트 루트의 .env 파일을 자동으로 찾아 환경 변수로 로드
load_dotenv()
# 환경 변수에서 키 읽기
openai_api_key = os.getenv("OPENAI_API_KEY")
gemini_api_key = os.getenv("GEMINI_API_KEY")
# 키가 제대로 로드됐는지 확인 (실제 키 값은 출력하지 않음)
if not openai_api_key:
raise ValueError("OPENAI_API_KEY가 설정되지 않았습니다. .env 파일을 확인하세요.")
if not gemini_api_key:
raise ValueError("GEMINI_API_KEY가 설정되지 않았습니다. .env 파일을 확인하세요.")
print("✅ API 키 로드 완료")
print(f"OpenAI 키 앞 8자리: {openai_api_key[:8]}...")
print(f"Gemini 키 앞 8자리: {gemini_api_key[:8]}...")
load_dotenv()는 .env 파일의 내용을 읽어 os.environ에 등록합니다. 이후 os.getenv()로 어디서든 꺼내 쓸 수 있습니다. 키 값을 직접 출력하는 대신 앞 몇 글자만 확인하는 습관을 들이세요.
🖥️ 환경 변수(OS Environment Variable)로 관리하기
.env 파일 방식은 로컬 개발에 적합하고, 서버나 CI/CD 환경에서는 OS 환경 변수를 직접 설정하는 방식이 더 안전합니다.
운영체제별 환경 변수 설정
# macOS / Linux (터미널)
export OPENAI_API_KEY="sk-proj-여기에_실제_키"
export GEMINI_API_KEY="AIza여기에_실제_키"
# 영구 적용: ~/.bashrc 또는 ~/.zshrc 파일 맨 아래에 위 두 줄 추가 후
source ~/.zshrc
# Windows (PowerShell)
$env:OPENAI_API_KEY="sk-proj-여기에_실제_키"
$env:GEMINI_API_KEY="AIza여기에_실제_키"
# 영구 적용 (시스템 환경 변수)
[System.Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-proj-여기에_실제_키", "User")
OS 환경 변수로 설정하면 load_dotenv() 없이도 os.getenv()로 바로 읽을 수 있습니다. GitHub Actions, AWS, GCP 같은 클라우드 환경에서는 각 플랫폼의 Secrets 기능을 사용해 환경 변수를 주입합니다.
🛡️ .gitignore 설정으로 키 유출 원천 차단
.env 파일을 만들었다면 반드시 .gitignore에 등록해야 합니다. Git이 해당 파일을 추적하지 않도록 막는 것입니다.
# .gitignore 파일에 아래 내용 추가
.env
.env.local
.env.*.local
*.pem
*_secret*
secrets/
이미 실수로 .env를 커밋했다면, 단순히 .gitignore에 추가하는 것만으로는 부족합니다. Git 캐시에서도 제거해야 합니다.
# 이미 커밋된 .env를 Git 추적에서 제거 (파일 자체는 삭제되지 않음)
git rm --cached .env
git commit -m "chore: .env를 Git 추적에서 제거"
git push
그리고 즉시 해당 API 키를 폐기하고 새 키를 발급받으세요. 한 번 커밋 히스토리에 올라간 키는 히스토리를 완전히 재작성하지 않는 한 남아있습니다.
⚙️ OpenAI·Gemini 키 로드 및 연결 검증 코드
키를 안전하게 불러왔다면, 실제로 API에 연결되는지 검증하는 코드를 작성해봅니다.
🔽 [Click to expand] OpenAI 연결 검증 코드
import os
from dotenv import load_dotenv
from openai import OpenAI
# .env 파일 로드
load_dotenv()
# OpenAI 클라이언트 초기화 (api_key를 명시적으로 전달)
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def verify_openai_connection():
"""OpenAI API 연결을 검증하는 함수"""
try:
# 가장 저렴한 모델로 최소한의 요청을 보내 연결 확인
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "ping"}],
max_tokens=5 # 비용 최소화를 위해 응답 토큰 제한
)
print("✅ OpenAI 연결 성공")
print(f"모델: {response.model}")
print(f"응답: {response.choices[0].message.content}")
return True
except Exception as e:
print(f"❌ OpenAI 연결 실패: {e}")
return False
verify_openai_connection()
🔽 [Click to expand] Gemini 연결 검증 코드
import os
from dotenv import load_dotenv
import google.generativeai as genai
# .env 파일 로드
load_dotenv()
# Gemini API 키 설정
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
def verify_gemini_connection():
"""Gemini API 연결을 검증하는 함수"""
try:
# Gemini 모델 초기화
model = genai.GenerativeModel("gemini-1.5-flash")
# 간단한 요청으로 연결 확인
response = model.generate_content("ping")
print("✅ Gemini 연결 성공")
print(f"응답: {response.text}")
return True
except Exception as e:
print(f"❌ Gemini 연결 실패: {e}")
return False
verify_gemini_connection()
📸 스크린샷 지시: 터미널에서 위 검증 코드를 실행했을 때 "✅ OpenAI 연결 성공"과 "✅ Gemini 연결 성공" 메시지가 출력된 화면.
파일명: 20250101_2.png
💰 토큰 비용 계산: 요금 폭탄 막는 법
토큰(Token)은 AI 모델이 텍스트를 처리하는 단위입니다. 영어는 단어 하나가 대략 1~2토큰, 한국어는 글자 하나가 1~3토큰 정도입니다. API 요금은 입력(Input) 토큰과 출력(Output) 토큰을 합산해 청구됩니다.
(tiktoken)"] Tokenizer --> InputTokens["입력 토큰 수"] InputTokens --> API["OpenAI / Gemini API"] API --> OutputTokens["출력 토큰 수"] InputTokens --> CostCalc["비용 계산"] OutputTokens --> CostCalc CostCalc --> Bill["💰 최종 청구 금액"]
OpenAI 토큰 수 미리 계산하기 (tiktoken)
OpenAI는 tiktoken이라는 공식 라이브러리로 API 호출 전에 토큰 수를 정확히 계산할 수 있습니다.
🔽 [Click to expand] tiktoken으로 토큰 수 및 예상 비용 계산
import tiktoken
def count_tokens_and_cost(text: str, model: str = "gpt-4o-mini") -> dict:
"""
텍스트의 토큰 수와 예상 비용을 계산하는 함수
Args:
text: 토큰을 계산할 텍스트
model: 사용할 OpenAI 모델명
Returns:
토큰 수와 예상 비용 정보 딕셔너리
"""
# 모델에 맞는 인코더 로드
try:
encoding = tiktoken.encoding_for_model(model)
except KeyError:
# 모델을 찾지 못하면 기본 인코더 사용
encoding = tiktoken.get_encoding("cl100k_base")
# 토큰 수 계산
tokens = encoding.encode(text)
token_count = len(tokens)
# 2025년 기준 gpt-4o-mini 가격 (달러/1M 토큰)
# 최신 가격은 platform.openai.com/docs/pricing 에서 확인하세요
pricing = {
"gpt-4o-mini": {"input": 0.15, "output": 0.60}, # $0.15 / 1M input tokens
"gpt-4o": {"input": 2.50, "output": 10.00}, # $2.50 / 1M input tokens
"gpt-3.5-turbo": {"input": 0.50, "output": 1.50}, # $0.50 / 1M input tokens
}
# 해당 모델의 가격 정보 가져오기
model_price = pricing.get(model, {"input": 0, "output": 0})
# 입력 토큰 비용 계산 (달러)
input_cost_usd = (token_count / 1_000_000) * model_price["input"]
# 원화 환산 (환율은 변동되므로 참고용)
usd_to_krw = 1380
input_cost_krw = input_cost_usd * usd_to_krw
return {
"model": model,
"token_count": token_count,
"input_cost_usd": round(input_cost_usd, 6),
"input_cost_krw": round(input_cost_krw, 4),
}
# 사용 예시
sample_text = """
안녕하세요! 오늘 날씨가 정말 좋네요.
Python으로 API를 호출하는 방법을 배우고 있습니다.
OpenAI와 Gemini API를 함께 사용하면 정말 강력한 애플리케이션을 만들 수 있어요.
"""
result = count_tokens_and_cost(sample_text, model="gpt-4o-mini")
print(f"모델: {result['model']}")
print(f"토큰 수: {result['token_count']:,}개")
print(f"예상 입력 비용: ${result['input_cost_usd']} (약 {result['input_cost_krw']}원)")
API 응답에서 실제 사용 토큰 확인하기
API 호출 후 응답 객체에는 실제로 사용된 토큰 정보가 포함됩니다. 이를 누적해서 모니터링하면 비용을 정확히 추적할 수 있습니다.
🔽 [Click to expand] 실제 사용 토큰 추적 코드
import os
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# 세션 누적 비용 추적
total_input_tokens = 0
total_output_tokens = 0
def chat_with_cost_tracking(user_message: str, model: str = "gpt-4o-mini") -> str:
"""
비용을 추적하면서 채팅하는 함수
Args:
user_message: 사용자 메시지
model: 사용할 모델
Returns:
AI 응답 텍스트
"""
global total_input_tokens, total_output_tokens
# 2025년 기준 가격 (달러/1M 토큰)
pricing = {
"gpt-4o-mini": {"input": 0.15, "output": 0.60},
"gpt-4o": {"input": 2.50, "output": 10.00},
}
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": user_message}]
)
# 응답 객체에서 실제 사용 토큰 추출
usage = response.usage
input_tokens = usage.prompt_tokens
output_tokens = usage.completion_tokens
# 누적 토큰 업데이트
total_input_tokens += input_tokens
total_output_tokens += output_tokens
# 이번 요청 비용 계산
model_price = pricing.get(model, {"input": 0, "output": 0})
this_cost = (
(input_tokens / 1_000_000) * model_price["input"] +
(output_tokens / 1_000_000) * model_price["output"]
)
# 누적 총 비용 계산
total_cost = (
(total_input_tokens / 1_000_000) * model_price["input"] +
(total_output_tokens / 1_000_000) * model_price["output"]
)
print(f"[이번 요청] 입력: {input_tokens}토큰, 출력: {output_tokens}토큰, 비용: ${this_cost:.6f}")
print(f"[누적 합계] 입력: {total_input_tokens}토큰, 출력: {total_output_tokens}토큰, 총 비용: ${total_cost:.6f}")
return response.choices[0].message.content
# 사용 예시
reply = chat_with_cost_tracking("Python에서 리스트와 튜플의 차이를 간단히 설명해줘")
print(f"\n응답: {reply}")
Gemini 토큰 수 확인하기
import os
from dotenv import load_dotenv
import google.generativeai as genai
load_dotenv()
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
model = genai.GenerativeModel("gemini-1.5-flash")
# API 호출 전 토큰 수 미리 계산
sample_prompt = "Python의 장점을 세 가지 설명해줘"
token_count = model.count_tokens(sample_prompt)
print(f"예상 입력 토큰 수: {token_count.total_tokens}")
# 실제 호출 후 사용 토큰 확인
response = model.generate_content(sample_prompt)
print(f"실제 사용 토큰: {response.usage_metadata}")
🔒 실무에서 쓰는 고급 보안 패턴
키 유효성 검사 및 설정 클래스 패턴
프로젝트 규모가 커지면 API 키 관련 설정을 한 곳에서 관리하는 것이 좋습니다. 아래는 pydantic을 활용한 설정 관리 패턴입니다. 이 방식은 키가 없거나 형식이 잘못됐을 때 앱 시작 시점에 즉시 오류를 발생시켜 런타임 중 예상치 못한 실패를 방지합니다.
🔽 [Click to expand] Pydantic 기반 설정 관리 클래스
import os
from dotenv import load_dotenv
from pydantic import BaseModel, field_validator
load_dotenv()
class APISettings(BaseModel):
"""API 키 설정을 검증하고 관리하는 클래스"""
openai_api_key: str
gemini_api_key: str
@field_validator("openai_api_key")
@classmethod
def validate_openai_key(cls, v: str) -> str:
"""OpenAI 키 형식 검증 (sk- 또는 sk-proj- 로 시작해야 함)"""
if not v.startswith(("sk-", "sk-proj-")):
raise ValueError("유효하지 않은 OpenAI API 키 형식입니다.")
if len(v) < 20:
raise ValueError("OpenAI API 키가 너무 짧습니다.")
return v
@field_validator("gemini_api_key")
@classmethod
def validate_gemini_key(cls, v: str) -> str:
"""Gemini 키 형식 검증 (AIza로 시작해야 함)"""
if not v.startswith("AIza"):
raise ValueError("유효하지 않은 Gemini API 키 형식입니다.")
return v
@property
def masked_openai_key(self) -> str:
"""로그 출력용 마스킹된 OpenAI 키"""
return f"{self.openai_api_key[:8]}...{self.openai_api_key[-4:]}"
@property
def masked_gemini_key(self) -> str:
"""로그 출력용 마스킹된 Gemini 키"""
return f"{self.gemini_api_key[:8]}...{self.gemini_api_key[-4:]}"
# 앱 시작 시 한 번만 초기화 (키 오류 시 즉시 예외 발생)
try:
settings = APISettings(
openai_api_key=os.getenv("OPENAI_API_KEY", ""),
gemini_api_key=os.getenv("GEMINI_API_KEY", ""),
)
print(f"✅ 설정 로드 완료")
print(f"OpenAI 키: {settings.masked_openai_key}")
print(f"Gemini 키: {settings.masked_gemini_key}")
except Exception as e:
print(f"❌ 설정 오류: {e}")
raise SystemExit(1) # 키 오류 시 앱 종료
API 사용량 한도 설정 (필수!)
코드 레벨의 보안과 함께, 플랫폼 대시보드에서 월별 지출 한도를 설정하는 것이 가장 확실한 요금 폭탄 방지책입니다.
- OpenAI:
platform.openai.com→ Settings → Limits → Set a monthly budget - Google AI Studio:
aistudio.google.com→ API 키 관리 → 할당량 설정. 또는 Google Cloud Console에서 API 할당량 제한 설정
📸 스크린샷 지시: OpenAI 플랫폼 대시보드의 Settings > Limits 화면에서 Monthly budget 설정 필드가 보이는 화면.
파일명: 20250101_3.png
✅ 마무리 요약
API 키는 절대 소스 코드에 직접 쓰지 말고, .env 파일 + python-dotenv 조합으로 관리하며 .gitignore에 반드시 등록하세요. tiktoken으로 호출 전 토큰 수를 미리 계산하고, 응답 객체의 usage 필드로 실제 비용을 추적하면 예상치 못한 청구를 막을 수 있습니다. 코드 보안과 함께 플랫폼 대시보드의 월별 지출 한도 설정을 병행하는 것이 가장 안전한 이중 방어선입니다.
Comments
Post a Comment