구조화 출력

JSON 스키마로 응답 형식을 고정한다

response_format 을 쓰면 자유 형식 텍스트 대신, 여러분이 정의한 스키마에 맞는 JSON 을 모델이 돌려주게 할 수 있습니다. 응답을 코드에서 파싱한다면 항상 쓸 가치가 있습니다 — "마크다운으로 감싸서 왔다", "필드 하나를 멋대로 만들어냈다" 같은 오류를 통째로 없애줍니다.

사용법

typejson_schema 로 설정하고 스키마에 name 을 붙입니다.

json
{
  "model": "google/gemma-4-26b-a4b",
  "messages": [
    { "role": "user", "content": "도시와 기온을 추출해줘: 오늘 부산은 21도야." }
  ],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "weather",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "city": { "type": "string" },
          "temperature_c": { "type": "number" }
        },
        "required": ["city", "temperature_c"],
        "additionalProperties": false
      }
    }
  }
}

응답의 message.content 는 스키마에 맞는 JSON 문자열입니다.

json
{ "city": "Busan", "temperature_c": 21 }

여전히 문자열이므로 직접 JSON.parse 해야 합니다. 우리가 대신 디코딩해주지 않는 이유는, 그렇게 하면 모델이 잘못된 JSON 을 만들었을 때 그 사실이 조용히 묻히기 때문입니다.

모델 지원 여부

우리 카탈로그의 두 모델 모두 supported_parametersresponse_format 을 포함합니다.

bash
curl -s "https://openrouter.myip.co.kr/api/v1/models" | jq '.data[] | {id, supported_parameters}'

supported_parameters 에 없는 모델에 response_format 을 보내는 것 자체를 우리가 막지는 않습니다 — 그 필드를 지킬지, 무시할지, 오류를 낼지는 서빙 엔진이 정합니다. 지원하지 않는 후보를 조용히 평문으로 응답시키는 대신 체인에서 아예 빼고 싶다면 provider.require_parameters: true 를 쓰세요(Provider 라우팅).

스트리밍

response_formatstream: true 와도 그대로 동작합니다. 모델이 JSON 텍스트를 토큰 단위로 delta.content 에 스트리밍하므로, 델타를 이어 붙였다가 finish_reason 이 오면 일반 텍스트 스트리밍과 똑같이 한 번에 파싱하세요. 스트리밍 을 보세요.

typescript
let json = '';
for await (const chunk of stream) {
  json += chunk.choices[0]?.delta?.content ?? '';
}
const data = JSON.parse(json);

청크마다 아직 다 안 온 버퍼를 JSON.parse 하려 하지 마세요 — 스트림이 끝나기 전까지는 유효한 JSON 이 아닙니다.

전체 예제

curl https://openrouter.myip.co.kr/api/v1/chat/completions \
  -H "Authorization: Bearer $MYIP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-26b-a4b",
    "messages": [
      {"role": "user", "content": "도시와 기온을 추출해줘: 오늘 부산은 21도야."}
    ],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "weather",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "city": {"type": "string"},
            "temperature_c": {"type": "number"}
          },
          "required": ["city", "temperature_c"],
          "additionalProperties": false
        }
      }
    }
  }'

잘 쓰는 법

  1. 스키마 안에 설명을 적으세요. 속성에 "description": "ISO 4217 통화 코드" 를 붙이면 필드 이름만 있을 때보다 모델을 더 잘 이끕니다.
  2. 호출하는 엔진이 지원한다면 strict: true 를 쓰세요. 다만 그 모델로 직접 검증하기 전까지는 "항상 지켜진다"가 아니라 "대체로 지켜진다"로 취급하세요.
  3. 가능하면 스키마를 평평하게 유지하세요. 깊은 중첩이나 oneOf, $ref 같은 드문 JSON Schema 기능은 엔진의 strict 모드가 부분적으로만 지원할 가능성이 높습니다.
  4. 그래도 검증하세요. 문자열을 파싱한 뒤, 신뢰하기 전에 여러분의 코드에서(ajv, zod 등으로) 스키마와 대조해 검증하세요. response_format 은 형식이 어긋난 출력을 줄여줄 뿐, 그것을 처리할 필요를 없애주지는 않습니다.

오류

상황결과
모델이 response_format 을 지원하지 않음엔진마다 다릅니다 — 대개 그 필드를 무시하고 오류 없이 평문을 돌려줍니다
json_schema 가 유효한 JSON Schema 가 아님업스트림 호출이 실패하고 502 provider_error 로 드러나며, 업스트림 메시지가 metadata 에 실립니다
strict: true 인데도 스키마와 맞지 않는 텍스트가 옴우리가 잡아내지 않습니다 — 파싱한 객체를 직접 검증하세요

일반적인 오류 형식은 오류와 디버깅 을 보세요.

마지막 수정 2026. 9. 5.