메인 콘텐츠로 건너뛰기
구조화된 출력은 모델이 사용자가 정의한 스키마에 맞는 JSON 객체를 반환하도록 강제합니다. 이를 통해 비정형 모델 출력을 파싱, 검증 또는 재시도할 필요가 없어집니다. ARouter는 두 가지 구조화된 출력 모드를 지원합니다:
모드설명
json_object유효한 JSON을 보장하지만 스키마는 강제하지 않음
json_schema정확한 스키마에 맞는 JSON을 보장

구조화된 출력 사용

요청 본문에 response_format을 전달하세요:

JSON Object 모드

{
  "model": "openai/gpt-5.4",
  "messages": [
    {
      "role": "user",
      "content": "Return information about the planet Mars as JSON"
    }
  ],
  "response_format": { "type": "json_object" }
}
모델은 유효한 JSON을 반환하지만 스키마는 강제되지 않습니다:
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "{\"name\":\"Mars\",\"diameter_km\":6779,\"moons\":2,\"habitable\":false}"
      }
    }
  ]
}

JSON Schema 모드

엄격한 스키마를 강제하려면 json_schema를 사용하세요:
{
  "model": "openai/gpt-5.4",
  "messages": [
    {
      "role": "system",
      "content": "You are a data extraction assistant."
    },
    {
      "role": "user",
      "content": "Extract the planet information: Mars is a terrestrial planet with 2 moons and a diameter of 6779 km."
    }
  ],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "planet_info",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "diameter_km": { "type": "number" },
          "moons": { "type": "integer" },
          "habitable": { "type": "boolean" }
        },
        "required": ["name", "diameter_km", "moons", "habitable"],
        "additionalProperties": false
      }
    }
  }
}
응답:
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "{\"name\":\"Mars\",\"diameter_km\":6779,\"moons\":2,\"habitable\":false}"
      },
      "finish_reason": "stop"
    }
  ]
}

전체 예제

import json
from openai import OpenAI
from pydantic import BaseModel

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

# Pydantic을 사용하여 스키마 정의
class PlanetInfo(BaseModel):
    name: str
    diameter_km: float
    moons: int
    habitable: bool

# OpenAI의 parse() 메서드 사용(권장)
response = client.beta.chat.completions.parse(
    model="openai/gpt-5.4",
    messages=[
        {"role": "system", "content": "You are a data extraction assistant."},
        {"role": "user", "content": "Tell me about Mars."},
    ],
    response_format=PlanetInfo,
)

planet = response.choices[0].message.parsed
print(planet.name)        # "Mars"
print(planet.moons)       # 2
print(planet.diameter_km) # 6779.0

# 또는 response_format dict를 수동으로 사용
response = client.chat.completions.create(
    model="openai/gpt-5.4",
    messages=[
        {"role": "user", "content": "Tell me about Mars as JSON."},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "planet_info",
            "strict": True,
            "schema": PlanetInfo.model_json_schema(),
        },
    },
)
data = json.loads(response.choices[0].message.content)
planet = PlanetInfo(**data)

모델 지원

strict: truejson_schema 모드를 지원하는 모델:
  • openai/gpt-5.4, openai/gpt-5.4-pro, openai/o3, openai/o4-mini
  • anthropic/claude-sonnet-4.6, anthropic/claude-opus-4.5
  • google/gemini-2.5-flash, google/gemini-2.5-pro
json_object 모드(스키마 강제 없음)는 더 광범위하게 지원됩니다. 최신 기능 정보는 GET /v1/models를 확인하세요.

구조화된 출력과 스트리밍

구조화된 출력은 스트리밍을 지원합니다. JSON 콘텐츠는 점진적으로 전달되며 클라이언트 측에서 조합합니다:
const stream = await client.chat.completions.create({
  model: "openai/gpt-5.4",
  messages: [{ role: "user", content: "Tell me about Mars." }],
  response_format: {
    type: "json_schema",
    json_schema: {
      name: "planet_info",
      strict: true,
      schema: { /* ... */ },
    },
  },
  stream: true,
});

let jsonBuffer = "";
for await (const chunk of stream) {
  const content = chunk.choices[0]?.delta?.content;
  if (content) jsonBuffer += content;
}

const data = JSON.parse(jsonBuffer);

모범 사례

  1. strict: true 사용 — 이것이 스키마 준수를 보장합니다. 사용하지 않으면 모델이 스키마에 정확히 맞지 않는 유효한 JSON을 반환할 수 있습니다.
  2. additionalProperties: false 설정 — 엄격 모드에 필수입니다. 모델이 추가 키를 추가하는 것을 방지합니다.
  3. 모든 필수 필드를 명시적으로 나열 — 엄격 모드에서 properties의 모든 필드를 required에도 포함해야 합니다.
  4. 시스템 프롬프트 포함 — 모델에게 데이터 추출 또는 구조화된 출력 어시스턴트로서의 역할을 알려주면 신뢰성이 향상됩니다.

오류 처리

모델이 스키마와 일치하는 유효한 JSON을 생성할 수 없는 경우(예: 프롬프트가 스키마와 근본적으로 충돌하는 경우), 응답의 finish_reason"length" 또는 "content_filter"가 됩니다. 콘텐츠를 파싱하기 전에 항상 finish_reason을 확인하세요.
response = client.chat.completions.create(...)

choice = response.choices[0]
if choice.finish_reason != "stop":
    raise ValueError(f"Unexpected finish reason: {choice.finish_reason}")

data = json.loads(choice.message.content)