Qwen 구조화 출력: JSON Schema로 출력 형태 고정하기

Qwen 구조화 출력: JSON Schema로 출력 형태 고정하기

정보 추출이나 구조화 데이터 생성에서 모델이 ```json 래퍼 같은 부가 텍스트를 섞으면 파싱이 깨져요. 구조화 출력을 켜면 모델이 항상 유효한 JSON 문자열을 반환하고, JSON Schema 모드는 출력 구조와 타입까지 정밀하게 고정해서 별도 검증·재시도 없이 쓸 수 있게 해줍니다. 이 문서는 두 모드의 차이와 응답 형식 설정을 안내해요.

출처: QwenCloud 공식 문서 - Structured output

두 가지 모드

기능 JSON Object 모드 JSON Schema 모드
유효한 JSON 출력 Yes Yes
스키마를 엄격히 따름 No Yes
지원 모델 대부분의 Qwen, Kimi, GLM, DeepSeek 일부 모델만
response_format 설정 {"type": "json_object"} {"type": "json_schema", "json_schema": {…, "strict": true}}
프롬프트 요구사항 반드시 "JSON" 포함 명시적으로 기술 권장
사용 사례 유연한 JSON 출력 정밀한 스키마 검증

JSON Object 모드는 유효한 JSON 문자열을 보장하지만 특정 구조까지는 보장하지 않아요. 쓰는 방법은 두 가지 조건을 지키면 되죠.

  1. 요청 본문의 response_format{"type": "json_object"}로 설정
  2. system 또는 user 메시지에 "JSON"이라는 단어(대소문자 무관)를 포함

"JSON" 단어가 없으면 API가 이렇게 거부해요: 'messages' must contain the word 'json' in some form, to use 'response_format' of type 'json_object'.

JSON Schema 모드는 지정한 구조를 따르는 출력을 보장해요. response_format{"type": "json_schema", "json_schema": {…, "strict": true}}로 설정하세요. 이 모드에서는 프롬프트에 "JSON" 키워드가 필요 없습니다.

지원 모델 요약

JSON Object는 대부분의 Qwen 텍스트 생성 모델(Qwen3.8/3.7/3.6/3.5 계열, Qwen-Turbo(비-thinking) 등), Qwen-Coder 계열, Qwen-Long 계열, Qwen3.8 오픈소스 계열, 그리고 kimi-k3, kimi-k2-thinking, glm-5.1, deepseek-v4-pro-0813 같은 서드파티 모델에서 지원돼요.

⚠️ "비-thinking 모드"로 분류된 모델은 thinking 모드에서 response_format{"type": "json_object"}로 설정해도 오류는 나지 않지만, 구조화 출력이 효과를 발휘하지 않을 수 있어요. 이런 모델에서 확실히 유효한 JSON을 얻으려면 FAQ의 2단계 보정법을 쓰세요.

JSON Schema는 Qwen3.8-Max 계열, Qwen3.8-Flash 계열, Qwen3.7-Max 계열, Qwen3.7-Plus 계열, Qwen3.7-Flash 계열에서 지원돼요.

시작하기 (JSON Object 모드)

프로필에서 이름과 나이를 추출하는 예시예요. response_format={"type": "json_object"}만 추가하면 됩니다.

from openai import OpenAI
import os

client = OpenAI(
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)

completion = client.chat.completions.create(
  model="qwen3.8-max",
  messages=[
    {"role": "system", "content": "Extract the user's name and age, and return them in JSON format"},
    {"role": "user", "content": "Hi everyone, my name is Alex Brown, I'm 34 years old, my email is [email protected]"},
  ],
  response_format={"type": "json_object"},
)
print(completion.choices[0].message.content)

응답은 이렇게 옵니다.

{
  "name": "Alex Brown",
  "age": 34
}

JSON Object 모드는 키 이름이나 필드 타입을 안정적으로 보장하지 않기 때문에 프롬프트·호출에 따라 결과가 달라질 수 있어요. 구조를 반드시 고정해야 하면 JSON Schema 모드를 쓰세요.

thinking 모드에서 구조화 출력 얻기 (2단계 보정)

"비-thinking 모드" 라벨이 붙은 모델은 thinking이 켜지면 엄밀히 유효한 JSON이 아닌 내용을 반환할 수 있어요. 이때는 두 단계로 접근합니다.

  • 1단계: thinking 모드로 고품질 출력을 얻기. 이 예시는 response_format을 의도적으로 생략한 폴백인데, stream=True가 필수예요. 청크의 delta.content를 누적해 json_string을 만듭니다.
  • 2단계: json.loads(json_string)로 파싱을 시도해 유효하면 그대로 쓰고, 실패하면 구조화 출력을 지원하는 저비용 모델(예: 비-thinking의 qwen-flashenable_thinking: False)로 response_format={"type": "json_object"}을 걸어 고쳐달라고 합니다.

더 알아보기