Chapter 01

OpenAI API란 무엇인가?

1.1 개요

OpenAI API는 GPT 시리즈를 비롯한 OpenAI의 AI 모델을 프로그래밍 방식으로 호출할 수 있는 인터페이스입니다. 텍스트 생성, 이미지 분석, 코드 작성, 음성 인식, 이미지 생성, 벡터 임베딩 등 다양한 AI 기능을 여러분의 애플리케이션에 직접 통합할 수 있습니다.

한마디로, ChatGPT의 두뇌를 여러분의 서비스에 API 호출 한 번으로 연결하는 것이라 생각하면 됩니다. 웹사이트, 모바일 앱, 슬랙 봇, 데이터 파이프라인 — 어디서든 HTTP 요청만 보내면 AI의 응답을 받아볼 수 있습니다.

1.2 무엇을 할 수 있는가?

OpenAI API가 제공하는 주요 기능은 다음과 같습니다.

  • 텍스트 생성 (Completions) : 질문에 답하기, 문서 요약, 번역, 글쓰기, 코드 생성 등
  • 비전 (Vision) : 이미지를 입력하여 분석·설명·OCR 등
  • 이미지 생성 : 텍스트 프롬프트로 이미지를 생성하거나 편집 (GPT Image)
  • 음성 (Audio) : 음성→텍스트(STT), 텍스트→음성(TTS), 실시간 대화
  • 임베딩 (Embeddings) : 텍스트를 벡터로 변환하여 의미 검색, 분류 등에 활용
  • Function Calling : 모델이 외부 API나 데이터베이스를 호출하도록 연결
  • 에이전트 (Agents) : 도구를 사용해 여러 단계를 자율적으로 수행하는 AI 에이전트 구축

1.3 두 가지 핵심 API

OpenAI는 현재 두 가지 주요 API 엔드포인트를 제공합니다.

API특징권장 용도
Responses API최신 인터페이스. 상태 관리, 내장 도구, 멀티턴 지원새로운 프로젝트, 에이전트, 도구 활용
Chat Completions API기존 인터페이스. 메시지 배열 기반, 널리 사용됨기존 프로젝트, 단순 텍스트 생성
참고 : OpenAI는 Responses API를 미래의 주력 인터페이스로 밀고 있습니다. 새로운 프로젝트를 시작한다면 Responses API를 권장합니다. 기존 Assistants API는 2025년 8월 deprecation이 발표되었으며, 2026년 8월까지 사용 가능합니다.

1.4 이 튜토리얼의 구성

이 문서에서는 API 키 발급부터 모델 선택, 핵심 API 사용법, Function Calling, Streaming, 요금 체계, 보안, Agents SDK까지 OpenAI API의 전 영역을 체계적으로 다룹니다. 코드 예제는 Python을 기본으로 하되, 핵심 개념은 어떤 언어에서든 동일하게 적용됩니다.

Chapter 02

시작하기 · API 키 발급과 인증

2.1 API 키 발급

OpenAI API를 사용하려면 먼저 API 키가 필요합니다. platform.openai.com에 가입한 뒤, Settings → API Keys에서 새 키를 생성할 수 있습니다. 키는 sk-proj-... 형태이며, 생성 직후 한 번만 전체 값을 확인할 수 있으니 반드시 안전한 곳에 저장해야 합니다.

2.2 SDK 설치

Bash
# Python SDK 설치
pip install openai

# Node.js SDK 설치
npm install openai

2.3 환경 변수 설정

API 키는 절대로 소스 코드에 직접 하드코딩하면 안 됩니다. 환경 변수로 관리하는 것이 기본 원칙입니다.

Bash
# Linux / Mac
export OPENAI_API_KEY="sk-proj-여러분의키..."

# Windows (PowerShell)
$env:OPENAI_API_KEY = "sk-proj-여러분의키..."

# .env 파일에 저장 (권장)
echo 'OPENAI_API_KEY=sk-proj-여러분의키...' >> .env

2.4 첫 번째 API 호출

Python
from openai import OpenAI

client = OpenAI()  # 환경 변수에서 자동으로 API 키를 읽음

response = client.responses.create(
    model="gpt-4.1",
    input="안녕하세요! OpenAI API를 처음 사용합니다."
)

print(response.output_text)
실행 결과 (예시)
안녕하세요! OpenAI API에 오신 것을 환영합니다. 궁금한 점이 있으시면 무엇이든 물어보세요!
보안 주의! API 키는 절대로 GitHub, 블로그, 프론트엔드 코드 등에 노출하지 마세요. 키가 유출되면 누구나 여러분의 계정으로 API를 호출할 수 있고, 그 비용은 여러분에게 청구됩니다. 팀 프로젝트에서는 멤버마다 별도의 키를 발급하세요.

2.5 Organization과 Project

OpenAI 플랫폼은 Organization(조직) → Project(프로젝트) 구조로 관리됩니다. 하나의 조직 안에 여러 프로젝트를 만들 수 있고, 각 프로젝트마다 별도의 API 키, 사용량 한도, 접근 권한을 설정할 수 있습니다. 예를 들어 "프로덕션"과 "개발" 프로젝트를 분리하면 비용 추적과 보안 관리가 훨씬 수월해집니다.

Chapter 03

모델 총정리

3.1 모델 패밀리 개요

OpenAI는 다양한 모델 패밀리를 제공하며, 각 패밀리는 서로 다른 강점과 용도를 가지고 있습니다. 2026년 현재 기준으로, GPT-5 시리즈가 주력 모델이며 GPT-4.1 시리즈도 여전히 널리 사용됩니다.

모델특징컨텍스트 윈도우최적 용도
GPT-5.5최상위 추론·코딩 모델대규모복잡한 멀티스텝, 코딩, 에이전트
GPT-5.4강력하면서도 합리적 비용대규모코딩, 전문 업무, 도구 사용
GPT-5.4 mini빠르고 저렴한 소형 모델대규모경량 에이전트, 서브에이전트
GPT-5.4 nano최저 비용·최저 지연대규모분류, 라우팅, 간단한 작업
GPT-4.1비추론 모델 중 최고 성능1M 토큰긴 문서 처리, 코딩, 지시 따르기
GPT-4.1 mini빠르고 균형 잡힌 비추론 모델1M 토큰일반 대화, 요약, 분류
GPT-4.1 nano가장 빠른 비추론 모델1M 토큰실시간 응답, 자동 완성

3.2 추론 모델 vs 비추론 모델

GPT-5 시리즈는 "추론 모델(Reasoning Model)"입니다. 응답을 생성하기 전에 내부적으로 "생각하는 과정"을 거치며, 이 추론 토큰은 별도로 생성됩니다. 복잡한 수학, 코딩, 다단계 논리 문제에서 뛰어난 성능을 보이지만, 단순 작업에서는 오히려 비추론 모델(GPT-4.1 등)이 더 빠르고 저렴할 수 있습니다.

추론 강도는 reasoning.effort 파라미터로 조절 가능합니다. low, medium(기본값), high, xhigh 중 선택할 수 있으며, 낮게 설정할수록 빠르고 저렴하지만 복잡한 문제의 정확도가 떨어질 수 있습니다.

Python
response = client.responses.create(
    model="gpt-5.4",
    reasoning={"effort": "high"},  # 복잡한 작업에 적합
    input="다음 코드의 버그를 찾아서 수정해 주세요: ..."
)

3.3 특수 목적 모델

모델용도
GPT Image (gpt-image-2)이미지 생성 및 편집
GPT Realtime (gpt-realtime-1.5)실시간 음성 대화 (WebSocket)
GPT-4o Transcribe음성을 텍스트로 변환 (STT)
text-embedding-3-large / small텍스트 벡터 임베딩
Sora 2비디오 생성
모델 선택 가이드 : 새 프로젝트를 시작할 때는 GPT-5.4부터 시도해 보세요. 성능이 부족하면 GPT-5.5로 올리고, 비용이 부담되면 GPT-5.4 mini나 nano로 내려보는 것이 실용적입니다. 단순 작업(분류, 추출)이라면 GPT-4.1 nano가 가장 경제적입니다.
Chapter 04

요금 체계 이해하기

4.1 토큰 기반 과금

OpenAI API는 "토큰(Token)" 단위로 비용을 청구합니다. 토큰은 텍스트의 최소 처리 단위로, 영어 기준 약 4글자(0.75단어)가 1토큰이고, 한국어는 한 글자가 약 2~3토큰에 해당합니다. 입력(Input) 토큰과 출력(Output) 토큰의 가격이 다르며, 일반적으로 출력 토큰이 더 비쌉니다.

4.2 주요 모델 가격표 (1M 토큰 기준)

모델입력캐시 입력출력
GPT-5.5$5.00$0.50$30.00
GPT-5.4$2.50$0.25$15.00
GPT-5.4 mini$0.75$0.075$4.50
GPT-5.4 nano$0.20$0.02$1.25
GPT-4.1$2.00$0.50$8.00
GPT-4.1 mini$0.40$0.10$1.60
GPT-4.1 nano$0.10$0.025$0.40

4.3 프롬프트 캐싱 (Prompt Caching)

동일한 프롬프트 접두사가 반복되면 OpenAI가 자동으로 캐싱하여 입력 토큰 비용을 최대 90%까지 절감합니다. 시스템 프롬프트처럼 변하지 않는 부분을 앞에 두고, 사용자 입력 등 동적인 부분을 뒤에 배치하면 캐시 적중률이 극대화됩니다.

4.4 도구 요금

도구요금
Web Search$10.00 / 1,000 calls
File Search (tool call)$2.50 / 1,000 calls
File Search (storage)$0.10 / GB·day (1GB 무료)
Containers (Code Interpreter 등)$0.03~$1.92 / 세션 (용량별)

4.5 비용 절감 전략

실무에서 API 비용을 줄이기 위한 핵심 전략이 있습니다. 첫째, 프롬프트 캐싱을 적극 활용하세요. 둘째, 작업 복잡도에 맞는 모델을 선택하세요 — 단순 분류에 GPT-5.5를 쓸 필요가 없습니다. 셋째, Batch API를 활용하면 비동기 처리로 50% 할인된 가격에 대량 요청을 처리할 수 있습니다. 넷째, max_tokens를 적절히 설정하여 불필요한 출력을 줄이세요.

Batch API : 즉각적인 응답이 필요 없는 대량 요청(데이터 라벨링, 번역, 분류 등)은 Batch API를 사용하면 비용을 크게 절감할 수 있습니다. 요청을 JSONL 파일로 묶어 제출하면 24시간 내에 결과를 돌려받습니다.
Chapter 05

Responses API — 새로운 표준

5.1 Responses API란?

Responses API는 OpenAI가 제공하는 가장 최신 인터페이스로, 텍스트·이미지 입력을 받아 텍스트를 출력하며, 내장 도구(웹 검색, 파일 검색, 코드 인터프리터, 이미지 생성 등)를 네이티브로 지원합니다. Chat Completions API의 단순 메시지 배열과 달리, 상태 관리(stateful interaction)가 가능하여 멀티턴 대화와 에이전트 워크플로우에 최적화되어 있습니다.

5.2 기본 호출

Python
from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="gpt-4.1",
    input="대한민국의 수도는 어디인가요?"
)

print(response.output_text)
# → "대한민국의 수도는 서울특별시입니다."

5.3 시스템 프롬프트 (instructions)

시스템 프롬프트는 모델의 역할, 톤, 규칙을 정의합니다. Responses API에서는 instructions 파라미터를 사용합니다.

Python
response = client.responses.create(
    model="gpt-4.1",
    instructions="당신은 친절한 한국어 요리 전문가입니다. "
                 "모든 답변은 존댓말로, 300자 이내로 작성하세요.",
    input="김치찌개 만드는 법을 알려주세요."
)

print(response.output_text)

5.4 멀티턴 대화 (previous_response_id)

Responses API의 강력한 기능 중 하나는 previous_response_id를 통한 대화 연결입니다. 이전 응답의 ID를 전달하면 OpenAI 서버에서 대화 상태를 자동으로 관리해 줍니다.

Python
# 첫 번째 대화
resp1 = client.responses.create(
    model="gpt-4.1",
    input="파이썬에서 리스트와 튜플의 차이가 뭐야?"
)
print(resp1.output_text)

# 두 번째 대화 — 이전 맥락을 이어감
resp2 = client.responses.create(
    model="gpt-4.1",
    previous_response_id=resp1.id,
    input="그럼 언제 튜플을 써야 해?"
)
print(resp2.output_text)  # 이전 대화 맥락을 기억하고 답변

5.5 수동 상태 관리 (input 배열)

previous_response_id를 사용하지 않고, 직접 대화 이력을 관리하고 싶다면 input에 배열을 전달합니다. Zero Data Retention(ZDR) 정책이 필요한 경우 이 방식을 사용합니다.

Python
response = client.responses.create(
    model="gpt-4.1",
    input=[
        {"role": "user", "content": "서울에서 부산까지 거리가 얼마야?"},
        {"role": "assistant", "content": "서울에서 부산까지는 약 325km입니다."},
        {"role": "user", "content": "KTX로 얼마나 걸려?"}
    ]
)
print(response.output_text)
Responses vs Chat Completions : 새 프로젝트에는 Responses API를 사용하세요. 내장 도구, 상태 관리, 에이전트 워크플로우 등 최신 기능이 모두 Responses API에 우선 제공됩니다. Chat Completions API도 계속 지원되지만, 신기능은 Responses API 중심으로 출시됩니다.
Chapter 06

Chat Completions API — 레거시 호환

6.1 기본 구조

Chat Completions API는 OpenAI의 기존 표준 인터페이스로, 여전히 가장 널리 사용되고 있습니다. 입력은 messages 배열로 구성되며, 각 메시지에는 role(system, user, assistant)과 content가 있습니다.

Python
from openai import OpenAI
client = OpenAI()

response = client.chat.completions.create(
    model="gpt-4.1",
    messages=[
        {
            "role": "system",
            "content": "당신은 도움이 되는 한국어 어시스턴트입니다."
        },
        {
            "role": "user",
            "content": "JWT 토큰이 뭔지 쉽게 설명해 줘."
        }
    ],
    temperature=0.7,
    max_tokens=500
)

print(response.choices[0].message.content)

6.2 주요 파라미터

파라미터설명기본값
model사용할 모델 ID필수
messages대화 메시지 배열필수
temperature응답의 창의성 (0.0~2.0)1.0
max_tokens최대 출력 토큰 수모델에 따라 다름
top_p핵 샘플링 (0.0~1.0)1.0
stream스트리밍 활성화false
tools사용 가능한 도구 정의없음
response_format출력 형식 (JSON 등)text

6.3 temperature 이해하기

temperature는 응답의 "랜덤성"을 조절합니다. 0에 가까울수록 일관되고 예측 가능한 답변을, 높을수록 다양하고 창의적인 답변을 생성합니다. 코드 생성이나 데이터 추출처럼 정확성이 중요한 작업은 0~0.3, 창작 글이나 브레인스토밍은 0.7~1.2가 적당합니다.

temperature vs top_p : 둘 다 응답의 다양성을 조절하지만, 동시에 변경하는 것은 권장하지 않습니다. 하나만 조절하고 나머지는 기본값으로 두세요.
Chapter 07

토큰과 컨텍스트 윈도우

7.1 토큰이란?

토큰(Token)은 모델이 텍스트를 처리하는 최소 단위입니다. 영어에서는 대략 1단어 ≈ 1.3토큰이고, 한국어에서는 한 글자가 보통 2~3토큰에 해당합니다. 모든 API 요청의 비용과 한도는 토큰 단위로 계산되므로, 토큰 개념을 정확히 이해하는 것이 중요합니다.

Python
# tiktoken 라이브러리로 토큰 수 계산
import tiktoken

enc = tiktoken.encoding_for_model("gpt-4.1")
text = "안녕하세요, OpenAI API를 배우고 있습니다!"
tokens = enc.encode(text)

print(f"텍스트: {text}")
print(f"토큰 수: {len(tokens)}")
print(f"토큰 목록: {tokens}")

7.2 컨텍스트 윈도우

컨텍스트 윈도우(Context Window)는 모델이 한 번에 처리할 수 있는 최대 토큰 수입니다. 입력 토큰 + 출력 토큰의 합이 이 한도를 초과할 수 없습니다. GPT-4.1 시리즈는 1M(100만) 토큰, GPT-5 시리즈는 그보다 더 큰 컨텍스트를 지원합니다.

긴 컨텍스트의 요청은 "Long Context" 가격이 적용될 수 있습니다. 예를 들어 GPT-5.5의 경우, 270K 토큰을 초과하는 요청은 입력·출력 가격이 모두 약 1.5배로 올라갑니다.

7.3 토큰 사용량 확인

Python
response = client.responses.create(
    model="gpt-4.1",
    input="파이썬 데코레이터를 설명해 주세요."
)

# 토큰 사용량 확인
print(f"입력 토큰: {response.usage.input_tokens}")
print(f"출력 토큰: {response.usage.output_tokens}")
print(f"전체 토큰: {response.usage.total_tokens}")
비용 최적화 : API 응답의 usage 필드를 항상 로깅하세요. 예상보다 토큰을 많이 사용하는 요청을 조기에 발견하고 프롬프트를 개선할 수 있습니다.
Chapter 08

Function Calling — 모델에 도구 연결하기

8.1 Function Calling이란?

Function Calling(Tool Calling)은 모델이 외부 시스템과 상호작용할 수 있게 해주는 기능입니다. 예를 들어 "서울 날씨 알려줘"라는 질문에 모델이 직접 날씨를 아는 것이 아니라, 여러분이 정의한 get_weather 함수를 호출하라는 요청을 반환합니다. 여러분은 그 결과를 실행한 뒤 다시 모델에게 넘기면, 모델이 자연스러운 답변을 생성합니다.

8.2 동작 흐름 (5단계)

Function Calling은 다음과 같은 5단계 대화 흐름으로 진행됩니다. 첫째, 모델에 사용 가능한 도구 목록과 함께 프롬프트를 보냅니다. 둘째, 모델이 적절한 도구와 인자를 선택하여 "tool call"을 반환합니다. 셋째, 여러분의 애플리케이션에서 해당 함수를 실행합니다. 넷째, 실행 결과를 모델에게 다시 전달합니다. 다섯째, 모델이 결과를 기반으로 최종 자연어 응답을 생성합니다.

8.3 실전 예제 — 날씨 API

Python
from openai import OpenAI
import json

client = OpenAI()

# 1단계: 도구 정의
tools = [
    {
        "type": "function",
        "name": "get_weather",
        "description": "주어진 도시의 현재 날씨를 가져옵니다.",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "도시 이름 (예: Seoul, Tokyo)"
                },
                "units": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "온도 단위"
                }
            },
            "required": ["city", "units"],
            "additionalProperties": False
        },
        "strict": True
    }
]

# 실제 함수 구현 (보통은 외부 API 호출)
def get_weather(city, units="celsius"):
    # 여기서는 예시를 위해 하드코딩
    return json.dumps({
        "city": city,
        "temperature": 22,
        "units": units,
        "condition": "맑음"
    })

# 2단계: 모델에 프롬프트 + 도구 전달
input_list = [
    {"role": "user", "content": "서울 날씨가 어때?"}
]

response = client.responses.create(
    model="gpt-4.1",
    tools=tools,
    input=input_list,
)

# 3단계: 모델의 도구 호출 처리
input_list += response.output

for item in response.output:
    if item.type == "function_call":
        args = json.loads(item.arguments)
        result = get_weather(**args)
        
        # 4단계: 함수 결과를 모델에 반환
        input_list.append({
            "type": "function_call_output",
            "call_id": item.call_id,
            "output": result
        })

# 5단계: 최종 응답 받기
final = client.responses.create(
    model="gpt-4.1",
    tools=tools,
    input=input_list,
)

print(final.output_text)
# → "서울의 현재 날씨는 맑음이며, 기온은 22°C입니다."

8.4 핵심 설계 원칙

Function Calling을 효과적으로 사용하려면 몇 가지 원칙을 지켜야 합니다. 함수 이름과 설명을 명확하게 작성하세요 — 모델은 설명을 읽고 어떤 함수를 언제 호출할지 결정합니다. 파라미터에 enum을 활용하면 유효하지 않은 입력을 방지할 수 있습니다. 동시에 초기 로드되는 함수의 수는 20개 이하로 유지하는 것이 좋고, 그 이상이면 Tool Search를 활용하세요.

8.5 Strict Mode

strict: true를 설정하면 모델의 함수 호출이 JSON Schema를 100% 준수하도록 보장합니다. 이를 위해서는 additionalProperties: false를 설정하고, 모든 필드를 required에 포함해야 합니다. 선택적 필드는 타입에 null을 추가하여 표현합니다.

주의 : 모델은 함수를 직접 실행하지 않습니다. "이 함수를 이런 인자로 호출해 달라"고 요청만 하며, 실제 실행은 여러분의 코드에서 수행해야 합니다. 따라서 함수 결과에 대한 검증과 에러 처리를 반드시 구현하세요.
Chapter 09

Structured Outputs — 구조화된 출력

9.1 왜 Structured Outputs이 필요한가?

모델의 응답을 프로그래밍적으로 처리하려면 일정한 형식(JSON 등)이 보장되어야 합니다. 하지만 일반 텍스트 응답에서 JSON을 "부탁"하면 가끔 형식이 깨지거나, 필드가 누락되는 문제가 발생합니다. Structured Outputs는 모델이 지정한 JSON Schema를 100% 준수하는 응답을 생성하도록 강제하는 기능입니다.

9.2 기본 사용법

Python
response = client.responses.create(
    model="gpt-4.1",
    input="대한민국의 주요 도시 3개를 알려주세요.",
    text={
        "format": {
            "type": "json_schema",
            "name": "cities_response",
            "schema": {
                "type": "object",
                "properties": {
                    "cities": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "name": {"type": "string"},
                                "population": {"type": "integer"},
                                "description": {"type": "string"}
                            },
                            "required": ["name", "population", "description"],
                            "additionalProperties": False
                        }
                    }
                },
                "required": ["cities"],
                "additionalProperties": False
            },
            "strict": True
        }
    }
)

import json
data = json.loads(response.output_text)
for city in data["cities"]:
    print(f"{city['name']} (인구: {city['population']:,}명)")

9.3 Pydantic과 함께 사용 (Python SDK)

Python
from pydantic import BaseModel

class City(BaseModel):
    name: str
    population: int
    description: str

class CitiesResponse(BaseModel):
    cities: list[City]

response = client.responses.parse(
    model="gpt-4.1",
    input="대한민국의 주요 도시 3개를 알려주세요.",
    text_format=CitiesResponse,
)

# response.output_parsed는 CitiesResponse 객체
for city in response.output_parsed.cities:
    print(f"{city.name}: {city.description}")
활용 사례 : Structured Outputs는 데이터 추출(영수증 파싱, 이력서 분석), API 응답 생성, UI 컴포넌트 데이터 구성, 분류 결과 반환 등 프로그래밍적 처리가 필요한 거의 모든 상황에서 유용합니다.
Chapter 10

이미지 · 비전

10.1 이미지 입력 (Vision)

GPT-4o, GPT-4.1, GPT-5 시리즈 등 대부분의 최신 모델은 이미지를 입력으로 받아 분석할 수 있습니다. URL로 전달하거나 base64 인코딩된 이미지를 직접 보낼 수 있습니다.

Python
# URL로 이미지 전달
response = client.responses.create(
    model="gpt-4.1",
    input=[
        {
            "role": "user",
            "content": [
                {"type": "input_text", "text": "이 이미지에 무엇이 보이나요?"},
                {
                    "type": "input_image",
                    "image_url": "https://example.com/photo.jpg"
                }
            ]
        }
    ]
)
print(response.output_text)

10.2 이미지 생성 (GPT Image)

GPT Image 모델(gpt-image-2)을 사용하면 텍스트 프롬프트로 이미지를 생성할 수 있습니다. 사진처럼 사실적인 이미지부터 일러스트, 로고까지 다양한 스타일을 지원합니다.

Python
result = client.images.generate(
    model="gpt-image-2",
    prompt="파란 하늘 아래 벚꽃이 만개한 한국의 전통 한옥 마을",
    n=1,
    size="1024x1024"
)

# 생성된 이미지 URL 또는 base64 데이터 접근
print(result.data[0].url)

10.3 image_detail 옵션

이미지 입력 시 detail 파라미터로 해상도를 제어할 수 있습니다. low는 빠르고 토큰이 적게 들고, high는 세밀한 분석이 가능하지만 토큰을 더 많이 소비합니다. auto(기본값)는 모델이 자동으로 판단합니다.

Chapter 11

스트리밍 (Streaming)

11.1 왜 스트리밍인가?

기본적으로 API는 전체 응답이 완성된 후 한꺼번에 반환합니다. 긴 응답의 경우 사용자가 몇 초~수십 초를 기다려야 하죠. 스트리밍을 활성화하면 모델이 생성하는 즉시 토큰 단위로 전달받을 수 있어, 체감 응답 속도가 획기적으로 개선됩니다. ChatGPT에서 글자가 하나씩 나타나는 것이 바로 스트리밍입니다.

11.2 Responses API 스트리밍

Python
stream = client.responses.create(
    model="gpt-4.1",
    input="파이썬의 GIL에 대해 설명해 주세요.",
    stream=True
)

for event in stream:
    if event.type == "response.output_text.delta":
        print(event.delta, end="", flush=True)

print()  # 줄바꿈

11.3 Chat Completions 스트리밍

Python
stream = client.chat.completions.create(
    model="gpt-4.1",
    messages=[{"role": "user", "content": "REST API란?"}],
    stream=True
)

for chunk in stream:
    content = chunk.choices[0].delta.content
    if content:
        print(content, end="", flush=True)

11.4 주요 스트리밍 이벤트

Responses API의 스트리밍은 시맨틱 이벤트를 사용합니다. 각 이벤트는 타입이 지정되어 있어 원하는 이벤트만 선별적으로 처리할 수 있습니다. 가장 자주 사용하는 이벤트는 response.created(응답 시작), response.output_text.delta(텍스트 토큰), response.completed(응답 완료), error(오류)입니다. Function Calling의 인자도 response.function_call_arguments.delta 이벤트로 스트리밍됩니다.

주의 : 스트리밍 환경에서는 부분적으로 생성된 텍스트를 모더레이션하기 어려울 수 있습니다. 프로덕션 환경에서는 완성된 응답에 대한 후처리 검증을 함께 구현하세요.
Chapter 12

내장 도구 (Built-in Tools)

12.1 도구 생태계 개요

OpenAI는 Function Calling 외에도 플랫폼 차원에서 여러 내장 도구를 제공합니다. 이 도구들은 tools 파라미터에 타입만 지정하면 바로 사용할 수 있으며, 별도의 함수 구현이 필요 없습니다.

도구설명주요 사용 사례
Web Search인터넷에서 최신 정보를 검색실시간 뉴스, 최신 가격, 날씨
File Search업로드된 파일에서 RAG 검색문서 QA, 사내 지식 검색
Code Interpreter샌드박스에서 Python 실행데이터 분석, 수학 계산, 차트
Image GenerationGPT Image로 이미지 생성시각 콘텐츠 자동 생성
Computer Use컴퓨터 인터페이스 조작UI 자동화, 웹 브라우징 에이전트
Shell호스팅 컨테이너에서 셸 명령 실행코드 실행, 파일 조작, 빌드
Remote MCP외부 MCP 서버 연결서드파티 서비스 통합
Tool Search대규모 도구에서 필요한 것만 로드수십~수백 개 도구 관리

12.2 Web Search 예제

Python
response = client.responses.create(
    model="gpt-5.4",
    tools=[{"type": "web_search"}],
    input="오늘 주요 뉴스를 요약해 주세요."
)

print(response.output_text)
# → 웹 검색 결과를 기반으로 최신 뉴스 요약을 생성

12.3 Code Interpreter 예제

Python
response = client.responses.create(
    model="gpt-5.4",
    tools=[{
        "type": "code_interpreter",
        "container": {"type": "auto"}
    }],
    input="1부터 100까지의 피보나치 수열에서 짝수인 것만 합산해 주세요."
)

print(response.output_text)
# → 모델이 Python 코드를 작성·실행하여 정확한 결과를 반환

12.4 Remote MCP 서버

MCP(Model Context Protocol)는 외부 도구 서버와 모델을 연결하는 프로토콜입니다. GitHub, Slack, Notion 등의 서비스를 MCP 서버로 연결하면 모델이 해당 서비스의 기능을 도구처럼 사용할 수 있습니다. toolstype: "mcp"와 서버 URL을 지정하면 됩니다.

실무 조언 : 내장 도구는 직접 구현하는 것보다 안정적이고 유지보수가 쉽습니다. 웹 검색, 파일 검색, 코드 실행이 필요하다면 커스텀 함수보다 내장 도구를 먼저 검토하세요. 커스텀 Function Calling은 자사 비즈니스 로직이나 내부 시스템 연동에 사용하는 것이 좋습니다.
Chapter 13

Embeddings — 텍스트 벡터화

13.1 Embeddings란?

Embeddings(임베딩)은 텍스트를 고차원 벡터(숫자 배열)로 변환하는 기술입니다. 의미적으로 유사한 텍스트는 벡터 공간에서 가까이 위치하게 됩니다. 이를 활용하면 의미 기반 검색(Semantic Search), 텍스트 분류, 추천 시스템, 클러스터링, 이상 탐지 등 다양한 작업을 수행할 수 있습니다.

13.2 모델 및 가격

모델차원가격 (1M 토큰)특징
text-embedding-3-large3,072$0.13최고 정확도
text-embedding-3-small1,536$0.02가성비 우수

13.3 기본 사용법

Python
response = client.embeddings.create(
    model="text-embedding-3-small",
    input="OpenAI API는 강력한 AI 기능을 제공합니다."
)

vector = response.data[0].embedding
print(f"벡터 차원: {len(vector)}")
print(f"처음 5개 값: {vector[:5]}")

13.4 의미 검색 활용 예시

Python
import numpy as np

def cosine_similarity(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

# 문서 임베딩
docs = [
    "파이썬은 배우기 쉬운 프로그래밍 언어입니다.",
    "김치찌개는 한국의 대표적인 음식입니다.",
    "자바스크립트는 웹 개발에 필수적입니다.",
    "된장찌개는 한국인의 소울 푸드입니다."
]

doc_embeddings = client.embeddings.create(
    model="text-embedding-3-small",
    input=docs
).data

# 검색 쿼리 임베딩
query = "한국 전통 음식"
query_emb = client.embeddings.create(
    model="text-embedding-3-small",
    input=query
).data[0].embedding

# 유사도 계산 및 정렬
results = []
for i, doc_emb in enumerate(doc_embeddings):
    sim = cosine_similarity(query_emb, doc_emb.embedding)
    results.append((sim, docs[i]))

results.sort(reverse=True)
for sim, doc in results:
    print(f"[{sim:.4f}] {doc}")
실행 결과 (예시)
[0.8742] 김치찌개는 한국의 대표적인 음식입니다. [0.8451] 된장찌개는 한국인의 소울 푸드입니다. [0.3215] 파이썬은 배우기 쉬운 프로그래밍 언어입니다. [0.2987] 자바스크립트는 웹 개발에 필수적입니다.
RAG (Retrieval Augmented Generation) : Embeddings의 가장 대표적인 활용이 바로 RAG입니다. 문서를 임베딩하여 벡터 DB에 저장하고, 사용자 질문과 가장 유사한 문서 조각을 검색하여 모델의 프롬프트에 포함시키면, 모델이 해당 문서를 기반으로 정확한 답변을 생성합니다.
Chapter 14

Rate Limits · 사용량 티어

14.1 Rate Limit이란?

Rate Limit(속도 제한)은 일정 시간 내에 보낼 수 있는 API 요청의 최대 수량을 의미합니다. 남용 방지, 공정한 접근, 인프라 안정성을 위해 적용됩니다. RPM(분당 요청 수), TPM(분당 토큰 수), RPD(일당 요청 수), TPD(일당 토큰 수), IPM(분당 이미지 수)의 5가지 기준으로 측정되며, 어느 것이든 먼저 한도에 도달하면 제한됩니다.

14.2 사용량 티어

OpenAI는 API 사용 금액에 따라 자동으로 티어를 승급시키며, 상위 티어일수록 더 높은 Rate Limit을 받습니다.

티어조건월 사용 한도
Free허용 지역 내 가입$100 / 월
Tier 1$5 결제$100 / 월
Tier 2$50 결제 + 7일 이상$500 / 월
Tier 3$100 결제 + 7일 이상$1,000 / 월
Tier 4$250 결제 + 14일 이상$5,000 / 월
Tier 5$1,000 결제 + 30일 이상$200,000 / 월

14.3 Rate Limit 응답 헤더

API 응답 헤더에서 현재 남은 한도를 확인할 수 있습니다. x-ratelimit-remaining-requests, x-ratelimit-remaining-tokens, x-ratelimit-reset-requests 등의 헤더를 확인하면 한도 초과를 사전에 방지할 수 있습니다.

14.4 Rate Limit 대응 전략

429 에러(Rate Limit Exceeded)가 발생하면 지수 백오프(Exponential Backoff)로 재시도하는 것이 표준 방법입니다. 1초 대기 후 재시도하고, 실패하면 2초, 4초, 8초... 식으로 대기 시간을 늘립니다. 또한 대량 작업은 Batch API를 사용하면 동기 Rate Limit과 별개로 처리됩니다.

Python
from tenacity import retry, wait_random_exponential, stop_after_attempt

@retry(
    wait=wait_random_exponential(min=1, max=60),
    stop=stop_after_attempt(6)
)
def call_api(prompt):
    return client.responses.create(
        model="gpt-4.1",
        input=prompt
    )

response = call_api("안녕하세요?")
Chapter 15

보안 · 베스트 프랙티스

15.1 API 키 관리 원칙

API 키 보안은 가장 기본이자 가장 중요한 사항입니다. 팀 멤버마다 별도의 키를 발급하고, 절대로 브라우저나 모바일 앱 같은 클라이언트 측 코드에 키를 포함하지 마세요. 환경 변수나 시크릿 매니저(AWS Secrets Manager, Vault 등)를 사용하고, 사용하지 않는 키는 즉시 폐기(revoke)하세요.

15.2 프로덕션 체크리스트

  • 키 분리 : 개발용·프로덕션용 API 키와 프로젝트를 분리하세요.
  • 사용량 한도 : 프로젝트별 월간 사용량 상한(Spending Limit)을 설정하세요.
  • 입력 검증 : 사용자 입력을 모델에 전달하기 전 반드시 정제(sanitize)하세요.
  • 출력 검증 : 모델의 응답을 그대로 DB에 저장하거나 실행하지 마세요.
  • 모더레이션 : OpenAI의 Moderation API로 유해 콘텐츠를 사전 필터링하세요.
  • 로깅 : 모든 API 호출의 토큰 사용량과 비용을 로깅하세요.
  • 에러 핸들링 : 타임아웃, Rate Limit, 서버 에러에 대한 재시도 로직을 구현하세요.

15.3 프롬프트 인젝션 방어

프롬프트 인젝션(Prompt Injection)은 사용자가 악의적인 입력을 통해 시스템 프롬프트를 무시하거나 의도치 않은 동작을 유도하는 공격입니다. 방어 방법으로는 사용자 입력과 시스템 프롬프트를 명확히 구분하고, 입력 길이를 제한하며, 민감한 작업에는 별도의 확인 단계를 추가하는 것이 있습니다.

절대 하지 말 것! API 키를 프론트엔드 JavaScript에 넣기, GitHub 퍼블릭 저장소에 커밋하기, 모델 응답을 검증 없이 eval() 실행하기, 사용자가 시스템 프롬프트를 직접 조작할 수 있게 하기.
Chapter 16

Agents SDK — AI 에이전트 구축

16.1 에이전트란?

AI 에이전트(Agent)는 단순히 질문에 답하는 것을 넘어, 여러 도구를 사용하고 다단계 작업을 자율적으로 수행하는 AI 시스템입니다. 예를 들어 "이번 달 매출 데이터를 분석해서 보고서를 작성하고, 팀 채널에 공유해 줘"라는 요청을 받으면, 에이전트는 DB 조회 → 데이터 분석 → 보고서 작성 → Slack 전송의 전체 과정을 스스로 수행합니다.

16.2 Agents SDK 개요

OpenAI Agents SDK는 에이전트 구축을 위한 공식 프레임워크입니다. Python과 Node.js를 지원하며, 에이전트 정의, 도구 연결, 핸드오프(에이전트 간 전환), 가드레일, 트레이싱 등의 기능을 제공합니다.

Python
from agents import Agent, Runner, function_tool

@function_tool
def search_database(query: str) -> str:
    """데이터베이스에서 정보를 검색합니다."""
    # 실제 DB 쿼리 로직
    return f"'{query}'에 대한 검색 결과: ..."

@function_tool
def send_email(to: str, subject: str, body: str) -> str:
    """이메일을 발송합니다."""
    return f"{to}에게 이메일을 발송했습니다."

# 에이전트 정의
agent = Agent(
    name="비즈니스 어시스턴트",
    instructions="당신은 비즈니스 업무를 돕는 어시스턴트입니다. "
                 "필요한 정보는 DB에서 검색하고, "
                 "보고가 필요하면 이메일로 발송하세요.",
    tools=[search_database, send_email],
    model="gpt-5.4"
)

# 에이전트 실행
result = Runner.run_sync(
    agent,
    "이번 달 매출 현황을 조회해서 manager@company.com에 보고해 줘."
)
print(result.final_output)

16.3 핸드오프 (Multi-Agent)

복잡한 워크플로우에서는 여러 전문 에이전트를 만들고, 작업 특성에 따라 에이전트 간에 제어를 넘기는 "핸드오프" 패턴을 사용합니다. 예를 들어 "일반 문의 에이전트"가 기술적 질문을 받으면 "기술 전문가 에이전트"에게 핸드오프하는 식입니다.

시작하기 : Agents SDK 없이도 Responses API + Function Calling 만으로 간단한 에이전트를 만들 수 있습니다. SDK는 복잡한 멀티 에이전트 시스템에서 오케스트레이션, 트레이싱, 가드레일 등이 필요할 때 도입하세요.
Chapter 17

실전 프로젝트 — 종합 활용

17.1 프로젝트 1: 문서 요약 봇

긴 문서를 입력받아 핵심 내용을 요약하는 봇입니다. Structured Outputs로 제목, 요약, 키워드를 JSON으로 반환합니다.

Python
from pydantic import BaseModel

class DocumentSummary(BaseModel):
    title: str
    summary: str
    keywords: list[str]
    key_points: list[str]

def summarize_document(text: str) -> DocumentSummary:
    response = client.responses.parse(
        model="gpt-4.1",
        instructions="주어진 문서를 분석하여 한국어로 요약하세요. "
                     "핵심 포인트는 3~5개로 정리하세요.",
        input=text,
        text_format=DocumentSummary,
    )
    return response.output_parsed

# 사용 예시
long_text = """여기에 긴 문서 내용을 넣습니다..."""
result = summarize_document(long_text)
print(f"제목: {result.title}")
print(f"요약: {result.summary}")
print(f"키워드: {', '.join(result.keywords)}")
for point in result.key_points:
    print(f"  • {point}")

17.2 프로젝트 2: 멀티턴 고객 상담 챗봇

Python
import json

# 도구 정의
tools = [
    {
        "type": "function",
        "name": "check_order_status",
        "description": "주문번호로 배송 상태를 조회합니다.",
        "parameters": {
            "type": "object",
            "properties": {
                "order_id": {
                    "type": "string",
                    "description": "주문번호 (예: ORD-12345)"
                }
            },
            "required": ["order_id"],
            "additionalProperties": False
        },
        "strict": True
    },
    {
        "type": "function",
        "name": "request_refund",
        "description": "환불을 요청합니다.",
        "parameters": {
            "type": "object",
            "properties": {
                "order_id": {"type": "string"},
                "reason": {"type": "string"}
            },
            "required": ["order_id", "reason"],
            "additionalProperties": False
        },
        "strict": True
    }
]

# 함수 구현 (실제로는 DB/API 호출)
def check_order_status(order_id):
    return json.dumps({
        "order_id": order_id,
        "status": "배송중",
        "carrier": "CJ대한통운",
        "estimated_delivery": "2026-05-01"
    })

def request_refund(order_id, reason):
    return json.dumps({
        "success": True,
        "refund_id": "REF-99887",
        "message": "환불 요청이 접수되었습니다. 3영업일 내 처리됩니다."
    })

system_prompt = """당신은 '해피몰'의 고객 상담 AI입니다.
- 항상 친절하고 정중하게 응대하세요.
- 주문 조회, 환불 요청 등 도구를 활용하세요.
- 해결할 수 없는 문제는 상담원 연결을 안내하세요."""

# 대화 루프
prev_id = None
while True:
    user_input = input("\n고객: ")
    if user_input.lower() in ['quit', '종료']:
        break
    
    kwargs = {
        "model": "gpt-4.1",
        "instructions": system_prompt,
        "tools": tools,
        "input": user_input,
    }
    if prev_id:
        kwargs["previous_response_id"] = prev_id
    
    response = client.responses.create(**kwargs)
    
    # Function Call 처리
    needs_followup = False
    for item in response.output:
        if item.type == "function_call":
            needs_followup = True
            args = json.loads(item.arguments)
            
            if item.name == "check_order_status":
                result = check_order_status(**args)
            elif item.name == "request_refund":
                result = request_refund(**args)
            else:
                result = json.dumps({"error": "Unknown function"})
            
            # 도구 결과를 돌려보내기
            response = client.responses.create(
                model="gpt-4.1",
                instructions=system_prompt,
                tools=tools,
                previous_response_id=response.id,
                input=[{
                    "type": "function_call_output",
                    "call_id": item.call_id,
                    "output": result
                }]
            )
    
    prev_id = response.id
    print(f"\n상담AI: {response.output_text}")

17.3 프로젝트 3: 웹 검색 기반 리서치 어시스턴트

Python
response = client.responses.create(
    model="gpt-5.4",
    instructions="당신은 리서치 어시스턴트입니다. "
                 "웹 검색을 통해 최신 정보를 수집하고 "
                 "출처와 함께 한국어로 보고서를 작성하세요.",
    tools=[{"type": "web_search"}],
    input="2026년 AI 산업의 주요 트렌드를 조사해 주세요."
)

print(response.output_text)
Chapter 18

부록 — 치트시트 & 학습 로드맵

18.1 API 호출 치트시트

Python — API Cheat Sheet
# =============================================
# OpenAI API 치트시트 — 핵심 패턴 정리
# =============================================
from openai import OpenAI
client = OpenAI()  # OPENAI_API_KEY 환경 변수 자동 사용

# ── 1. 기본 텍스트 생성 (Responses API) ──
response = client.responses.create(
    model="gpt-4.1",
    input="질문 또는 프롬프트"
)
print(response.output_text)

# ── 2. 시스템 프롬프트 + 멀티턴 ──
resp1 = client.responses.create(
    model="gpt-4.1",
    instructions="시스템 프롬프트 (역할, 규칙 등)",
    input="사용자 메시지"
)
resp2 = client.responses.create(
    model="gpt-4.1",
    previous_response_id=resp1.id,
    input="후속 질문"
)

# ── 3. Chat Completions API (레거시) ──
response = client.chat.completions.create(
    model="gpt-4.1",
    messages=[
        {"role": "system", "content": "시스템 프롬프트"},
        {"role": "user",   "content": "사용자 메시지"}
    ],
    temperature=0.7,
    max_tokens=1000
)
print(response.choices[0].message.content)

# ── 4. 스트리밍 ──
stream = client.responses.create(
    model="gpt-4.1",
    input="긴 답변이 필요한 질문",
    stream=True
)
for event in stream:
    if event.type == "response.output_text.delta":
        print(event.delta, end="")

# ── 5. Structured Outputs ──
from pydantic import BaseModel
class MySchema(BaseModel):
    field1: str
    field2: int

resp = client.responses.parse(
    model="gpt-4.1",
    input="...",
    text_format=MySchema
)
parsed = resp.output_parsed  # MySchema 인스턴스

# ── 6. Function Calling ──
tools = [{
    "type": "function",
    "name": "my_function",
    "description": "함수 설명",
    "parameters": {
        "type": "object",
        "properties": {
            "param1": {"type": "string", "description": "설명"}
        },
        "required": ["param1"],
        "additionalProperties": False
    },
    "strict": True
}]
resp = client.responses.create(
    model="gpt-4.1",
    tools=tools,
    input="..."
)
# resp.output에서 function_call 아이템 처리

# ── 7. 내장 도구 ──
# 웹 검색
client.responses.create(
    model="gpt-5.4",
    tools=[{"type": "web_search"}],
    input="최신 뉴스 검색"
)

# ── 8. 이미지 입력 (Vision) ──
client.responses.create(
    model="gpt-4.1",
    input=[{
        "role": "user",
        "content": [
            {"type": "input_text", "text": "이 이미지를 설명해줘"},
            {"type": "input_image", "image_url": "https://..."}
        ]
    }]
)

# ── 9. 이미지 생성 ──
client.images.generate(
    model="gpt-image-2",
    prompt="이미지 설명",
    n=1,
    size="1024x1024"
)

# ── 10. Embeddings ──
client.embeddings.create(
    model="text-embedding-3-small",
    input="텍스트"
)

# ── 11. 추론 강도 조절 (GPT-5 시리즈) ──
client.responses.create(
    model="gpt-5.4",
    reasoning={"effort": "high"},  # low | medium | high | xhigh
    input="복잡한 문제..."
)

18.2 자주 하는 실수 & 해결법

실수증상해결법
API 키 하드코딩Git에 키가 노출환경 변수 또는 시크릿 매니저 사용
temperature 미지정코드 생성 결과가 불안정정확성이 중요하면 0~0.3으로 설정
max_tokens 미설정응답이 중간에 잘림 또는 과도한 비용예상 응답 길이에 맞게 설정
에러 처리 미구현서비스 장애 발생지수 백오프 재시도 + 타임아웃 설정
프롬프트 캐싱 미활용동일한 프롬프트에 반복 과금정적 부분을 앞에, 동적 부분을 뒤에 배치
모든 작업에 최고 모델 사용불필요한 비용 낭비작업 복잡도에 맞는 모델 선택
스트리밍 미사용 (UX)사용자가 긴 대기 시간 체감스트리밍으로 즉시 토큰 표시
토큰 사용량 미추적예상 못한 청구서response.usage를 항상 로깅
한국어 토큰 과다 소비영어 대비 2~3배 비용프롬프트를 간결하게, 불필요한 문맥 제거

18.3 HTTP 직접 호출 (curl)

SDK 없이 직접 HTTP 요청을 보낼 수도 있습니다. 디버깅이나 다른 언어에서 참고할 때 유용합니다.

Bash (curl)
curl https://api.openai.com/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4.1",
    "input": "안녕하세요, curl로 API를 호출합니다!"
  }'

18.4 학습 로드맵

단계기간학습 내용이 튜토리얼
Level 1 입문1~2일API 키, 기본 호출, 모델 선택, 토큰 이해Ch.1~Ch.4
Level 2 기초1주Responses/Chat API, 파라미터 튜닝, StreamingCh.5~Ch.7, Ch.11
Level 3 중급2~3주Function Calling, Structured Outputs, EmbeddingsCh.8~Ch.10, Ch.13
Level 4 고급1~2개월내장 도구, Agents SDK, RAG, 프로덕션 배포Ch.12, Ch.15~Ch.17
Level 5 전문가지속Fine-tuning, 비용 최적화, 멀티 에이전트 오케스트레이션공식 문서 + 실무

18.5 유용한 리소스

18.6 마치며

OpenAI API 학습의 핵심 3원칙

1. 작게 시작하세요 — 처음부터 복잡한 에이전트를 만들 필요 없습니다. 단순한 텍스트 생성부터 시작하여 점차 Function Calling, Streaming, 에이전트로 확장하세요.

2. 비용을 항상 의식하세요 — 토큰 사용량을 로깅하고, 작업에 적합한 최소 모델을 선택하세요. 프롬프트 캐싱과 Batch API를 적극 활용하면 비용을 크게 줄일 수 있습니다.

3. 공식 문서를 가까이 하세요 — OpenAI의 모델과 API는 빠르게 진화합니다. 이 튜토리얼은 핵심 개념을 잡아주지만, 최신 변경 사항은 항상 공식 문서에서 확인하세요.

AI 개발의 세계에 오신 것을 환영합니다. OpenAI API를 활용하면 여러분의 아이디어를 현실로 만들 수 있습니다. 이 튜토리얼이 여러분의 AI 여정에 든든한 첫걸음이 되기를 바랍니다!