Si vous construisez une application au-dessus de Gemma 4, vous avez besoin d'une sortie structurée — pas de texte libre. Vous avez besoin de JSON que vous pouvez parser, valider et injecter dans votre base de données ou API. À chaque fois, sans exception.
C'est l'une des parties les plus délicates du travail avec les LLM locaux, mais avec les bonnes techniques, Gemma 4 peut être étonnamment fiable. Passons en revue chaque méthode.
Pourquoi la sortie structurée compte
Quand vous utilisez Gemma 4 comme composant d'un système plus large — pas juste pour discuter avec — vous avez besoin d'une sortie prévisible :
# C'est ce que vous voulez :
{"sentiment": "positive", "confidence": 0.92, "topics": ["pricing", "support"]}
# Ce n'est pas ce que vous voulez :
"Le sentiment de ce texte est positif, avec une confiance d'environ 92%..."Le premier peut être parsé et utilisé de manière programmatique. Le second nécessite un autre round de parsing, ce qui ajoute de la latence, du coût et des points de défaillance.
Méthode 1 : technique du system prompt
L'approche la plus simple — dire au modèle exactement ce que vous voulez dans le system prompt :
import requests
import json
response = requests.post("http://localhost:11434/api/chat", json={
"model": "gemma4:26b",
"messages": [
{
"role": "system",
"content": """Tu es une API qui répond UNIQUEMENT en JSON.
Tu DOIS répondre avec du JSON valide et rien d'autre.
Pas de markdown, pas d'explication, pas de blocs de code — juste du JSON brut.
Schéma :
{
"sentiment": "positive" | "negative" | "neutral",
"confidence": nombre entre 0 et 1,
"topics": string[],
"summary": string (une phrase)
}"""
},
{
"role": "user",
"content": "Analyse : 'La nouvelle mise à jour est incroyable ! L'interface est tellement plus propre et tout charge plus vite. Seule plainte : le prix a augmenté.'"
}
],
"stream": False,
})
result = json.loads(response.json()["message"]["content"])
print(result)Ça fonctionne la plupart du temps. Mais « la plupart du temps » n'est pas suffisant pour la production. Le modèle pourrait occasionnellement ajouter un préambule comme « Voici le JSON : » ou encapsuler la sortie dans des blocs de code markdown.
Méthode 2 : paramètre format d'Ollama
Ollama a un paramètre format intégré qui contraint la sortie à du JSON valide :
response = requests.post("http://localhost:11434/api/chat", json={
"model": "gemma4:26b",
"messages": [
{
"role": "system",
"content": "Analyse le sentiment du texte donné. Retourne : sentiment (positive/negative/neutral), confidence (0-1), topics (liste), summary (une phrase)."
},
{
"role": "user",
"content": "Le service client était terrible mais le produit lui-même est excellent."
}
],
"format": "json",
"stream": False,
})
# C'est garanti d'être du JSON valide
result = response.json()["message"]["content"]
parsed = json.loads(result)Le flag format: "json" indique à Ollama de contraindre la génération de tokens pour ne produire que du JSON valide. C'est beaucoup plus fiable que le prompt engineering seul.
Limitation : Cela garantit une syntaxe JSON valide, mais ne garantit pas le schéma. Le modèle pourrait retourner {"answer": "positive"} au lieu de votre format attendu. Vous avez toujours besoin de validation.
Méthode 3 : définition de schéma avec Pydantic
Pour le code de production, définissez votre schéma attendu avec Pydantic et validez contre lui :
from pydantic import BaseModel, Field
from typing import Literal
import json
import requests
class SentimentResult(BaseModel):
sentiment: Literal["positive", "negative", "neutral"]
confidence: float = Field(ge=0, le=1)
topics: list[str]
summary: str
def analyze_sentiment(text: str) -> SentimentResult:
schema_str = json.dumps(SentimentResult.model_json_schema(), indent=2)
response = requests.post("http://localhost:11434/api/chat", json={
"model": "gemma4:26b",
"messages": [
{
"role": "system",
"content": f"""Réponds avec du JSON correspondant exactement à ce schéma :
{schema_str}
Aucun autre texte. Juste du JSON valide."""
},
{
"role": "user",
"content": f"Analyse ce texte : {text}"
}
],
"format": "json",
"stream": False,
})
raw = json.loads(response.json()["message"]["content"])
return SentimentResult.model_validate(raw)
# Utilisation
result = analyze_sentiment("Super produit, temps de livraison horrible.")
print(f"Sentiment : {result.sentiment} ({result.confidence:.0%})")
print(f"Sujets : {', '.join(result.topics)}")Cela vous donne la sécurité de type et la validation. Si le modèle retourne quelque chose d'inattendu, Pydantic lève une erreur claire au lieu de corrompre silencieusement vos données.
Méthode 4 : pattern de validation et retry
Pour une fiabilité maximale, ajoutez une boucle de retry :
from pydantic import BaseModel, ValidationError
import json
import requests
import time
def get_structured_output(
prompt: str,
schema_class: type[BaseModel],
model: str = "gemma4:26b",
max_retries: int = 3,
) -> BaseModel:
schema_str = json.dumps(schema_class.model_json_schema(), indent=2)
for attempt in range(max_retries):
try:
response = requests.post("http://localhost:11434/api/chat", json={
"model": model,
"messages": [
{
"role": "system",
"content": f"Réponds UNIQUEMENT avec du JSON correspondant à ce schéma :\n{schema_str}"
},
{"role": "user", "content": prompt}
],
"format": "json",
"stream": False,
"options": {
"temperature": 0.1 if attempt == 0 else 0.3,
},
})
raw = json.loads(response.json()["message"]["content"])
return schema_class.model_validate(raw)
except (json.JSONDecodeError, ValidationError) as e:
if attempt == max_retries - 1:
raise ValueError(
f"Échec d'obtention d'une sortie valide après {max_retries} tentatives : {e}"
)
time.sleep(0.5)
raise ValueError("Inaccessible")
# Utilisation
class ProductReview(BaseModel):
rating: int = Field(ge=1, le=5)
pros: list[str]
cons: list[str]
recommendation: bool
review = get_structured_output(
"Avis : 'Laptop solide, super clavier, la batterie pourrait être meilleure. 4/5, je rachèterais.'",
ProductReview,
)Choix de conception clés :
- Commencez avec une température basse (0,1) pour la cohérence, augmentez lors des retries pour la variété
- Utilisez
format: "json"pour garantir une syntaxe JSON valide - Validez avec Pydantic pour la correction du schéma
- Limitez les retries à 3 — si ça échoue 3 fois, le prompt a probablement besoin de travail
Échecs courants et solutions
Le modèle encapsule le JSON dans du markdown :
```json
{"key": "value"}
Solution : Utilisez `format: "json"` dans Ollama. Si ce n'est pas disponible, retirez le markdown :
```python
def clean_json(text: str) -> str:
text = text.strip()
if text.startswith("```"):
text = text.split("\n", 1)[1] # Retirer la première ligne
text = text.rsplit("```", 1)[0] # Retirer le dernier ```
return text.strip()Le modèle ajoute des champs supplémentaires :
Le modèle pourrait retourner des champs que vous n'avez pas demandés. Pydantic gère cela — par défaut il ignore les champs supplémentaires. Ou définissez model_config = ConfigDict(extra="forbid") pour les rejeter.
Le modèle utilise de mauvais types :
Parfois le modèle retourne "0.92" (string) au lieu de 0.92 (nombre). model_validate de Pydantic gère automatiquement la plupart des coercitions de type.
Champs vides ou nuls :
Rendez les champs optionnels quand ils pourraient être vides :
class Result(BaseModel):
name: str
email: str | None = None # Le modèle pourrait ne pas trouver d'email
topics: list[str] = [] # Par défaut liste videObjets imbriqués :
Gemma 4 gère bien le JSON imbriqué, mais gardez l'imbrication à 2-3 niveaux max :
class Address(BaseModel):
city: str
country: str
class Person(BaseModel):
name: str
age: int
address: Address # Un niveau d'imbrication — OKConseils de performance
- Température plus basse (0,1-0,3) produit un JSON plus cohérent
- Schémas plus courts obtiennent une meilleure conformité — ne demandez pas 20 champs d'un coup
- Exemples few-shot dans le system prompt améliorent dramatiquement la fiabilité
- Le modèle 26B est significativement meilleur pour le JSON que E4B — voir comparaison des modèles
- Le mode thinking aide avec les schémas complexes — voir guide du mode thinking
Prochaines étapes
- Utilisez la sortie JSON avec l'API Ollama dans vos applications
- Déployez un serveur API JSON avec vLLM + Docker
- Fine-tunez Gemma 4 pour votre format JSON spécifique
- Apprenez le mode thinking pour les tâches structurées complexes
Stop reading. Start building.
~/gemma4 $ Get hands-on with the models discussed in this guide. No deployment, no friction, 100% free playground.
Launch Playground />


