Structured outputs JSON : réponses LLM typées pour le DevOps
À la fin de ce tutoriel, vous comprendrez les structured outputs (JSON mode / JSON Schema), distinguerez function calling (arguments d’outils) et réponse finale typée, déclarerez un schéma strict, validerez avec Pydantic, et brancherez un digest d’incident sur un pipeline DevOps — sans parser du markdown « presque JSON ».
Niveau : Intermédiaire · Temps estimé : 50–65 min · Versions cibles : OpenAI Chat Completions
response_format/json_schema2026 · Anthropic Messages · Python 3.12 · Pydantic v2 · Dernière vérification : 2026-09-11← Précédent : Function calling / tool use · → Suivant : Prompt injection & sécurité · Hub : IA pour DevOps : parcours 2026
Prérequis
- Bases Python 3.12, JSON et JSON Schema
- Clé API lab OpenAI ou Anthropic (sandbox, budget plafonné)
- Avoir lu Function calling / tool use : tools = actions ; ici = forme de la réponse
- Hub IA pour DevOps : parcours 2026 pour le contexte série
/ia/
Objectif : obtenir un objet JSON valide et conforme à un contrat, prêt pour CI, tickets ou webhooks.
Ce que nous allons construire
Prompt + JSON Schema (strict)
│
▼
LLM (structured outputs / JSON mode)
│ JSON candidat
▼
Validation runtime (Pydantic / jsonschema)
│ OK / erreur contrôlée
▼
Pipeline DevOps (ticket, CI, runbook)
(Schéma — alt : « Structured outputs : schéma strict, LLM, validation, pipeline DevOps ».)
Le modèle reste probabiliste ; le contrat (schéma + validation) rend le résultat actionnable. Même en mode strict, gardez une validation runtime : défense en profondeur.
Étape 1 — Pourquoi le JSON libre casse les pipelines
Sans contrainte, le modèle mélange prose, fences markdown et champs inventés. Un json.loads fragile finit en incident de parsing en CI.
| Approche | Fiabilité parse | Contrat champs |
|---|---|---|
| Texte libre + regex | Faible | Aucun |
| « Réponds en JSON » (prompt seul) | Moyenne | Soft |
| JSON mode (objet JSON) | Bonne | Partiel |
Structured outputs (json_schema strict) |
Forte | Fort |
Pour DevOps Elastic Hayway 2026 : digérer une alerte, classer une sévérité, ouvrir un ticket, alimenter un step GitHub Actions — tout exige enums et champs required.
Étape 2 — Function calling vs structured outputs
- Function calling (leçon 46) : appels d’outils (
name+arguments) exécutés par votre runtime. - Structured outputs : réponse finale conforme à un JSON Schema. Pas d’exécution d’outil requise.
Les deux s’empilent : tools pour lire CloudWatch / kubectl, puis structured output pour le digest typé. Les tool schemas et response schemas partagent JSON Schema — réutilisez enums et $defs.
Étape 3 — OpenAI : response_format + json_schema strict
import json
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
INCIDENT_SCHEMA = {
"type": "object",
"properties": {
"title": {"type": "string", "minLength": 5, "maxLength": 120},
"severity": {
"type": "string",
"enum": ["sev1", "sev2", "sev3", "sev4"],
},
"service": {"type": "string"},
"region": {
"type": "string",
"description": "Région AWS, ex. ca-central-1",
},
"summary": {"type": "string"},
"recommended_actions": {
"type": "array",
"items": {"type": "string"},
"minItems": 1,
"maxItems": 8,
},
"needs_human": {"type": "boolean"},
},
"required": [
"title", "severity", "service", "region",
"summary", "recommended_actions", "needs_human",
],
"additionalProperties": False,
}
resp = client.chat.completions.create(
model="gpt-4.1-mini",
messages=[
{
"role": "system",
"content": (
"Tu es un SRE. Produis uniquement le digest d'incident. "
"Ne invente pas de métriques absentes du contexte."
),
},
{
"role": "user",
"content": (
"Alerte: 5xx rate 12% sur api-gateway, "
"région ca-central-1, depuis 8 min. "
"Latency p99 2.4s. Pas de deploy récent."
),
},
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "incident_digest",
"strict": True,
"schema": INCIDENT_SCHEMA,
},
},
)
digest = json.loads(resp.choices[0].message.content)
print(digest["severity"], digest["region"], digest["needs_human"])
strict: True force la conformité ; gardez le schéma petit (tokens). Pour un estate Canada, ancrez ca-central-1 dans exemples et enums région.
Étape 4 — Claude / Anthropic : même contrat
Chez Anthropic, le pattern 2026 : déclarer un schéma, obtenir du JSON contraint, parser. Selon le SDK, schéma dédié ou outil forcé emit_incident_digest (même input_schema que les tools).
# Pseudocode Anthropic — contrat conceptuel 2026
# 1) Fournir le JSON Schema (ou tool dédié)
# 2) Recevoir un JSON (texte ou tool_use forcé)
# 3) json.loads + validation Pydantic — identique à OpenAI
incident_schema = {
"type": "object",
"properties": {
"title": {"type": "string"},
"severity": {"type": "string", "enum": ["sev1", "sev2", "sev3", "sev4"]},
"service": {"type": "string"},
"region": {"type": "string"},
"summary": {"type": "string"},
"recommended_actions": {"type": "array", "items": {"type": "string"}},
"needs_human": {"type": "boolean"},
},
"required": [
"title", "severity", "service", "region",
"summary", "recommended_actions", "needs_human",
],
"additionalProperties": False,
}
Stack multi-fournisseurs (OpenAI + Claude + Vercel AI SDK) : un seul schemas/incident_digest.json. Voir Claude API : premiers appels.
Étape 5 — JSON Schema utile en DevOps
- Enums pour severity, env (
dev/staging/prod). additionalProperties: falsecontre les champs fantômes.requiredexhaustif en mode strict OpenAI.- Bornes
minLength/maxItemspour éviter les pavés. - Descriptions courtes ; jamais de secrets dedans.
- Types simples — évitez
oneOfexotiques si le strict les refuse.
| Objet | Usage pipeline |
|---|---|
IncidentDigest |
Ticket + Slack |
CiFailureSummary |
Commentaire PR |
KubectlHealthReport |
Gate deploy |
CostAnomaly |
Alerte FinOps |
Exemple estate multi-compte : le digest inclut region (ca-central-1) et service pour router l’alerte vers la bonne équipe on-call et le bon board. Sans ces champs typés, un bot Slack « libre » envoie le même pavé à tout le monde.
Étape 6 — Validation runtime (Pydantic v2)
from pydantic import BaseModel, Field, ValidationError
from typing import Literal
class IncidentDigest(BaseModel):
title: str = Field(min_length=5, max_length=120)
severity: Literal["sev1", "sev2", "sev3", "sev4"]
service: str
region: str
summary: str
recommended_actions: list[str] = Field(min_length=1, max_length=8)
needs_human: bool
def parse_digest(raw: str) -> IncidentDigest:
try:
return IncidentDigest.model_validate_json(raw)
except ValidationError as exc:
raise RuntimeError(f"digest_invalid: {exc}") from exc
En CI : fixtures golden. En prod : métrique llm_structured_parse_fail_total.
Étape 7 — Lab : digest d’incident → ticket
But : texte d’alerte → IncidentDigest valide → ticket simulé.
OPENAI_API_KEYou stub du client en tests.- Schéma Étape 3 +
parse_digest. - Si
needs_humanouseverity in {"sev1","sev2"}→ ticket + page, pas d’auto-remediation. Tracez la décision dans l’audit (severity,needs_human, timestamp). - Sinon,
recommended_actionsen commentaire CI seulement (pas dekubectlauto). - Logs :
model,region,severity, latence ; redactez PII. - Région lab :
ca-central-1.
Checklist lab :
- Budget API plafonné ; modèle mini.
- Schéma unique versionné (
schemas/incident_digest.json). - Afficher le JSON brut avant tout ticket réel.
- Contexte pauvre →
needs_human: true. - Stub JSON incomplet → erreur contrôlée.
- Publish HOLD : pas de page WordPress live.
Étape 8 — Coût, tokens et pièges
Les schémas comptent en tokens d’entrée : descriptions courtes, un seul blob (pas system + response_format en double).
Pièges : valeurs hallucinées malgré des clés contraintes ; schéma trop large ; fallback JSON mode sans validation ; secrets dans les descriptions ; confusion tools vs réponse (leçon 46).
Attaques via logs/tickets : Prompt injection & sécurité. Outils avant digest : Function calling, MCP DevOps, ChatGPT Actions.
Compléments opérationnels
Standard de brief réutilisable
Pour ai-structured-outputs, adoptez un brief unique partagé par l’équipe. Il contient toujours cinq champs : objectif mesurable, contexte borné (lab/staging), liste blanche de fichiers ou ressources, interdits explicites (secrets, réseau, prod), et definition of done exécutable (commande de test ou checklist). Sans ces champs, l’outil improvisera — parfois avec élégance, souvent hors périmètre.
Stockez les briefs gagnants sous briefs/ai-structured-outputs/ dans un dépôt de documentation interne. Chaque brief cite le commit de référence et le modèle utilisé. Au troisième succès comparable, ouvrez une PR qui transforme le brief en rule, Skill ou slash command. Voir ai-skills-concept, claude-skills-instructions et evaluer-qualite-skill.
Revue de diff comme compétence P0
La vitesse d’un agent n’a aucune valeur si personne ne sait lire un diff. Instituez une règle simple : aucun apply massif sans parcours hunk par hunk. Posez-vous trois questions : ce changement est-il demandé ? est-il testé ? est-il réversible ? Si une réponse est non, refusez ou exigez un plan plus petit.
En atelier, faites commenter un diff à voix haute pendant cinq minutes. Les juniors apprennent ainsi le vocabulaire du refus. Reliez cette pratique à ai-code-review-pr et aux workflows ai-agent-workflows.
Sécurité continue
Les surfaces ai-structured-outputs multiplient les occasions d’injection et de fuite. Traitez tickets, README upstream, logs et ressources MCP comme des données non fiables. Séparez instructions et données. Allowlist tools. Confirmation humaine avant mutation. Guide : ai-prompt-injection-securite, mcp-servers-devops, claude-code-mcp.
Secrets : variables d’environnement de session, gestionnaire d’équipe, rotation, jamais de commit. Si un secret fuit dans un chat vendor, supposez-le compromis et rotatez.
Coûts, modèles et mode dégradé
Documentez un mapping fast/strong et un soft-cap mensuel dans la stack perso. OpenRouter peut aider à basculer — openrouter-multi-modeles. Le local (ollama-llm-locaux + continue-dev) sert de mode dégradé ou de bac à sable confidentialité.
Surveillez les changements silencieux de modèle par défaut : une régression de qualité est souvent un routing vendor, pas « l’équipe qui a oublié comment prompter ».
Ancrage parcours
ai-structured-outputs n’est qu’une étape du parcours IA DevOps 2026. Tronc commun d’abord (prompts, injection, skills), puis surface spécialisée, puis industrialisation (routines, MCP, RAG). Hub de navigation : /ia/. Comparatifs utiles : claude-vs-gpt-code, codex-vs-claude-code, claude-vs-cursor-vs-copilot.
Rituals hebdomadaires
Hebdo : promouvoir un brief en Skill/rule ; archiver un échec instructif ; vérifier le budget tokens. Mensuel : revoir la stack (retirer l’inutile) ; rejouer un lab gold ; mettre à jour les versions d’outils. Ces rituals valent mieux que d’ajouter un cinquième abonnement.
Exemple de NOTES.md
# NOTES ai-structured-outputs
Date:
Modèle:
Brief (résumé):
Fichiers touchés:
Commande DoD:
Refus utiles:
Commit:
Leçon:
Sans ce journal, vous réapprendrez les mêmes leçons chaque sprint. Avec ce journal, vous construisez un avantage composé d’équipe.
FAQ
Les structured outputs remplacent-ils le function calling ?
Non. Tools = actions. Structured outputs = forme de la donnée. Les agents DevOps combinent souvent les deux.
JSON mode (json_object) suffit-il ?
Pour un prototype. En pipeline : json_schema strict + Pydantic (enums, required, pas de parasites).
Le fournisseur refuse mon schéma en strict ?
Simplifiez (pas de oneOf exotiques), alignez required / additionalProperties, ou soft mode + retry. Documentez dans le README du schéma.
Même schéma OpenAI et Claude ?
Oui pour le cœur JSON Schema ; adaptez l’enveloppe SDK. Un fichier unique consommé aussi par Vercel AI SDK.
Où en CI GitHub Actions ?
Step Python après logs d’échec → artifact CiFailureSummary → commentaire PR. Secrets via OIDC / vault, jamais dans le prompt. Échec de validation = job rouge explicite (digest_invalid), pas un silent skip.
Quiz (5 questions)
1. Structured outputs servent surtout à :
– A. Exécuter kubectl dans le cloud du LLM
– B. Contraindre la forme JSON de la réponse
– C. Remplacer IAM
2. Par rapport au function calling :
– A. C’est strictement la même API
– B. Réponse typée vs appels d’outils exécutés par votre runtime
– C. Interdit Anthropic
3. strict: True + json_schema chez OpenAI vise à :
– A. Chiffrer la réponse
– B. Forcer la conformité au schéma
– C. Désactiver les tokens de sortie
4. Après réception du JSON, la bonne posture DevOps est :
– A. eval sur la string
– B. Valider (Pydantic / jsonschema) puis brancher le pipeline
– C. Ignorer additionalProperties
5. Pour un incident sev1 avec needs_human: true :
– A. Auto-remédiation silencieuse
– B. Ticket / page humaine, pas de mutation auto
– C. Coller la clé API dans le ticket
Réponses : 1‑B · 2‑B · 3‑B · 4‑B · 5‑B
Pour aller plus loin
- OpenAI — Structured Outputs
- Anthropic — Tool use / structured data
- JSON Schema · Pydantic
- Function calling / tool use (46) · Prompt injection & sécurité (48)
- Vercel AI SDK · Claude API
Maillage série IA Outils 2026 (F — Patterns)
| ← Précédent | Function calling / tool use |
| → Suivant | Prompt injection & sécurité |
| Hub | IA pour DevOps : parcours 2026 |
| Landing | Cours IA |
| Aussi | MCP · ChatGPT Actions · Vercel AI SDK · Claude API |
Conclusion
Les structured outputs JSON transforment un LLM en producteur de contrats exploitables : schéma strict, validation runtime, branchement CI/tickets, région d’exemple ca-central-1. Pattern 47/50 après function calling et avant prompt injection — socle fiable des pipelines IA sur DevOps Elastic Hayway.
Publish : HOLD — attendre le feu vert Maître avant publication WordPress.
Retour parcours IA — hub Claude, Codex, ChatGPT et Skills.