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 :
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
| Aspect | Sans strict | Avec strict: true |
|---|---|---|
| Champs requis | Généralement présents | Toujours présents |
| Types corrects | Presque toujours | Toujours corrects |
| Valeurs enum | Parfois hors liste | Toujours dans la liste |
| Champs extra | Possibles | Jamais 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"}]
)
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
| Valeur | Comportement |
|---|---|
{"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}]
)
Avantages du Tool Search
| Sans Tool Search | Avec Tool Search |
|---|---|
| 200 définitions × ~200 tokens = 40K tokens | Description 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ête | Coût réduit de ~90% |
| Latence accrue | Latence 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
- →Toujours utiliser
strict: truepour les outils de sortie structurée - →Toujours spécifier
requiredpour les champs obligatoires - →Utiliser
enumpour les valeurs à choix contraint - →Forcer l'outil avec
tool_choicequand la sortie structurée est le but principal - →Descriptions claires et concises — elles guident Claude autant que le schéma
- →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égie | Impact |
|---|---|
| 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 minimalistes | Moins de tokens, résultats identiques |
| Réutiliser les conversations | Cache 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é
| Concept | Point clé |
|---|---|
strict: true | Garantit la conformité JSON au schéma — aucune erreur de parsing |
tool_choice forcé | Force Claude à utiliser un outil spécifique |
| Outils client | Vous exécutez l'outil — contrôle total |
| Outils serveur | L'API exécute (web_search, code_execution) |
| Tool search | Réduit les tokens de ~90% pour 100+ outils |
enum + required | Contraignent les valeurs et garantissent les champs |
| Prompt caching | Ré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
- →Tool Use avec Claude : Guide Complet — Outils intégrés et custom
- →Sortie JSON Fiable des LLM — Techniques complémentaires
- →Pourquoi les Sorties Structurées Comptent — Contexte et motivations
- →Architecture d'Agents Claude — Patterns pour systèmes complexes
- →Guide Complet de l'API Claude — Référence API complète
Weekly AI Insights
Tools, techniques & news — curated for AI practitioners. Free, no spam.
Free, no spam. Unsubscribe anytime.
→Related Articles
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.