Pourquoi les agents IA ont désormais besoin de JSON Schema : du Tool Calling aux workflows structurés
Avant 2024, la plupart des « agents » tenaient en un prompt et deux ou trois fonctions. En 2026, ce n'est plus tenable : Function Calling doit décrire les paramètres, MCP enregistrer les outils, Structured Outputs contraindre les retours, A2A négocier les capacités, et le Agents SDK router sur des objets handoff. Ces couches ont évolué chacune de leur côté, mais elles retombent sur le même langage de contrat — JSON Schema. Cet article explique pourquoi il est passé de « syntaxe de validation dans la doc » au runtime de l'agent, et où poser le Schema quand on quitte un Tool Calling unique pour un workflow multi-étapes.
Aperçu
| Étape | Sans Schema | Avec Schema |
|---|---|---|
| Tool Calling unique | Les paramètres sont des chaînes, les types au hasard, un champ en trop passe encore | parameters / inputSchema interceptent avant l'appel |
| Agent multi-étapes | L'aval parse de la prose, le handoff se fie à « on a parlé de billing » | L'objet handoff porte output_type, le routage est testable |
| Réemploi inter-protocoles | Function Calling, MCP, A2A : une copie chacun, elles dérivent | Un Schema dans Git, exporté en trois adaptateurs |
Pour le dire d'emblée : JSON Schema n'est pas « de la doc pour le modèle », c'est le validateur que l'hôte de l'agent exécute avant chaque étape, à chaque handoff et à l'évaluation.
Pourquoi « désormais » besoin, et pas depuis toujours ?
Le Tool Calling des débuts tenait parce que la chaîne était courte : le modèle émettait un nom de fonction et des paramètres, l'hôte exécutait, le résultat revenait dans le dialogue. En cas d'erreur, on réessayait ; l'utilisateur voyait. Le Schema, au mieux dans un README, restait du « nice to have ».
En 2025–2026, la chaîne s'est allongée. Un agent de tickets peut classer, consulter la commande, décider d'un remboursement ou d'un transfert humain, puis passer l'objet à un autre agent. Si un saut intermédiaire n'est que « du JSON en apparence », les étapes suivantes traitent l'erreur comme un fait. Le Schema passe alors de la documentation à un sas runtime : ça ne passe pas, on n'avance pas.
Une autre pression vient de la couche protocole. Dans MCP Tool Schema vs Function Calling, nous l'avons déjà dit : les API vendeurs utilisent parameters, MCP utilise inputSchema. A2A Extensions inscrit encore les capacités dans l'Agent Card. Les trois protocoles ne partagent pas de runtime, mais tous reconnaissent un sous-ensemble JSON Schema. Si vous ne figez pas le Schema dès le départ, vous maintiendrez trois définitions « presque identiques », puis découvrirez à la troisième semaine que order_id est string ici et number là.
Les prévisions DevDay 2026 le disent plus net : Structured Outputs, Function Calling et le runtime agent se referment sur le même tuyau JSON. Le Schema en est le calibre. Sans calibre fixé, quel que soit le protocole branché ensuite, ça fuit.
Tool Calling a déjà l'air « structuré » — où est le trou ?
Dans tools[] de Function Calling, il y a déjà un parameters qui ressemble à un Schema. Beaucoup d'équipes en concluent « nous sommes déjà structurés ». En production, les vrais incidents tombent souvent dans les quatre cas suivants.
Premier : arguments reste une chaîne. Le modèle renvoie :
{
"tool_calls": [{
"id": "call_8f2a",
"type": "function",
"function": {
"name": "create_refund",
"arguments": "{\"order_id\":\"A-1042\",\"amount\":\"99.00\",\"reason\":\"late\"}"
}
}]
}
L'hôte doit encore faire un JSON.parse. amount est-il une chaîne ou un nombre, reason est-il dans l'énumération, le note en trop peut-il entrer dans le système de facturation — si parameters n'est pas appliqué côté hôte, tout dépend de « l'humeur du modèle aujourd'hui ». Écrire le Schema ne l'active pas tout seul ; strict: true ne contraint que le côté modèle, l'hôte doit encore valider.
Deuxième : le résultat d'outil n'a pas de Schema. role: tool est le plus souvent une chaîne libre. L'étape suivante « comprend » à nouveau ce texte. Succès de requête, stock à 0, droits insuffisants : si les trois formes diffèrent, le workflow multi-étapes forkera au troisième saut vers la mauvaise branche.
Troisième : des types trop larges perdent tout pouvoir de filtre. Un priority en type: string seulement, et le modèle peut sortir "urgent!!!". Un Schema sans enum, required, additionalProperties: false n'est qu'un commentaire.
Quatrième : un succès unique masque l'échec du workflow. Au premier pas, lookup_order renvoie un status: "ok" de trop ; au second, l'agent de remboursement prend status pour l'état de commande. Un parcours local sans accroc ne le montre pas ; ça explose dans le jeu de régression. C'est là la valeur du Schema : il transforme « l'objet que ce saut peut passer au suivant » en assertion testable, pas en historique de conversation.
Pour déboguer ce JSON imbriqué, formatez et contrôlez la syntaxe en local, puis faites un Diff avec la définition qui tournait la semaine dernière. Ne collez pas une réponse d'outil contenant données utilisateur ou secrets sur un site JSON public.
JSON Schema a en réalité quatre rôles dans un agent
Réduire le Schema à « la notice des paramètres d'outil » fait manquer les trois couches qui grandissent vraiment en 2026. Le tableau complet :
- Entrée d'outil.
parametersde Function Calling,inputSchemade MCP. Décide ce que le modèle « peut demander ». - Sortie d'outil. Objets renvoyés par les lectures, écritures, API externes. Décide ce que le saut suivant « peut croire ». C'est la couche la plus souvent absente aujourd'hui.
- Handoff d'agent. Résultat de classification, intention, confiance, destinataire. Dans le Agents SDK, c'est le critère de routage, pas un résumé de chat.
- État de workflow et évaluation. Points de contrôle, traces, fixtures d'eval. Un travail long doit se reprendre depuis du JSON, pas en devinant l'avancement dans l'historique.
Exemple de Schema d'entrée (outil de remboursement) :
{
"$id": "https://example.com/schemas/tools/create_refund.json",
"type": "object",
"properties": {
"order_id": { "type": "string", "pattern": "^A-[0-9]{4,}$" },
"amount": { "type": "number", "exclusiveMinimum": 0 },
"reason": { "type": "string", "enum": ["late", "damaged", "duplicate", "other"] }
},
"required": ["order_id", "amount", "reason"],
"additionalProperties": false
}
Exemple de Schema de handoff (triage → facturation) :
{
"$id": "https://example.com/schemas/handoffs/triage_to_billing.json",
"type": "object",
"properties": {
"intent": { "type": "string", "enum": ["refund", "exchange", "human"] },
"order_id": { "type": "string" },
"confidence": { "type": "number", "minimum": 0, "maximum": 1 },
"from": { "const": "triage" },
"to": { "const": "billing_agent" }
},
"required": ["intent", "order_id", "confidence", "from", "to"],
"additionalProperties": false
}
Les points communs des deux fichiers importent plus que les différences : objets, énumérations, champs en trop interdits, versionnables dans Git, exécutables en CI par ajv (ou un équivalent). Changement d'instantané modèle, passage MCP ou Function Calling : le validateur ne se réécrit pas. Pour les mots-clés, voir le tutoriel JSON Schema.
De l'appel unique au workflow structuré : où le Schema pose des portes
Un Tool Calling unique n'a qu'une porte : les paramètres sont-ils valides. Un workflow d'agent structuré en a au moins quatre.
Porte 1 : avant de choisir l'outil. Au-delà de dix outils, fourrer tout le Schema dans une requête coûte cher et multiplie les mauvais choix. Quand on recherche puis appelle, le résultat de recherche doit lui-même être une short-list schématisée, pas une présentation d'outils générée par le modèle.
Porte 2 : avant d'exécuter. parse → validate → execute. Si validate échoue, renvoyer une erreur structurée (champ manquant, type faux, hors enum), ne pas jeter la chaîne brute au saut suivant. Cette étape bloque aussi les clés extra de type injection de prompt.
Porte 3 : avant le handoff. Le triage doit remettre un objet conforme au Schema de handoff, sinon billing ne démarre pas. La condition de routage s'écrit intent === "refund" && confidence >= 0.8, pas « le mot remboursement est apparu dans la réponse ».
Porte 4 : reprise et évaluation. Les longs travaux écrivent les points de contrôle en JSON valide :
{
"run_id": "run_20260903_014",
"step": "await_refund_ack",
"state": {
"order_id": "A-1042",
"intent": "refund",
"amount": 99.0
},
"schema": "https://example.com/schemas/state/refund_flow.json"
}
Le jeu d'évaluation est le même type d'objet : entrée donnée, on affirme que la sortie passe le Schema et que les champs clés sont égaux. Quand l'agent « a empiré », Diff d'abord Schema et fixtures de cette semaine et de la précédente, avant de soupçonner le modèle. Beaucoup d'incidents viennent d'un required en trop, ou d'une valeur enum en moins.
Un Schema, comment le servir à Function Calling, MCP et A2A
Que la couche protocole n'écrive pas chacun de son côté. La direction recommandée : un fichier de spécification, trois projections :
| Protocole | Où tombe le Schema | Comment exporter depuis le même fichier |
|---|---|---|
| Function Calling | function.parameters |
Copier type/properties/required, activer strict |
| MCP | inputSchema |
Le même objet, partie de tools/list |
| Structured Outputs | text.format.json_schema |
Handoff / réponse finale : la même définition d'objet |
| A2A | Agent Card / Extension metadata | La déclaration de capacité externe référence le même $id |
À la projection, attention aux écarts de sous-ensemble : le mode strict des vendeurs exige souvent que toute property soit dans required, et désactive une partie de oneOf / $ref. Le fichier de spec peut rester plus complet ; l'exporteur taille selon la cible, et la CI fait un Diff de structure « spec vs projection » pour éviter une retouche manuelle d'un seul côté.
MCP gère l'offre d'outils, Function Calling la façon dont le modèle exprime l'intention d'appel, A2A la découverte et la négociation entre agents. Le Schema ne remplace pas ces trois couches : c'est leur dictionnaire de champs commun. Même conclusion que les deux articles précédents, sauf que le « dictionnaire » devient un fichier dans le dépôt.
Mise en œuvre : traiter JSON Schema comme source unique de vérité
Des gestes immédiats, qui ne dépendent d'aucune keynote :
- Dans le dépôt :
schemas/tools/,schemas/handoffs/,schemas/state/. Chaque fichier a un$idstable et une version. - Exporter par script les trois adaptations Function Calling / MCP / Structured Outputs ; interdiction de retoucher les champs à la main dans les fichiers d'adaptation.
- La CI valide avec ajv (ou équivalent) : payloads d'exemple, fixtures historiques, échantillons de prod (après anonymisation) doivent passer le Schema courant.
- Nouveaux outils :
additionalProperties: falseetenumexplicite par défaut. Pour une extension ouverte, un objetmetadataà part — ne pas élargir la racine. - Au-delà de dix outils, ajouter routage ou recherche ; ne pas verser tout le catalogue dans une requête.
- L'hôte accepte
argumentsen chaîne ou en objet, pour qu'un resserrement de type côté vendeur ne fasse pas alerter tout le site. - Les payloads à secrets ou données utilisateur se regardent uniquement en local dans le navigateur : formater, Diff, zéro envoi.
Le catalogue peut rester mince. L'essentiel : d'abord le fichier, ensuite le prompt. « Merci de renvoyer du JSON » dans un prompt ne peut pas échouer en CI ; un Schema, si.
Pièges fréquents
- Croire que coller le Schema dans le prompt système suffit. Contrainte côté modèle et validation côté hôte sont deux choses. Sans validation hôte, dès que
strictest coupé ou que l'instantané change, le contrat disparaît. - Valider seulement l'entrée, pas la sortie ni le handoff. Les incidents d'agents multi-étapes naissent surtout de « l'étape d'avant a renvoyé une forme inattendue ».
- Écrire à la main un Schema « à peu près pareil » par protocole. À la troisième semaine, ça diverge. Exportez, ne copiez pas.
- Fuir le design derrière un
type: objecttrop large. Un objet ouvert, c'est aucune porte. Pour vraiment étendre : un numéro de version ou unmetadataexplicite. - Traiter le Schema comme corpus d'entraînement du modèle. Il est d'abord pour le validateur et les tests. Une description claire aide à choisir l'outil ; elle ne remplace pas
enumetrequired. - Changer les champs dans un orchestrateur visuel sans réécrire Git. Les nœuds de la toile ne sont pas la source de vérité. Exportez d'abord le Schema, puis faites lire le fichier à la toile.
FAQ
Peut-on mettre Tool Calling en production sans Schema ?
Un prototype, oui. Outils fixes, moins de trois étapes, échecs visibles par un humain : les paramètres en chaîne suffisent souvent. Dès qu'apparaissent des branches, des retries automatiques ou un second agent, les erreurs sans Schema se propagent en silence.
JSON Schema sera-t-il remplacé par Structured Outputs ou MCP ?
Non. Ce sont des couches qui consomment le Schema, pas un autre système de types. La tendance 2026 : davantage de protocoles référencent le même Schema, plutôt que d'inventer un nouveau langage de champs.
Faut-il draft-07 ou 2020-12 ?
Suivez votre bibliothèque de validation et le sous-ensemble vendeur. Ce dont un agent se sert vraiment : type, properties, required, enum, additionalProperties. Un sous-ensemble aligné entre CI et API modèle compte plus que le dernier draft.
API interne privée : faut-il encore MCP et A2A ?
Pas forcément. Une boucle interne tient avec Function Calling + Schema. L'intérêt de réserver MCP / A2A : une fois le même Schema dans le dépôt, brancher un protocole plus tard n'est qu'un exporteur de plus, sans réinventer les champs.
Comment déboguer un JSON d'outil / de handoff qui échoue ?
Formatez en local dans le navigateur, voyez quel required manque face au Schema, puis Diff avec la version précédente. JSONSort n'envoie rien. Ne collez pas une réponse à secrets sur un site public.
Conclusion
Les agents IA ont « désormais » besoin de JSON Schema, non parce que le modèle cesserait soudain de lire le naturel, mais parce que les workflows s'allongent, les protocoles se multiplient, et les erreurs doivent être arrêtées côté hôte. Tool Calling donne l'intention d'appel ; Structured Outputs, l'objet final ; MCP et A2A, l'offre et la négociation. Ce qui colle ces couches : le jeu de fichiers Schema du dépôt, validables, diffables, exportables.
Dès aujourd'hui, plutôt qu'un prompt plus long, écrivez d'abord schemas/tools/create_refund.json. Les modèles changeront, les protocoles aussi ; le calibre, lui, doit d'abord tenir.
Pour aller plus loin
- Qu'est-ce que JSON Schema ? Usage et tutoriel Mots-clés, required et additionalProperties
- MCP Tool Schema vs Function Calling Frontière de protocole du JSON d'outils
- A2A Extensions et le protocole JSON Troisième couche d'interop multi-agents
- Prévisions OpenAI DevDay 2026 Comment les trois couches se referment sur un tuyau JSON
- Boîte à outils locale JSONSort Formater, valider, Diff
- Tous les articles Plus de notes JSON et développement IA
Journal : première version