Skip to main content
Lesson 11 of 12 · Structured JSON Outputs

Entity Extraction and Classification

Lesson 11 of 12 Updated July 30, 2026 Developer
On this page
  1. Core use cases
  2. Named entity extraction
  3. Content classification
  4. Multi-label classification
  5. Tabular data extraction
  6. Granular sentiment analysis
  7. Key takeaways

Core use cases

Structured outputs shine in two categories of tasks: extracting information from unstructured text, and classifying content. These two use cases are central to most enterprise AI applications.

Named entity extraction

Entity extraction involves identifying and categorizing key elements in a text: people, companies, locations, dates, amounts, and so on.

from pydantic import BaseModel
from typing import Literal

class Entite(BaseModel):
    texte: str
    type: Literal[
        "person", "company", "location",
        "date", "amount", "product"
    ]
    contexte: str

class ExtractionEntites(BaseModel):
    entites: list[Entite]
    nombre_total: int
    langue_detectee: str

response, parsed = client.chat.parse(
    model="grok-4.20-0309-reasoning",
    messages=[{
        "role": "user",
        "content": """Extract all entities from this text:

        On March 15, 2026, Mistral AI raised €600 million
        from General Catalyst. Arthur Mensch, the CEO based in
        Paris, plans to launch Mistral Large 3 by June."""
    }],
    response_format=ExtractionEntites
)

for e in parsed.entites:
    print(f"[{e.type}] {e.texte} — {e.contexte}")

Content classification

Classification assigns predefined categories to content. Structured outputs guarantee that the model returns only valid categories.

class ClassificationEmail(BaseModel):
    categorie: Literal[
        "sales", "support", "billing",
        "partnership", "application", "spam", "other"
    ]
    sous_categorie: str
    priorite: Literal["low", "medium", "high", "urgent"]
    sentiment: Literal["positive", "neutral", "negative"]
    action_requise: bool
    resume: str

response, parsed = client.chat.parse(
    model="grok-4.20-0309-reasoning",
    messages=[{
        "role": "user",
        "content": """Classify this email:

        Subject: Urgent billing issue

        Hello, our latest invoice #2847 contains an error.
        The amount shown is €3,500 instead of the agreed €2,800.
        Please correct this quickly."""
    }],
    response_format=ClassificationEmail
)

print(f"Category: {parsed.categorie}")      # "billing"
print(f"Priority: {parsed.priorite}")        # "high"
print(f"Action required: {parsed.action_requise}")  # True

Multi-label classification

When content can belong to multiple categories:

class ClassificationArticle(BaseModel):
    titre: str
    themes: list[str]
    audience_cible: list[Literal[
        "developers", "managers", "data_scientists",
        "designers", "executives", "general_public"
    ]]
    niveau_technique: Literal["beginner", "intermediate", "advanced"]
    mots_cles_seo: list[str]
    temps_lecture_minutes: int

Tabular data extraction

Transform text into actionable structured data:

class LigneCommande(BaseModel):
    reference: str
    designation: str
    quantite: int
    prix_unitaire: float
    montant_total: float

class BonCommande(BaseModel):
    numero: str
    date: str
    fournisseur: str
    lignes: list[LigneCommande]
    montant_ht: float
    tva: float
    montant_ttc: float

response, parsed = client.chat.parse(
    model="grok-4.20-0309-reasoning",
    messages=[{
        "role": "user",
        "content": """Extract data from this purchase order:

        PO-2026-0847 dated 03/28/2026 — Supplier: TechParts SAS

        REF-001 | USB-C Cable 2m | x50 | €3.20
        REF-002 | HDMI Adapter | x20 | €12.50
        REF-003 | 4-port USB Hub | x10 | €24.90"""
    }],
    response_format=BonCommande
)

Granular sentiment analysis

Beyond simple positive/negative, structure a complete analysis:

class AspectSentiment(BaseModel):
    aspect: str
    sentiment: Literal["very_positive", "positive", "neutral", "negative", "very_negative"]
    mention: str

class AnalyseAvis(BaseModel):
    note_globale: float
    sentiment_global: str
    aspects: list[AspectSentiment]
    points_forts: list[str]
    points_faibles: list[str]
    recommande: bool

Key takeaways

  • Entity extraction identifies people, locations, dates, and amounts in free text
  • Classification enforces predefined categories using Literal and enum
  • Multi-label classification uses lists of Literal
  • Tabular extraction transforms unstructured text into actionable data
  • Sentiment analysis can be granular with individual aspects
  • All these patterns work with parse() or response_format