메인 콘텐츠로 건너뛰기

기능 개요

구조화된 출력(Structured Outputs)은 모델의 응답이 사용자가 정의한 JSON Schema를 엄격하게 준수하도록 하여, 반환값을 정규식이나 후처리 없이 프로그램에서 직접 파싱할 수 있도록 합니다. 프롬프트에서 모델에게 “JSON으로 반환해 주세요”라고 요청하는 것과 달리, 구조화된 출력은 **제약 디코딩(Constrained Decoding)**에 기반합니다. 업스트림에서 JSON Schema를 문법 규칙으로 컴파일하여 추론 과정에서 토큰 단위로 생성을 제약하므로, 모델이 Schema를 위반하는 출력을 생성하는 것은 불가능합니다. 대표적인 활용 시나리오:
  • 비정형 텍스트에서 엔티티 및 필드 추출
  • 분류 / 레이블링 / 감성 분석
  • 다단계 추론 중간 결과의 표준화된 전달
  • Agent 도구 호출 파라미터의 강타입 제약

각 프로토콜 파라미터 비교

세 가지 프로토콜의 파라미터 이름은 다르지만 기본 메커니즘은 동일합니다. 모델 출력이 제공된 JSON Schema와 엄격하게 일치합니다.
프로토콜파라미터지원 모델
OpenAI Chat /v1/chat/completionsresponse_format.type: "json_schema"Claude 4.5+, GPT-4o / GPT-5 시리즈, Gemini 시리즈
Anthropic Messages /v1/messagesoutput_config.format.type: "json_schema"Claude 4.5+ (직접 연결 / Vertex); Bedrock은 4.5-4.6만 지원
OpenAI Responses /v1/responsestext.format.type: "json_schema"업스트림 모델 능력에 따름

AWS Bedrock 제한 사항

AWS Bedrock에서 Claude 4.7 이상 버전은 Mantle 추론 경로를 사용하며, 해당 경로는 현재 output_config.format을 지원하지 않습니다. 게이트웨이는 이러한 모델에 대해 자동으로 format 필드를 제거하고 응답 헤더에 디그레이드를 표시합니다(아래 디그레이드 메커니즘 참조). 이로 인해 요청이 오류를 반환하지는 않습니다.

빠른 시작

OpenAI 프로토콜 (권장)

구조화된 출력을 지원하는 모든 모델에 적용되며, 벤더 간 공통으로 사용할 수 있습니다.
from openai import OpenAI

client = OpenAI(
    api_key="<AIHUBMIX_API_KEY>",
    base_url="https://aihubmix.com/v1",
)

response = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[
        {"role": "user", "content": "다음 정보를 추출하세요: 김철수, 28세, 서울특별시 강남구"}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person_info",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "age": {"type": "integer"},
                    "city": {"type": "string"}
                },
                "required": ["name", "age", "city"],
                "additionalProperties": False
            }
        }
    }
)

import json
data = json.loads(response.choices[0].message.content)
print(data)
# {"name": "김철수", "age": 28, "city": "서울특별시 강남구"}

다른 모델 사용 (GLM-5.2 예시)

동일한 OpenAI 프로토콜 파라미터가 구조화된 출력을 지원하는 모든 모델에 적용되며, model만 변경하면 됩니다.
Python
from openai import OpenAI

client = OpenAI(
    api_key="<AIHUBMIX_API_KEY>",
    base_url="https://aihubmix.com/v1",
)

response = client.chat.completions.create(
    model="glm-5.2",
    messages=[
        {"role": "user", "content": "다음 정보를 추출하세요: 김철수, 28세, 서울특별시 강남구"}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person_info",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "age": {"type": "integer"},
                    "city": {"type": "string"}
                },
                "required": ["name", "age", "city"],
                "additionalProperties": False
            }
        }
    }
)

import json
data = json.loads(response.choices[0].message.content)
print(data)
# {"name": "김철수", "age": 28, "city": "서울특별시 강남구"}

Claude 네이티브 프로토콜

Anthropic SDK를 사용하여 직접 호출하며, 파라미터는 output_config.format입니다.
import anthropic

client = anthropic.Anthropic(
    api_key="<AIHUBMIX_API_KEY>",
    base_url="https://aihubmix.com",
)

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "다음 정보를 추출하세요: 김철수, 28세, 서울특별시 강남구"}
    ],
    output_config={
        "format": {
            "type": "json_schema",
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "age": {"type": "integer"},
                    "city": {"type": "string"}
                },
                "required": ["name", "age", "city"],
                "additionalProperties": False
            }
        }
    }
)

import json
data = json.loads(response.content[0].text)
print(data)

Schema 작성 요점

필수 필드

모든 object 타입은 additionalProperties: false를 명시적으로 선언해야 합니다. 그렇지 않으면 일부 업스트림에서 요청을 거부합니다.
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "score": { "type": "number" }
  },
  "required": ["name", "score"],
  "additionalProperties": false
}

중첩 객체

중첩된 object에도 마찬가지로 additionalProperties: false가 필요합니다:
{
  "type": "object",
  "properties": {
    "user": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "email": { "type": "string" }
      },
      "required": ["name", "email"],
      "additionalProperties": false
    }
  },
  "required": ["user"],
  "additionalProperties": false
}

크로스 프로토콜 Schema 차이

특성OpenAI 프로토콜Anthropic 프로토콜
name 필드필수미지원 (게이트웨이가 크로스 프로토콜 호출 시 자동 처리)
strict 필드선택 사항, true 권장미지원
숫자 제약 (minimum, maximum 등)지원미지원 (게이트웨이가 자동 정리, 요청에 영향 없음)
문자열 제약 (minLength, maxLength)지원미지원 (게이트웨이가 자동 정리)
OpenAI 프로토콜로 Claude 모델을 호출할 때, 게이트웨이가 Schema 형식을 자동 변환하고 호환되지 않는 키워드를 정리하므로 수동 조정이 필요하지 않습니다.

자동 디그레이드 메커니즘

게이트웨이는 기본적으로 모든 요청에 대해 구조화된 출력의 자동 디그레이드 보호를 활성화합니다. 모델이나 플랫폼에서 지원하지 않을 경우, 게이트웨이는 오류를 반환하지 않고 Schema 제약을 자동으로 제거한 후 응답 헤더에 디그레이드 사유를 표시합니다. 요청은 여전히 정상적인 모델 응답을 받으며, 다만 출력이 Schema에 의해 강제 제약되지 않을 뿐입니다. 이는 클라이언트에서 각 모델별 호환성 판단 없이 안심하고 구조화된 출력을 일괄 활성화할 수 있음을 의미합니다:
  • 멀티 모델 전환 걱정 없음: 동일한 코드로 Claude, GPT, Gemini, GLM 간에 모델을 전환할 때, 대상 모델이 구조화된 출력을 지원하지 않더라도 요청이 오류를 발생시키지 않습니다
  • Fallback 라우팅 투명성: 기본 채널이 사용 불가하여 Fallback 라우팅이 백업 채널로 트리거될 때, 백업 채널의 모델 버전이 구조화된 출력을 지원하지 않더라도 요청이 정상적으로 완료됩니다
  • 클라이언트 로직 간소화: “어떤 모델이 구조화된 출력을 지원하는지” 목록을 유지할 필요가 없으며, 게이트웨이가 자동으로 처리합니다. 클라이언트는 응답 헤더만 확인하여 추가 파싱이 필요한지 결정하면 됩니다

응답 헤더

X-Structured-Output-Degraded: <reason>
reason의미
model_unsupported해당 모델(또는 현재 플랫폼에서의 해당 모델)이 구조화된 출력을 지원하지 않습니다
json_object_unsupported_on_anthropicjson_object 모드를 Anthropic 형식으로 변환할 수 없습니다
json_schema_missing_schemajson_schema 타입을 지정했지만 schema 필드가 누락되었습니다
schema_keywords_strippedSchema의 일부 제약 키워드가 정리되었습니다 (예: minimum, maxLength)

감지 예시

Python
import httpx

response = httpx.post(
    "https://aihubmix.com/v1/chat/completions",
    headers={
        "Authorization": "Bearer <AIHUBMIX_API_KEY>",
        "Content-Type": "application/json",
    },
    json={
        "model": "claude-sonnet-5",
        "messages": [{"role": "user", "content": "정보를 추출하세요: 김철수, 28세"}],
        "response_format": {
            "type": "json_schema",
            "json_schema": {
                "name": "person",
                "strict": True,
                "schema": {
                    "type": "object",
                    "properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
                    "required": ["name", "age"],
                    "additionalProperties": False,
                }
            }
        }
    }
)

# 디그레이드 발생 여부 확인 (예: 요청이 미지원 Bedrock 채널로 라우팅된 경우)
degraded = response.headers.get("X-Structured-Output-Degraded")
if degraded:
    print(f"구조화된 출력이 디그레이드되었습니다: {degraded}")
    # 이 경우 모델 응답은 정상이지만 출력이 Schema에 의해 강제 제약되지 않습니다
else:
    import json
    data = json.loads(response.json()["choices"][0]["message"]["content"])
    print(data)  # {"name": "김철수", "age": 28}

json_object 모드와의 차이

json_schema (구조화된 출력)json_object
출력 보장지정된 Schema와 엄격하게 일치유효한 JSON임만 보장
필드 제어필드명, 타입, 필수 여부 모두 제약제약 없음
적용 프로토콜OpenAI / Anthropic / ResponsesOpenAI 호환 프로토콜만
Claude 지원output_config.format을 통해 지원미지원
json_object 모드는 Claude 네이티브 프로토콜로의 변환을 지원하지 않습니다. OpenAI 프로토콜을 통해 Claude에 response_format: {"type": "json_object"}를 전송하면, 응답 헤더에 json_object_unsupported_on_anthropic 디그레이드가 표시됩니다. json_schema 타입을 직접 사용하는 것을 권장합니다.

자주 묻는 질문

Claude 시리즈 (Anthropic API의 output_config.format을 통해):
  • Opus / Sonnet / Haiku 4.5 이상 버전
  • Fable / Mythos 5 이상 버전
  • Bedrock 플랫폼은 4.5-4.6만 지원; Vertex AI는 직접 연결과 동일
OpenAI 시리즈 (response_format을 통해):
  • GPT-4o 이상, GPT-5 시리즈
Gemini 시리즈 (responseSchema를 통해):
  • Gemini 2.5 이상
모델 목록 페이지에서 각 모델의 기능 태그를 확인할 수 있습니다.
AWS Bedrock에서 Claude 4.7+는 새로운 Mantle 추론 경로를 사용하며, 해당 경로는 현재 output_config.format 파라미터를 허용하지 않습니다. 게이트웨이가 자동으로 처리합니다: format을 제거하고 정상적으로 응답을 반환하며, 동시에 디그레이드 헤더 X-Structured-Output-Degraded: model_unsupported를 표시합니다. Claude 4.5-4.6은 Bedrock에서 완전히 지원됩니다.
네. OpenAI 프로토콜로 Claude 모델을 호출할 때, 게이트웨이가 자동으로:
  1. response_formatoutput_config.format으로 변환합니다
  2. Anthropic에서 지원하지 않는 Schema 키워드(minimum, maxLength 등)를 제거합니다
  3. 키워드가 정리된 경우 응답 헤더에 schema_keywords_stripped를 표시합니다
역방향(Claude 프로토콜로 OpenAI 모델 호출)도 마찬가지로 자동 변환됩니다.
네. output_configformat(구조화된 출력)과 reasoningeffort(사고 강도)는 독립적인 파라미터이므로 동시에 설정할 수 있습니다:
{
  "output_config": {
    "format": {
      "type": "json_schema",
      "schema": { ... }
    }
  },
  "reasoning": {
    "effort": "high"
  }
}
대부분의 API 통합 플랫폼은 모델이 구조화된 출력을 지원하지 않을 때 오류를 직접 반환합니다. AIHubMix는 그레이스풀 디그레이드 전략을 채택합니다: 호환되지 않는 파라미터를 자동으로 제거하고, 정상적으로 모델 응답을 반환하며, X-Structured-Output-Degraded 응답 헤더를 통해 클라이언트에 디그레이드 사유를 알립니다. 이로 인해 애플리케이션이 중단되지 않습니다.