구조화된 출력

구조화된 출력 (Structured Outputs)

이번 가이드에서는 Inference Providers로 정해진 JSON 스키마를 따르는 구조화된 출력을 만드는 방법을 다뤄요. 예측 가능하고 파싱하기 쉬운 응답이 필요한 안정적인 AI 앱을 만들 때 정말 유용한 기능이에요.

구조화된 출력은 모델이 매번 여러분이 정의한 스키마와 정확히 일치하는 응답을 반환하도록 보장해요. 그래서 복잡한 파싱 로직이 필요 없어지고, 앱이 훨씬 견고해집니다.

💡 이 가이드는 Hugging Face 계정이 있다고 가정해요. 없으면 huggingface.co에서 무료로 만들 수 있어요.

구조화된 출력이란?

구조화된 출력은 모델 응답이 항상 특정 구조(보통 JSON Schema)를 따르게 합니다. 덕분에 예측 가능하고 타입 안전한 데이터를 얻어, 시스템에 쉽게 통합할 수 있어요. 모델은 엄격한 템플릿을 따르므로 항상 기대한 형식의 데이터를 돌려줍니다.

전통적으로 LLM에서 구조화된 데이터를 얻으려면 프롬프트 엔지니어링("JSON 형식으로 응답해줘"라고 요청), 응답 후처리·파싱, 파싱 실패 시 재시도 같은 과정이 필요했어요. 이 방식은 불안정하고 앱을 취약하게 만들 수 있죠.

구조화된 출력을 쓰면:

  • 정의한 스키마에 대한 준수 보장
  • 잘못 형성되거나 파싱할 수 없는 JSON으로 인한 오류 감소
  • 다운스트림 시스템과의 쉬운 통합
  • 재시도 로직이나 복잡한 에러 처리 불필요
  • 토큰의 효율적 사용(장황한 지시가 줄어듦)

요약하면, 구조화된 출력은 내장된 검증과 타입 안전성으로 매 응답이 스키마와 일치하도록 만들어 앱을 더 견고하고 안정적으로 해 줍니다.

Step 1: 스키마 정의하기

API 호출 전에 원하는 구조를 먼저 정의해야 해요. 실용적인 예시를 만들어 볼게요: 연구 논문에서 구조화된 정보 추출하기. 학술 논문을 파싱해서 제목·저자·기여·방법론 같은 핵심 정보를 뽑아내는 흔한 실제 사례예요.

가장 필수적인 요소(논문 제목과 초록 요약)를 담는 간단한 스키마를 만들 거예요. 가장 쉬운 방법은 Pydantic을 쓰는 것인데, JSON 스키마를 나타내는 파이썬 클래스를 정의할 수 있게 해 주는 라이브러리예요.

from pydantic import BaseModel

class PaperAnalysis(BaseModel):
    title: str
    abstract_summary: str

model_json_schema를 쓰면 Pydantic 모델을 JSON Schema로 변환할 수 있어요. 이게 모델이 응답 형식 지시로 받게 될 스키마가 되어, 모델이 응답을 생성할 때 사용해요.

{
  "type": "object",
  "properties": {
    "title": {"type": "string"},
    "abstract_summary": {"type": "string"}
  },
  "required": ["title", "abstract_summary"]
}

이 간단한 스키마 덕분에 항상 논문 제목과 초록 요약을 얻을 수 있어요. 두 필드를 모두 required로 표시한 점에 주목하세요 — 이렇게 하면 응답에 항상 존재함이 보장되어 앱이 더 안정적이 됩니다.

Step 2: inference 클라이언트 설정하기

스키마가 준비됐으니, inference 제공자와 통신할 클라이언트를 설정할게요. 두 가지 방식을 보여줄 거예요: Hugging Face Hub 클라이언트(모든 Inference Providers에 직접 접근)와 OpenAI 클라이언트(OpenAI 호환 엔드포인트를 통해 동작).

Hugging Face Hub 파이썬 패키지를 설치하세요:

pip install huggingface_hub

InferenceClient를 Inference Provider와 Hugging Face 토큰으로 초기화해요 (전체 제공자 목록은 이 목록 참고).

import os
from huggingface_hub import InferenceClient

# Initialize the client
client = InferenceClient(
    provider="cerebras",  # or use "auto" for automatic selection
    api_key=os.environ["HF_TOKEN"],
)

OpenAI 파이썬 패키지를 설치하세요:

pip install openai

base_url과 Hugging Face 토큰으로 OpenAI 클라이언트를 초기화해요.

import os
from openai import OpenAI
from pydantic import BaseModel
from typing import List

# Initialize the OpenAI client (works with Inference Providers)
client = OpenAI(
    base_url="https://router.huggingface.co/cerebras/v1",
    api_key=os.environ["HF_TOKEN"]
)

💡 구조화된 출력은 특정 제공자·모델을 고르기 좋은 사례예요. 모델·제공자·스키마 사이의 호환성 문제를 피하고 싶기 때문이에요.

Step 3: 구조화된 출력 생성하기

이제 연구 논문에서 구조화된 정보를 추출해 볼게요. 논문 내용과 스키마를 모델에 보내면, 완벽하게 구조화된 데이터를 돌려받아요.

이 예시에서는 유명한 AI 연구 논문을 분석할 거예요. 모델이 논문을 읽고 미리 정의한 스키마에 따라 핵심 정보를 뽑아냅니다.

Hugging Face Hub 클라이언트로 구조화된 출력을 생성하는 방법:

from pydantic import BaseModel

# Example paper text (truncated for brevity)
paper_text = """
Title: Attention Is All You Need

Abstract: The dominant sequence transduction models are based on complex recurrent 
or convolutional neural networks that include an encoder and a decoder. The best 
performing models also connect the encoder and decoder through an attention mechanism. 
We propose a new simple network architecture, the Transformer, based solely on 
attention mechanisms, dispensing with recurrence and convolutions entirely...
"""

# Define the response format
class PaperAnalysis(BaseModel):
    title: str
    abstract_summary: str

# Convert the Pydantic model to a JSON Schema and wrap it in a dictionary
response_format = {
    "type": "json_schema",
    "json_schema": {
        "name": "PaperAnalysis",
        "schema": PaperAnalysis.model_json_schema(),
        "strict": True,
    },
}

# Define your messages with a system prompt and a user prompt
# The system prompt is a description of the task you want the model to perform
# The user prompt is the input data you want to process
messages = [
    {
        "role": "system", 
        "content": "Extract paper title and abstract summary."
    },
    {
        "role": "user", 
        "content": paper_text
    }
]

# Generate structured output using Qwen/Qwen3-32B model
response = client.chat_completion(
    messages=messages,
    response_format=response_format,
    model="Qwen/Qwen3-32B",
)

# The response is guaranteed to match your schema
structured_data = response.choices[0].message.content
print(structured_data)

OpenAI 클라이언트로 구조화된 출력을 생성하는 방법:

# Example paper text (truncated for brevity)
paper_text = """
Title: Attention Is All You Need

Abstract: The dominant sequence transduction models are based on complex recurrent 
or convolutional neural networks that include an encoder and a decoder...
"""

# Generate structured output using Qwen/Qwen3-32B model
# With the OpenAI client, you can use the `response_format` as a pydantic model
completion = client.beta.chat.completions.parse(
    model="qwen-3-32b",
    messages=[
        {"role": "system", "content": "Extract paper title and abstract summary."},
        {"role": "user", "content": paper_text}
    ],
    response_format=PaperAnalysis
)

Step 4: 응답 다루기

두 방식 모두 응답이 지정한 스키마와 일치함을 보장해요. 구조화된 데이터에 접근해서 쓰는 방법은 다음과 같아요.

Hugging Face Hub 클라이언트는 ChatCompletion 객체를 반환하며, 여기엔 모델 응답이 문자열로 들어 있어요. json.loads를 써서 응답을 파싱하고 구조화된 데이터를 얻으세요.

# The response is guaranteed to match your schema
structured_data = response.choices[0].message.content
print("Paper Analysis Results:")
print(structured_data)

# Parse the JSON to work with individual fields
import json
analysis = json.loads(structured_data)
print(f"Title: {analysis['title']}")
print(f"Abstract Summary: {analysis['abstract_summary']}")

OpenAI 클라이언트는 ChatCompletion 객체를 반환하며, 모델 응답이 파이썬 객체로 들어 있어요. PaperAnalysis 클래스의 title·abstract_summary 속성으로 구조화된 데이터에 접근하세요.

# Get the parsed response as a Python object
analysis = completion.choices[0].message.parsed
print(f"Title: {analysis.title}")
print(f"Abstract Summary: {analysis.abstract_summary}")

# The data is already type-safe and validated
print(f"Title type: {type(analysis.title)}")
print(f"Summary type: {type(analysis.abstract_summary)}")

구조화된 출력은 대략 이런 모양이에요:

{
  "title": "Attention Is All You Need",
  "abstract_summary": "Introduces the Transformer architecture based solely on attention mechanisms, eliminating recurrence and convolutions for sequence transduction tasks. Shows superior quality in machine translation while being more parallelizable and requiring less training time."
}

이제 파싱 오류나 필드 누락을 걱정하지 않고 이 데이터를 자신 있게 처리할 수 있어요. 스키마 검증이 필수 필드는 항상 존재하고 데이터 타입도 올바르게 보장해 주거든요.

완전한 실행 예제

바로 실행해서 구조화된 출력을 직접 볼 수 있는 완전한 스크립트예요.

import os
import json

from huggingface_hub import InferenceClient
from pydantic import BaseModel
from typing import List

# Set your Hugging Face token
# export HF_TOKEN="your_token_here"

def analyze_paper_structured():
    """Complete example of structured output for research paper analysis."""
    
    # Initialize the client
    client = InferenceClient(
        provider="cerebras",  # or use "auto" for automatic selection
        api_key=os.environ["HF_TOKEN"],
    )
    
    # Example paper text (you can replace this with any research paper)
    paper_text = """
    Title: Attention Is All You Need
    
    Abstract: The dominant sequence transduction models are based on complex recurrent 
    or convolutional neural networks that include an encoder and a decoder. The best 
    performing models also connect the encoder and decoder through an attention mechanism. 
    We propose a new simple network architecture, the Transformer, based solely on 
    attention mechanisms, dispensing with recurrence and convolutions entirely. 
    Experiments on two machine translation tasks show these models to be superior 
    in quality while being more parallelizable and requiring significantly less time to train.
    
    Introduction: Recurrent neural networks, long short-term memory and gated recurrent 
    neural networks in particular, have been firmly established as state of the art approaches 
    in sequence modeling and transduction problems such as language modeling and machine translation.
    """
    
    # Define the response format (JSON Schema)
    class PaperAnalysis(BaseModel):
        title: str
        abstract_summary: str

    response_format = {
        "type": "json_schema",
        "json_schema": {
            "name": "PaperAnalysis",
            "schema": PaperAnalysis.model_json_schema(),
            "strict": True,
        },
    }
    
    # Define your messages
    messages = [
        {
            "role": "system", 
            "content": "Extract paper title and abstract summary."
        },
        {
            "role": "user", 
            "content": paper_text
        }
    ]
    
    # Generate structured output
    response = client.chat_completion(
        messages=messages,
        response_format=response_format,
        model="Qwen/Qwen3-32B",
    )
    
    # The response is guaranteed to match your schema
    structured_data = response.choices[0].message.content
    
    # Parse and display results
    analysis = json.loads(structured_data)
    
    print(f"Title: {analysis['title']}")
    print(f"Abstract Summary: {analysis['abstract_summary']}")

if __name__ == "__main__":
    # Make sure you have set your HF_TOKEN environment variable
    analyze_paper_structured()

OpenAI 클라이언트 버전:

import os
from openai import OpenAI
from pydantic import BaseModel, Field
from typing import List

# Set your Hugging Face token
# export HF_TOKEN="your_token_here"

class PaperAnalysis(BaseModel):
    """Structured model for research paper analysis."""
    title: str
    abstract_summary: str

def analyze_paper_structured():
    """Complete example of structured output for research paper analysis."""
    
    # Initialize the OpenAI client (works with Inference Providers)
    client = OpenAI(
        base_url="https://router.huggingface.co/cerebras/v1",
        api_key=os.environ["HF_TOKEN"]
    )
    
    # Example paper text (you can replace this with any research paper)
    paper_text = """
    Title: Attention Is All You Need
    
    Abstract: The dominant sequence transduction models are based on complex recurrent 
    or convolutional neural networks that include an encoder and a decoder. The best 
    performing models also connect the encoder and decoder through an attention mechanism. 
    We propose a new simple network architecture, the Transformer, based solely on 
    attention mechanisms, dispensing with recurrence and convolutions entirely. 
    Experiments on two machine translation tasks show these models to be superior 
    in quality while being more parallelizable and requiring significantly less time to train.
    
    Introduction: Recurrent neural networks, long short-term memory and gated recurrent 
    neural networks in particular, have been firmly established as state of the art approaches 
    in sequence modeling and transduction problems such as language modeling and machine translation.
    """
    
    # Define the response format (JSON Schema)
    # Generate structured output
    messages = [
        {
            "role": "system",
            "content": "Extract paper title and abstract summary.",
        },
        {
            "role": "user",
            "content": paper_text,
        },
    ]
    
    completion = client.beta.chat.completions.parse(
        model="qwen-3-32b",
        messages=messages,
        response_format=PaperAnalysis,
    )
    
    # Get the parsed response as a Python object
    analysis = completion.choices[0].message.parsed
    
    print(f"Title: {analysis.title}")
    print(f"Abstract Summary: {analysis.abstract_summary}")

다음 단계

구조화된 출력을 이해했으니, 이걸 쓰는 앱을 만들어 보고 싶을 거예요. 재미로 해볼 수 있는 아이디어들:

  • 다른 모델: 다양한 모델로 실험해 보세요. 구조화된 출력엔 가장 큰 모델이 항상 최선은 아니에요!
  • 다중 턴 대화: 대화 턴을 넘나들며 구조화된 형식을 유지하기
  • 복잡한 스키마: 사용 사례에 맞는 도메인 특화 스키마 만들기
  • 성능 최적화: 구조화된 출력에 맞는 제공자 선택하기

더 알아보기 (Learn more)

출처: 공식문서