IMPORTANT: To view this page as Markdown, append `.md` to the URL (e.g. /get-started.md). For the complete documentation index, see llms.txt.
Skip to main content
For the complete documentation index, see llms.txt. Markdown versions of all pages are available by appending .md to any URL (e.g. /get-started.md).

Structured output

MAX supports structured output using xgrammar as the default backend, and you can switch to llguidance. Structured output, also called constrained decoding, lets you enforce specific output formats so a model returns structured, predictable responses.

When to use structured output

If you want to structure a model's output when it responds to a user, then you should use a structured output response_format.

If you are connecting a model to tools, functions, data, or other systems, then you should use function calling instead of structured outputs.

Learn more about structured output in the LLM Inference Handbook.

How structured output works

To use structured output, include the --enable-structured-output flag when serving your model with the max CLI.

max serve \
  --model "google/gemma-4-31B-it" \
  --enable-structured-output

You can tune structured output behavior with the following options:

  • --structured-output-backend: Selects the grammar backend for constrained decoding, either xgrammar (the default) or llguidance. Some architectures declare their own default, but an explicit value on the command line overrides it.
  • --structured-output-any-whitespace: Controls whether structured output grammars accept whitespace between JSON tokens. The default, false, constrains the model to compact JSON, which mitigates runaway output on some models. Pass true to allow whitespace-tolerant JSON.

Both the /chat/completions and /completions API endpoints are compatible with structured output.

You can define your structured output response format in two ways:

  1. JSON schema: Specify the schema directly in your request.
  2. Pydantic: Use Pydantic to define and validate your schema as a Python class.

We recommend testing your structured output responses thoroughly as they are sensitive to the way the model was trained.

JSON schema

To specify structured output within your inference request, use the following format:

structured-image-description.py
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")

response = client.chat.completions.create(
    model="google/gemma-4-31B-it",
    messages=[
        {
            "role": "system",
            "content": "You are an assistant that analyzes images and returns structured descriptions."
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "Analyze this image and describe what you see."
                },
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/0052a70beed5bf71b92610a43a52df6d286cd5f3/diffusers/rabbit.jpg"
                    }
                }
            ]
        }
    ],
    max_completion_tokens=300,
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "ImageAnalysis",
            "schema": {
                "type": "object",
                "properties": {
                    "description": {"type": "string"},
                    "subjects": {
                        "type": "array",
                        "items": {"type": "string"}
                    },
                    "colors": {
                        "type": "array",
                        "items": {"type": "string"}
                    },
                    "setting": {"type": "string"},
                    "mood": {"type": "string"}
                },
                "required": ["description", "subjects", "colors", "setting", "mood"],
                "additionalProperties": False
            }
        }
    }
)

print(response.choices[0].message.content)

Instead of a typical text response from the model, the response_format schema defined above results in a JSON-formatted structured output such as the following:

{
  "description": "A full-body shot of Peter Rabbit, the fictional character, standing on a dirt path. He is dressed in a blue jacket with brass buttons over a white shirt and a small yellow tie. He also wears brown pants and appears to be holding a small basket. The background consists of a rustic stone house with a thatched roof, a winding dirt road, green fields, and rolling hills under a bright sky. Wildflowers in shades of purple and white line the path in the foreground.",
  "subjects": [
    "rabbit",
    "house",
    "path",
    "fields",
    "hills",
    "flowers",
    "basket"
  ],
  "colors": [
    "blue",
    "brown",
    "green",
    "white",
    "yellow",
    "purple"
  ],
  "setting": "Rural countryside",
  "mood": "Whimsical, charming, idyllic"
}

Pydantic

For production Python code, you can define your structured output using Pydantic. This gives you type-safe attribute access and automatic validation instead of manually parsing JSON strings.

Here's an example using a Pydantic BaseModel to analyze an image and return a validated response:

structured-image-analysis.py
from pydantic import BaseModel
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")

class ImageAnalysis(BaseModel):
    description: str
    subjects: list[str]
    colors: list[str]
    setting: str
    mood: str

completion = client.chat.completions.parse(
    model="google/gemma-4-31B-it",
    messages=[
        {
            "role": "system",
            "content": "You are an assistant that analyzes images and returns structured descriptions."
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "Analyze this image and describe what you see."
                },
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/0052a70beed5bf71b92610a43a52df6d286cd5f3/diffusers/rabbit.jpg"
                    }
                }
            ]
        }
    ],
    max_completion_tokens=300,
    response_format=ImageAnalysis,
)

analysis = completion.choices[0].message.parsed
print(analysis)

Supported models

All text generation models support structured output with MAX. As new models are added, they will also be compatible with structured output. This functionality is implemented at the pipeline level, ensuring consistency across different models.

However, structured output currently doesn't support CPU deployments, only GPU deployments.

Next steps

Next, try processing local image files or deploying to the cloud.

Was this page helpful?