Structured output & JSON
Constrain model outputs to parseable JSON — either an arbitrary JSON object or a value that conforms exactly to a JSON Schema. No regex fallbacks, no retry loops, no post-processing.
Two modes
Select the mode by setting response_format on your chat completion request.
| Mode | Use when | Config |
|---|---|---|
| JSON object | You want valid JSON but the shape is flexible. | {"type": "json_object"} |
| JSON Schema | You need a strict, validated shape (recommended). | {"type": "json_schema", "json_schema": { … }} |
verified
Prefer JSON Schema. The schema is enforced at decode time via guided
decoding, so the output is guaranteed valid against the schema — not just valid JSON.
JSON object mode
The simplest mode — the model returns valid JSON with a shape it chooses. Always include the word “JSON” in your prompt, and ideally describe the target shape.
import json, os
from openai import OpenAI
client = OpenAI(base_url="https://api.wylon.cn/v1", api_key=os.environ["WYLON_API_KEY"])
resp = client.chat.completions.create(
model="moonshotai/kimi-k2.5",
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": "Reply only with JSON."},
{"role": "user", "content": "List three Nordic capitals with their populations."},
],
)
data = json.loads(resp.choices[0].message.content)
print(data)
curl https://api.wylon.cn/v1/chat/completions \
-H "Authorization: Bearer $WYLON_API_KEY" -H "Content-Type: application/json" \
-d '{
"model": "moonshotai/kimi-k2.5",
"response_format": {"type": "json_object"},
"messages": [{"role":"user","content":"List three Nordic capitals as JSON."}]
}'
JSON Schema mode
Supply a full JSON Schema. The model is decoded with grammar constraints so every field,
type, and enum is guaranteed to match. Ideal for data extraction, RPC-style calls,
and any place you plan to json.loads() & trust the result.
from pydantic import BaseModel
from openai import OpenAI
import os
class Capital(BaseModel):
city: str
country: str
population: int
class Capitals(BaseModel):
items: list[Capital]
client = OpenAI(base_url="https://api.wylon.cn/v1", api_key=os.environ["WYLON_API_KEY"])
resp = client.chat.completions.create(
model="moonshotai/kimi-k2.5",
messages=[{"role": "user", "content": "Three Nordic capitals with populations."}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "capitals",
"schema": Capitals.model_json_schema(),
"strict": True,
},
},
)
parsed = Capitals.model_validate_json(resp.choices[0].message.content)
for c in parsed.items: print(c.city, c.population)
import OpenAI from "openai";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
const Capital = z.object({ city: z.string(), country: z.string(), population: z.number().int() });
const Capitals = z.object({ items: z.array(Capital) });
const client = new OpenAI({ baseURL: "https://api.wylon.cn/v1", apiKey: process.env.WYLON_API_KEY });
const resp = await client.chat.completions.create({
model: "moonshotai/kimi-k2.5",
messages: [{ role: "user", content: "Three Nordic capitals with populations." }],
response_format: {
type: "json_schema",
json_schema: { name: "capitals", schema: zodToJsonSchema(Capitals), strict: true },
},
});
const parsed = Capitals.parse(JSON.parse(resp.choices[0].message.content));
{
"type": "json_schema",
"json_schema": {
"name": "capitals",
"strict": true,
"schema": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"city": { "type": "string" },
"country": { "type": "string" },
"population": { "type": "integer" }
},
"required": ["city", "country", "population"],
"additionalProperties": false
}
}
},
"required": ["items"],
"additionalProperties": false
}
}
}
Best practices
- Describe the shape in the prompt too. Grammar constraints guarantee syntactic validity — the prompt steers semantic quality.
- Prefer JSON Schema over JSON object. Strict mode eliminates an entire class of parsing bugs.
- Flatten deeply-nested unions. Models generate cleaner output for flat records than for deeply discriminated unions.
- Mark optional fields explicitly. In JSON Schema use
"required"precisely — don’t rely on the model skipping absent fields. - Try a smaller model first. Many extraction tasks don’t need frontier reasoning — save cost by benchmarking a
fast-flavor model on a validation set.