Comparaison des sorties structurées chez les principaux fournisseurs de LLM - OpenAI, Gemini, Anthropic, Mistral et AWS Bedrock
Des API légèrement différentes nécessitent une approche particulière.
Voici une comparaison côte à côte du support de la sortie structurée (obtention de JSON fiable) chez les principaux fournisseurs de LLM, ainsi que des exemples Python minimaux.

Nous avons déjà examiné comment demander une sortie structurée au LLM hébergé sur Ollama. Une fois le JSON récupéré, la validation de la sortie structurée des LLM en Python qui tient la route passe en revue l’analyse (parsing), les vérifications Pydantic, les tentatives (retries) et les tests dans votre service. Ici, nous examinons comment demander la même chose aux autres fournisseurs.
Matrice TL;DR
| Fournisseur | Mode « JSON » natif | Application du schéma JSON | Paramètre typique | Remarques |
|---|---|---|---|---|
| OpenAI | Oui | Oui (première classe) | response_format={"type":"json_schema", ...} |
Fonctionne via l’API Responses ou Chat Completions ; peut également utiliser l’appel de fonction. |
| Google Gemini | Oui | Oui (première classe) | response_schema= + response_mime_type="application/json" |
Retourne un JSON strictement validé lorsque le schéma est défini. |
| Anthropic (Claude) | Indirect | Oui (via Tool Use avec schéma JSON) | tools=[{input_schema=...}] + tool_choice |
Force le modèle à « appeler » votre outil défini par le schéma ; fournit des arguments conformes au schéma. |
| Mistral | Oui | Partielle (JSON uniquement ; pas de schéma côté serveur) | response_format={"type":"json_object"} |
Garantit le JSON, mais vous devez valider selon votre schéma côté client. |
| AWS Bedrock (plateforme) | Varie selon le modèle | Oui (via schéma Tool/Converse) | toolConfig.tools[].toolSpec.inputSchema |
L’API Converse de Bedrock valide l’entrée de l’outil selon un schéma JSON. |
Sortie structurée des LLM - Informations générales
La sortie structurée des LLM fait référence à la capacité des grands modèles de langage (LLMs) à générer des réponses qui respectent strictement un format ou une structure prédéfinis, plutôt que de produire du texte libre. Cette sortie structurée peut être dans des formats tels que JSON, XML, tableaux ou modèles, rendant les données lisibles par machine, cohérentes et facilement analysables par les logiciels pour une utilisation dans diverses applications.
Les sorties structurées diffèrent des sorties traditionnelles des LLM, qui génèrent généralement du texte en langage naturel ouvert. Au lieu de cela, les sorties structurées imposent un schéma ou un format, tel que des objets JSON avec des clés et des types de valeurs définis, ou des classes spécifiques dans la sortie (par exemple, des réponses à choix multiples, des classes de sentiment ou des formats de lignes de base de données). Cette approche améliore la fiabilité, réduit les erreurs et les hallucinations, et simplifie l’intégration dans des systèmes tels que des bases de données, des API ou des flux de travail.
La génération de sorties structurées dans les LLM implique souvent des techniques telles que :
- La spécification d’instructions de prompt détaillées pour guider le modèle afin de produire une sortie dans le format souhaité.
- L’utilisation d’outils de validation et d’analyse comme Pydantic en Python pour s’assurer que la sortie correspond au schéma.
- Parfois, l’imposition de contraintes de décodage basées sur la grammaire ou les automates à états finis pour assurer la conformité au niveau des tokens avec le format.
Les avantages des sorties structurées des LLM incluent :
- Lisibilité par machine et facilité d’intégration.
- Réduction de la variabilité et des erreurs.
- Amélioration de la prédictibilité et de la vérifiabilité pour les tâches nécessitant des formats de données cohérents.
Les défis incluent la conception de schémas efficaces, la gestion de données imbriquées complexes et les limitations potentielles en termes de capacités de raisonnement par rapport à la génération de texte libre.
Dans l’ensemble, la sortie structurée permet aux LLM d’être plus utiles dans les applications nécessitant des données précises et formatées plutôt que du texte simplement lisible par l’homme.
Exemples Python de sortie structurée
Tous les extraits extraient les informations de l’événement en JSON : {title, date, location}. Remplacez les clés/modèles selon vos besoins.
1) OpenAI — Schéma JSON (strict)
from openai import OpenAI
import json
client = OpenAI()
schema = {
"name": "Event",
"schema": {
"type": "object",
"properties": {
"title": {"type": "string"},
"date": {"type": "string", "description": "YYYY-MM-DD"},
"location": {"type": "string"}
},
"required": ["title", "date", "location"],
"additionalProperties": False
},
"strict": True
}
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}
],
response_format={"type": "json_schema", "json_schema": schema},
)
data = json.loads(resp.choices[0].message.content)
print(data)
La fonction Structured Outputs d’OpenAI applique ce schéma côté serveur.
2) Google Gemini — Schéma de réponse + MIME JSON
import google.generativeai as genai
from google.genai import types
# Configure with your API key
# genai.configure(api_key="your-api-key")
schema = types.Schema(
type=types.Type.OBJECT,
properties={
"title": types.Schema(type=types.Type.STRING),
"date": types.Schema(type=types.Type.STRING),
"location": types.Schema(type=types.Type.STRING),
},
required=["title", "date", "location"],
additional_properties=False,
)
resp = genai.generate_content(
model="gemini-2.0-flash",
contents="Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'",
generation_config=genai.GenerationConfig(
response_mime_type="application/json",
response_schema=schema,
),
)
print(resp.text) # already valid JSON per schema
Gemini retournera un JSON strict conforme à response_schema.
3) Anthropic (Claude) — Utilisation d’outils avec schéma JSON
from anthropic import Anthropic
import json
client = Anthropic()
tool = {
"name": "extract_event",
"description": "Return event details.",
"input_schema": {
"type": "object",
"properties": {
"title": {"type": "string"},
"date": {"type": "string"},
"location": {"type": "string"}
},
"required": ["title", "date", "location"],
"additionalProperties": False
}
}
msg = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=256,
tools=[tool],
tool_choice={"type": "tool", "name": "extract_event"}, # force schema
messages=[{"role": "user", "content":
"Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
)
# Claude will "call" the tool; grab the args (which match your schema)
tool_use = next(b for b in msg.content if b.type == "tool_use")
print(json.dumps(tool_use.input, indent=2))
Claude n’a pas de bascule générique « mode JSON » ; au lieu de cela, l’utilisation d’outils (Tool Use) avec un input_schema vous donne des arguments validés et conformes au schéma (et vous pouvez forcer son utilisation).
4) Mistral — Mode JSON (validation côté client)
from mistralai import Mistral
import json
client = Mistral()
resp = client.chat.complete(
model="mistral-large-latest",
messages=[{"role":"user","content":
"Return JSON with keys title, date (YYYY-MM-DD), location for: "
"'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
response_format={"type": "json_object"} # guarantees valid JSON
)
data = json.loads(resp.choices[0].message.content)
print(data)
# Tip: validate `data` against your Pydantic/JSON Schema locally.
Le json_object de Mistral impose la forme JSON (pas votre schéma exact) — validez côté client.
5) AWS Bedrock — Schéma d’outil API Converse (indépendant du modèle)
import boto3, json
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
model_id = "anthropic.claude-3-5-sonnet-20240620-v1:0"
tools = [{
"toolSpec": {
"name": "extract_event",
"inputSchema": {
"json": {
"type": "object",
"properties": {
"title": {"type": "string"},
"date": {"type": "string"},
"location": {"type": "string"}
},
"required": ["title","date","location"],
"additionalProperties": False
}
}
}
}]
resp = bedrock.converse(
modelId=model_id,
toolConfig={"tools": tools},
toolChoice={"tool": {"name": "extract_event"}}, # force schema
messages=[{"role":"user","content":[{"text":
"Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}]}],
)
# Pull toolUse content
tool_use = next(
c["toolUse"] for c in resp["output"]["message"]["content"] if "toolUse" in c
)
print(json.dumps(tool_use["input"], indent=2))
Bedrock valide l’entrée de l’outil selon votre schéma JSON et de nombreux modèles hébergés (par exemple, Claude) le supportent via Converse.
Conseils pratiques et validation
- Si vous souhaitez les garanties les plus fortes côté serveur : sorties structurées OpenAI ou schéma de réponse Gemini.
- Si vous utilisez déjà Claude/Bedrock : définissez un outil avec un schéma JSON et forcez son utilisation ; lisez les arguments de l’outil en tant qu’objet typé.
- Si vous utilisez Mistral : activez
json_objectet validez localement (par exemple, avec Pydantic).
Motif de validation (fonctionne pour tous)
from pydantic import BaseModel, ValidationError
class Event(BaseModel):
title: str
date: str
location: str
try:
event = Event.model_validate(data) # `data` from any provider
except ValidationError as e:
# handle / retry / ask model to fix with e.errors()
print(e)
Liens utiles
- https://platform.openai.com/docs/guides/structured-outputs
- https://ai.google.dev/gemini-api/docs/structured-output
- https://docs.mistral.ai/capabilities/structured-output/json_mode/
- https://aws.amazon.com/blogs/machine-learning/structured-data-response-with-amazon-bedrock-prompt-engineering-and-tool-use
- https://github.com/aws-samples/anthropic-on-aws/blob/main/complex-schema-tool-use/README.md
- https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html
- Comment demander une sortie structurée au LLM hébergé sur Ollama
- Python Cheatsheet
- AWS SAM + AWS SQS + Python PowerTools
- Comparaison des performances AWS Lambda : JavaScript vs Python vs Golang