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

Extraction and Validation with Tools

Lesson 10 of 12 Updated July 30, 2026 Developer
On this page
  1. Build reliable extraction pipelines
  2. Pattern: enriched extraction
  3. Pattern: cross-validation
  4. Pattern: calculation and structuring
  5. Architecture of a robust pipeline
  6. Error handling in production
  7. Key takeaways

Build reliable extraction pipelines

By combining structured outputs with tools (web search, code execution), you can build robust extraction and validation pipelines. This lesson shows how to architect these pipelines for production use.

Pattern: enriched extraction

The most common pattern is enriching data extraction with web search. You start with raw text, and the model extracts entities then enriches them with information found online.

from pydantic import BaseModel

class EntrepriseEnrichie(BaseModel):
    nom: str
    secteur: str
    pays_siege: str
    site_web: str | None
    description_courte: str
    nombre_employes_estime: str | None
    technologies_utilisees: list[str]

class ExtractionEnrichie(BaseModel):
    entreprises: list[EntrepriseEnrichie]
    relations: list[str]
    contexte: str

response, parsed = client.chat.parse(
    model="grok-4.20-0309-reasoning",
    messages=[{
        "role": "user",
        "content": """Extract and enrich the companies mentioned in this text:

        'Mistral AI announced a partnership with Scaleway to
        host its models in France. Meanwhile, Hugging Face
        continues to collaborate with OVHcloud on open source
        infrastructure.'"""
    }],
    response_format=ExtractionEnrichie,
    tools=[{"type": "web_search"}]
)

Pattern: cross-validation

Cross-validation uses web search to verify information extracted from a document:

class FactCheck(BaseModel):
    affirmation: str
    verifie: bool
    source: str | None
    correction: str | None
    confiance: float

class RapportValidation(BaseModel):
    document_original: str
    verifications: list[FactCheck]
    fiabilite_globale: float
    resume: str

response, parsed = client.chat.parse(
    model="grok-4.20-0309-reasoning",
    messages=[{
        "role": "user",
        "content": """Verify the facts in this text:
        'France has 68 million inhabitants. Paris is the
        largest city in Europe. France's GDP is the 7th
        largest worldwide.'"""
    }],
    response_format=RapportValidation,
    tools=[{"type": "web_search"}]
)

for v in parsed.verifications:
    status = "Verified" if v.verifie else "Unverified"
    print(f"[{status}] {v.affirmation}")
    if v.correction:
        print(f"  → Correction: {v.correction}")

Pattern: calculation and structuring

Combine code execution for calculations and structured outputs for formatting:

class LigneFacture(BaseModel):
    description: str
    quantite: int
    prix_unitaire_ht: float
    montant_ht: float
    tva: float
    montant_ttc: float

class Facture(BaseModel):
    lignes: list[LigneFacture]
    total_ht: float
    total_tva: float
    total_ttc: float

response, parsed = client.chat.parse(
    model="grok-4.20-0309-reasoning",
    messages=[{
        "role": "user",
        "content": """Calculate the invoice:
        - 3x Pro License at 299 EUR excl. VAT (VAT 20%)
        - 1x Training at 1500 EUR excl. VAT (VAT 20%)
        - 12x Monthly Support at 49 EUR excl. VAT (VAT 20%)"""
    }],
    response_format=Facture,
    tools=[{"type": "code_interpreter"}]
)

print(f"Total excl. VAT: {parsed.total_ht} EUR")
print(f"Total incl. VAT: {parsed.total_ttc} EUR")

Architecture of a robust pipeline

For production use, structure your pipeline into steps:

# Step 1: Raw extraction
class ExtractionBrute(BaseModel):
    entites: list[str]
    dates: list[str]
    montants: list[str]

# Step 2: Enrichment
class EntiteEnrichie(BaseModel):
    nom: str
    type: str
    details: str

# Step 3: Validation
class ResultatValide(BaseModel):
    entites: list[EntiteEnrichie]
    score_qualite: float
    alertes: list[str]

Each step uses a separate call with a tailored schema. This modular approach simplifies debugging and monitoring.

Error handling in production

try:
    response, parsed = client.chat.parse(
        model="grok-4.20-0309-reasoning",
        messages=messages,
        response_format=MonSchema,
        tools=[{"type": "web_search"}]
    )
except Exception as e:
    # Fallback without web search
    response, parsed = client.chat.parse(
        model="grok-4.20-0309-reasoning",
        messages=messages,
        response_format=MonSchema
    )

Key takeaways

  • Enriched extraction combines web search + structured outputs for complete data
  • Cross-validation verifies facts with web search
  • Code execution ensures exact calculations in financial pipelines
  • Structure into separate steps for robustness and debugging
  • Always plan for a fallback if tools fail