본문으로 건너뛰기
구조화된 출력

구조화된 출력

답변을 JSON으로 요청하세요: 임의의 JSON 객체, 또는 보낸 스키마를 따르는 JSON. 사람이 아니라 프로그램이 응답을 읽을 때 사용하세요.

POST https://api.shannon-ai.com/v1/chat/completions

import json
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1")

response = client.chat.completions.create(
    model="Kimi-K3-3BIT-REAP",
    messages=[
        {"role": "user", "content": "Extract the person: John Doe, 30 years old, engineer."}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "age": {"type": "integer"},
                    "occupation": {"type": "string"},
                },
                "required": ["name", "age", "occupation"],
            },
        },
    },
)

# The JSON arrives as text in message.content: parse it, then check it.
try:
    person = json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
    person = None  # ask again, or report the failure

print(person)

JSON은 답변의 텍스트이며 choices[0].message.content에 있습니다.

200 JSON
{
  "id": "chatcmpl-0c4e7a1b9d2f4e6a8b3c5d7e9f1a2b3c",
  "object": "chat.completion",
  "created": 1791590400,
  "model": "Kimi-K3-3BIT-REAP",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "{\"name\":\"John Doe\",\"age\":30,\"occupation\":\"engineer\"}",
        "reasoning_content": null
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 96,
    "completion_tokens": 19,
    "total_tokens": 115,
    "prompt_tokens_details": {"cached_tokens": 0},
    "completion_tokens_details": {"reasoning_tokens": 0}
  }
}

response_format의 모드 종류와 설명

response_format은 /v1/chat/completions의 필드입니다. 없으면 답변은 일반 텍스트입니다.

모드 값 결과
JSON 객체 {"type": "json_object"} 답변은 정해진 형태가 없는 JSON입니다. 원하는 키는 프롬프트에서 알려 주세요.
JSON 스키마 {"type": "json_schema", "json_schema": {"name": "…", "schema": {…}}} 답변은 보낸 스키마의 키, 타입, 필수 필드를 따릅니다.
Strict "strict": true 세 번째 모드가 아니라 json_schema의 필드입니다. false를 보내지 않으면 true입니다.
필드 유형 기본값 설명 적용 대상
type string json_object 또는 json_schema입니다. response_format 안에서 필수입니다. text도 허용되며 일반 텍스트 답변을 줍니다. 해당 모드를 지원하는 모든 모델
json_schema.schema object 답변이 따르는 JSON Schema입니다. type이 json_schema일 때는 항상 보내세요. 해당 모드를 지원하는 모든 모델
json_schema.name string OpenAI 형식에서와 같은 스키마의 라벨입니다. 호스팅 오픈 웨이트 모델
json_schema.strict boolean true 답변이 스키마를 정확히 따라야 하는지 여부입니다. Shannon 모델은 모든 스키마를 strict로 적용합니다. 호스팅 오픈 웨이트 모델

JSON 객체 모드에는 스키마가 필요하지 않습니다. 키는 프롬프트에서 지정하세요.

요청 본문
{
  "model": "shannon-3",
  "messages": [
    {
      "role": "user",
      "content": "Name the capital of France. Answer as JSON with the keys city and country."
    }
  ],
  "response_format": {"type": "json_object"}
}

모델별 지원

모델 json_object json_schema
모든 Shannon 모델(shannon-*) 예 예
아래에 이름이 나온 모델을 제외한 호스팅 오픈 웨이트 모델 예 예
Laguna-S-2.1-W4A16-AUTOROUND-REAP — —
inkling-W4A16-AUTOROUND-REAP 예 —

GET /v1/models는 id마다 같은 정보를 보고합니다. 모든 모델에 capabilities.json_schema가, 호스팅 오픈 웨이트 모델에 capabilities.response_format이 있습니다. 모델 및 가격

지원하는 스키마 키워드

모델이 스키마에서 받는 내용은 모델과 엔드포인트에 따라 다릅니다.

모델 /v1/chat/completions /v1/responses
Shannon 모델 아래의 키워드 부분집합이며 strict로 적용됩니다. 보낸 그대로의 스키마이며 strict로 적용됩니다.
호스팅 오픈 웨이트 모델 보낸 그대로의 스키마입니다. strict를 보내지 않으면 true입니다. 보낸 그대로의 스키마입니다. strict를 보내지 않으면 true입니다.

/v1/chat/completions에서 Shannon 모델의 키워드 부분집합입니다.

키워드 처리 방식
읽는 키워드 type, format, title, description, nullable, enum, items, properties, required, minItems, maxItems, minimum, maximum, minLength, maxLength, pattern, anyOf, default
$ref 스키마 최상위의 $defs 또는 definitions에서 해석됩니다. description처럼 $ref 옆에 쓴 키워드는 유지됩니다. 일치하는 정의가 없는 참조는 {"type": "object"}로 처리됩니다.
allOf 멤버들이 하나의 스키마로 병합됩니다. 두 멤버가 같은 키워드를 설정하면 나중 것이 적용됩니다.
oneOf anyOf로 처리됩니다.
자기 자신을 참조하는 스키마 24단계까지 펼쳐집니다. 그보다 깊은 단계는 {"type": "object"}로 처리됩니다.
부분집합 밖 그 밖의 모든 키워드입니다. 예를 들어 additionalProperties, const, multipleOf, uniqueItems, exclusiveMinimum, exclusiveMaximum, patternProperties, prefixItems, minProperties, maxProperties, not, if / then / else가 있습니다. 이들은 모델이 받는 스키마에 포함되지 않습니다.

/v1/responses에서 구조화된 출력을 요청하는 text.format

/v1/responses는 같은 요청을 text.format으로 표기합니다. 스키마는 json_schema 키 아래가 아니라 name, strict와 나란히 format에 직접 들어갑니다. JSON 객체 모드에는 {"format": {"type": "json_object"}}를 보내세요.

요청 본문
{
  "model": "Kimi-K3-3BIT-REAP",
  "input": "Extract the person: John Doe, 30 years old, engineer.",
  "text": {
    "format": {
      "type": "json_schema",
      "name": "person",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "name": {"type": "string"},
          "age": {"type": "integer"},
          "occupation": {"type": "string"}
        },
        "required": ["name", "age", "occupation"]
      }
    }
  }
}

JSON은 message 항목의 output_text 파트에 있는 text입니다.

200 JSON
{
  "output": [
    {
      "id": "msg_7e1d3c5b9a2f4d6e8c0b1a3f5e7d9c2b",
      "type": "message",
      "role": "assistant",
      "status": "completed",
      "content": [
        {
          "type": "output_text",
          "text": "{\"name\":\"John Doe\",\"age\":30,\"occupation\":\"engineer\"}",
          "annotations": []
        }
      ]
    }
  ]
}

모델별 지원과 오류는 /v1/chat/completions와 같습니다. Responses API

/v1/messages에서: 스키마로서의 도구

Messages 형식에는 구조화된 출력 필드가 없습니다. 같은 모델에서 JSON을 받으려면 같은 키로 /v1/chat/completions 또는 /v1/responses를 호출하세요.

/v1/messages에 머물려면 객체를 도구로 설명하세요. 스키마를 input_schema에 넣고 tool_choice에 도구 이름을 지정합니다. 그러면 tool_use 블록의 input이 이미 파싱된 객체입니다. 이름을 지정한 tool_choice는 호스팅 오픈 웨이트 모델이 적용합니다.

요청 본문
{
  "model": "Kimi-K3-3BIT-REAP",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": "Extract the person: John Doe, 30 years old, engineer."
    }
  ],
  "tools": [
    {
      "name": "record_person",
      "description": "Record the extracted person.",
      "input_schema": {
        "type": "object",
        "properties": {
          "name": {"type": "string"},
          "age": {"type": "integer"},
          "occupation": {"type": "string"}
        },
        "required": ["name", "age", "occupation"]
      }
    }
  ],
  "tool_choice": {"type": "tool", "name": "record_person"}
}
200 JSON
{
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_4b8d2f6a1c3e4a5b9d7f0e2c4a6b8d1f",
      "name": "record_person",
      "input": {"name": "John Doe", "age": 30, "occupation": "engineer"}
    }
  ]
}

블록을 읽기 전에 stop_reason이 tool_use인지 확인하세요. 함수 호출

JSON이 도착하는 방식

  • JSON은 문자열입니다. 응답에는 파싱된 객체가 따로 없으므로 message.content에 JSON 파서를 실행하세요.
  • stream: true이면 JSON이 delta.content 조각으로 도착합니다. 스트림이 끝난 뒤 이어 붙여 한 번에 파싱하세요. 조각 하나만으로는 유효한 JSON이 아닙니다.
  • 호스팅 오픈 웨이트 모델은 response_format 요청에 추론 텍스트 없이 답변합니다. reasoning_content는 null입니다.

받은 내용 검증

스키마는 모델이 작성하는 방식을 안내합니다. API는 완성된 답변을 스키마와 대조하지 않으므로 최종 검사는 코드에서 해야 합니다.

  • 맨 위의 샘플처럼 오류 핸들러 안에서 파싱하세요.
  • 파싱된 객체를 코드에서 같은 스키마로 검증하세요. 예를 들어 JSON Schema 라이브러리, Pydantic, Zod를 사용할 수 있습니다.
  • 긴 답변은 JSON이 완성되기 전에 끝날 수 있습니다. 스트리밍이 아닌 응답은 finish_reason을 stop 또는 tool_calls로만 보고하므로 파싱 오류가 신호입니다. 다시 요청하거나 더 작은 객체를 요청하세요.

오류

상태 유형 메시지 시점
400 invalid_request_error <id> does not accept response_format 모델이 두 모드 모두 지원하지 않습니다.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object 모델은 json_object를 지원하는데 json_schema를 보냈습니다.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … response_format에 type이 없거나 JSON 객체가 아닙니다.

두 400 응답은 잔액에서 아무것도 차감되기 전에 전송됩니다. 오류 처리