최근 업데이트: 2025년 12월
📋 목차
지원하는 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}")비교 분석
기능 비교표
| 기능 | OpenAI | Claude | Gemini |
|---|---|---|---|
| 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 openaifrom 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 anthropicfrom 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-generativeaiimport 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)⚠️ 주의사항
- 베타 기능: Claude structured output은 아직 공개 베타 상태
- 캐싱: Claude는 첫 요청 시 추가 지연 (이후 24시간 캐시)
- 스키마 복잡도: 너무 복잡한 스키마는 거부될 수 있음
- Token 비용: 구조화된 응답 포맷 설명으로 약간의 추가 토큰 비용
- Refusal: 안전상 이유로 거부 시 스키마 미준수 가능
참고 자료
- OpenAI Cookbook - Structured Outputs
- Claude Docs - Structured Outputs
- Gemini API - Structured Output
- OpenAI GitHub - Structured Output Samples
마지막 업데이트: 2025년 12월 13일