Skip to main content
Models

Structured output

Make the model return valid JSON, and use JSON Schema to constrain the output structure precisely

When performing information extraction or structured data generation, a model may return extra text (such as a ```json wrapper) that breaks downstream parsing. Enabling structured output ensures the model returns a valid JSON string. JSON Schema mode goes further and gives you precise control over the output structure and types, eliminating extra validation or retries.

Two modes

FeatureJSON Object modeJSON Schema mode
Outputs valid JSONYesYes
Strictly follows schemaNoYes
Supported modelsMost Qwen models, Kimi, GLM, DeepSeekSelected models only
response_format setting{"type": "json_object"}{"type": "json_schema", "json_schema": {..., "strict": true}}
Prompt requirementMust include "JSON"Recommended to describe explicitly
Use caseFlexible JSON outputPrecise schema validation
JSON Object mode ensures the output is a valid JSON string, but does not guarantee a specific structure. To use it:
  1. Set response_format in the request body to {"type": "json_object"}.
  2. Include the word "JSON" (case-insensitive) in the system message or user message. Otherwise the API returns: 'messages' must contain the word 'json' in some form, to use 'response_format' of type 'json_object'.
JSON Schema mode ensures the output conforms to a specified structure. Set response_format to {"type": "json_schema", "json_schema": {..., "strict": true}}.
The parameters above apply to the Chat Completions API. If you use the Responses API, set text.format instead; the value format is the same. See the examples below. In JSON Object mode, the Responses API also requires the prompt to contain the word "JSON"; otherwise, a 400 error is returned.
JSON Schema mode does not require the "JSON" keyword in the prompt.

Supported models

JSON Object

Qwen

Text generation models
  • Qwen-Max: Qwen4.0-Max (Token Plan only), Qwen3.8-Max series, Qwen3.7-Max series
  • Qwen-Max (non-thinking mode): Qwen3.6-Max series, Qwen3-Max series, Qwen-Max series
  • Qwen-Plus: Qwen3.7-Plus series
  • Qwen-Plus (non-thinking mode): Qwen3.6-Plus series, Qwen3.5-Plus series, Qwen-Plus series
  • Qwen-Flash: Qwen3.8-Flash series, Qwen3.7-Flash series
  • Qwen-Flash (non-thinking mode): Qwen3.6-Flash series, Qwen3.5-Flash series, Qwen-Flash series
  • Qwen-Coder: Qwen3-Coder series
  • Qwen-Long: Qwen-Long series
  • Qwen3.8 open-source series
  • Open-source series (non-thinking mode): Qwen3.6 open-source series, Qwen3.5 open-source series, Qwen3 open-source series
  • Open-source series: Qwen3.8 open-source series (qwen3.8-2.4t-a95b), Qwen3-Coder open-source series, Qwen2.5 open-source series (excluding math and coder models)
Multimodal models (non-thinking mode)
  • Qwen-VL: Qwen3-VL-Plus series
  • Qwen-Omni: Qwen3.8-Omni-Flash, Qwen3.5-Omni-Plus series
  • Open-source series: Qwen3-VL open-source series

Kimi

  • kimi-k3.1-pro
  • kimi-k3

GLM

  • glm-5.1
  • Non-thinking mode: glm-5 (China North 2 (Beijing) only)

DeepSeek

  • deepseek-v4.1-flash, deepseek-v4.1-flash-1017, deepseek-v4-pro-0813, deepseek-v4-pro, deepseek-v4-flash-0731
Models labeled "non-thinking mode" support structured output only in non-thinking mode.

JSON Schema

Qwen4.0-Max (Token Plan only), Qwen3.8-Max series, Qwen3.8-Flash series, Qwen3.7-Max series, Qwen3.7-Plus series, and Qwen3.7-Flash series, as well as DeepSeek: deepseek-v4.1-flash, deepseek-v4.1-flash-1017, and deepseek-v4-pro. More models are coming soon.

Getting started

This example extracts structured information from a personal profile using JSON Object mode.
JSON Object mode does not guarantee stable key names or field types. Results may vary across different prompts or calls. To enforce a fixed structure, use JSON Schema mode.
Before calling, obtain an API key and export it as an environment variable. To call through the OpenAI SDK or DashScope SDK, install the SDK first.
  • OpenAI compatible
  • OpenAI compatible - Responses
  • DashScope
from openai import OpenAI
import os

client = OpenAI(
  # If you have not configured the environment variable, replace the next line with: api_key="sk-xxx"
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  # Singapore (ap-southeast-1). For another region, replace ap-southeast-1 in the URL.
  # API keys are region-specific. See https://docs.qwencloud.com/developer-guides/getting-started/regions
  base_url="https://ap-southeast-1.maas.qwencloudapi.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 alexbrown@example.com, and I enjoy playing basketball and traveling"},
  ],
  response_format={"type": "json_object"},
)
json_string = completion.choices[0].message.content
print(json_string)
SDK response:
{
  "name": "Alex Brown",
  "age": 34
}
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "{\"name\":\"Alex Brown\",\"age\":34}"
      },
      "finish_reason": "stop",
      "index": 0,
      "logprobs": null
    }
  ],
  "object": "chat.completion",
  "usage": {
    "prompt_tokens": 207,
    "completion_tokens": 20,
    "total_tokens": 227,
    "prompt_tokens_details": {
      "cached_tokens": 0
    }
  },
  "created": 1756455080,
  "system_fingerprint": null,
  "model": "qwen3.8-max",
  "id": "chatcmpl-624b665b-fb93-99e7-9ebd-bb6d86d314d2"
}

Extract structured data from images and video

Multimodal models support structured output for images and video. Use JSON mode to pull structured data out of visual content, such as field values from receipts, object locations in images, or events in video. The following example extracts ticket and invoice fields from a scanned receipt.
For image and video file limits, see Image and video understanding.
  • OpenAI compatible
  • DashScope
import os
from openai import OpenAI

client = OpenAI(
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  # Singapore (ap-southeast-1). For another region, replace ap-southeast-1 in the URL.
  # API keys are region-specific. See https://docs.qwencloud.com/developer-guides/getting-started/regions
  base_url="https://ap-southeast-1.maas.qwencloudapi.com/compatible-mode/v1",
)

completion = client.chat.completions.create(
  model="qwen3-vl-plus",
  messages=[
    {
      "role": "system",
      "content": [{"type": "text", "text": "You are a helpful assistant."}],
    },
    {
      "role": "user",
      "content": [
        {
          "type": "image_url",
          "image_url": {
            "url": "http://duguang-labelling.oss-cn-shanghai.aliyuncs.com/demo_ocr/receipt_zh_demo.jpg"
          },
        },
        {"type": "text", "text": "Extract ticket (array type, including travel_date, trains, seat_num, arrival_site, price) and invoice information (array type, including invoice_code and invoice_number) from the image. Output a JSON containing both ticket and invoice arrays"},
      ],
    },
  ],
  response_format={"type": "json_object"},
)
json_string = completion.choices[0].message.content
print(json_string)
Response:
{
  "ticket": [
    {
      "travel_date": "2013-06-29",
      "trains": "Liushui",
      "seat_num": "371",
      "arrival_site": "Development Zone",
      "price": "8.00"
    }
  ],
  "invoice": [
    {
      "invoice_code": "221021325353",
      "invoice_number": "10283819"
    }
  ]
}

Optimize prompts

Ambiguous prompts like "return user information" lead to unpredictable output structures. For reliable results, describe the expected schema in your prompt: specify field names, types, required vs. optional status, format constraints (such as date format), and include examples. The system prompt below does all of this. It constrains field types, distinguishes required from optional fields, and uses four examples to show that the hobby field is omitted entirely when hobbies are not mentioned.
System prompt
Extract personal information from the user input and output it in the specified JSON Schema format:

[Output format requirements]
The output must strictly follow this JSON structure:
{
  "info": {
    "name": "string type, required field, user's name",
    "age": "string type, required field, format 'number years old', e.g., '25 years old'",
    "email": "string type, required field, standard email format, e.g., 'user@example.com'"
  },
  "hobby": ["string array type, optional field, contains all user hobbies; omit entirely if not mentioned"]
}

[Field extraction rules]
1. name: Identify the user's name from the text, must extract
2. age: Identify age information, convert to 'number years old' format, must extract
3. email: Identify email address, keep original format, must extract
4. hobby: Identify user hobbies, output as string array; omit hobby field entirely if hobbies are not mentioned

[Reference examples]
Example 1 (with hobby):
Q: My name is Alice, I'm 25 years old, my email is alice@example.com, and my hobby is singing
A: {"info":{"name":"Alice","age":"25 years old","email":"alice@example.com"},"hobby":["singing"]}
Example 2 (with multiple hobbies):
Q: My name is Bob, I'm 30 years old, my email is bob@example.com, and I enjoy dancing and swimming
A: {"info":{"name":"Bob","age":"30 years old","email":"bob@example.com"},"hobby":["dancing","swimming"]}
Example 3 (without hobby):
Q: My name is Dave, I'm 28 years old, and my email is dave@example.com
A: {"info":{"name":"Dave","age":"28 years old","email":"dave@example.com"}}
Example 4 (without hobby):
Q: I'm Sun Qi, 35 years old, and my email is sunqi@example.com
A: {"info":{"name":"Sun Qi","age":"35 years old","email":"sunqi@example.com"}}

Extract information and output JSON strictly according to the above format and rules. Do not include the hobby field if the user doesn't mention hobbies.
Pass it as the system message:
  • OpenAI compatible
  • DashScope
from openai import OpenAI
import os

client = OpenAI(
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  # Singapore (ap-southeast-1). For another region, replace ap-southeast-1 in the URL.
  # API keys are region-specific. See https://docs.qwencloud.com/developer-guides/getting-started/regions
  base_url="https://ap-southeast-1.maas.qwencloudapi.com/compatible-mode/v1",
)

system_prompt = """..."""  # Replace with the system prompt above

completion = client.chat.completions.create(
  model="qwen3.8-max",
  messages=[
    {"role": "system", "content": system_prompt},
    {"role": "user", "content": "Hi everyone, my name is Alex Brown, I'm 34 years old, my email is alexbrown@example.com, and I enjoy playing basketball and traveling"},
  ],
  response_format={"type": "json_object"},
)
print(completion.choices[0].message.content)
Response:
{
  "info": {
    "name": "Alex Brown",
    "age": "34 years old",
    "email": "alexbrown@example.com"
  },
  "hobby": ["Basketball", "Traveling"]
}

Constrain output precisely with JSON Schema

JSON Object mode only guarantees that the output is valid JSON — field names, types, and nesting may still differ from what you expect. For automated parsing, API interoperability, and other cases that need strict type constraints, set type to json_schema. The model then follows the schema exactly. The response_format structure looks like this:
Multimodal inputs (image, video, audio, etc.) do not support json_schema and will automatically fall back to json_object; the schema constraints will not take effect.
{
  "type": "json_schema",
  "json_schema": {
    "name": "schema_name",       // Name of the schema
    "strict": true,              // Recommended: strictly follow the format
    "schema": {
      "type": "object",
      "properties": {...},       // Define field structure
      "required": [...],         // List of required fields
      "additionalProperties": false  // Recommended: only output defined fields
    }
  }
}
This example forces the model to output a JSON object with the required fields name and age, plus the optional field email.

How to use

The OpenAI SDK's parse method accepts a Python Pydantic class or a Node.js Zod object directly and converts it to a JSON Schema for you, so you never write the schema by hand. With the DashScope SDK, construct the JSON Schema manually using the format above.
  • OpenAI compatible
  • OpenAI compatible - Responses
  • DashScope
from pydantic import BaseModel, Field
from openai import OpenAI
import os

client = OpenAI(
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  # Singapore (ap-southeast-1). For another region, replace ap-southeast-1 in the URL.
  # API keys are region-specific. See https://docs.qwencloud.com/developer-guides/getting-started/regions
  base_url="https://ap-southeast-1.maas.qwencloudapi.com/compatible-mode/v1",
)

class UserInfo(BaseModel):
  name: str = Field(description="User name")
  age: int = Field(description="User age in years")

completion = client.chat.completions.parse(
  model="qwen3.8-max",
  messages=[
    {"role": "system", "content": "Extract name and age information."},
    {"role": "user", "content": "My name is Liu Wu, I'm 25 years old."},
  ],
  response_format=UserInfo,          # <-- pass the Pydantic class directly
)
result = completion.choices[0].message.parsed
print(f"Name: {result.name}, Age: {result.age}")
Response:
Name: Liu Wu, Age: 25

Configuration guide

List required fields in the required array and leave optional fields out:
{
  "properties": {
    "name": {"type": "string"},
    "age": {"type": "integer"},
    "email": {"type": "string"}
  },
  "required": ["name", "age"]
}
If the input does not provide email information, the output omits the field.
Besides leaving a field out of required, you can allow the null type:
{
  "properties": {
    "name": {"type": "string"},
    "email": {"type": ["string", "null"]}  // Can be string or null
  },
  "required": ["name", "email"]  // Both in required
}
The output then always includes the email field, but its value may be null.
Controls whether the model may output fields not defined in the schema:
{
  "properties": {"name": {"type": "string"}},
  "required": ["name"],
  "additionalProperties": true  // Allow extra fields
}
For the input "I'm Zhang San, 25 years old", the output is {"name": "Zhang San", "age": 25} — including the undefined age field.
ValueBehaviorUse case
falseOnly output defined fieldsPrecise structure control
trueAllow extra fieldsCapture more information
string, number, integer, boolean, object, array, enum.
The following lists the keywords supported by JSON Schema mode (strict mode). Keywords marked as "unsupported" return a 400 error when submitted. For the complete keyword definitions, see the JSON Schema specification.Schema-level common keywords
KeywordDescription
typeSupports string, number, integer, boolean, null, array, object; union types such as ["string", "null"] are also supported
enum / constenum restricts the value to a set of allowed values; const restricts it to a single fixed value
$defs + $refLocal references are supported (e.g., #/$defs/address); external URL references do not cause errors but have no effect
anyOf / oneOf / allOf / notComposition and conditional constraints are supported. Note that oneOf does not strictly guarantee exactly-one semantics
if / then / elseConditional schemas are supported, enabling dynamic validation rules based on field values
title / description / default / examplesAccepted as semantic hints for the model; not enforced as hard constraints
$schema / $id / $commentMeta identifiers; accepted without affecting validation behavior
deprecated / readOnly / writeOnlyAnnotation keywords; accepted without affecting validation behavior
Type-specific keywords
TypeSupported keywordsUnsupported keywords (400 error)
stringminLength, maxLength, pattern, format (e.g., email, date), contentMediaType, contentEncoding-
number / integerminimum, maximum, exclusiveMinimum, exclusiveMaximummultipleOf
arrayitems, prefixItems (tuple mode), minItems, maxItems, unevaluatedItemsuniqueItems, contains, minContains, maxContains, additionalItems
objectproperties, required, additionalProperties, minProperties, maxProperties, dependentRequired, dependentSchemas, unevaluatedPropertiespatternProperties, propertyNames

Going live

Validate before passing downstream In JSON Object mode the output is guaranteed to be valid JSON, but not to match your business schema. Validate it with a library such as jsonschema (Python), Ajv (JavaScript), or Everit (Java) before handing it to downstream services, so missing fields or type errors don't cause parsing failures, data loss, or broken business logic. On failure, retry the request or have a model rewrite the output. Do not set max_tokens Leave max_tokens unset when structured output is enabled. This parameter caps the number of output tokens (the default is the model's maximum) and can truncate the JSON string mid-output, producing invalid JSON. Use the SDK to generate schemas Let the SDK generate the schema. This avoids errors from hand-maintained schemas and gives you automatic validation plus a type-safe parsed result.
from pydantic import BaseModel, Field
from typing import Optional
from openai import OpenAI
import os

client = OpenAI(
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  # Singapore (ap-southeast-1). For another region, replace ap-southeast-1 in the URL.
  # API keys are region-specific. See https://docs.qwencloud.com/developer-guides/getting-started/regions
  base_url="https://ap-southeast-1.maas.qwencloudapi.com/compatible-mode/v1",
)

class UserInfo(BaseModel):
  name: str = Field(description="User name")
  age: int = Field(description="User age")
  email: Optional[str] = None        # Optional field

completion = client.chat.completions.parse(
  model="qwen3.8-max",
  messages=[
    {"role": "system", "content": "Extract name and age information."},
    {"role": "user", "content": "My name is Liu Wu, I'm 25 years old."},
  ],
  response_format=UserInfo,          # Pass the Pydantic model directly
)
result = completion.choices[0].message.parsed   # Type-safe parsed result
print(f"Name: {result.name}, Age: {result.age}")

Error codes

If a call fails and returns an error message, see Error messages for resolution.