최근 업데이트: 2025년 12월

📋 목차

  1. 지원하는 Provider와 모델
  2. 각 Provider별 상세 가이드
  3. 사용 예시 및 코드
  4. 비교 분석

지원하는 Provider와 모델

1. OpenAI ✅ (공식 지원)

모델상태지원 방식
gpt-4o-2024-08-06 이상✅ 완전 지원JSON Schema, Strict Mode
gpt-4o-mini-2024-07-18 이상✅ 완전 지원JSON Schema, Strict Mode
gpt-4.5-preview✅ 지원JSON Schema, Strict Mode
o3-mini✅ 지원JSON Schema, Strict Mode
o1✅ 지원JSON Schema, Strict Mode

2. Anthropic (Claude) ✅ (공식 지원 - 베타)

모델상태지원 기간
claude-sonnet-4-5✅ 공개 베타2025-11-14~
claude-opus-4-1✅ 공개 베타2025-11-14~
claude-opus-4-5✅ 공개 베타2025-11-14~
claude-haiku-4-5✅ 공개 베타2025-12-04~

3. Google (Gemini) ✅ (공식 지원)

모델상태비고
gemini-2.0-flash✅ 완전 지원최신 모델
gemini-2.0-flash-lite✅ 지원경량 모델
gemini-2.5-pro✅ 지원Vertex AI
gemini-2.5-flash✅ 지원Vertex AI
gemini-2.5-flash-lite✅ 지원Vertex AI
gemini-3-pro (preview)✅ 지원Vertex AI 미리보기

4. Mistral ✅ (지원)

  • Mistral API를 통한 structured output 지원 가능

5. AWS Bedrock ✅ (일부 모델 지원)

  • Claude, Gemini 모델을 통한 간접 지원

각 Provider별 상세 가이드

OpenAI - Structured Outputs

특징

  • JSON Schema 기반 응답 포맷 강제
  • strict: true 파라미터로 엄격한 스키마 준수 보장
  • 100% 스키마 준수 보장 (파싱 오류 없음)
  • Pydantic 모델과 SDK 통합

필요한 헤더/설정

# SDK에서는 자동 처리
from openai import OpenAI
client = OpenAI(api_key="your-key")

사용 방법

방법 1: JSON Schema 직접 정의

from openai import OpenAI
 
client = OpenAI()
 
response = client.chat.completions.create(
    model="gpt-4o-2024-08-06",
    messages=[
        {
            "role": "user",
            "content": "Extract contact info: John Smith ([email protected]) wants Enterprise plan demo for Tuesday 2pm"
        }
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "contact_info",
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "email": {"type": "string"},
                    "plan_interest": {"type": "string"},
                    "demo_requested": {"type": "boolean"}
                },
                "required": ["name", "email", "plan_interest", "demo_requested"],
                "additionalProperties": False
            },
            "strict": True
        }
    }
)
 
print(response.choices[0].message.content)
# Output: {"name": "John Smith", "email": "[email protected]", "plan_interest": "Enterprise", "demo_requested": true}

방법 2: Pydantic 모델 사용 (권장)

from pydantic import BaseModel
from openai import OpenAI
 
class MathStep(BaseModel):
    explanation: str
    output: str
 
class MathSolution(BaseModel):
    steps: list[MathStep]
    final_answer: str
 
client = OpenAI()
 
completion = client.beta.chat.completions.parse(
    model="gpt-4o-2024-08-06",
    messages=[
        {
            "role": "system",
            "content": "You are a math tutor. Solve step by step."
        },
        {
            "role": "user",
            "content": "Solve: 8x + 7 = -23"
        }
    ],
    response_format=MathSolution,
)
 
result = completion.choices[0].message.parsed
print(f"Steps: {result.steps}")
print(f"Answer: {result.final_answer}")

Claude (Anthropic) - Structured Outputs

특징

  • 공개 베타 (2025-11-14 시작)
  • 두 가지 모드: JSON Outputs / Strict Tool Use
  • Constrained decoding으로 100% 스키마 준수 보장
  • Pydantic / Zod 통합 지원

필요한 헤더

# 반드시 베타 헤더 포함
header: "anthropic-beta: structured-outputs-2025-11-13"

사용 방법

방법 1: JSON Schema (Python)

from anthropic import Anthropic
 
client = Anthropic(api_key="your-key")
 
response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    messages=[
        {
            "role": "user",
            "content": "Extract info: John Smith ([email protected]) wants Enterprise plan demo Tuesday 2pm"
        }
    ],
    output_format={
        "type": "json_schema",
        "schema": {
            "type": "object",
            "properties": {
                "name": {"type": "string"},
                "email": {"type": "string"},
                "plan_interest": {"type": "string"},
                "demo_requested": {"type": "boolean"}
            },
            "required": ["name", "email", "plan_interest", "demo_requested"],
            "additionalProperties": False
        }
    }
)
 
print(response.content[0].text)
# Output: {"name": "John Smith", "email": "[email protected]", "plan_interest": "Enterprise", "demo_requested": true}

방법 2: Pydantic 모델 + parse() 메소드 (권장)

from pydantic import BaseModel
from anthropic import Anthropic
 
class ContactInfo(BaseModel):
    name: str
    email: str
    plan_interest: str
    demo_requested: bool
 
client = Anthropic(api_key="your-key")
 
response = client.beta.messages.parse(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    messages=[
        {
            "role": "user",
            "content": "Extract contact info from email: John Smith ([email protected]) interested in Enterprise plan, wants demo Tuesday 2pm"
        }
    ],
    output_format=ContactInfo,
)
 
result = response.parsed_output
print(f"Name: {result.name}")
print(f"Email: {result.email}")

방법 3: Strict Tool Use (Agent 워크플로우)

from anthropic import Anthropic
from pydantic import BaseModel
 
class BookingParams(BaseModel):
    passengers: int
    date: str
    destination: str
 
client = Anthropic(api_key="your-key")
 
tools = [
    {
        "name": "book_flight",
        "description": "Book a flight for passengers",
        "input_schema": {
            "type": "object",
            "properties": {
                "passengers": {"type": "integer", "description": "Number of passengers"},
                "date": {"type": "string", "description": "Travel date"},
                "destination": {"type": "string", "description": "Destination city"}
            },
            "required": ["passengers", "date", "destination"]
        },
        "strict": True  # 엄격한 스키마 강제
    }
]
 
response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    messages=[
        {
            "role": "user",
            "content": "Book flights for 3 people to Paris on December 25"
        }
    ],
    tools=tools
)
 
# Tool use 응답은 항상 올바른 타입 보장
for block in response.content:
    if block.type == "tool_use":
        print(f"Tool: {block.name}")
        print(f"Input: {block.input}")  # passengers: int (문자열 아님!)

Google Gemini - Structured Output

특징

  • Response Schema 기반 JSON 제한
  • response_mime_type: "application/json" 설정 필수
  • OpenAPI 3.0 스키마 부분집합 사용
  • Pydantic 모델 지원

사용 방법

방법 1: Pydantic 모델 사용

import google.generativeai as genai
from pydantic import BaseModel
 
class Cat(BaseModel):
    name: str
    color: str
    special_ability: str
 
genai.configure(api_key="your-api-key")
 
client = genai.Client()
 
response = client.models.generate_content(
    model="gemini-2.0-flash",
    contents="Generate data for 3 cats including name, color, and special ability",
    config={
        "response_mime_type": "application/json",
        "response_schema": list[Cat]  # Pydantic 모델을 스키마로 사용
    }
)
 
print(response.text)
# Output: [{"name": "Whiskers", "color": "orange", "special_ability": "laser vision"}, ...]

방법 2: JSON Schema 직접 정의

import google.generativeai as genai
 
genai.configure(api_key="your-api-key")
 
response_schema = {
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "course": {
                "type": "string",
                "enum": ["appetizer", "salad", "soup", "main", "dessert"]
            },
            "name": {"type": "string"},
            "ingredients": {
                "type": "array",
                "items": {"type": "string"}
            }
        },
        "required": ["course", "name", "ingredients"]
    }
}
 
response = genai.GenerativeModel(
    "gemini-2.0-flash",
    generation_config={
        "response_mime_type": "application/json",
        "response_schema": response_schema
    }
).generate_content("Create a 3-course meal plan")
 
print(response.text)

방법 3: TypeScript 예제

const schema = {
    description: "List of questions and answers",
    type: "ARRAY",
    items: {
        type: "OBJECT",
        properties: {
            question: {
                type: "STRING",
                description: "Question text"
            },
            options: {
                type: "ARRAY",
                items: { type: "STRING" },
                description: "Multiple choice options"
            },
            answer: {
                type: "INTEGER",
                description: "Correct answer index"
            }
        }
    }
};
 
const model = genai.getGenerativeModel({
    model: "gemini-2.0-flash",
    generationConfig: {
        responseMimeType: "application/json",
        responseSchema: schema
    }
});
 
const response = await model.generateContent(
    "Create 5 quiz questions about AI"
);

사용 예시 및 코드

실제 사용 사례 1: 이메일 정보 추출

OpenAI 방식

from openai import OpenAI
from pydantic import BaseModel
 
class EmailExtraction(BaseModel):
    sender: str
    subject: str
    action_required: bool
    priority: str  # high, medium, low
 
client = OpenAI()
 
email_text = """
From: [email protected]
Subject: Urgent: Enterprise License Update
Body: Your enterprise license expires in 30 days. Please renew immediately.
"""
 
completion = client.beta.chat.completions.parse(
    model="gpt-4o-2024-08-06",
    messages=[
        {
            "role": "user",
            "content": f"Extract email metadata:\n{email_text}"
        }
    ],
    response_format=EmailExtraction,
)
 
result = completion.choices[0].message.parsed
print(f"Sender: {result.sender}")
print(f"Action Required: {result.action_required}")
print(f"Priority: {result.priority}")

Claude 방식

from anthropic import Anthropic
from pydantic import BaseModel
 
class EmailExtraction(BaseModel):
    sender: str
    subject: str
    action_required: bool
    priority: str
 
client = Anthropic()
 
response = client.beta.messages.parse(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    messages=[
        {
            "role": "user",
            "content": f"Extract email metadata:\n{email_text}"
        }
    ],
    output_format=EmailExtraction,
)
 
result = response.parsed_output
print(f"Sender: {result.sender}")

Gemini 방식

import google.generativeai as genai
from pydantic import BaseModel
 
class EmailExtraction(BaseModel):
    sender: str
    subject: str
    action_required: bool
    priority: str
 
genai.configure(api_key="your-api-key")
 
response = genai.GenerativeModel(
    "gemini-2.0-flash",
    generation_config={
        "response_mime_type": "application/json",
        "response_schema": EmailExtraction
    }
).generate_content(f"Extract email metadata:\n{email_text}")
 
import json
result = json.loads(response.text)
print(f"Sender: {result['sender']}")

실제 사용 사례 2: 데이터베이스 레코드 생성

from pydantic import BaseModel
from typing import List
from openai import OpenAI
 
class Address(BaseModel):
    street: str
    city: str
    zip_code: str
    country: str
 
class Customer(BaseModel):
    id: int
    name: str
    email: str
    phone: str
    address: Address
    is_premium: bool
 
# PDF/이미지에서 고객 정보 추출 후 DB 저장
client = OpenAI()
 
document_content = """
Customer Record #1234
Name: Jane Doe
Email: [email protected]
Phone: +1-555-0123
Address: 123 Main St, San Francisco, CA 94102, USA
Premium Member: Yes
"""
 
completion = client.beta.chat.completions.parse(
    model="gpt-4o-2024-08-06",
    messages=[
        {
            "role": "user",
            "content": f"Extract customer record:\n{document_content}"
        }
    ],
    response_format=Customer,
)
 
customer = completion.choices[0].message.parsed
 
# DB에 저장 (예: SQLAlchemy)
# db.add(CustomerModel(
#     id=customer.id,
#     name=customer.name,
#     email=customer.email,
#     ...
# ))
# db.commit()
 
print(f"✅ Customer {customer.name} extracted and saved")

실제 사용 사례 3: Agent Tool Call 검증

from anthropic import Anthropic
from pydantic import BaseModel
 
class SearchParams(BaseModel):
    query: str
    max_results: int
    date_range: str  # YYYY-MM-DD to YYYY-MM-DD
 
client = Anthropic()
 
# Strict Tool Use로 타입 안전성 보장
response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    messages=[
        {
            "role": "user",
            "content": "Search articles about AI from last month, limit to 10 results"
        }
    ],
    tools=[
        {
            "name": "search_articles",
            "description": "Search for articles",
            "input_schema": {
                "type": "object",
                "properties": {
                    "query": {"type": "string"},
                    "max_results": {"type": "integer"},
                    "date_range": {"type": "string"}
                },
                "required": ["query", "max_results", "date_range"]
            },
            "strict": True  # max_results는 항상 정수 보장!
        }
    ]
)
 
for block in response.content:
    if block.type == "tool_use":
        # input 필드의 max_results는 항상 정수입니다
        # "10" (문자열) 이 아니라 10 (정수)
        assert isinstance(block.input["max_results"], int)
        print(f"Tool call arguments validated: {block.input}")

비교 분석

기능 비교표

기능OpenAIClaudeGemini
JSON Schema 강제
Pydantic 통합✅ (parse)✅ (parse)
Zod 통합✅ (TypeScript)
Tool Use 강제✅ (strict: true)
공식 지원 상태✅ GA✅ 베타✅ GA
응답 100% 보장
Streaming 지원

성능 특성

OpenAI

  • 장점: 가장 성숙한 구현, 안정적인 성능
  • 단점: Tool Call 강제 불가 (별도 로직 필요)

Claude

  • 장점: Strict Tool Use로 Agent 신뢰성 극대화, 최신 기술
  • 단점: 아직 베타, 첫 요청 시 100-300ms 추가 지연 (24시간 캐시)

Gemini

  • 장점: 빠른 속도, 비용 효율적, propertyOrdering 지원
  • 단점: TypeScript/JS 중심, Python 예제 상대적으로 적음

선택 가이드

OpenAI 선택 시기

  • 프로덕션 안정성이 최우선
  • JSON 데이터 추출이 주 목적
  • 기존 OpenAI 인프라 사용 중

Claude 선택 시기

  • Agent/Tool 워크플로우 신뢰성이 중요
  • Multi-turn 복잡한 대화 필요
  • 타입 안전한 Tool call이 필수

Gemini 선택 시기

  • 비용 최적화가 중요
  • 빠른 응답 속도 필요
  • Google Cloud 에코시스템 통합

🚀 빠른 시작 스니펫

1분 안에 시작하기 (OpenAI)

pip install openai
from openai import OpenAI
from pydantic import BaseModel
 
class Item(BaseModel):
    name: str
    price: float
 
client = OpenAI()
completion = client.beta.chat.completions.parse(
    model="gpt-4o-2024-08-06",
    messages=[{"role": "user", "content": "Extract: Apple costs $5"}],
    response_format=Item,
)
print(completion.choices[0].message.parsed)

1분 안에 시작하기 (Claude)

pip install anthropic
from anthropic import Anthropic
from pydantic import BaseModel
 
class Item(BaseModel):
    name: str
    price: float
 
client = Anthropic()
response = client.beta.messages.parse(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    messages=[{"role": "user", "content": "Extract: Apple costs $5"}],
    output_format=Item,
)
print(response.parsed_output)

1분 안에 시작하기 (Gemini)

pip install google-generativeai
import google.generativeai as genai
from pydantic import BaseModel
 
class Item(BaseModel):
    name: str
    price: float
 
genai.configure(api_key="your-key")
response = genai.GenerativeModel(
    "gemini-2.0-flash",
    generation_config={
        "response_mime_type": "application/json",
        "response_schema": Item
    }
).generate_content("Extract: Apple costs $5")
print(response.text)

⚠️ 주의사항

  1. 베타 기능: Claude structured output은 아직 공개 베타 상태
  2. 캐싱: Claude는 첫 요청 시 추가 지연 (이후 24시간 캐시)
  3. 스키마 복잡도: 너무 복잡한 스키마는 거부될 수 있음
  4. Token 비용: 구조화된 응답 포맷 설명으로 약간의 추가 토큰 비용
  5. Refusal: 안전상 이유로 거부 시 스키마 미준수 가능

참고 자료


마지막 업데이트: 2025년 12월 13일