JSON Mode

Get structured JSON responses from models using Oru-el's JSON mode.

JSON Mode#

JSON mode forces the model to produce valid JSON in its response. This is essential when you need structured data — parsing entities, extracting information, generating configs, or building data pipelines.

Enabling JSON mode#

Set response_format to {"type": "json_object"} in your request:

response = client.chat.completions.create(
    model="llama-4-maverick",
    messages=[
        {"role": "system", "content": "You are a helpful assistant. Respond with valid JSON."},
        {"role": "user", "content": "List 3 programming languages with their year of creation."},
    ],
    response_format={"type": "json_object"},
)

data = json.loads(response.choices[0].message.content)

Important: You must include an instruction to produce JSON in your prompt (either in the system message or user message). JSON mode ensures the output is valid JSON, but the model still needs direction on what JSON to produce.

Basic example#

Python#

import json
from openai import OpenAI

client = OpenAI(
    base_url="https://api.oru-el.com/v1/inference",
    api_key="oruel_your_api_key_here",
)

response = client.chat.completions.create(
    model="llama-4-maverick",
    messages=[
        {
            "role": "system",
            "content": "You extract structured data. Always respond with a JSON object.",
        },
        {
            "role": "user",
            "content": "Extract the person's info: John Smith is a 34-year-old software engineer from Austin, Texas.",
        },
    ],
    response_format={"type": "json_object"},
    temperature=0,
)

data = json.loads(response.choices[0].message.content)
print(json.dumps(data, indent=2))

Output:

{
  "name": "John Smith",
  "age": 34,
  "occupation": "software engineer",
  "city": "Austin",
  "state": "Texas"
}

JavaScript#

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.oru-el.com/v1/inference",
  apiKey: "oruel_your_api_key_here",
});

const response = await client.chat.completions.create({
  model: "llama-4-maverick",
  messages: [
    {
      role: "system",
      content: "You extract structured data. Always respond with a JSON object.",
    },
    {
      role: "user",
      content:
        "Extract the person's info: John Smith is a 34-year-old software engineer from Austin, Texas.",
    },
  ],
  response_format: { type: "json_object" },
  temperature: 0,
});

const data = JSON.parse(response.choices[0].message.content);
console.log(data);

cURL#

curl https://api.oru-el.com/v1/inference/chat/completions \
  -H "Authorization: Bearer oruel_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama-4-maverick",
    "messages": [
      {"role": "system", "content": "You extract structured data. Always respond with a JSON object."},
      {"role": "user", "content": "Extract the person'\''s info: John Smith is a 34-year-old software engineer from Austin, Texas."}
    ],
    "response_format": {"type": "json_object"},
    "temperature": 0
  }'

Entity extraction#

Extract structured entities from unstructured text:

response = client.chat.completions.create(
    model="llama-4-maverick",
    messages=[
        {
            "role": "system",
            "content": """Extract entities from the text. Return a JSON object with this schema:
{
  "companies": [{"name": string, "role": string}],
  "monetary_values": [{"amount": number, "currency": string, "context": string}],
  "dates": [{"date": string, "context": string}],
  "people": [{"name": string, "title": string}]
}""",
        },
        {
            "role": "user",
            "content": "On March 15, 2024, Acme Corp CEO Jane Doe announced a $2.5 billion acquisition of Beta Inc. The deal is expected to close by Q3 2024.",
        },
    ],
    response_format={"type": "json_object"},
    temperature=0,
)

entities = json.loads(response.choices[0].message.content)

Expected output:

{
  "companies": [
    { "name": "Acme Corp", "role": "acquirer" },
    { "name": "Beta Inc", "role": "target" }
  ],
  "monetary_values": [
    { "amount": 2500000000, "currency": "USD", "context": "acquisition price" }
  ],
  "dates": [
    { "date": "2024-03-15", "context": "announcement date" },
    { "date": "2024-Q3", "context": "expected close" }
  ],
  "people": [
    { "name": "Jane Doe", "title": "CEO of Acme Corp" }
  ]
}

Structured data parsing#

Parse documents into a consistent schema:

response = client.chat.completions.create(
    model="llama-4-maverick",
    messages=[
        {
            "role": "system",
            "content": """Parse the product review into JSON with this schema:
{
  "rating": number (1-5),
  "sentiment": "positive" | "negative" | "mixed",
  "pros": [string],
  "cons": [string],
  "summary": string,
  "would_recommend": boolean
}""",
        },
        {
            "role": "user",
            "content": "I've been using this keyboard for 3 months. The mechanical switches feel amazing and the build quality is top-notch. However, the software is buggy and the RGB lighting flickers occasionally. Battery life is decent at about 2 weeks. Overall I like it but the software needs work. 4 out of 5 stars.",
        },
    ],
    response_format={"type": "json_object"},
    temperature=0,
)

review = json.loads(response.choices[0].message.content)

Classification#

Use JSON mode for classification tasks with structured output:

response = client.chat.completions.create(
    model="llama-4-maverick",
    messages=[
        {
            "role": "system",
            "content": """Classify the support ticket. Return JSON:
{
  "category": "billing" | "technical" | "account" | "feature_request" | "other",
  "priority": "low" | "medium" | "high" | "critical",
  "sentiment": "positive" | "neutral" | "negative" | "angry",
  "requires_human": boolean,
  "suggested_response_template": string
}""",
        },
        {
            "role": "user",
            "content": "I've been charged twice for my subscription this month! This is the third time this has happened. Fix this immediately or I'm canceling.",
        },
    ],
    response_format={"type": "json_object"},
    temperature=0,
)

ticket = json.loads(response.choices[0].message.content)
print(f"Category: {ticket['category']}, Priority: {ticket['priority']}")

Error handling#

Always wrap JSON parsing in error handling. While JSON mode ensures valid JSON syntax, the structure may not match your expected schema:

import json
from openai import OpenAI

client = OpenAI(
    base_url="https://api.oru-el.com/v1/inference",
    api_key="oruel_your_api_key_here",
)

response = client.chat.completions.create(
    model="llama-4-maverick",
    messages=[
        {"role": "system", "content": "Respond with a JSON object containing 'name' and 'age'."},
        {"role": "user", "content": "Tell me about Alice, who is 30."},
    ],
    response_format={"type": "json_object"},
    temperature=0,
)

content = response.choices[0].message.content

try:
    data = json.loads(content)
except json.JSONDecodeError:
    print(f"Failed to parse JSON: {content}")
    data = None

if data:
    # Validate expected fields exist
    name = data.get("name")
    age = data.get("age")
    if name is None or age is None:
        print(f"Missing expected fields. Got: {data}")
const content = response.choices[0].message.content;

let data;
try {
  data = JSON.parse(content);
} catch (error) {
  console.error("Failed to parse JSON:", content);
}

if (data) {
  const { name, age } = data;
  if (name === undefined || age === undefined) {
    console.error("Missing expected fields:", data);
  }
}

Tips for reliable JSON output#

  1. Specify the schema in the system message — show the exact JSON structure you expect, including field names, types, and allowed values.

  2. Use temperature: 0 — deterministic output is more reliable for structured data tasks.

  3. Provide examples — if the schema is complex, include a sample JSON object in your prompt.

  4. Keep schemas simple — deeply nested schemas with many optional fields are harder for models to follow consistently.

  5. Validate after parsing — JSON mode guarantees valid JSON syntax but not that the output matches your schema. Always validate the structure and types.

  6. Handle truncation — if the response is cut off by max_tokens, the JSON may be incomplete. Set max_tokens high enough for your expected output, and check finish_reason for "length".

JSON mode vs. tool calling#

Both can produce structured data, but they serve different purposes:

FeatureJSON modeTool calling
Use caseExtract data, classify, parseTrigger actions, fetch real-time data
OutputRaw JSON in contentStructured tool_calls with function.arguments
Schema enforcementVia prompt instructionsVia JSON Schema in tool definition
Follow-up requiredNoYes (return tool result, then get final response)
Best forData extraction, classificationMulti-step workflows, external integrations

Use JSON mode when you need structured data as the final output. Use tool calling when the model needs to trigger an action and then reason about the result.