AI API를 활용할 때 가장 까다로운 문제 중 하나는 출력 형식의 일관성입니다. "JSON을 반환해줘"라고 요청했는데, 모델이 때로는 유효한 JSON을, 때로는 일반 텍스트를 반환한다면?

이번 튜토리얼에서는 Structured Output(구조화 출력)과 JSON Mode를 활용해 안정적으로 예측 가능한 데이터 구조를 얻는 방법을 다룹니다. HolySheep AI의 단일 API 키로 다양한 모델의 구조화 출력을 통합 관리하는 실전 방법을 소개합니다.

왜 구조화 출력이 필요한가?

실무에서 자주 마주치는 고통스러운 시나리오를 살펴보겠습니다:

시나리오 1: ParsingError로 인한 서버 장애

# ❌ JSON Mode 없이 AI 응답을 파싱하려 할 때 발생하는 오류
import openai
import json

response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "사용자 정보를 JSON으로 반환: 이름, 나이, 이메일"}]
)

모델이 반환한 텍스트

raw_text = response.choices[0].message.content print(f"반환 타입: {type(raw_text)}") # <class 'str'> print(f"원본 응답: {raw_text}")

❌ 파싱 실패 시나리오

"사용자 정보는 다음과 같습니다: {이름: '김철수', 나이: 30, ...}"

json.loads() 실행 시 JSONDecodeError 발생

try: user_data = json.loads(raw_text) except json.JSONDecodeError as e: print(f"파싱 오류: {e}") # 결과: {'이름': '김철수', '나이': 30, ...} — 키가 따옴표 없이 반환됨

시나리오 2: 응답 형식 불일치로 인한 데이터 무결성 문제

# ❌ 일관성 없는 응답 형식으로 인한 로직 오류
responses = []

여러 요청의 응답 형식이 제각각

response_1 = '{"status": "success", "data": {"id": 1}}' response_2 = '{"success": true, "result": {"user_id": 1}}' response_3 = '{"code": 200, "payload": {"userId": 1}}' for resp in [response_1, response_2, response_3]: data = json.loads(resp) # ❌ 각각 다른 키 구조 -> 일관된 접근 불가 # data['data']['id'] vs data['result']['user_id'] vs data['payload']['userId'] print(f"응답: {resp}")

이러한 문제들을 Structured OutputJSON Mode를 통해 원천적으로 해결할 수 있습니다.

Structured Output과 JSON Mode의 차이점

JSON Mode

Structured Output (严格 구조화 출력)

HolySheep AI에서 구조화 출력 사용하기

HolySheep AI는 지금 가입하면 단일 API 키로 다양한 모델의 구조화 출력을 동일한 인터페이스로 관리할 수 있습니다.

1. Python + OpenAI SDK (GPT-4o, GPT-4 Turbo)

# HolySheep AI - Structured Output 예제

pip install openai

from openai import OpenAI from pydantic import BaseModel from typing import List, Optional

응답 스키마 정의 (Pydantic)

class UserProfile(BaseModel): user_id: int username: str email: str preferences: Optional[dict] = None created_at: str class UserListResponse(BaseModel): total: int users: List[UserProfile] page: int

HolySheep AI 클라이언트 초기화

client = OpenAI( api_key="YOUR_HOLYSHEEP_API_KEY", base_url="https://api.holysheep.ai/v1" # HolySheep AI 엔드포인트 )

✅ Structured Output 사용 - Pydantic 스키마 전달

response = client.beta.chat.completions.parse( model="gpt-4o-2024-08-06", messages=[ {"role": "system", "content": "당신은 사용자 정보 관리 어시스턴트입니다."}, {"role": "user", "content": "테스트용 사용자 3명의 정보를 생성해주세요."} ], response_format=UserListResponse # Pydantic 모델로 스키마 지정 )

✅ 자동 파싱 - 바로 Python 객체로 변환

result = response.choices[0].message.parsed print(f"총 사용자 수: {result.total}") print(f"첫 번째 사용자: {result.users[0].username}")

isinstance 확인

print(f"반환 타입: {type(result)}") # <class '__main__.UserListResponse'> print(f"users 타입: {type(result.users)}") # <class 'list'>

2. JSON Mode (범용)

# HolySheep AI - JSON Mode 예제 (모든 모델 호환)

from openai import OpenAI
import json

client = OpenAI(
    api_key="YOUR_HOLYSHEEP_API_KEY",
    base_url="https://api.holysheep.ai/v1"
)

✅ JSON Mode 활성화 - response_format 사용

response = client.chat.completions.create( model="gpt-4o-mini", # 또는 "claude-3-5-sonnet-20240620" messages=[ {"role": "system", "content": "응답은 반드시 유효한 JSON 형식으로만 반환하세요."}, {"role": "user", "content": """ 다음 제품 정보를 JSON으로 반환해주세요: - product_id: 정수 - name: 문자열 - price: 숫자 - in_stock: 불리언 - tags: 문자열 배열 """} ], response_format={"type": "json_object"}, # JSON Mode 활성화 max_tokens=500, temperature=0.3 )

✅ 항상 유효한 JSON 반환 보장

raw_response = response.choices[0].message.content product_data = json.loads(raw_response) print(f"제품명: {product_data['name']}") print(f"가격: {product_data['price']}") print(f"재고: {product_data['in_stock']}")

JSON Schema와 함께 사용

response_with_schema = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "user", "content": "뉴스 기사를 분석해서 다음 스키마에 맞춰 JSON을 반환:\n{\n 'headline': str,\n 'sentiment': 'positive'|'negative'|'neutral',\n 'key_points': list[str],\n 'source': str\n}"} ], response_format={"type": "json_object"}, temperature=0.1 )

3. JavaScript / Node.js

// HolySheep AI - JavaScript Structured Output
// npm install openai

import OpenAI from 'openai';

const client = new OpenAI({
    apiKey: 'YOUR_HOLYSHEEP_API_KEY',
    baseURL: 'https://api.holysheep.ai/v1'
});

// JSON Schema 정의
const jsonSchema = {
    type: 'json_object',
    schema: {
        type: 'object',
        properties: {
            order_id: { type: 'string' },
            customer: {
                type: 'object',
                properties: {
                    name: { type: 'string' },
                    email: { type: 'string' }
                },
                required: ['name', 'email']
            },
            items: {
                type: 'array',
                items: {
                    type: 'object',
                    properties: {
                        product_id: { type: 'string' },
                        quantity: { type: 'integer' },
                        price: { type: 'number' }
                    }
                }
            },
            total_amount: { type: 'number' },
            status: { 
                type: 'string', 
                enum: ['pending', 'processing', 'shipped', 'delivered'] 
            }
        },
        required: ['order_id', 'customer', 'items', 'total_amount', 'status']
    }
};

async function createOrderSummary() {
    const completion = await client.chat.completions.create({
        model: 'gpt-4o',
        messages: [
            {
                role: 'system',
                content: '당신은 이커머스 주문 분석 시스템입니다.'
            },
            {
                role: 'user', 
                content: '최근 7일간의 주문 데이터를 분석해서 요약해주세요.'
            }
        ],
        response_format: jsonSchema,
        temperature: 0.1
    });

    const orderData = JSON.parse(completion.choices[0].message.content);
    
    console.log('주문 ID:', orderData.order_id);
    console.log('고객명:', orderData.customer.name);
    console.log('총액:', orderData.total_amount);
    console.log('상태:', orderData.status);
    
    return orderData;
}

createOrderSummary().catch(console.error);

4. cURL

# HolySheep AI - cURL로 Structured Output 요청

HolySheep AI의 단일 엔드포인트로 모든 모델 지원

GPT-4o로 JSON Mode 요청

curl https://api.holysheep.ai/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_HOLYSHEEP_API_KEY" \ -d '{ "model": "gpt-4o", "messages": [ { "role": "system", "content": "응답은 유효한 JSON으로만 반환하세요." }, { "role": "user", "content": "제품 리뷰를 감정 분석해서 {\"sentiment\": string, \"score\": number, \"keywords\": array} 형식으로 반환" } ], "response_format": { "type": "json_object" }, "max_tokens": 300, "temperature": 0.1 }'

Claude로 JSON Mode 요청 (동일 엔드포인트)

curl https://api.holysheep.ai/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_HOLYSHEEP_API_KEY" \ -d '{ "model": "claude-3-5-sonnet-20240620", "messages": [ { "role": "system", "content": "You must respond only with valid JSON matching the schema." }, { "role": "user", "content": "Analyze this code and return: {\"language\": string, \"complexity\": \"low\"|\"medium\"|\"high\", \"issues\": array}" } ], "response_format": { "type": "json_object" } }'

모델별 구조화 출력 지원 현황

모델JSON ModeStructured Output권장 사용
GPT-4o✅ (Pydantic)일반 추천
GPT-4 Turbo비용 최적화
Claude 3.5 Sonnet정확도 높은 작업
Claude 3 Opus복잡한 분석
Gemini 1.5 Pro장문 처리
DeepSeek V3비용 효율적

자주 발생하는 오류 해결

1. "400 Bad Request: response_format not supported"

# ❌ 해당 모델이 response_format을 지원하지 않는 경우

에러 메시지: "response_format is not supported for this model"

✅ 해결 방법 1: HolySheep AI에서 지원하는 모델로 변경

response = client.chat.completions.create( model="gpt-4o", # Structured Output 지원 모델로 교체 messages=[...], response_format={"type": "json_object"} )

✅ 해결 방법 2: JSON Mode 대신 프롬프트 엔지니어링 사용

response = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "응답 형식: {\"key\": \"value\"}"}, {"role": "user", "content": "..."} ], # response_format 없이 프롬프트로 구조 유도 )

2. "JSONDecodeError: Expecting value"

# ❌ JSON 파싱 실패 - 모델이 유효하지 않은 JSON 반환
import json

raw = response.choices[0].message.content
try:
    data = json.loads(raw)
except json.JSONDecodeError:
    # ❌ 흔한 원인들:
    # 1. ```json 코드 블록으로 감싸서 반환
    # 2. 텍스트 설명이 함께 반환
    # 3. 불완전한 JSON (중간에 잘림)
    
    # ✅ 해결 방법 1: 코드 블록 파싱
    import re
    json_match = re.search(r'``(?:json)?\s*(\{.*?\})\s*``', raw, re.DOTALL)
    if json_match:
        data = json.loads(json_match.group(1))
    
    # ✅ 해결 방법 2: response_format 강제 설정
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[...],
        response_format={"type": "json_object"},  # 반드시 설정
        max_tokens=1000  # 충분한 토큰 확보
    )
    
    # ✅ 해결 방법 3: HolySheep AI 사용 시 추가 검증
    raw_content = response.choices[0].message.content
    if raw_content.startswith('```'):
        raw_content = raw_content.split('```')[1]
        if raw_content.startswith('json'):
            raw_content = raw_content[4:]
        data = json.loads(raw_content.strip())

3. "ValidationError: Missing required field"

# ❌ Pydantic 모델의 필수 필드가 누락된 경우

에러: "ValidationError: Field required: user_id"

from pydantic import BaseModel, field_validator class UserProfile(BaseModel): user_id: int username: str email: str @field_validator('user_id') @classmethod def validate_user_id(cls, v): if v <= 0: raise ValueError('user_id must be positive') return v

✅ 해결 방법 1: Optional 필드로 변경

class UserProfile(BaseModel): user_id: Optional[int] = None # 필수 -> 선택 username: str email: Optional[str] = None

✅ 해결 방법 2: 재시도 로직 구현

def fetch_user_with_retry(client, max_retries=3): for attempt in range(max_retries): try: response = client.beta.chat.completions.parse( model="gpt-4o", messages=[...], response_format=UserProfile ) return response.choices[0].message.