The Appeal: Guaranteed JSON
Structured output (JSON mode) promises: “The model will always output valid JSON, never unstructured text.”
Sounds great. But there’s a catch: forcing structure sometimes makes the model dumber.
How JSON Mode Works
Most LLM APIs let you specify output format:
import anthropic
client = anthropic.Anthropic()
message = client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=1024, response_format={"type": "json_object"}, messages=[ {"role": "user", "content": "Extract names and ages from: 'Alice is 30, Bob is 25'"} ])
# Response is guaranteed valid JSONresult = json.loads(message.content[0].text)Ollama also supports this:
curl http://localhost:11434/api/generate -d '{ "model": "mistral", "prompt": "Extract JSON: {\"name\": \"...\", \"age\": ...} from: Alice is 30", "format": "json", "stream": false}'The model’s output will be valid JSON, not “name: Alice, age: 30” or other variations.
When JSON Mode Saves You
Use JSON mode when:
-
Extraction from unstructured text
- “Pull names, emails, dates from this doc”
- Model knows exactly what to extract
-
Form filling / structured categorization
- “Assign sentiment: positive/negative/neutral”
- “Extract: name, email, phone from this resume”
-
Data pipeline integrations
- You can’t afford parsing errors
- JSON→database is standard
# Example: Extract structured data from free textprompt = """Extract the following fields from this support ticket:- issue: What's the problem?- priority: critical/high/medium/low- component: backend/frontend/database/infrastructure- action_required: A brief next step
Ticket: "The login page is broken. Users can't sign in. This is blocking our launch.""""
# With JSON mode, you get valid JSON guaranteed# Without it, you might get: "issue: The login page is broken\npriority: critical"When JSON Mode Hurts
JSON mode constraints the model’s reasoning. Some models perform worse when forced into JSON.
Consider:
User: "Explain why OAuth is better than basic auth"
With JSON mode:- Model is constrained to structure- May oversimplify to fit the schema- Loses nuance
Without JSON mode:- Model can write naturally, include caveats- Can say "it depends" with explanationReal example:
# Without JSON mode$ curl http://localhost:11434/api/generate -d '{ "model": "mistral", "prompt": "What are the tradeoffs of microservices?", "stream": false}'
# Output: "Microservices offer scalability and independence, but they add complexity..."# (Clear, nuanced, well-reasoned)
# With JSON modecurl http://localhost:11434/api/generate -d '{ "model": "mistral", "prompt": "What are the tradeoffs of microservices? Output as JSON: {\"pros\": [...], \"cons\": [...]}", "format": "json", "stream": false}'
# Output: {"pros": ["Scalability", "Independence"], "cons": ["Complexity", "Cost"]}# (Oversimplified, loses explanation)Decision Tree
Use JSON mode if:
- Output feeds directly into code/database
- You need strict validation
- Schema is simple and obvious
- You don’t care about explanation/nuance
Skip JSON mode if:
- You need reasoning or explanation
- The output is for a human to read
- The model might struggle with the constraint
- You can parse unstructured text with a regex/parser
Hybrid Approach: JSON + Explanation
Get the best of both worlds:
prompt = """Analyze this code for security issues. Output as JSON:{ "vulnerability": "name of issue", "severity": "critical/high/medium/low", "explanation": "why this is a problem", "fix": "how to fix it"}
Code:```pythonimport ospassword = os.getenv("DB_PASSWORD") # Hardcoded in logs"""
Model can explain fully within the “explanation” field
while still outputting valid JSON
This works because JSON allows text fields. The model can be verbose and nuanced, but the output is still machine-parseable.
## Testing: Before and After
Always benchmark JSON mode vs. free form:
```bash#!/bin/bash
# Test both modes on the same promptprompt="Extract: name, email, age from 'John Doe (john@example.com) is 35 years old'"
echo "=== Without JSON mode ==="curl -s http://localhost:11434/api/generate -d "{ \"model\": \"mistral\", \"prompt\": \"$prompt\", \"stream\": false}" | jq '.response'
echo ""echo "=== With JSON mode ==="curl -s http://localhost:11434/api/generate -d "{ \"model\": \"mistral\", \"prompt\": \"$prompt\nOutput as valid JSON: {\\\"name\\\": ..., \\\"email\\\": ..., \\\"age\\\": ...}\", \"format\": \"json\", \"stream\": false}" | jq '.response'
# Compare:# - Which is easier to parse?# - Which is more accurate?# - Does quality differ?The Real Cost
JSON mode adds computational overhead. The model has to track syntax, ensure quotes match, etc. This makes inference slightly slower and can degrade quality on complex reasoning tasks.
For simple extraction? The overhead is negligible and the safety gain is huge.
For “explain this concept”? You’re paying a real penalty for no benefit.
Bottom Line
JSON mode is a power tool for extraction and data pipelines. Use it there. Don’t use it for explanation, analysis, or anything where nuance matters.
When in doubt, let the model write freely, then parse the output with a simple regex or JSON.loads(). Your model will thank you with better output.