본문 바로가기
AI System/OpenAI API와 바이브 코딩으로 배우는 AI 서비스 개발

d01 - 01. text_generation - 05. reasoning_vs_general_response_v2

by Toddler_AD 2026. 6. 1.

05. 일반 응답 vs 추론 기반 응답 v2

이 노트북은 일반 모델 호출과 추론 모델 호출을 비교합니다. reasoning={"effort": "low"}가 API 요청 안에 어떻게 들어가는지 확인하세요.

# Colab 또는 로컬 노트북 실행 환경을 구분하기 위해 sys를 가져옵니다.
import sys
# 패키지 설치 명령을 현재 Python 커널에서 실행하기 위해 subprocess를 가져옵니다.
import subprocess
# 패키지 설치 여부를 확인하기 위해 importlib.util을 가져옵니다.
import importlib.util
# 환경 변수에서 API 키를 읽고 설정하기 위해 os를 가져옵니다.
import os
# API 키를 화면에 노출하지 않고 입력받기 위해 getpass를 가져옵니다.
import getpass
# .env 파일 위치를 다루기 위해 pathlib의 Path를 가져옵니다.
from pathlib import Path

# google.colab 모듈이 있으면 현재 런타임이 Google Colab이라고 판단합니다.
IN_COLAB = "google.colab" in sys.modules
# 노트북에서 사용하는 import 이름과 pip 패키지 이름을 짝지어 둡니다.
REQUIRED_PACKAGES = {
    "openai": "openai>=2.26.0",
    "dotenv": "python-dotenv>=1.2.2",
    "pydantic": "pydantic>=2.11.0",
    "PIL": "pillow>=12.1.1",
    "requests": "requests>=2.32.5",
    "numpy": "numpy>=2.3.3",
    "websockets": "websockets>=15.0.1",
    "websocket": "websocket-client>=1.8.0",
    "nest_asyncio": "nest-asyncio>=1.6.0",
}

# 현재 커널에서 import할 수 없는 패키지만 설치하는 함수입니다.
def ensure_package(import_name: str, package_name: str) -> None:
    # 이미 import 가능한 패키지는 설치를 건너뜁니다.
    if importlib.util.find_spec(import_name) is not None:
        # 설치가 필요 없음을 호출자에게 조용히 알리고 돌아갑니다.
        return
    # Colab에서는 현재 노트북 커널의 Python에 패키지를 설치해야 합니다.
    subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", package_name])

# Colab 기본 런타임에는 일부 OpenAI 실습 패키지가 없을 수 있으므로 먼저 준비합니다.
if IN_COLAB:
    # 실습 전체에서 필요한 패키지를 하나씩 확인하고 부족한 것만 설치합니다.
    for import_name, package_name in REQUIRED_PACKAGES.items():
        # 누락된 패키지를 현재 Colab 런타임에 설치합니다.
        ensure_package(import_name, package_name)

# 패키지 설치 이후 .env 로딩 기능을 사용할 수 있도록 load_dotenv를 가져옵니다.
from dotenv import load_dotenv

# 현재 작업 폴더의 .env 파일이 있으면 로컬 실행처럼 환경 변수로 올립니다.
load_dotenv(Path.cwd() / ".env")
# OPENAI_API_KEY가 이미 있으면 그대로 사용하고, 없으면 Colab Secrets 또는 입력으로 보완합니다.
if not os.getenv("OPENAI_API_KEY"):
    # Colab Secrets에서 OPENAI_API_KEY를 읽어 볼 변수를 준비합니다.
    secret_key = None
    # Colab이 아닌 로컬 환경에서는 google.colab import가 실패할 수 있으므로 예외를 허용합니다.
    try:
        # Colab Secrets의 userdata API를 가져옵니다.
        from google.colab import userdata
        # Secrets에 저장된 OPENAI_API_KEY 값을 읽습니다.
        secret_key = userdata.get("OPENAI_API_KEY")
    except Exception:
        # Colab Secrets를 사용할 수 없으면 이후 수동 입력 단계로 넘어갑니다.
        secret_key = None
    # Secrets에서 키를 찾았다면 현재 런타임 환경 변수로 설정합니다.
    if secret_key:
        # OpenAI SDK가 자동으로 읽을 수 있도록 표준 환경 변수 이름에 저장합니다.
        os.environ["OPENAI_API_KEY"] = secret_key
    else:
        # 키가 없으면 노트북 실행자가 직접 입력하도록 요청합니다.
        entered_key = getpass.getpass("OPENAI_API_KEY를 입력하세요: ").strip()
        # 빈 문자열이 아닌 값을 입력한 경우에만 환경 변수로 등록합니다.
        if entered_key:
            # OpenAI SDK가 자동으로 읽을 수 있도록 표준 환경 변수 이름에 저장합니다.
            os.environ["OPENAI_API_KEY"] = entered_key

# API 키가 끝까지 없으면 다음 OpenAI API 호출이 실패하므로 명확한 오류를 냅니다.
if not os.getenv("OPENAI_API_KEY"):
    # Colab에서는 Secrets 또는 입력, 로컬에서는 .env 또는 환경 변수를 설정해야 함을 알려 줍니다.
    raise RuntimeError("OPENAI_API_KEY가 없습니다. Colab Secrets, 수동 입력, 또는 .env 파일로 설정해 주세요.")

# 이후 셀에서 Colab 여부를 참고할 수 있도록 간단히 출력합니다.
print(f"개발환경: {'Colab' if IN_COLAB else '로컬'}")
# API 키를 직접 출력하지 않고 준비 완료 여부만 알려 줍니다.
print("OPENAI_API_KEY 준비 완료")

 

1단계. 최소 실행 환경 준비

이 단계에서는 API 호출에 필요한 기본 준비를 합니다. import, .env 로드, OpenAI() 클라이언트 생성, output 폴더 생성을 차례대로 확인합니다.

아래 셀에서 특히 client = OpenAI() 줄을 확인하세요. 이후 모든 API 호출은 이 client 객체에서 시작됩니다.

# 운영체제 환경 변수와 .env 값을 읽기 위해 os를 사용합니다.
import os
# JSON 메타데이터를 파일로 저장하기 위해 json을 사용합니다.
import json
# 실행 시간을 비교하는 예제에서 사용할 시간 측정 모듈입니다.
import time
# 노트북 실행 위치와 output 폴더 경로를 안전하게 다루기 위한 Path입니다.
from pathlib import Path

# .env 파일에 저장된 OPENAI_API_KEY를 현재 Python 환경으로 불러옵니다.
from dotenv import load_dotenv
# OpenAI API를 직접 호출하기 위한 공식 SDK 클라이언트입니다.
from openai import OpenAI

# 현재 노트북이 워크스페이스 루트에서 실행되는지, 01.text_generation 폴더에서 실행되는지 확인합니다.
CURRENT_DIR = Path.cwd().resolve()
# 워크스페이스 루트에서 실행 중이면 01.text_generation 폴더를 실습 루트로 사용합니다.
if (CURRENT_DIR / "01.text_generation").exists():
    TEXT_GENERATION_DIR = CURRENT_DIR / "01.text_generation"
# 이미 01.text_generation 폴더 안에서 실행 중이면 현재 폴더를 실습 루트로 사용합니다.
else:
    TEXT_GENERATION_DIR = CURRENT_DIR

# 워크스페이스 루트는 01.text_generation 폴더의 부모 폴더입니다.
WORKSPACE_ROOT = TEXT_GENERATION_DIR.parent
# 실행 결과를 저장할 output 폴더 경로입니다.
OUTPUT_DIR = TEXT_GENERATION_DIR / "output"
# output 폴더가 없으면 새로 만들고, 이미 있으면 그대로 둡니다.
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

# 워크스페이스 루트의 .env 파일을 읽습니다.
load_dotenv(WORKSPACE_ROOT / ".env")

# OpenAI API 키가 설정되어 있는지 먼저 확인합니다.
if not os.getenv("OPENAI_API_KEY"):
    raise RuntimeError("OPENAI_API_KEY가 없습니다. 워크스페이스 루트의 .env 파일을 확인해 주세요.")

# OpenAI API를 호출할 클라이언트를 생성합니다. 이 줄이 모든 API 호출의 출발점입니다.
client = OpenAI()

# 이후 셀에서 저장 경로를 확인할 수 있도록 출력합니다.
print(f"실습 폴더: {TEXT_GENERATION_DIR}")
print(f"결과 저장 폴더: {OUTPUT_DIR}")
실습 폴더: C:\Users\ai4nu\2026-ai-tech\AS.1.1_0601\01.text_generation
결과 저장 폴더: C:\Users\ai4nu\2026-ai-tech\AS.1.1_0601\01.text_generation\output
 

2단계. 비교할 모델과 프롬프트 준비하기

# 일반 응답 모델입니다.
GENERAL_MODEL = os.getenv("OPENAI_GENERAL_MODEL", "gpt-4.1-mini")
# 추론 응답 모델입니다.
REASONING_MODEL = os.getenv("OPENAI_REASONING_MODEL", "gpt-5-mini")

# 두 모델에 공통으로 줄 역할 지시문입니다.
INSTRUCTIONS = "당신은 학습 코치입니다. 초급자가 이해할 수 있도록 한국어로 명확히 설명하세요."
# 두 모델에 공통으로 보낼 사용자 요청입니다.
PROMPT = "다음 조건을 모두 만족하는 2주 학습 계획을 작성해 주세요. 조건: 평일 하루 1시간, 주말 하루 2시간, 기초 이론/실습/복습 비율을 제안하고 이유를 함께 설명."

print(f"일반 모델: {GENERAL_MODEL}")
print(f"추론 모델: {REASONING_MODEL}")
print(PROMPT)
일반 모델: gpt-4.1-mini
추론 모델: gpt-5-mini
다음 조건을 모두 만족하는 2주 학습 계획을 작성해 주세요. 조건: 평일 하루 1시간, 주말 하루 2시간, 기초 이론/실습/복습 비율을 제안하고 이유를 함께 설명.
 

3단계. 일반 모델 직접 호출하기

# 일반 모델 호출 시작 시간을 기록합니다.
general_started = time.perf_counter()
# 일반 모델에 Responses API 요청을 보냅니다.
general_response = client.responses.create(
    # 일반 응답 모델입니다.
    model=GENERAL_MODEL,
    # 모델의 역할 지시문입니다.
    instructions=INSTRUCTIONS,
    # 실제 사용자 요청입니다.
    input=PROMPT,
    # 최대 출력 토큰 수입니다.
    max_output_tokens=320,
)
# 일반 모델 실행 시간을 계산합니다.
general_elapsed = time.perf_counter() - general_started
# 일반 모델 응답 텍스트를 읽습니다.
general_text = general_response.output_text

print("[일반 모델 응답]")
print(general_text)
print(f"모델: {general_response.model}")
print(f"실행 시간: {general_elapsed:.4f}초")
print(f"사용량: {general_response.usage}")
[일반 모델 응답]
네! 2주 학습 계획과 함께 기초 이론, 실습, 복습의 비율과 그 이유를 초급자가 이해하기 쉽게 설명해 드릴게요.

---

### 1. 학습 시간 총정리
- 평일: 5일 × 1시간 = 5시간
- 주말: 2일 × 2시간 = 4시간  
**총 9시간**

---

### 2. 기초 이론 / 실습 / 복습 비율 제안  
**비율: 이론 30%, 실습 50%, 복습 20%**

- 이론 (약 3시간): 기초를 이해하는 시간  
- 실습 (약 4.5시간): 직접 해보며 익히는 시간  
- 복습 (약 1.5시간): 배운 내용을 다시 정리하고 확인하는 시간

---

### 3. 비율 이유 설명

- **이론 30%**  
  처음 배울 땐 기본 개념을 이해하는 것이 중요하지만, 이론만 너무 오래 하면 지루할 수 있으므로 적당한 시간만 투자합니다.

- **실습 50%**  
  실제로 해보는 것이 가장 효과적인 학습 방법입니다. 실습을 통해 이론을 몸에 익히고 문제 해결 능력을 키울 수 있습니다.

- **복습 20%**  
  학습한 내용을 잊지 않도록 정리하고, 문제점을 확인하며 보완하는 시간이
모델: gpt-4.1-mini-2025-04-14
실행 시간: 6.0253초
사용량: ResponseUsage(input_tokens=91, input_tokens_details=InputTokensDetails(cached_tokens=0), output_tokens=320, output_tokens_details=OutputTokensDetails(reasoning_tokens=0), total_tokens=411)
 

4단계. 추론 모델 직접 호출하기

추론 모델 요청에서는 reasoning 매개변수를 직접 넣습니다. 계정이나 모델 접근 권한에 따라 실패할 수 있으므로 오류를 출력하고 다음 셀에서 비교가 이어지도록 처리합니다.

# 추론 모델 호출 시작 시간을 기록합니다.
reasoning_started = time.perf_counter()
# 오류 메시지를 저장할 변수입니다.
reasoning_error = None

# 추론 모델은 접근 권한이 없을 수 있으므로 예외 처리를 합니다.
try:
    # 추론 모델에 Responses API 요청을 보냅니다.
    reasoning_response = client.responses.create(
        # 추론 응답 모델입니다.
        model=REASONING_MODEL,
        # 모델의 역할 지시문입니다.
        instructions=INSTRUCTIONS,
        # 실제 사용자 요청입니다.
        input=PROMPT,
        # 최대 출력 토큰 수입니다.
        max_output_tokens=420,
        # 추론 강도를 직접 지정합니다.
        reasoning={"effort": "low"},
    )
    # 추론 모델 응답 텍스트를 읽습니다.
    reasoning_text = reasoning_response.output_text
# 호출이 실패하면 오류를 저장합니다.
except Exception as exc:
    # 실패 원인을 문자열로 저장합니다.
    reasoning_error = str(exc)
    # 비교 파일 구조를 유지하기 위한 안내 텍스트입니다.
    reasoning_text = "추론 모델 호출 실패로 결과를 생성하지 못했습니다. API 권한 또는 모델 설정을 확인해 주세요."
    # 응답 객체가 없음을 표시합니다.
    reasoning_response = None

# 추론 모델 실행 시간을 계산합니다.
reasoning_elapsed = time.perf_counter() - reasoning_started

print("[추론 모델 응답]")
print(reasoning_text)
print(f"실행 시간: {reasoning_elapsed:.4f}초")
print(f"오류: {reasoning_error}")
if reasoning_response:
    print(f"모델: {reasoning_response.model}")
    print(f"사용량: {reasoning_response.usage}")
[추론 모델 응답]
아래는 “2주(14일)” 동안 평일 하루 1시간, 주말 하루 2시간을 지키는 초급자용 학습 계획입니다. 주제는 어떤 과목·기술이든 적용할 수 있도록 일반적인 이론/실습/복습 활동으로 구성했습니다.

총시간 계산
- 평일(10일) = 10 × 1시간 = 10시간  
- 주말(4일) = 4 × 2시간 = 8시간  
- 총
실행 시간: 5.7230초
오류: None
모델: gpt-5-mini-2025-08-07
사용량: ResponseUsage(input_tokens=90, input_tokens_details=InputTokensDetails(cached_tokens=0), output_tokens=420, output_tokens_details=OutputTokensDetails(reasoning_tokens=256), total_tokens=510)
 

5단계. 비교 결과 저장하기

# 저장 경로를 정합니다.
general_path = OUTPUT_DIR / "05_general_response_v2_output.txt"
reasoning_path = OUTPUT_DIR / "05_reasoning_response_v2_output.txt"
metadata_path = OUTPUT_DIR / "05_reasoning_vs_general_response_v2_meta.json"

# 두 응답 텍스트를 각각 저장합니다.
general_path.write_text(general_text + "\\n", encoding="utf-8")
reasoning_path.write_text(reasoning_text + "\\n", encoding="utf-8")

# 일반 모델 usage를 저장 가능한 딕셔너리로 변환합니다.
general_usage = general_response.usage.model_dump() if general_response.usage else {}
# 추론 모델 usage를 저장 가능한 딕셔너리로 변환합니다.
reasoning_usage = reasoning_response.usage.model_dump() if reasoning_response and reasoning_response.usage else {}

# 비교 메타데이터를 구성합니다.
metadata = {
    "example": "05.reasoning_vs_general_response_v2",
    "general_model": general_response.model,
    "reasoning_model": reasoning_response.model if reasoning_response else REASONING_MODEL,
    "general_elapsed_seconds": round(general_elapsed, 4),
    "reasoning_elapsed_seconds": round(reasoning_elapsed, 4),
    "general_usage": general_usage,
    "reasoning_usage": reasoning_usage,
    "reasoning_error": reasoning_error,
    "general_output_path": str(general_path),
    "reasoning_output_path": str(reasoning_path),
}
# 메타데이터를 저장합니다.
metadata_path.write_text(json.dumps(metadata, ensure_ascii=False, indent=2) + "\\n", encoding="utf-8")

print(json.dumps(metadata, ensure_ascii=False, indent=2))
{
  "example": "05.reasoning_vs_general_response_v2",
  "general_model": "gpt-4.1-mini-2025-04-14",
  "reasoning_model": "gpt-5-mini-2025-08-07",
  "general_elapsed_seconds": 6.0253,
  "reasoning_elapsed_seconds": 5.723,
  "general_usage": {
    "input_tokens": 91,
    "input_tokens_details": {
      "cached_tokens": 0
    },
    "output_tokens": 320,
    "output_tokens_details": {
      "reasoning_tokens": 0
    },
    "total_tokens": 411
  },
  "reasoning_usage": {
    "input_tokens": 90,
    "input_tokens_details": {
      "cached_tokens": 0
    },
    "output_tokens": 420,
    "output_tokens_details": {
      "reasoning_tokens": 256
    },
    "total_tokens": 510
  },
  "reasoning_error": null,
  "general_output_path": "C:\\Users\\ai4nu\\2026-ai-tech\\AS.1.1_0601\\01.text_generation\\output\\05_general_response_v2_output.txt",
  "reasoning_output_path": "C:\\Users\\ai4nu\\2026-ai-tech\\AS.1.1_0601\\01.text_generation\\output\\05_reasoning_response_v2_output.txt"
}
Click to add a cell.