Retour aux articles
14 MIN READ

Outputs Structurés avec le Mode Strict de Claude

By Learnia AI Research Team

Outputs Structurés avec le Mode Strict de Claude

📅 Dernière mise à jour : 10 mars 2026 — Couvre strict: true, JSON schema validation, outils client/serveur et tool search.

🔗 Articles liés : Tool Use avec Claude · Guide complet de l'API Claude · Sorties JSON fiables des LLM


En production, un LLM qui retourne du texte libre est un risque. Un champ manquant, un type incorrect, une clé renommée — et votre pipeline casse. Le mode strict de Claude résout ce problème : il garantit que chaque sortie respecte exactement votre schéma JSON.

Pourquoi les Outputs Structurés sont Essentiels

Quand vous intégrez Claude dans une application, vous avez besoin de données prévisibles :

  • APIs : les endpoints attendent des formats précis
  • Bases de données : les insertions nécessitent des types exacts
  • Pipelines : chaque étape consomme la sortie de la précédente
  • UI : les composants front-end attendent des structures définies

Sans structure garantie, vous devez écrire du code de validation, gérer des cas d'erreur, et espérer que le modèle ne change pas de format entre deux appels.

Pour une vue d'ensemble de pourquoi les sorties structurées sont importantes dans les systèmes d'IA, consultez notre article détaillé sur pourquoi les sorties structurées comptent.


Le Mécanisme Tool Use de Claude

Claude utilise les outils (tools) comme mécanisme principal pour produire des sorties structurées. Le flux est le suivant :

Loading diagram…

Quand vous définissez un outil avec un schéma JSON, Claude génère les paramètres dans le format exact que vous avez spécifié. C'est ce mécanisme que le mode strict renforce.

Définir un Outil de Base

import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "extract_contact",
        "description": "Extraire les informations de contact d'un texte",
        "input_schema": {
            "type": "object",
            "properties": {
                "name": {
                    "type": "string",
                    "description": "Nom complet de la personne"
                },
                "email": {
                    "type": "string",
                    "description": "Adresse email"
                },
                "phone": {
                    "type": "string",
                    "description": "Numéro de téléphone"
                }
            },
            "required": ["name", "email"]
        }
    }
]

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    tools=tools,
    messages=[{
        "role": "user",
        "content": "Contactez Marie Dupont à marie@example.com ou au 06 12 34 56 78"
    }]
)

Le Paramètre strict: true

Le mode strict est activé en ajoutant strict: true au niveau de la définition de chaque outil. Cela force Claude à produire un JSON qui passe la validation du schéma — à chaque appel, sans exception.

tools = [
    {
        "name": "analyze_sentiment",
        "description": "Analyser le sentiment d'un texte",
        "strict": True,  # ← Active le mode strict
        "input_schema": {
            "type": "object",
            "properties": {
                "sentiment": {
                    "type": "string",
                    "enum": ["positive", "negative", "neutral"]
                },
                "confidence": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                },
                "keywords": {
                    "type": "array",
                    "items": {"type": "string"}
                }
            },
            "required": ["sentiment", "confidence", "keywords"]
        }
    }
]

Ce que strict: true Garantit

AspectSans strictAvec strict: true
Champs requisGénéralement présentsToujours présents
Types correctsPresque toujoursToujours corrects
Valeurs enumParfois hors listeToujours dans la liste
Champs extraPossiblesJamais ajoutés
Parsing fiable~95-99%100% sans erreur

Patterns de Schéma JSON Avancés

Objets Imbriqués (Nested Objects)

Pour des structures complexes, imbriquez des objets dans votre schéma :

tools = [
    {
        "name": "extract_invoice",
        "description": "Extraire les données d'une facture",
        "strict": True,
        "input_schema": {
            "type": "object",
            "properties": {
                "invoice_number": {"type": "string"},
                "date": {"type": "string", "description": "Format ISO 8601"},
                "vendor": {
                    "type": "object",
                    "properties": {
                        "name": {"type": "string"},
                        "address": {"type": "string"},
                        "tax_id": {"type": "string"}
                    },
                    "required": ["name", "address"]
                },
                "line_items": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "description": {"type": "string"},
                            "quantity": {"type": "integer"},
                            "unit_price": {"type": "number"},
                            "total": {"type": "number"}
                        },
                        "required": ["description", "quantity", "unit_price", "total"]
                    }
                },
                "total_amount": {"type": "number"},
                "currency": {
                    "type": "string",
                    "enum": ["EUR", "USD", "GBP"]
                }
            },
            "required": ["invoice_number", "date", "vendor", "line_items", "total_amount", "currency"]
        }
    }
]

Enums et Catégories Contraintes

Les enum sont particulièrement puissants en mode strict — Claude ne produira jamais de valeur hors de la liste :

"priority": {
    "type": "string",
    "enum": ["critical", "high", "medium", "low"],
    "description": "Niveau de priorité du ticket"
}

Tableaux Typés

Pour des listes d'éléments avec structure garantie :

"tags": {
    "type": "array",
    "items": {
        "type": "string",
        "enum": ["bug", "feature", "improvement", "documentation"]
    },
    "description": "Tags applicables à l'issue"
}

Outils Client vs Outils Serveur

Claude supporte deux types d'outils, et les deux peuvent utiliser le mode strict :

Workflow Outil Client

C'est le pattern le plus courant pour les sorties structurées en production :

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": user_input}]
)

# Extraire le résultat structuré
for block in response.content:
    if block.type == "tool_use":
        # block.input contient le JSON validé par le schéma
        structured_data = block.input
        print(f"Outil: {block.name}")
        print(f"Données: {structured_data}")
        
        # Pas besoin de try/except pour le parsing JSON
        # En mode strict, la structure est garantie
        process_data(structured_data)

Workflow Outil Serveur (Built-in)

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=4096,
    tools=[{
        "type": "web_search_20250305",
        "name": "web_search",
        "max_uses": 3
    }],
    messages=[{"role": "user", "content": "Dernières actualités sur Claude"}]
)
Loading diagram…

Appel d'Outil Programmatique (Forcer l'utilisation)

Par défaut, Claude décide s'il utilise un outil. Pour les sorties structurées, vous voulez souvent forcer l'appel :

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "tool", "name": "extract_contact"},  # Force l'outil
    messages=[{"role": "user", "content": text}]
)

Les Options de tool_choice

ValeurComportement
{"type": "auto"}Claude décide s'il utilise un outil (défaut)
{"type": "any"}Claude doit utiliser au moins un outil
{"type": "tool", "name": "X"}Claude doit utiliser l'outil X spécifiquement
{"type": "none"}Claude ne peut utiliser aucun outil

💡 Astuce production : Utilisez tool_choice: {"type": "tool", "name": "..."} quand vous utilisez un outil comme mécanisme de sortie structurée — pas comme fonction à exécuter. C'est le pattern le plus fiable.


Tool Search : Gérer des Centaines d'Outils

Quand votre système propose plus de 100 outils, les inclure tous dans chaque requête est coûteux en tokens et réduit la précision de la sélection. Le tool search résout ce problème.

Le Principe

Au lieu d'envoyer toutes les définitions d'outils, vous envoyez une description textuelle de chaque outil. Claude sélectionne les outils pertinents, puis vous renvoyez uniquement les définitions complètes de ceux-ci.

# Étape 1 : Descriptions légères de tous les outils
tool_descriptions = """
Outils disponibles :
- get_user_profile: Récupère le profil d'un utilisateur par ID
- update_user_email: Met à jour l'email d'un utilisateur
- list_invoices: Liste les factures d'un client
- create_invoice: Crée une nouvelle facture
- send_notification: Envoie une notification push
- get_analytics: Récupère les métriques d'usage
... (200+ outils)
"""

# Étape 2 : Claude sélectionne les outils pertinents
selection_response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=512,
    messages=[{
        "role": "user",
        "content": f"Utilisateur demande : '{user_query}'\n\n{tool_descriptions}\n\nQuels outils sont nécessaires ? Réponds avec les noms uniquement."
    }]
)

# Étape 3 : Appel avec uniquement les outils sélectionnés
selected_tools = parse_tool_names(selection_response)
full_tool_defs = [t for t in all_tools if t["name"] in selected_tools]

final_response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=2048,
    tools=full_tool_defs,  # Seulement les outils pertinents
    messages=[{"role": "user", "content": user_query}]
)
Sans Tool SearchAvec Tool Search
200 définitions × ~200 tokens = 40K tokensDescription légère ~2K + 3 définitions = ~2.6K tokens
Sélection imprécise (trop de choix)Sélection ciblée et précise
Coût élevé par requêteCoût réduit de ~90%
Latence accrueLatence optimisée

Pour voir comment ce pattern s'intègre dans des architectures d'agents complexes, consultez notre guide sur les patterns d'architecture d'agents Claude.


Gestion des Erreurs et Bonnes Pratiques

Extraire les Résultats Proprement

def extract_tool_result(response):
    """Extraire le résultat structuré d'une réponse Claude avec outil."""
    for block in response.content:
        if block.type == "tool_use":
            return {
                "tool_name": block.name,
                "tool_id": block.id,
                "data": block.input  # JSON garanti valide en mode strict
            }
    return None

# Usage
result = extract_tool_result(response)
if result:
    # En mode strict, chaque champ est garanti présent et typé
    contact = result["data"]
    save_to_database(contact["name"], contact["email"])

Pattern Multi-tour (Conversation avec Outils)

messages = [{"role": "user", "content": user_query}]

while True:
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=2048,
        tools=tools,
        messages=messages
    )
    
    # Vérifier si Claude veut utiliser un outil
    if response.stop_reason == "tool_use":
        # Exécuter chaque outil demandé
        tool_results = []
        for block in response.content:
            if block.type == "tool_use":
                result = execute_tool(block.name, block.input)
                tool_results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": str(result)
                })
        
        # Ajouter la réponse de Claude et les résultats
        messages.append({"role": "assistant", "content": response.content})
        messages.append({"role": "user", "content": tool_results})
    else:
        # Réponse finale (pas d'outil)
        break

Checklist Production

  1. Toujours utiliser strict: true pour les outils de sortie structurée
  2. Toujours spécifier required pour les champs obligatoires
  3. Utiliser enum pour les valeurs à choix contraint
  4. Forcer l'outil avec tool_choice quand la sortie structurée est le but principal
  5. Descriptions claires et concises — elles guident Claude autant que le schéma
  6. Tester avec des entrées edge case (texte vide, langues mixtes, données bruitées)

Considérations de Coût

Les définitions d'outils consomment des tokens d'entrée. Voici comment optimiser :

StratégieImpact
Descriptions concises-30% de tokens par outil
Tool search pour 50+ outils-80-90% de tokens d'entrée
tool_choice forcéÉvite un tour supplémentaire
Schémas minimalistesMoins de tokens, résultats identiques
Réutiliser les conversationsCache de prompt (réduction automatique)

💡 Les définitions d'outils bénéficient du prompt caching d'Anthropic. Si vous envoyez les mêmes outils à chaque requête, le coût en tokens est automatiquement réduit après le premier appel.

Pour plus de détails sur l'API Claude et les options de tarification, consultez le Guide complet de l'API Claude.


Exemple Complet : Pipeline d'Extraction de Données

Voici un exemple production complet qui combine tous les concepts :

import anthropic
import json

client = anthropic.Anthropic()

# Définition d'outil avec mode strict
extraction_tool = {
    "name": "extract_product_review",
    "description": "Extraire les données structurées d'un avis produit",
    "strict": True,
    "input_schema": {
        "type": "object",
        "properties": {
            "product_name": {"type": "string"},
            "rating": {
                "type": "integer",
                "description": "Note de 1 à 5"
            },
            "sentiment": {
                "type": "string",
                "enum": ["very_positive", "positive", "neutral", "negative", "very_negative"]
            },
            "pros": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Points positifs mentionnés"
            },
            "cons": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Points négatifs mentionnés"
            },
            "recommendation": {"type": "boolean"},
            "summary": {
                "type": "string",
                "description": "Résumé en une phrase de l'avis"
            }
        },
        "required": [
            "product_name", "rating", "sentiment",
            "pros", "cons", "recommendation", "summary"
        ]
    }
}

def analyze_review(review_text: str) -> dict:
    """Analyser un avis produit et retourner des données structurées."""
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        tools=[extraction_tool],
        tool_choice={"type": "tool", "name": "extract_product_review"},
        messages=[{
            "role": "user",
            "content": f"Analyse cet avis produit :\n\n{review_text}"
        }]
    )
    
    for block in response.content:
        if block.type == "tool_use":
            return block.input  # Structure garantie par strict: true
    
    return None

# Utilisation
review = """
J'ai acheté le casque Sony WH-1000XM5 il y a 3 mois. La réduction de bruit
est exceptionnelle, le confort est au top et la batterie tient facilement
30 heures. Seul bémol : le prix est un peu élevé et l'étui de transport
est moins compact que le XM4. Malgré ça, je recommande à 100%.
"""

result = analyze_review(review)
print(json.dumps(result, indent=2, ensure_ascii=False))
# {
#   "product_name": "Sony WH-1000XM5",
#   "rating": 4,
#   "sentiment": "very_positive",
#   "pros": ["Réduction de bruit exceptionnelle", "Confort excellent", "Batterie 30h"],
#   "cons": ["Prix élevé", "Étui moins compact que le XM4"],
#   "recommendation": true,
#   "summary": "Excellent casque avec réduction de bruit de pointe, malgré un prix premium."
# }

Résumé

ConceptPoint clé
strict: trueGarantit la conformité JSON au schéma — aucune erreur de parsing
tool_choice forcéForce Claude à utiliser un outil spécifique
Outils clientVous exécutez l'outil — contrôle total
Outils serveurL'API exécute (web_search, code_execution)
Tool searchRéduit les tokens de ~90% pour 100+ outils
enum + requiredContraignent les valeurs et garantissent les champs
Prompt cachingRéduit automatiquement le coût des définitions d'outils répétées

Les outputs structurés avec le mode strict transforment Claude d'un générateur de texte en un moteur de données fiable. Combiné avec les patterns d'architecture d'agents et un pipeline JSON robuste, vous avez tous les outils pour construire des systèmes de production solides.


Continuez Votre Apprentissage

Newsletter

Weekly AI Insights

Tools, techniques & news — curated for AI practitioners. Free, no spam.

Free, no spam. Unsubscribe anytime.

FAQ

Qu'est-ce que le mode strict dans les outils Claude ?+

Le mode strict (strict: true) force Claude à produire des sorties JSON qui respectent exactement le schéma défini dans l'outil. Chaque champ, type et contrainte du schéma est garanti — éliminant les erreurs de parsing en production.

Quelle est la différence entre un outil client et un outil serveur ?+

Un outil client (client tool) renvoie le résultat à votre code pour exécution locale. Un outil serveur (server tool) est exécuté directement par l'API Anthropic (comme web_search ou code_execution). Les deux supportent le mode strict.

Comment gérer plus de 100 outils avec Claude ?+

Utilisez le tool search (recherche d'outils) : envoyez une description textuelle de tous vos outils et laissez Claude sélectionner les plus pertinents. Cela réduit le nombre de tokens et améliore la précision des appels.

Le mode strict a-t-il un impact sur les coûts ?+

Le mode strict lui-même n'ajoute pas de coût direct. Cependant, les définitions d'outils consomment des tokens d'entrée. Optimisez en utilisant des descriptions concises et le tool search pour les grands ensembles d'outils.