구조화된 출력 (Structured Outputs)

구조화된 출력 (Structured Outputs)

모델이 JSON 형태로 답을 주도록 강제하고 싶을 때가 많죠. 지저분한 자연어 응답을 파싱해서 쓰는 대신, 구조화된 출력(Structured Outputs)을 쓰면 모델이 직접 제공한 JSON Schema 규격에 맞는 응답을 만들어 내요. response_format 파라미터 하나로 쓸 수 있어서 부담이 덜해요.

출처: Novita AI - Structured Outputs

개요

구조화된 출력은 모델이 사용자가 제공한 JSON Schema 규격을 따르는 응답을 생성하도록 하는 기능이에요. 응답 형식을 미리 잡아 두면 후처리 파싱 코드가 훨씬 단순해져요.

지원 모델

현재 구조화된 출력을 지원하는 모델 목록은 문서의 모델 섹션을 참고하면 돼요.

퀵스타트 가이드

response_formatjson_schema로 지정해 JSON 응답을 생성하는 방법을 보여드릴게요. 전체 Python 코드 예제를 따라가면 돼요.

1. 클라이언트 초기화

먼저 Novita API 키로 클라이언트를 초기화해요.

from openai import OpenAI

client = OpenAI(
    base_url="https://api.novita.ai/openai",
    # Get the Novita AI API Key from: https://novita.ai/settings/key-management.
    api_key="<YOUR Novita AI API Key>",
)

# Go to the Models page to see the models that support Structured Outputs.
model = "mistralai/mistral-7b-instruct"

2. JSON 스키마 정의

이 예시는 사용자 입력에서 지출(expense) 정보를 추출하는 스키마를 만들어요.

# Define system prompt for expense tracking.
system_prompt = """You are an expense tracking assistant. 
Extract expense information from the user's input and format it according to the provided schema."""

# Define JSON schema for structured response.
response_format = {
    "type": "json_schema",
    "json_schema": {
        "name": "expense_tracking_schema",
        "schema": {
            "type": "object",
            "properties": {
                "expenses": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "description": {
                                "type": "string",
                                "description": "Description of the expense"
                            },
                            "amount": {
                                "type": "number",
                                "description": "Amount spent in dollars"
                            },
                            "date": {
                                "type": "string",
                                "description": "When the expense occurred"
                            },
                            "category": {
                                "type": "string",
                                "description": "Category of expense (e.g., food, office, travel)"
                            }
                        },
                        "required": [
                            "description",
                            "amount"
                        ]
                    }
                },
                "total": {
                    "type": "number",
                    "description": "Total amount of all expenses"
                }
            },
            "required": [
                "expenses",
                "total"
            ],
        },
    },
}

3. 채팅 완성 API 요청

이제 Novita 엔드포인트로 채팅 완성 요청을 보내요. 이 요청에는 앞서 정의한 JSON 스키마를 담은 response_format 파라미터가 포함돼요.

chat_completion = client.chat.completions.create(
    model=model,
    messages=[
        {
            "role": "system",
            "content": system_prompt,
        },
        {
            "role": "user",
            "content": """I spent $120 on dinner at an Italian restaurant last Friday with my colleagues.
Also bought office supplies for $45 on Monday.""",
        },
    ],
    max_tokens=1024,
    temperature=0.8,
    stream=False,
    response_format=response_format,
)

response_content = chat_completion.choices[0].message.content

# Parse and prettify the JSON
try:
    json_response = json.loads(response_content)
    prettified_json = json.dumps(json_response, indent=2)
    print(prettified_json)
except json.JSONDecodeError:
    print("Could not parse response as JSON. Raw response:")
    print(response_content)

출력:

{
  "expenses": [
    {
      "date": "2023-03-17",
      "description": "Dinner at Italian restaurant",
      "amount": 120,
      "category": "Food & Dining"
    },
    {
      "date": "2023-03-13",
      "description": "Office supplies",
      "amount": 45,
      "category": "Office Supplies"
    }
  ],
  "total": 165
}

완전한 코드

from openai import OpenAI
import json

client = OpenAI(
    base_url="https://api.novita.ai/openai",
    # Get the Novita AI API Key from: https://novita.ai/settings/key-management.
    api_key="<YOUR Novita AI API Key>",
)

# Go to the Models page to see the models that support Structured Outputs.
model = "mistralai/mistral-7b-instruct"

# Example of using JSON Schema for structured output
# This example creates a schema for extracting expense information

system_prompt = """You are an expense tracking assistant. 
Extract expense information from the user's input and format it according to the provided schema."""

response_format = {
    "type": "json_schema",
    "json_schema": {
        "name": "expense_tracking_schema",
        "schema": {
            "type": "object",
            "properties": {
                "expenses": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "description": {
                                "type": "string",
                                "description": "Description of the expense"
                            },
                            "amount": {
                                "type": "number",
                                "description": "Amount spent in dollars"
                            },
                            "date": {
                                "type": "string",
                                "description": "When the expense occurred"
                            },
                            "category": {
                                "type": "string",
                                "description": "Category of expense (e.g., food, office, travel)"
                            }
                        },
                        "required": [
                            "description",
                            "amount"
                        ]
                    }
                },
                "total": {
                    "type": "number",
                    "description": "Total amount of all expenses"
                }
            },
            "required": [
                "expenses",
                "total"
            ],
        },
    },
}

chat_completion = client.chat.completions.create(
    model=model,
    messages=[
        {
            "role": "system",
            "content": system_prompt,
        },
        {
            "role": "user",
            "content": """I spent $120 on dinner at an Italian restaurant last Friday with my colleagues.
Also bought office supplies for $45 on Monday.""",
        },
    ],
    max_tokens=1024,
    temperature=0.8,
    stream=False,
    response_format=response_format,
)

response_content = chat_completion.choices[0].message.content

try:
    json_response = json.loads(response_content)
    prettified_json = json.dumps(json_response, indent=2)
    print(prettified_json)
except json.JSONDecodeError:
    print("Could not parse response as JSON. Raw response:")
    print(response_content)

더 알아보기