[!NOTE] Traduction automatique Cet article a été traduit automatiquement depuis la version originale en anglais.
Raisonnement guidé par un schéma sur vLLM : Structured Outputs à l’aide de xgrammar et Pydantic
Tenter à nouveau une appel LLM ne garantit pas l’obtention de JSON valide. Le prochain échantillon peut échouer de la même manière, et les appels répétés augmentent à la fois le temps de réponse et les coûts.
Le raisonnement guidé par schéma (SGR) impose le respect d’un schéma au fur et à mesure que le modèle génère chaque token. Vous définissez les champs requis à l’aide de Pydantic, et le moteur d’inférence bloque les tokens qui contreviendraient à cette structure. Ainsi, le résultat est par construction syntaxiquement valide, sans nécessiter de tentatives supplémentaires.
En résumé. SGR utilise constrained decoding afin de lier la sortie d’un LLM à un schéma Pydantic que vous contrôlez. En l’associant au xgrammar backend de vLLM, vous obtenez systématiquement des JSON valides, avec des coûts en latence négligeables.
Qu’est-ce que le raisonnement guidé par schéma ?
Le raisonnement guidé par schéma est une technique qui Rinat Abdullin Rédigé en 2024. Au lieu de laisser le modèle compléter librement du texte (ce qui peut entraîner des résultats incohérents ou ambigus), on lui fournit un modèle strict qui définit :
- Les étapes qu’il doit impérativement suivre, afin d’éviter tout saut dans l’analyse
- L’ordre de ces étapes, de sorte que le raisonnement s’effectue du données à la décision
- Les points sur lesquels il doit concentrer son attention, pour que l’analyse approfondie porte là où cela est essentiel
Considérez-le comme une liste de contrôle cognitive que le modèle doit suivre.
Ce que le schéma contrôle
Des champs tels que churn_analysis, margin_math, et max_discount_percent Il convient de rendre explicites les sorties intermédiaires attendues. Le modèle doit remplir la structure requise avant de pouvoir retourner la décision finale concernant la remise.
Cela vous donne :
- un raisonnement reproductible lors de multiples exécutions
- des sorties auditable dont chaque étape est inspectable
- des champs intermédiaires pouvant être évalués par rapport à un test dataset
- des modèles plus petits qui deviennent exploitables, puisque le schéma impose ce que le modèle aurait sinon dû apprendre
- une amélioration de la précision rapportée de 5 à 10 % dans le les charges de travail de production des praticiens originaux, ce que vous devez vérifier sur vos propres données
SGR contre la chaîne de réflexion contre prompt engineering
Les trois approches diffèrent principalement par le degré de contrainte qu’elles imposent au modèle.
| Fonctionnalité | Prompt Engineering | Chaîne de réflexion | Raisonnement guidé par schéma |
|---|---|---|---|
| Structure de sortie | Texte variable | Prose libre | Rigide JSON/Pydantic |
| Mécanisme de contrôle | Persuasion sémantique (“Veuillez afficher JSON”) | Incitation heuristique (« Prenons le temps de réfléchir étape par étape ») | Constrained decoding (basé sur la grammaire) |
| Flux de raisonnement | Le modèle détermine | Le modèle détermine | Le développeur définit la topologie du schéma. |
| Auditable | Faible (nécessite du parsing) | Faible (nécessite la lecture du texte) | Inspection de haut niveau (au niveau du champ) |
| Intégration | Difficile (format variable) | Trivial (désérialisation d’objet natif) | |
| Taux d’erreur | Élevée (variabilité de format) | Modéré (hallucination de format) | |
| Exigences relatives au modèle | Suivi strict des instructions | Capacité de raisonnement puissant | Fonctionne également avec des modèles plus petits. |
Prompt engineering : persuasion sémantique
Please analyze the customer data and output your response as valid JSON
with the following structure: {"discount": <number>, "reason": <string>}
Be careful with the formatting!
Vous espérez que la compréhension du modèle concernant « output JSON » l’emportera sur sa tendance à adopter un style conversationnel. Une mise à jour du modèle, une modification de la température, ou l’utilisation d’un exemple de type few-shot différent peut compromettre le bon fonctionnement de votre analyseur.
Chaîne de réflexion : raisonnement amélioré, même problème de structure
Let's think step by step:
1. First, I'll analyze the customer's churn risk...
2. Then I'll calculate the margin...
3. Therefore, I recommend a 15% discount.
CoT améliore la précision du raisonnement, mais détériore la structure. Le résultat est un texte imprévisible dont il est presque impossible d’effectuer une analyse fiable. Il est généralement nécessaire d’exécuter une seconde invocation de LLM afin d’extraire les données structurées.
SGR : chaîne structurée de réflexion
SGR conserve l’intuition de CoT selon laquelle le raisonnement intermédiaire améliore la précision. Il se contente de formaliser les étapes correspondantes :
class PricingLogic(BaseModel):
# 1. Data Analysis (must complete before decision)
churn_analysis: str = Field(..., description="Analyze churn_probability")
financial_analysis: str = Field(..., description="Analyze cart_value and margin")
# 2. Math Enforcement (explicit calculation)
margin_math: str = Field(..., description="Calculate: 'Cart $X * Y% = $Z'")
# 3. Decision Constraint (bounded by prior analysis)
max_discount_percent: float = Field(..., description="Max allowed discount")
# 4. Final Output
offer_code: str
customer_message: str
Le modèle ne peut pas générer de sortie. max_discount_percent jusqu’à churn_analysis, financial_analysis, et margin_math Ils sont remplis. Le schéma impose l’ordre de raisonnement.
Patterns SGR
SGR comporte trois motifs fondamentaux qui s’assemblent pour former des flux de travail plus complexes.
1. Cascade : étapes successives de raisonnement
Cascade impose un ordre de raisonnement : chaque champ doit être rempli avant le suivant.
from pydantic import BaseModel
from typing import Literal, Annotated
from annotated_types import Ge, Le
class CandidateEvaluation(BaseModel):
"""Evaluate a job candidate with enforced reasoning order."""
# Step 1: Summarize (forces context awareness)
brief_candidate_summary: str
# Step 2: Rate (bounded integer)
rate_skill_match: Annotated[int, Ge(1), Le(10)]
# Step 3: Decide (constrained choices)
final_recommendation: Literal["hire", "reject", "hold"]
Cas d’usage pertinents : évaluation des candidats, classification de documents, analyse de conformité, diagnostic médical.
Le modèle doit écrire brief_candidate_summary Avant de pouvoir évaluer, il faut d’abord évaluer ; avant de pouvoir recommander, il faut d’abord évaluer. Il n’existe pas de raccourci.
2. Acheminement : une instruction conditionnelle sémantique
Le routage amène le modèle à choisir une voie parmi un ensemble d’options, ce qui est réalisé grâce à Union types.
from pydantic import BaseModel
from typing import Literal, Union
class FeatureLookup(BaseModel):
"""Route to database lookup."""
rationale: str
tool_name: Literal["fetch_user_features"] = "fetch_user_features"
user_id: str
class GeneralResponse(BaseModel):
"""Standard response for non-pricing queries."""
tool_name: Literal["respond"] = "respond"
content: str
class RouterSchema(BaseModel):
"""The model must pick exactly ONE branch."""
action: Union[FeatureLookup, GeneralResponse]
Cas d’usage pertinents : classification de l’intention, sélection d’outils, tri des demandes de support, et diffusion multi-agent.
Le Literal déterminanttool_name) amène le modèle à sélectionner une seule branche et à remplir uniquement les champs requis par cette branche.
3. Cycle : raisonnement itératif à l’aide de listes
Cycle force le modèle à générer plusieurs éléments, en imposant des limites sur leur nombre.
from pydantic import BaseModel
from typing import List, Literal, Annotated
from annotated_types import MinLen, MaxLen
class RiskFactor(BaseModel):
explanation: str
severity: Literal["low", "medium", "high"]
class RiskAssessment(BaseModel):
"""Generate 2-4 risk factors."""
factors: Annotated[List[RiskFactor], MinLen(2), MaxLen(4)]
Cas d’usage pertinents : évaluation des risques, extraction des problèmes, traitement parallèle tool calls, planification en plusieurs étapes.
Le MinLen et MaxLen La contrainte de limite impose d’utiliser au moins 2 et au plus 4 éléments. En combinaison avec le routage, c’est ainsi que l’on envoie un lot à largeur fixe de tool calls.
Faire fonctionner SGR : constrained decoding
Les schémas présentés ci-dessus ne sont rien d’autre que des schémas Pydantic. Ce qui leur confère un caractère contraignant, c’est constrained decoding (également désigné sous le nom de Structured Output).
Constrained decoding modifie l’étape de génération des tokens. Au lieu de permettre au modèle de sélectionner librement dans son vocabulaire, le moteur applique un masque grammatical qui bloque les tokens susceptibles de violer le schéma. Ce processus a lieu au niveau du moteur d’inférence, et non dans le code de votre application.
[!TIP] SGR n’a pas besoin de « modèles de raisonnement » tels que o1 ou DeepSeek-R1. Il fonctionne parfaitement avec des modèles affinés par des instructions, et encore mieux avec des modèles distillés à partir de modèles de raisonnement.
Fournisseurs de cloud qui le prennent en charge
La plupart des fournisseurs modernes de LLM proposent des structured outputs via constrained decoding :
| Fournisseur | Support technique |
|---|---|
| OpenAI | Structured Outputs (y compris Azure). GPT-5 utilise JSON Schema grâce à llguidance |
| Google/Gemini | JSON Schema Support depuis novembre 2025 (Pydantic et Zod) |
| Mistral | Personnalisation Structured Output |
| Grok | Structured Outputs pour plusieurs modèles |
| Feux d’artifice AI | JSON Schema |
| Cerebras | Structured Outputs |
| OpenRouter | Cela dépend du fournisseur intermédiaire, ce qui correspond à JSON Schema |
Moteurs d’inférence qui le prennent en charge
Pour les modèles auto-hébergés, tous les principaux moteurs disposent d’un constrained decoding backend :
| Moteur | Backend |
|---|---|
| vLLM | xgrammar ou directives |
| SGLang | Aperçus, XGrammar, ou guidance LL |
| TensorRT-LLM | GuidéDécodage |
| Ollama | Structured Outputs |
Pourquoi cet article se concentre sur vLLM et xgrammar
Quelques raisons :
- vLLM est le moteur d’inférence LLM open source le plus largement déployé, ce qui permet une portabilité aisée des solutions développées ici.
- xgrammar est implémenté en C++ et ne génère qu’une latence négligeable.
- La API de vLLM est compatible avec OpenAI, ce qui réduit considérablement les coûts de migration depuis les fournisseurs de cloud.
- xgrammar gère des schémas imbriqués complexes, des unions ainsi que des structures récursives.
La section suivante explique en détail comment xgrammar applique réellement un schéma au niveau des tokens.
Comment xgrammar impose les schémas
Il est essentiel de bien comprendre cette partie, car elle modifie la manière dont vous déboguez et ajustez les workflows SGR.
Où a lieu le masquage
xgrammar modifie les logits de sortie après le passage en avant du modèle et avant l’échantillonnage. Il ne modifie pas le modèle lui-même ; il filtre les tokens qui peuvent être sélectionnés.
Un cycle d’inférence standard se présente comme suit :
1. Input tokens → GPU Forward Pass → Logits (probability scores for all ~128K tokens)
2. Logits → Sampling (temperature, top-p, etc.) → Next Token
3. Repeat until done
xgrammar glisse entre les étapes 1 et 2 :
1. Input tokens → GPU Forward Pass → Raw Logits
2. Raw Logits → xgrammar Logits Processor → Masked Logits
3. Masked Logits → Sampling → Next Token (guaranteed valid)
4. Repeat until done
Le modèle calcule toujours sa distribution de probabilité complète sur le GPU. xgrammar s’exécute ensuite sur le CPU et applique un masque binaire à ces logits avant l’échantillonnage. Les tokens invalides voient leurs logits être mis à -∞ce qui fait que leur probabilité devient exactement 0 après application de la fonction softmax.
Deux phases
xgrammar divise le travail en phase de compilation et en runtime, ce qui est la raison de sa grande rapidité.
Phase 1 : compilation de la grammaire, une fois par schéma
# This happens once per schema
tokenizer_info = xgr.TokenizerInfo.from_huggingface(tokenizer)
grammar_compiler = xgr.GrammarCompiler(tokenizer_info)
compiled_grammar = grammar_compiler.compile_json_schema(schema_json)
Lors de la compilation, xgrammar :
- Convertit le JSON Schema en une grammaire libre de contexte.
- Construit un automate à pile (PDA), qui est un automate à états doté d’une pile afin de pouvoir gérer des structures imbriquées telles que
{"a": {"b": {"c": ...}}}. - Il calcule à l’avance quels tokens sont valables à chaque position grammaticale. Le résultat correspond à la « cache de masques de tokens adaptatifs ».
- Les tokens sont classés comme « indépendants du contexte » (pouvant être mémorisés en cache) ou « dépendants du contexte » (doivent être vérifiés à runtime par rapport à l’état de la pile).
[!NOTE] Environ 99 % des tokens s’avèrent indépendants du contexte et sont finalement mis en cache (Article sur XGrammar). La plupart des vérifications de validité effectuées à runtime ne sont en réalité que des recherches dans le cache, d’où la grande rapidité de xgrammar.
Phase 2 : génération de la masque runtime, pour chaque token
À chaque étape de génération :
- Le
GrammarMatcherIl suit la position actuelle dans la grammaire. - Il consulte le masque précalculé destiné aux tokens indépendants du contexte.
- Il exécute le PDA afin de vérifier les tokens restants dépendants du contexte.
- Il les combine en un masque binaire final et l’applique aux logits.
Pourquoi les automates à pile et non les expressions régulières ?
En raison du chevauchement des niveaux. Une expression régulière (une machine à états finis) ne peut pas correspondre de manière fiable à des structures telles que :
{ "user": { "profile": { "settings": { "theme": "dark" } } } }
La partie difficile réside dans la fermeture des crochets. }}}: il vous faut garder en mémoire le nombre d’éléments que vous avez ouverts. Un automate à pile permet de suivre ce compteur grâce à sa pile interne, ce qui lui permet de gérer des profondeurs de nesting arbitraires. C’est également la raison pour laquelle xgrammar peut imposer des types Union, des objets imbriqués ainsi que des schémas récursifs, là où les approches basées sur les regex se révèlent insuffisantes.
Exemple concret : génération d’un champ à virgule flottante
Lorsque le modèle génère "max_discount_percent":, xgrammar sait, à partir du schéma, qu’un float Voici ce qui suit. La masque :
- autorise (probabilité inchangée) :
0,1,2, …,9,.,- - blocs (probabilité réglée sur 0) :
",{,[,true,false,null, ainsi que le reste du vocabulaire de 128 K+ mots.
La passe avant a pu attribuer une haute probabilité au mot "fifteen". Après le masquage effectué par xgrammar, cette token possède une probabilité nulle. Le modèle doit donc générer des chiffres.
Pourquoi un surcoût quasi nul
Trois raisons :
- Exécution parallèle. Le calcul de la masque sur le CPU coïncide avec le prochain passage en avant sur le GPU. Tandis que le GPU calcule les logits du token N+1, le CPU génère la masque correspondant au token N.
- Mémorisation. La majeure partie du travail de validation s’effectue à l’étape de compilation. Les Runtime consistent principalement en des recherches dans la mémoire cache.
- Implémentation en C++. Le chemin le plus fréquemment exécuté est écrit en C++, et non en Python ; la masque est appliquée directement aux logits.
Dans benchmarks, le xgrammar présente des coûts d’overhead négligeables, et la génération structurée peut parfois être plus rapide que la génération non contrainte, car un vocabulaire restreint rend l’échantillonnage moins coûteux.
Implémentation pratique avec vLLM
Le référent est le sgr – gestionnaire de remises projet : une petite démonstration qui utilise SGR pour la tarification dynamique.
Structure du projet
sgr/
├── agent.py # Main orchestration
├── models/
│ └── schemas.py # Pydantic SGR schemas
├── prompts/
│ ├── routing.py # Phase 1 prompts
│ └── pricing.py # Phase 3 prompts
├── store/
│ └── hybrid_store.py # Hot/Cold data retrieval
└── utils/
└── llm_client.py # LLM client wrapper with xgrammar
Étape 1 : définir les schémas
# sgr/models/schemas.py
from pydantic import BaseModel, Field
from typing import Literal, Union
# --- Phase 1: Routing (Union for branching) ---
class FeatureLookup(BaseModel):
"""Route to DB lookup if pricing context is needed."""
rationale: str
tool_name: Literal["fetch_user_features"] = "fetch_user_features"
user_id: str
class GeneralResponse(BaseModel):
"""Standard response for non-pricing queries."""
tool_name: Literal["respond"] = "respond"
content: str
class RouterSchema(BaseModel):
action: Union[FeatureLookup, GeneralResponse]
# --- Phase 2: Pricing Logic (Cascade for sequential reasoning) ---
class PricingLogic(BaseModel):
"""
Strict reasoning topology for dynamic pricing.
Fields are ordered to enforce the analysis→decision flow.
"""
# 1. Data Analysis (Reflection)
churn_analysis: str = Field(...,
description="Analyze churn_probability (High > 0.7).")
financial_analysis: str = Field(...,
description="Analyze cart_value and profit_margin.")
# 2. Hard Math Enforcement
margin_math: str = Field(...,
description="Calculate absolute profit: 'Cart $200 * 0.20 Margin = $40'.")
# 3. The Decision Constraint
max_discount_percent: float = Field(...,
description="Max allowed discount %. NEVER exceed margin.")
# 4. Final Output
offer_code: str = Field(..., description="Generated code (e.g. SAVE20).")
customer_message: str = Field(..., description="The final polite offer text.")
Étape 2 : un client LLM qui active xgrammar
# sgr/utils/llm_client.py
from openai import OpenAI
from pydantic import BaseModel
from typing import TypeVar
import json
T = TypeVar("T", bound=BaseModel)
class LLMClient:
"""Wrapper for vLLM with xgrammar-enforced structured generation."""
def __init__(self, base_url: str = "http://localhost:8000/v1"):
self.client = OpenAI(base_url=base_url, api_key="EMPTY")
self.model = self._get_available_model()
def _get_available_model(self) -> str:
"""Auto-detect the model running on vLLM server."""
try:
models = self.client.models.list()
if models.data:
return models.data[0].id
except Exception:
pass
return "Qwen/Qwen2.5-7B-Instruct"
def run_sgr(self, messages: list[dict], schema_class: type[T]) -> T:
"""Run inference with Schema-Guided Response constraints.
Uses vLLM's guided_json with xgrammar backend to enforce
strict schema constraints at the token generation level.
"""
schema_dict = schema_class.model_json_schema()
# Enhance system message with schema for model guidance
enhanced_messages = messages.copy()
if enhanced_messages and enhanced_messages[0]["role"] == "system":
schema_json = json.dumps(schema_dict, indent=2)
enhanced_messages[0] = {
"role": "system",
"content": (
enhanced_messages[0]["content"]
+ f"\n\nRespond with JSON matching this schema:\n{schema_json}"
),
}
# vLLM's guided_json with the xgrammar backend
completion = self.client.chat.completions.create(
model=self.model,
messages=enhanced_messages,
temperature=0.1, # Low temp for deterministic reasoning
extra_body={
"guided_json": schema_dict, # Pydantic schema as dict
"guided_decoding_backend": "xgrammar", # Hardware-enforced
},
)
raw_response = completion.choices[0].message.content
return schema_class.model_validate_json(raw_response)
[!NOTE] >
guided_jsonaccepte un dictionnaire JSON Schema. Avecguided_decoding_backend: "xgrammar"Le LLM ne peut générer que des tokens qui forment des JSON valides conformes à votre schéma.
Étape 3 : orchestrer l’agent
# sgr/agent.py
from .models.schemas import PricingLogic, RouterSchema
from .prompts.routing import build_routing_prompt
from .prompts.pricing import build_pricing_context_prompt, ASSISTANT_FETCH_MESSAGE
from .store.hybrid_store import HybridFeatureStore
from .utils.llm_client import LLMClient
def pricing_agent(user_query: str, user_id: str) -> str:
"""Process a pricing query with three-phase SGR workflow."""
llm = LLMClient()
feature_store = HybridFeatureStore()
# Build conversation history
history = [
{"role": "system", "content": build_routing_prompt(user_id)},
{"role": "user", "content": user_query},
]
# --- Phase 1: Routing (Uses RouterSchema) ---
print(f"🤖 Processing: '{user_query}' for {user_id}")
decision = llm.run_sgr(history, RouterSchema)
print(f"📍 Routing decision: {decision.action.tool_name}")
if decision.action.tool_name == "respond":
return decision.action.content
# --- Phase 2: Context Retrieval ---
if decision.action.tool_name == "fetch_user_features":
print(f"🔍 Fetching features for {user_id}...")
context = feature_store.get_user_context(user_id)
if not context:
return "Error: User profile not found."
print(f" [Data] LTV: ${context.get('user_ltv')} | "
f"Margin: {context.get('cart_profit_margin', 0) * 100}%")
# Inject context into conversation
history.append({"role": "assistant", "content": ASSISTANT_FETCH_MESSAGE})
history.append({
"role": "user",
"content": build_pricing_context_prompt(
churn_prob=context.get("churn_probability", 0.5),
cart_val=context.get("current_cart_value", 100),
margin=context.get("cart_profit_margin", 0.2),
user_ltv=context.get("user_ltv", 0),
),
})
# --- Phase 3: SGR Logic Execution (Uses PricingLogic) ---
print("🧠 Calculating Offer (Schema Enforced)...")
offer = llm.run_sgr(history, PricingLogic)
# Audit log — the SGR benefit: explicit reasoning traces
print(f" [Audit] Math: {offer.margin_math}")
print(f" [Audit] Max Allowed: {offer.max_discount_percent}%")
return offer.customer_message
return "I'm sorry, I couldn't process your request."
if __name__ == "__main__":
response = pricing_agent("I want a discount or I'm leaving!", "user_102")
print(f"\n💬 Final Reply: {response}")
Étape 4 : exécuter vLLM à l’aide de xgrammar
# Start vLLM server with xgrammar backend (default in recent versions)
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-7B-Instruct \
--port 8000
# Run the agent
uv run python -m sgr.agent
Exemple de sortie
🤖 Processing: 'I want a discount or I'm leaving!' for user_102
📍 Routing decision: fetch_user_features
🔍 Fetching features for user_102...
[Data] LTV: $1,500 | Margin: 20%
🧠 Calculating Offer (Schema Enforced)...
[Audit] Math: Cart $200 * 0.20 Margin = $40
[Audit] Max Allowed: 15.0%
💬 Final Reply: We value your loyalty! Here's a special 15% discount
with code SAVE15. This reflects our appreciation for your continued
business with us.
Le journal d’audit montre le fonctionnement réel du modèle : il a calculé la marge (40 à 20 %) et a défini une limite pour le rabais, afin que l’offre reste conforme à la contrainte de profit.
Bonnes pratiques
Conception de schéma
- Classer les champs selon le flux de raisonnement : les champs d’analyse doivent précéder les champs de décision.
- Rédiger des descriptions explicites.
FieldDescriptions. Elles orientent l’attention du modèle tout autant que le nom de champ. - Restreindre par des contraintes
LiteraletAnnotated. UtiliserLiteral["a", "b"]pour les enums etAnnotated[int, Ge(1), Le(10)]pour les bornes. - Gardez les schémas ciblés : un schéma par phase de raisonnement, puis assemblez-les à l’aide de plusieurs appels.
Configuration vLLM
- Utilisez une température basse (0,1–0,3) pour un raisonnement déterministe.
- Laissez xgrammar gérer la structure ; évitez de contredire ses décisions en utilisant des instructions de formatage dans prompt.
- Faites attention à l’utilisation des tokens. SGR nécessite généralement moins de tokens que CoT, car il ne comporte pas de prose verbose.
Considérations de production
- Versionnez vos schémas de la même manière que vous versionnez APIs.
- Même avec SGR, les erreurs réseau et serveur nécessitent toujours une gestion souple.
- Enregistrez les sorties brutes SGR aux fins du respect des réglementations et du débogage.
- Testez avec des cas limites afin que le schéma reste valide en dehors des conditions normales.
Conclusion
SGR est ce qui permet de passer d’un fonctionnement en environnement de démonstration à un fonctionnement en production. Vous définez la topologie de raisonnement au sein de Pydantic, vous laissez xgrammar la faire respecter au moment du décodage, et le résultat obtenu est :
- Valide à chaque fois, sans boucles de tentative ni échecs de parsing
- Auditable au niveau du champ
- Utilisable avec des modèles plus petits, car ils n’ont plus besoin de gérer eux-mêmes le format
- Moins coûteux en termes de calcul, puisqu’on utilise moins de tokens, moins de tentatives et des modèles plus petits
Le sgr – gestionnaire de remises Exécutez les exemples de code présentés dans cette publication en les connectant à un serveur vLLM réel. Clonez-le puis commencez à adapter les schémas à votre propre flux de travail.
Points clés
- Le raisonnement guidé par schéma rend explicite la topologie du raisonnement, au lieu de compter sur le fait que le modèle suive des instructions écrites.
- Constrained decoding empêche l’apparition de JSON non valides au moment de la génération, ce qui est plus efficace que de valider et de réessayer ultérieurement.
- Placer les champs d’analyse avant les champs de décision lorsque le schéma exige un raisonnement préalable à la production du résultat.
- Utiliser SGR lorsque du code intermédiaire dépend de la structure, et non lorsque le produit final est constitué de texte libre.
Références
SGR Framework
- Raisonnement guidé par schéma (SGR) — La version originale de framework par Rinat Abdullin
- SGR Modèles — Modèles de cascade, d’acheminement et de cycle
xgrammar
- XGrammar : moteur de génération structurée flexible et efficace pour les grands modèles de langage — Yixin Dong et al., arXiv:2411.15100 (article technique contenant benchmarks) xgrammar GitHub — Bibliothèque de génération structurée rapide et flexible
- Documentation xgrammar — Documentation officielle incluant un guide de démarrage rapide xgrammar – Guide de démarrage rapide — Introduction à xgrammar
- Obtenir une génération structurée efficace à l’aide de XGrammar — Article de blog MLC sur les mécanismes internes de xgrammar
vLLM
- vLLM Structured Outputs — Documentation officielle
Projet de démonstration
- sgr – gestionnaire de remises — Démo fonctionnelle incluant tous les exemples de code de cette publication