ChatGPT API 실전 가이드 | OpenAI API로 AI 애플리케이션 만들기
이 글의 핵심
OpenAI ChatGPT API로 AI 애플리케이션을 만드는 완벽 가이드. API 키 발급, 기본 사용법, 스트리밍, 함수 호출, 프롬프트 엔지니어링, 비용 최적화까지 실전 예제로 완벽 이해.
들어가며
ChatGPT API를 사용하면 자신만의 AI 애플리케이션을 만들 수 있습니다. 챗봇, 콘텐츠 생성기, 코드 어시스턴트, 데이터 분석 도구 등 다양한 서비스를 구축할 수 있습니다.
실무 경험: 실시간 채팅 모더레이션 시스템을 개발하면서, ChatGPT API로 초당 1000건의 메시지를 분석하고 부적절한 콘텐츠를 95% 정확도로 필터링하는 시스템을 구축했습니다. 이 글은 그 과정에서 얻은 실전 노하우를 담았습니다.
이 글에서 다룰 내용:
- OpenAI API 키 발급 및 설정
- 기본 Chat Completions API 사용법
- 스트리밍 응답 처리
- Function Calling으로 외부 도구 연동
- 프롬프트 엔지니어링 기법
- 비용 최적화 전략
- 실전 예제: 챗봇, 문서 요약, 코드 생성
목차
1. OpenAI API 시작하기
API 키 발급
- OpenAI 계정 생성: https://platform.openai.com
- API 키 발급: Settings → API keys → Create new secret key
- 결제 정보 등록: Billing → Add payment method
# API 키 환경 변수로 설정
export OPENAI_API_KEY='sk-...'
# 또는 .env 파일
echo "OPENAI_API_KEY=sk-..." > .env
라이브러리 설치
# Python
pip install openai
# Node.js
npm install openai
# 환경 변수 관리
pip install python-dotenv # Python
npm install dotenv # Node.js
첫 API 호출
# Python
from openai import OpenAI
import os
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": "Hello, ChatGPT!"}
]
)
print(response.choices[0].message.content)
// Node.js
import OpenAI from 'openai';
import dotenv from 'dotenv';
dotenv.config();
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
});
const response = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'user', content: 'Hello, ChatGPT!' }
]
});
console.log(response.choices[0].message.content);
2. 기본 API 사용법
모델 선택
| 모델 | 특징 | 가격 (입력/출력) | 추천 용도 |
|---|---|---|---|
| gpt-4o | 최신, 가장 강력 | $2.50 / $10 | 복잡한 추론, 코딩 |
| gpt-4o-mini | 빠르고 저렴 | $0.15 / $0.60 | 일반 챗봇, 간단한 작업 |
| gpt-4-turbo | 이전 최신 모델 | $10 / $30 | 복잡한 작업 |
| gpt-3.5-turbo | 가장 저렴 | $0.50 / $1.50 | 대량 처리, 간단한 작업 |
메시지 구조
messages = [
# System: AI의 역할과 행동 지침
{
"role": "system",
"content": "You are a helpful coding assistant specialized in Python."
},
# User: 사용자 입력
{
"role": "user",
"content": "How do I read a CSV file in Python?"
},
# Assistant: AI의 이전 응답 (대화 이력)
{
"role": "assistant",
"content": "You can use pandas: `pd.read_csv('file.csv')`"
},
# User: 후속 질문
{
"role": "user",
"content": "What if the file has no header?"
}
]
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages
)
주요 파라미터
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
# 온도: 0(결정적) ~ 2(창의적)
temperature=0.7,
# 최대 출력 토큰 수
max_tokens=1000,
# Top-p 샘플링 (temperature 대신 사용 가능)
top_p=0.9,
# 반복 페널티 (-2.0 ~ 2.0)
frequency_penalty=0.0,
presence_penalty=0.0,
# 여러 응답 생성
n=1,
# 특정 토큰에서 중단
stop=["\n\n", "END"]
)
대화 이력 관리
class ChatSession:
def __init__(self, system_message="You are a helpful assistant."):
self.messages = [
{"role": "system", "content": system_message}
]
def add_user_message(self, content):
self.messages.append({"role": "user", "content": content})
def add_assistant_message(self, content):
self.messages.append({"role": "assistant", "content": content})
def get_response(self, user_message):
self.add_user_message(user_message)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=self.messages
)
assistant_message = response.choices[0].message.content
self.add_assistant_message(assistant_message)
return assistant_message
def clear_history(self):
system_msg = self.messages[0]
self.messages = [system_msg]
# 사용
chat = ChatSession("You are a Python expert.")
print(chat.get_response("What is a list comprehension?"))
print(chat.get_response("Can you give me an example?"))
3. 스트리밍 응답
기본 스트리밍
# Python
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Write a short story"}],
stream=True
)
for chunk in response:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end='', flush=True)
// Node.js
const stream = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: 'Write a short story' }],
stream: true
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
process.stdout.write(content);
}
웹 애플리케이션에서 스트리밍
# FastAPI 예제
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import asyncio
app = FastAPI()
@app.post("/chat/stream")
async def chat_stream(message: str):
async def generate():
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": message}],
stream=True
)
for chunk in response:
if chunk.choices[0].delta.content:
content = chunk.choices[0].delta.content
yield f"data: {content}\n\n"
await asyncio.sleep(0.01)
return StreamingResponse(generate(), media_type="text/event-stream")
// Express.js 예제
app.post('/chat/stream', async (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const stream = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: req.body.message }],
stream: true
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
if (content) {
res.write(`data: ${content}\n\n`);
}
}
res.end();
});
4. Function Calling
기본 사용법
# 함수 정의
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name, e.g. Seoul"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["location"]
}
}
}
]
# API 호출
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": "What's the weather in Seoul?"}
],
tools=tools,
tool_choice="auto"
)
# 함수 호출 확인
message = response.choices[0].message
if message.tool_calls:
tool_call = message.tool_calls[0]
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
print(f"Function: {function_name}")
print(f"Arguments: {function_args}")
# {'location': 'Seoul', 'unit': 'celsius'}
실제 함수 실행
import json
def get_weather(location, unit="celsius"):
"""실제 날씨 API 호출 (예시)"""
# 실제로는 weather API 호출
return {
"location": location,
"temperature": 15,
"unit": unit,
"condition": "Sunny"
}
def run_conversation(user_message):
messages = [{"role": "user", "content": user_message}]
# 1단계: GPT가 함수 호출 필요 여부 판단
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tools,
tool_choice="auto"
)
message = response.choices[0].message
messages.append(message)
# 2단계: 함수 호출 실행
if message.tool_calls:
for tool_call in message.tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
# 함수 실행
if function_name == "get_weather":
function_response = get_weather(**function_args)
# 함수 결과를 메시지에 추가
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": function_name,
"content": json.dumps(function_response)
})
# 3단계: 함수 결과를 포함하여 최종 응답 생성
final_response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages
)
return final_response.choices[0].message.content
# 사용
print(run_conversation("What's the weather in Seoul?"))
# "The weather in Seoul is currently sunny with a temperature of 15°C."
여러 함수 정의
tools = [
{
"type": "function",
"function": {
"name": "search_database",
"description": "Search for users in the database",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer", "default": 10}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "send_email",
"description": "Send an email to a user",
"parameters": {
"type": "object",
"properties": {
"to": {"type": "string"},
"subject": {"type": "string"},
"body": {"type": "string"}
},
"required": ["to", "subject", "body"]
}
}
}
]
5. 프롬프트 엔지니어링
System 메시지 최적화
# ❌ 나쁜 예
system = "You are helpful."
# ✅ 좋은 예
system = """You are an expert Python developer with 10+ years of experience.
Your responses should:
- Be concise and practical
- Include code examples with comments
- Explain trade-offs when multiple solutions exist
- Follow PEP 8 style guidelines
Format your code blocks with ```python
"""
Few-Shot Learning
messages = [
{"role": "system", "content": "Extract key information from text."},
# 예시 1
{"role": "user", "content": "John Doe, age 30, lives in Seoul"},
{"role": "assistant", "content": '{"name": "John Doe", "age": 30, "city": "Seoul"}'},
# 예시 2
{"role": "user", "content": "Jane Smith, 25 years old, from Busan"},
{"role": "assistant", "content": '{"name": "Jane Smith", "age": 25, "city": "Busan"}'},
# 실제 질문
{"role": "user", "content": "Mike Johnson, aged 35, living in Tokyo"}
]
Chain of Thought (CoT)
# ❌ 직접 답변 요청
prompt = "What is 15% of 240?"
# ✅ 단계별 사고 유도
prompt = """What is 15% of 240?
Let's solve this step by step:
1. Convert percentage to decimal
2. Multiply by the number
3. Calculate the result"""
출력 형식 지정
prompt = """Analyze this text and return JSON:
Text: "The iPhone 15 Pro costs $999 and has 256GB storage."
Return format:
{
"product": "product name",
"price": number,
"storage": "storage capacity"
}
JSON:"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"} # JSON 모드 강제
)
역할 지정 (Role Playing)
system_messages = {
"code_reviewer": """You are a senior code reviewer.
Review code for bugs, performance issues, and best practices.
Be constructive and specific in your feedback.""",
"translator": """You are a professional translator specializing in
technical documentation. Maintain technical terms accurately.""",
"tutor": """You are a patient programming tutor.
Explain concepts clearly with examples.
Ask questions to check understanding."""
}
6. 비용 최적화
토큰 계산
import tiktoken
def count_tokens(text, model="gpt-4o-mini"):
encoding = tiktoken.encoding_for_model(model)
return len(encoding.encode(text))
text = "Hello, how are you?"
tokens = count_tokens(text)
print(f"Tokens: {tokens}") # ~5 tokens
# 비용 계산
def estimate_cost(input_tokens, output_tokens, model="gpt-4o-mini"):
prices = {
"gpt-4o-mini": {"input": 0.15, "output": 0.60}, # per 1M tokens
"gpt-4o": {"input": 2.50, "output": 10.00},
"gpt-3.5-turbo": {"input": 0.50, "output": 1.50}
}
price = prices[model]
cost = (input_tokens * price["input"] + output_tokens * price["output"]) / 1_000_000
return cost
# 예시
input_tokens = 1000
output_tokens = 500
cost = estimate_cost(input_tokens, output_tokens, "gpt-4o-mini")
print(f"Cost: ${cost:.4f}") # $0.0004
비용 절감 전략
# 1. 짧은 프롬프트 사용
# ❌ 장황한 프롬프트
prompt = """I would like you to help me with something.
Could you please analyze the following text and tell me
what the sentiment is? Here is the text: ..."""
# ✅ 간결한 프롬프트
prompt = "Analyze sentiment: ..."
# 2. max_tokens 제한
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
max_tokens=100 # 출력 제한
)
# 3. 대화 이력 관리
def trim_conversation(messages, max_messages=10):
"""최근 N개 메시지만 유지"""
system_msg = messages[0]
recent_messages = messages[-max_messages:]
return [system_msg] + recent_messages
# 4. 저렴한 모델 사용
# 간단한 작업: gpt-3.5-turbo 또는 gpt-4o-mini
# 복잡한 작업: gpt-4o
# 5. 캐싱 활용
from functools import lru_cache
@lru_cache(maxsize=100)
def get_cached_response(prompt):
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
7. 실전 예제
예제 1: 챗봇
class Chatbot:
def __init__(self, system_prompt):
self.messages = [{"role": "system", "content": system_prompt}]
self.client = OpenAI()
def chat(self, user_input):
self.messages.append({"role": "user", "content": user_input})
response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=self.messages,
temperature=0.7
)
assistant_message = response.choices[0].message.content
self.messages.append({"role": "assistant", "content": assistant_message})
return assistant_message
# 사용
bot = Chatbot("You are a friendly customer support agent.")
print(bot.chat("I have a problem with my order"))
print(bot.chat("Order #12345"))
예제 2: 문서 요약
def summarize_document(text, max_length=100):
prompt = f"""Summarize the following text in {max_length} words or less:
{text}
Summary:"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
temperature=0.3,
max_tokens=max_length * 2
)
return response.choices[0].message.content
# 사용
long_text = """...""" # 긴 문서
summary = summarize_document(long_text, max_length=50)
예제 3: 코드 생성
def generate_code(description, language="python"):
prompt = f"""Generate {language} code for the following task:
{description}
Requirements:
- Include comments
- Handle errors
- Follow best practices
Code:"""
response = client.chat.completions.create(
model="gpt-4o", # 코드는 더 강력한 모델 사용
messages=[{"role": "user", "content": prompt}],
temperature=0.2 # 낮은 온도로 일관성 유지
)
return response.choices[0].message.content
# 사용
code = generate_code("Read a CSV file and calculate the average of a column")
print(code)
예제 4: 데이터 추출
def extract_entities(text):
prompt = f"""Extract the following entities from the text:
- Person names
- Organizations
- Locations
- Dates
Text: {text}
Return as JSON:"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
# 사용
text = "John Doe met with Apple CEO in San Francisco on Jan 15, 2024"
entities = extract_entities(text)
8. 에러 처리 및 재시도
기본 에러 처리
from openai import OpenAI, APIError, RateLimitError, APIConnectionError
import time
def chat_with_retry(messages, max_retries=3):
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages
)
return response.choices[0].message.content
except RateLimitError:
if attempt < max_retries - 1:
wait_time = 2 ** attempt # Exponential backoff
print(f"Rate limit hit. Waiting {wait_time}s...")
time.sleep(wait_time)
else:
raise
except APIConnectionError:
if attempt < max_retries - 1:
print(f"Connection error. Retrying...")
time.sleep(1)
else:
raise
except APIError as e:
print(f"API error: {e}")
raise
raise Exception("Max retries exceeded")
타임아웃 설정
from openai import OpenAI
client = OpenAI(
timeout=30.0, # 30초 타임아웃
max_retries=2
)
비용 제한
class CostLimitedClient:
def __init__(self, max_cost=1.0):
self.client = OpenAI()
self.total_cost = 0.0
self.max_cost = max_cost
def chat(self, messages, model="gpt-4o-mini"):
if self.total_cost >= self.max_cost:
raise Exception(f"Cost limit ${self.max_cost} exceeded")
response = self.client.chat.completions.create(
model=model,
messages=messages
)
# 비용 계산
usage = response.usage
cost = estimate_cost(
usage.prompt_tokens,
usage.completion_tokens,
model
)
self.total_cost += cost
print(f"Cost: ${cost:.6f} | Total: ${self.total_cost:.6f}")
return response.choices[0].message.content
고급 기능
이미지 입력 (Vision)
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What's in this image?"},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/image.jpg"
}
}
]
}
]
)
JSON 모드
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Extract user info as JSON"},
{"role": "user", "content": "John Doe, 30, engineer"}
],
response_format={"type": "json_object"}
)
data = json.loads(response.choices[0].message.content)
Seed (재현 가능한 출력)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
seed=12345, # 동일한 seed = 동일한 출력
temperature=0
)
베스트 프랙티스
1. 보안
# ✅ 환경 변수 사용
import os
api_key = os.getenv("OPENAI_API_KEY")
# ❌ 코드에 직접 하드코딩
api_key = "sk-..." # 절대 하지 마세요!
# ✅ .gitignore에 .env 추가
# .env
# .env.local
2. 에러 처리
# ✅ 모든 API 호출에 try-except
try:
response = client.chat.completions.create(...)
except Exception as e:
logger.error(f"OpenAI API error: {e}")
# 폴백 로직
3. 로깅
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def chat(messages):
logger.info(f"Sending {len(messages)} messages")
response = client.chat.completions.create(...)
logger.info(f"Received response: {response.usage.total_tokens} tokens")
return response
4. 테스트
# 단위 테스트
def test_chatbot():
bot = Chatbot("You are helpful")
response = bot.chat("Hello")
assert len(response) > 0
assert isinstance(response, str)
# Mock 사용
from unittest.mock import Mock
def test_with_mock():
client.chat.completions.create = Mock(return_value=mock_response)
# 테스트 코드
실전 프로젝트: AI 챗봇 웹앱
FastAPI 백엔드
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from openai import OpenAI
import os
app = FastAPI()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
class ChatRequest(BaseModel):
message: str
conversation_id: str = None
# 간단한 메모리 저장소 (실제로는 Redis/DB 사용)
conversations = {}
@app.post("/chat")
async def chat(request: ChatRequest):
# 대화 이력 가져오기
if request.conversation_id not in conversations:
conversations[request.conversation_id] = [
{"role": "system", "content": "You are a helpful assistant."}
]
messages = conversations[request.conversation_id]
messages.append({"role": "user", "content": request.message})
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages
)
assistant_message = response.choices[0].message.content
messages.append({"role": "assistant", "content": assistant_message})
return {
"response": assistant_message,
"conversation_id": request.conversation_id
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
React 프론트엔드
import { useState } from 'react';
function ChatApp() {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const [conversationId] = useState(Math.random().toString(36));
const sendMessage = async () => {
const userMessage = { role: 'user', content: input };
setMessages([...messages, userMessage]);
setInput('');
const response = await fetch('/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: input,
conversation_id: conversationId
})
});
const data = await response.json();
const assistantMessage = { role: 'assistant', content: data.response };
setMessages(prev => [...prev, assistantMessage]);
};
return (
<div>
<div className="messages">
{messages.map((msg, i) => (
<div key={i} className={msg.role}>
{msg.content}
</div>
))}
</div>
<input
value={input}
onChange={e => setInput(e.target.value)}
onKeyPress={e => e.key === 'Enter' && sendMessage()}
/>
<button onClick={sendMessage}>Send</button>
</div>
);
}
비용 및 제한사항
가격표 (2026년 4월 기준)
| 모델 | 입력 ($/1M 토큰) | 출력 ($/1M 토큰) |
|---|---|---|
| gpt-4o | $2.50 | $10.00 |
| gpt-4o-mini | $0.15 | $0.60 |
| gpt-4-turbo | $10.00 | $30.00 |
| gpt-3.5-turbo | $0.50 | $1.50 |
Rate Limits
| 티어 | RPM | TPM |
|---|---|---|
| Free | 3 | 40,000 |
| Tier 1 | 500 | 200,000 |
| Tier 2 | 5,000 | 2,000,000 |
참고 자료
한 줄 요약: ChatGPT API로 챗봇, 문서 요약, 코드 생성 등 다양한 AI 애플리케이션을 만들 수 있으며, Function Calling과 프롬프트 엔지니어링을 활용하면 더욱 강력한 서비스를 구축할 수 있습니다.