Skip to main content
Lesson 5 of 12 · Structured Output: JSON and Schemas

Practical JSON Mode Examples

Lesson 5 of 12 Updated November 3, 2026 Developer
On this page
  1. Putting JSON Mode into Practice
  2. Extracting Entities from Unstructured Text
  3. Classifying Support Tickets
  4. Converting a Description into a Product Sheet
  5. Processing Multiple Items in One Call
  6. Key Takeaways

Updated November 3, 2026: The TypeScript example previously imported Mistral as a default export, but the SDK only provides a named export (import { Mistral } from "@mistralai/mistralai"). It also hardcoded the API key and forced the type of content with !, which is insufficient because the field can also be a list of chunks. Verified by compilation with SDK 3.5.0 and TypeScript 7.0.2. Source: Mistral TypeScript SDK.

Putting JSON Mode into Practice

You know how to enable JSON Mode; now let’s look at worked examples. Three scenarios appear constantly in real-world projects, and each illustrates a different way to leverage the mode. The code is provided in Python, with TypeScript equivalents where the translation isn’t immediate.

Extracting Entities from Unstructured Text

Entity extraction is the most frequent and cost-effective use case: a sales email contains full contact details, but they are buried in a signature and pleasantries. The key instruction in the following example is the last line of the system prompt—requiring null for missing information prevents the model from inventing a phone number just to fill the field.

from mistralai.client import Mistral
import json

client = Mistral(api_key="your-api-key")

email_text = """
Hello,
I am Marie Dupont, Sales Director at TechVision SAS.
You can reach me at 06 12 34 56 78 or by email at [email protected].
Our headquarters are at 42 rue de la Paix, 75002 Paris.
Best regards,
Marie
"""

response = client.chat.complete(
    model="mistral-large-latest",
    messages=[
        {
            "role": "system",
            "content": """Extract contact information from the provided text.
Return a JSON with keys: name, title, company, phone, email, address.
If information is missing, use null."""
        },
        {"role": "user", "content": email_text}
    ],
    response_format={"type": "json_object"},
    temperature=0
)

contact = json.loads(response.choices[0].message.content)
print(f"Name: {contact['name']}")
print(f"Company: {contact['company']}")
print(f"Phone: {contact['phone']}")

Expected output:

{
  "name": "Marie Dupont",
  "title": "Sales Director",
  "company": "TechVision SAS",
  "phone": "06 12 34 56 78",
  "email": "[email protected]",
  "address": "42 rue de la Paix, 75002 Paris"
}

Classifying Support Tickets

Classification requires a different approach: instead of letting the model choose its own values, you enumerate the allowed values for each field in the prompt. This makes results comparable from one ticket to the next and directly usable for routing. Note the switch to mistral-small-latest—ticket triage does not justify using the most powerful model.

tickets = [
    "My payment was charged twice, I demand an immediate refund!",
    "How can I change my password?",
    "Your app crashes every time I open the settings tab.",
]

for ticket in tickets:
    response = client.chat.complete(
        model="mistral-small-latest",
        messages=[
            {
                "role": "system",
                "content": """Classify the support ticket.
Return a JSON with:
- category: "billing", "account", "technical", "feature_request", or "other"
- priority: "low", "medium", "high", or "critical"
- sentiment: "positive", "neutral", or "negative"
- summary: one-sentence summary"""
            },
            {"role": "user", "content": ticket}
        ],
        response_format={"type": "json_object"},
        temperature=0
    )

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

Here is the same classifier in TypeScript. The check before JSON.parse reminds us that the SDK types content as optional and as string | ContentChunk[]: only a string can be parsed.

import { Mistral } from "@mistralai/mistralai";

const client = new Mistral({ apiKey: process.env.MISTRAL_API_KEY });

const ticket = "My payment was charged twice!";

const response = await client.chat.complete({
  model: "mistral-small-latest",
  messages: [
    {
      role: "system",
      content: `Classify the support ticket.
Return a JSON with: category, priority, sentiment, summary.`,
    },
    { role: "user", content: ticket },
  ],
  responseFormat: { type: "json_object" },
  temperature: 0,
});

const contenu = response.choices[0]?.message?.content;
if (typeof contenu !== "string") {
  throw new Error("The response does not contain JSON text.");
}
const result = JSON.parse(contenu);
console.log(`Category: ${result.category}`);
console.log(`Priority: ${result.priority}`);

Converting a Description into a Product Sheet

Third scenario: transforming marketing text into a record ready for a database. This exercise is trickier because types matter—a price must arrive as a number, a delivery duration as two integers, and free shipping as a boolean. Hence the precise annotations in the prompt.

product_text = """
The 16-inch MacBook Pro with M4 Pro chip is available starting at €2,799.
It features 24 GB of unified RAM, a 512 GB SSD, and a Liquid Retina XDR display.
Available in Space Black and Silver. Free delivery within 3-5 days.
"""

response = client.chat.complete(
    model="mistral-large-latest",
    messages=[
        {
            "role": "system",
            "content": """Convert the product description into a structured sheet.
JSON with: name, brand, price_eur (number), specs (object with ram_gb, storage_gb, screen),
colors (list), delivery_days_min, delivery_days_max, free_shipping (boolean)."""
        },
        {"role": "user", "content": product_text}
    ],
    response_format={"type": "json_object"},
    temperature=0
)

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

Result:

{
  "name": "MacBook Pro 16-inch",
  "brand": "Apple",
  "price_eur": 2799,
  "specs": {
    "ram_gb": 24,
    "storage_gb": 512,
    "screen": "Liquid Retina XDR"
  },
  "colors": ["Space Black", "Silver"],
  "delivery_days_min": 3,
  "delivery_days_max": 5,
  "free_shipping": true
}

Notice that the brand, Apple, appears nowhere in the source text: the model inferred it from the product name. This is a strength for enrichment, but a risk to monitor if you require strictly literal extraction.

Processing Multiple Items in One Call

Nothing forces you to make one call per item. By asking the model for a list under a single key, you reduce the number of requests—and thus the cumulative latency—for short tasks like review analysis. The score requested here ranges from -1.0 to 1.0, a useful convention for aggregating results later.

texts = [
    "Excellent product, I recommend it!",
    "Late delivery, damaged product.",
    "Decent for the price, nothing exceptional."
]

response = client.chat.complete(
    model="mistral-small-latest",
    messages=[
        {
            "role": "system",
            "content": "Analyze the sentiment of each review. Return a JSON with a key 'reviews' containing a list of objects {text, sentiment, score}. The score ranges from -1.0 (very negative) to 1.0 (very positive)."
        },
        {"role": "user", "content": "\n---\n".join(texts)}
    ],
    response_format={"type": "json_object"},
    temperature=0
)

reviews = json.loads(response.choices[0].message.content)["reviews"]
for r in reviews:
    print(f"[{r['score']:+.1f}] {r['sentiment']} — {r['text'][:40]}...")

One detail common to all these examples deserves emphasis: temperature=0 is systematic here. For extraction and classification tasks, creativity adds nothing and costs reproducibility.

Key Takeaways

  • JSON Mode excels at data extraction, classification, and conversion
  • Use the system prompt to define the expected structure and types
  • temperature=0 ensures reproducible results
  • Batch processing in a single request is possible by requesting a JSON list
  • Always parse the response with json.loads() / JSON.parse() before accessing data