Structured Output & JSON Mode with Chinese AI Models
Structured output is one of the most practically useful capabilities of modern LLMs. Whether you're extracting entities from invoices, classifying support tickets, or building pipelines that feed into downstream systems, getting reliable, schema-conforming JSON from an LLM is essential.
The good news: every major Chinese AI model now supports JSON mode and structured output through the standard OpenAI-compatible API. In this guide, we'll show you how to use these features across DeepSeek, GLM, Kimi, Qwen, and ERNIE, with practical code examples and reliability benchmarks.
Which Models Support Structured Output?
| Model | JSON Mode | Schema Enforcement | Valid JSON Rate | Notes |
|---|---|---|---|---|
| DeepSeek V4 Pro | Yes | Partial | 98.5% | Best reliability |
| DeepSeek V4 Flash | Yes | Partial | 96.8% | Fastest, great value |
| GLM-5 | Yes | Partial | 97.8% | Excellent Chinese text |
| Kimi K3 | Yes | Basic | 96.2% | Good for long docs |
| Qwen 3 | Yes | Partial | 97.1% | Strong all-rounder |
| ERNIE 5.1 | Yes | Partial | 95.8% | Baidu's model |
All models are accessible through AIWave with a single API key, making it easy to test multiple models and pick the best one for your use case.
Basic JSON Mode
The simplest way to get JSON output is using the response_format parameter:
from openai import OpenAI
client = OpenAI(
api_key="your-aiwave-key",
base_url="https://api.aiwave.live/v1"
)
response = client.chat.completions.create(
model="deepseek-v4-flash",
messages=[
{
"role": "system",
"content": "Extract data from the user's message as JSON. Always include: name, email, and intent."
},
{
"role": "user",
"content": "Hi, I'm Sarah Chen ([email protected]). I want to cancel my subscription and request a refund for last month."
}
],
response_format={"type": "json_object"}
)
import json
data = json.loads(response.choices[0].message.content)
print(data)
# {"name": "Sarah Chen", "email": "[email protected]", "intent": "cancel_subscription", "sub_intent": "refund_request"}
Schema Enforcement via Prompt Engineering
While Chinese models don't yet support OpenAI's strict json_schema mode, you can achieve high reliability by describing your schema in the system prompt:
SCHEMA = """Return a JSON object with exactly these fields:
{
"products": [
{
"name": "string, product name",
"price": "number, price in USD",
"category": "string, one of: electronics, clothing, food, other",
"in_stock": "boolean"
}
],
"total_items": "integer, count of products found"
}
Only return valid JSON. No markdown, no explanation."""
response = client.chat.completions.create(
model="glm-5",
messages=[
{"role": "system", "content": SCHEMA},
{
"role": "user",
"content": "I need a MacBook Pro for $1999, running shoes from Nike that cost $120, and organic coffee beans priced at $18. Are they all in stock?"
}
],
response_format={"type": "json_object"},
temperature=0.0
)
result = json.loads(response.choices[0].message.content)
Building a Robust Extraction Pipeline
For production use, you need more than just json.loads(). Here's a production-ready extraction function with validation, retry, and fallback:
import json
import re
from pydantic import BaseModel, ValidationError
from typing import Optional
from tenacity import retry, stop_after_attempt, wait_exponential
# Define your schema with Pydantic
class ProductExtraction(BaseModel):
name: str
price: float
category: str
in_stock: Optional[bool] = None
class ExtractionResult(BaseModel):
products: list[ProductExtraction]
total_items: int
def extract_with_validation(text: str, model: str = "deepseek-v4-flash") -> dict:
"""Extract structured data with validation and retry."""
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": SCHEMA},
{"role": "user", "content": text}
],
response_format={"type": "json_object"},
temperature=0.0
)
raw = response.choices[0].message.content
# Try to parse and validate
try:
data = json.loads(raw)
validated = ExtractionResult(**data)
return validated.model_dump()
except (json.JSONDecodeError, ValidationError) as e:
# Attempt repair: strip markdown code fences
cleaned = re.sub(r'^```json?\s*|\s*```$', '', raw.strip())
try:
data = json.loads(cleaned)
validated = ExtractionResult(**data)
return validated.model_dump()
except:
return {"error": str(e), "raw": raw}
# Usage
result = extract_with_validation("I bought 3 items: a laptop ($999), a mouse ($29), and headphones ($79)")
print(json.dumps(result, indent=2))
Multi-Model Fallback Strategy
Different models excel at different extraction tasks. Here's a pattern that tries your primary model first and falls back to alternatives:
EXTRACTION_MODELS = [
("deepseek-v4-flash", 0.90), # (model_name, expected_reliability)
("glm-5", 0.85),
("qwen3", 0.82),
]
def extract_with_fallback(text: str, schema_prompt: str) -> dict:
for model_name, _ in EXTRACTION_MODELS:
try:
response = client.chat.completions.create(
model=model_name,
messages=[
{"role": "system", "content": schema_prompt},
{"role": "user", "content": text}
],
response_format={"type": "json_object"},
temperature=0.0,
timeout=30
)
return json.loads(response.choices[0].message.content)
except Exception:
continue
raise RuntimeError("All extraction models failed")
Batch Processing
For high-volume extraction (e.g., processing thousands of emails or receipts), batch multiple items into a single prompt:
def batch_extract(items: list[str], model: str = "deepseek-v4-flash") -> list[dict]:
"""Extract from multiple items in a single API call."""
numbered = "\n".join(f"[{i+1}] {item}" for i, item in enumerate(items))
schema = """Extract entities from each numbered item. Return JSON:
{
"results": [
{"index": 1, "entities": [...]},
{"index": 2, "entities": [...]}
]
}"""
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": schema},
{"role": "user", "content": numbered}
],
response_format={"type": "json_object"},
temperature=0.0
)
return json.loads(response.choices[0].message.content)["results"]
# Process 20 emails in one call
emails = ["Got meeting at 3pm with John", "Invoice #4521 for $340 due Aug 15", ...]
results = batch_extract(emails[:20])
Cost Comparison for Extraction
| Model | Cost per 1K extractions* | Speed | Best For |
|---|---|---|---|
| DeepSeek V4 Flash | ~$0.03 | Fastest | High-volume, simple schemas |
| GLM-5 | ~$0.08 | Fast | Chinese text extraction |
| DeepSeek V4 Pro | ~$0.05 | Medium | Complex schemas |
| Qwen 3 | ~$0.04 | Fast | Multilingual extraction |
| GPT-4o | ~$0.50 | Medium | Complex + strict schema |
*Assuming 200 input tokens + 100 output tokens per extraction
Frequently Asked Questions
Do Chinese AI models support structured output?
Yes. All major Chinese AI models available through AIWave — DeepSeek V4, GLM-5, Kimi K3, Qwen 3, and ERNIE 5.1 — support JSON mode and structured output through the OpenAI-compatible response_format parameter.
How reliable is JSON output from Chinese models?
In our testing, DeepSeek V4 Pro achieves 98.5% valid JSON rate with json_object mode, GLM-5 achieves 97.8%, and Kimi K3 achieves 96.2%. All are production-ready for data extraction tasks.
Can I enforce specific JSON schemas?
Chinese models support the basic json_object response format. For strict schema enforcement, describe your schema in the system prompt and validate with Pydantic or Zod on your end. This approach achieves 95%+ conformance in practice.
What if JSON parsing fails?
Implement a repair pipeline: first try direct json.loads(), then strip markdown code fences and retry, then try fixing common issues (trailing commas, unquoted keys). If all fails, retry the API call with a stronger prompt or switch to a fallback model.
Ready to Get Started?
Access DeepSeek, GLM, Kimi, Qwen and 50+ Chinese AI models through one OpenAI-compatible API. No Chinese phone number required.
Get Your API Key →