ChatGPT API 실전 가이드 | OpenAI API로 AI 애플리케이션 만들기

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 시작하기
  2. 기본 API 사용법
  3. 스트리밍 응답
  4. Function Calling
  5. 프롬프트 엔지니어링
  6. 비용 최적화
  7. 실전 예제
  8. 에러 처리 및 재시도

1. OpenAI API 시작하기

API 키 발급

  1. OpenAI 계정 생성: https://platform.openai.com
  2. API 키 발급: Settings → API keys → Create new secret key
  3. 결제 정보 등록: 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

티어RPMTPM
Free340,000
Tier 1500200,000
Tier 25,0002,000,000

참고 자료

한 줄 요약: ChatGPT API로 챗봇, 문서 요약, 코드 생성 등 다양한 AI 애플리케이션을 만들 수 있으며, Function Calling과 프롬프트 엔지니어링을 활용하면 더욱 강력한 서비스를 구축할 수 있습니다.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3