[!NOTE] Traducción automática Este artículo se tradujo automáticamente a partir de la versión original en inglés.
Razonamiento guiado por esquemas en vLLM: Structured Outputs mediante xgrammar y Pydantic
Volver a intentar una llamada a LLM no garantiza la obtención de un JSON válido. El siguiente ejemplo de datos puede fallar de la misma manera, y las llamadas repetidas incrementan la latencia y los costes.
El razonamiento guiado por esquema (SGR)) impone la estructura definida mientras el modelo genera cada token. Se definen los campos obligatorios mediante Pydantic, y el motor de inferencia bloquea aquellos tokens que violarían dicha estructura. Como resultado, los outputs obtenidos son sintácticamente válidos desde su creación, sin necesidad de intentos repetidos.
Resumen. SGR utiliza constrained decoding para fijar la salida de un LLM a un esquema Pydantic que se encuentra bajo nuestro control. Al combinarlo con el xgrammar backend de vLLM, se obtienen siempre JSON válidos, con una sobrecarga de latencia prácticamente nula.
¿Qué es el razonamiento guiado por esquema?
El razonamiento guiado por esquemas es una técnica que Rinat Abdullin Redactado en 2024. En lugar de permitir que el modelo complete el texto de forma libre (lo cual puede resultar inconsistente o ambiguo), se le proporciona una plantilla estricta que define:
- Los pasos que debe seguir para que no sea posible omitir el análisis.
- El orden de dichos pasos, de modo que el razonamiento se desarrolle desde los datos hasta la decisión.
- Los puntos en los que debe concentrar su atención, para que la profundidad del análisis se aplique donde realmente importa.
Considérenlo como una lista de verificación cognitiva que el modelo debe seguir.
Qué controla el esquema
Campos como churn_analysis, margin_math, y max_discount_percent Debe especificarse claramente cuáles son los resultados intermedios esperados. El modelo tiene que rellenar la estructura obligatoria antes de poder devolver la decisión final sobre el descuento.
Esto le proporciona:
- razonamiento reproducible en ejecuciones repetidas
- resultados auditables cuyos pasos pueden inspeccionarse uno por uno
- campos intermedios que se pueden evaluar mediante pruebas dataset
- modelos más pequeños que resultan viables, ya que el esquema impone las reglas que de otro modo el modelo tendría que aprender por sí mismo
- una mejora reportada del 5–10% en la precisión en el Cargas de trabajo de producción del desarrollador original, lo cual debería verificar con sus propios datos.
SGR frente a cadena de razonamiento frente a prompt engineering
Los tres enfoques difieren principalmente en la intensidad con la que imponen restricciones al modelo.
| Característica | Prompt Engineering | Cadena de razonamiento | Razonamiento guiado por esquema |
|---|---|---|---|
| Estructura de salida | Texto variable | Prosa de formato libre | Rígido JSON/Pydantic |
| Mecanismo de control | Persuasión semántica (“Por favor, genere JSON”) | Inducción heurística (“Pensemos paso a paso”) | Constrained decoding (basado en gramática) |
| Flujo de razonamiento | El modelo determina | El modelo determina | El desarrollador determina la topología del esquema. |
| Auditablez | Bajo (requiere análisis sintáctico) | Bajo (requiere leer el texto) | Inspección de alto nivel (a nivel de campo) |
| Integración | |||
| Tasa de error | Alto (variabilidad de formato) | Moderado (alucinación de formato) | |
| Requisito del modelo | Fuerte capacidad de seguimiento de instrucciones | Capacidad de razonamiento sólido | Funciona igualmente con modelos más pequeños. |
Prompt engineering: persuasión semántica
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!
Esperas que la comprensión del modelo sobre “output JSON” sea más fuerte que su tendencia a adoptar un tono conversacional. Una actualización del modelo, un cambio en la temperatura de sampling o un ejemplo de tipo few-shot diferente pueden invalidar tu analizador de texto.
Cadena de razonamiento: mejor capacidad de inferencia, mismo problema de estructura
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 mejora la precisión del razonamiento, pero empeora la estructura del resultado. La salida que se genera es un texto impredecible que resulta prácticamente imposible de analizar de forma fiable. Por lo general, es necesario realizar una segunda llamada a LLM solo para poder extraer los datos estructurados.
SGR: cadena estructurada de razonamiento
SGR mantiene la intuición de CoT de que el razonamiento intermedio mejora la precisión. Simplemente formaliza los pasos correspondientes:
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
El modelo no puede generar salida. max_discount_percent hasta que churn_analysis, financial_analysis, y margin_math Se llenan con los valores correspondientes. El esquema impone el orden de razonamiento.
Patrones SGR
SGR cuenta con tres patrones fundamentales que se combinan para formar flujos de trabajo más complejos.
1. Cascada: pasos secuenciales de razonamiento
El método Cascade impone un orden específico para el razonamiento: es necesario completar cada campo antes de pasar al siguiente.
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"]
Casos de uso adecuados: evaluación de candidatos, clasificación de documentos, análisis de cumplimiento, diagnóstico médico.
El modelo debe generar texto. brief_candidate_summary Antes de que pueda realizar una evaluación, es necesario primero evaluar; y antes de que pueda hacer una recomendación, debe haber realizado la evaluación previa. No existe atajo.
2. Enrutamiento: una instrucción de conmutación semántica
El enrutamiento hace que el modelo elija una única ruta entre un conjunto de opciones, implementado mediante Union Tipos.
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]
Casos de uso adecuados: clasificación de intenciones, selección de herramientas, triaje de soporte y envío de multi-agent.
El Literal discriminadortool_name) hace que el modelo elija una única rama y rellene únicamente los campos que esa rama requiere.
3. Ciclo: razonamiento repetido con listas
El ciclo obliga al modelo a generar varios elementos, estableciendo límites sobre cuántos pueden ser.
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)]
Casos de uso adecuados: evaluación de riesgos, extracción de problemas, tool calls en paralelo, planificación multietapa.
El MinLen y MaxLen El límite impone que haya al menos 2 y como máximo 4 elementos. Combinado con el enrutamiento, así es como se envía un lote de ancho fijo de tool calls.
Haciendo que SGR funcione: constrained decoding
Los patrones anteriores no son más que esquemas Pydantic. Lo que les confiere carácter vinculante es constrained decoding (también conocido como Structured Output).
Constrained decoding modifica la fase de generación de tokens. En lugar de permitir que el modelo seleccione libremente desde su vocabulario, el motor aplica una máscara gramatical que bloquea aquellos tokens que podrían violar el esquema. Este proceso tiene lugar en el motor de inferencia, y no en el código de la aplicación.
[!TIP] SGR no necesita “modelos de razonamiento” como o1 o DeepSeek-R1. Funciona perfectamente con modelos ajustados mediante instrucciones, y de forma especialmente eficaz con modelos derivados de aquellos basados en razonamiento.
Proveedores cloud que lo soportan
La mayoría de los proveedores modernos de LLM ofrecen structured outputs a través de constrained decoding:
| Proveedor | Soporte técnico |
|---|---|
| OpenAI | Structured Outputs (incluyendo Azure). GPT-5 utiliza JSON Schema a través de llguidance |
| Google/Gemini | JSON Schema Soporte disponible a partir de noviembre de 2025 (Pydantic y Zod). |
| Mistral | Personalizado Structured Output |
| Structured Outputs para múltiples modelos | |
| Fuegos artificiales AI | JSON Schema |
| Cerebras | Structured Outputs |
| OpenRouter | Depende del proveedor posterior en la cadena de procesamiento; se corresponde con JSON Schema. |
Motores de inferencia que lo soportan
En el caso de los modelos autohospedados, todos los motores principales disponen de un constrained decoding backend:
| Motor | Backend |
|---|---|
| vLLM | xgrammar o orientación |
| Esquemas, XGrammar, o guía de orientación | |
| TensorRT-LLM | Decodificación guiada |
| Ollama | Structured Outputs |
Por qué este artículo se centra en vLLM y xgrammar
Algunas razones:
- vLLM es el motor de inferencia de código abierto LLM más ampliamente implementado, por lo que lo que se desarrolle aquí se puede integrar con facilidad.
- xgrammar está implementado en C++ y genera una latencia prácticamente nula.
- La API de vLLM es compatible con OpenAI, lo que hace que la migración desde proveedores cloud sea económica.
- xgrammar es capaz de gestionar esquemas anidados complejos, uniones y estructuras recursivas.
La sección siguiente explica detalladamente cómo xgrammar aplica efectivamente un esquema a nivel de token.
Cómo aplica xgrammar los esquemas
Esta sección es fundamental comprenderla con precisión, ya que modifica la forma en la que se depuran y se ajustan los flujos de trabajo de SGR.
Dónde tiene lugar el enmascaramiento
xgrammar modifica los logits de salida después del paso forward del modelo y antes de la muestreo. No altera al propio modelo, sino que filtra qué tokens pueden ser seleccionados.
Un bucle de inferencia estándar se presenta de la siguiente manera:
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 se desliza entre los pasos 1 y 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
El modelo sigue calculando su distribución de probabilidad completa sobre el GPU. A continuación, xgrammar se ejecuta sobre el CPU y aplica una máscara de bits a dichos logits antes de realizar la muestreo. Los tokens inválidos tienen sus logits establecidos en -∞, lo que hace que su probabilidad sea exactamente 0 tras aplicar la función softmax.
Dos fases
xgrammar divide el proceso en fases de compilación y runtime, y es precisamente esto lo que garantiza su alta velocidad.
Fase 1: compilación de gramática, una vez por esquema
# 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)
Durante la compilación, xgrammar:
- Convierte el JSON Schema en una gramática libre de contexto.
- Construye un autómata de desplazamiento hacia abajo (PDA), que es un autómato de estados dotado de una pila para poder manejar estructuras anidadas como
{"a": {"b": {"c": ...}}}. - Precomputa qué tokens son válidos en cada posición gramatical. El resultado que se obtiene es la “caché de máscaras de tokens adaptativas”.
- Clasifica los tokens como “independientes del contexto” (que pueden almacenarse en caché) o “dependientes del contexto” (que deben verificarse en runtime en función del estado de la pila).
[!NOTA] Aproximadamente el 99 % de los tokens resultan ser independientes del contexto y terminan almacenándose en caché.El artículo sobre XGrammar). La mayoría de las comprobaciones de validez en runtime no son más que búsquedas en caché, y por eso xgrammar es tan rápido.
Fase 2: generación de la máscara runtime, para cada token
En cada paso de generación:
- El
GrammarMatcherRegistra la posición actual dentro de la gramática. - Consulta la máscara precalculada correspondiente a los tokens independientes del contexto.
- Ejecuta el PDA para analizar los tokens restantes que sí dependen del contexto.
- Combina todos ellos en una máscara binaria final y la aplica a los logits.
¿Por qué los autómatas de desplazamiento hacia abajo y no las expresiones regulares?
Debido al anidamiento, una expresión regular (una máquina de estados finitos) no puede coincidir de forma fiable con estructuras como:
{ "user": { "profile": { "settings": { "theme": "dark" } } } }
La parte más complicada son los corchetes de cierre. }}}: es necesario recordar cuántos se han abierto. Un autómata de pila cuenta con una pila que permite hacer un seguimiento de esto, lo que le permite gestionar profundidades de anidamiento arbitrarias. Por esa misma razón, xgrammar puede aplicar tipos de unión, objetos anidados y esquemas recursivos, algo que los enfoques basados en expresiones regulares no logran hacer.
Un ejemplo concreto: generación de un campo de tipo float
Cuando el modelo está generando "max_discount_percent":, xgrammar sabe, a partir del esquema, que un float A continuación se presenta la máscara:
- permite (la probabilidad se mantiene sin cambios):
0,1,2, …,9,.,- - bloques (probabilidad establecida en 0):
",{,[,true,false,null, y el resto del vocabulario de más de 128K palabras.
La pasada hacia adelante podría haber asignado una alta probabilidad a la palabra. "fifteen". Tras aplicar la máscara de xgrammar, dicho token tiene una probabilidad de 0. El modelo debe generar dígitos.
¿Por qué un sobrecoste casi nulo?
Tres razones:
- Ejecución paralela. El cálculo de la máscara en el CPU se superpone con el siguiente paso de propagación hacia adelante en el GPU. Mientras que el GPU está calculando los logit para el token N+1, el CPU está generando la máscara correspondiente al token N.
- Caché. La mayor parte del trabajo relacionado con la validez se realiza en tiempo de compilación. Las operaciones de Runtime consisten principalmente en búsquedas en el caché.
- Implementación en C++. La ruta crítica del algoritmo está escrita en C++, no en Python, y la máscara se aplica directamente sobre los logit.
En benchmarks, xgrammar presenta una sobrecarga prácticamente nula, y la generación estructurada puede ser ocasionalmente más rápida que la generación sin restricciones, ya que el vocabulario limitado reduce el costo de muestreo.
Implementación práctica con vLLM
La referencia es el sgr - gestor de descuentos proyecto: una pequeña demostración que utiliza SGR para la fijación dinámica de precios.
Estructura del proyecto
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
Paso 1: definir los esquemas
# 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.")
Paso 2: un cliente LLM que activa 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)
[!NOTA] >
guided_jsonAcepta un diccionario JSON Schema. Conguided_decoding_backend: "xgrammar"El LLM solo puede generar tokens que conformen JSON válidos acordes con su esquema.
Paso 3: orquestar el agente
# 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}")
Paso 4: ejecutar vLLM con 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
Ejemplo de salida
🤖 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.
El registro de auditoría muestra el funcionamiento real del modelo: calculó el margen (40 dólares en un carrito de 200 dólares con un 20% de comisión) y estableció un límite para el descuento, de modo que la oferta se mantuviera dentro de los parámetros de rentabilidad establecidos.
Mejores prácticas
Diseño de esquema
- Ordenar los campos según el flujo de razonamiento. Los campos de análisis deben ir antes que los campos de decisión.
- Escribir descripciones descriptivas.
FieldDescripciones. Estas guían la atención del modelo de forma similar a como lo hace el nombre del campo. - Restringir con
LiteralyAnnotated. UtilizarLiteral["a", "b"]para enums yAnnotated[int, Ge(1), Le(10)]Para los límites de validez. - Mantenga los esquemas enfocados: un esquema por fase de razonamiento, y posteriormente combínelos mediante múltiples llamadas.
Configuración de vLLM
- Utilice una temperatura baja (0.1-0.3) para lograr un razonamiento determinista.
- Deje que xgrammar se encargue de la estructura; no intente contrarrestarlo con instrucciones de formato en prompt.
- Vigile el consumo de tokens. SGR suele utilizar menos tokens que CoT, ya que no contiene prosa excesivamente extensa.
Consideraciones de producción
- Versione sus esquemas de la misma manera que versiona APIs.
- Incluso con SGR, los errores de red y del servidor siguen requiriendo un manejo adecuado.
- Registre las salidas brutas de SGR para fines de cumplimiento normativo y depuración.
- Pruebe con casos límite para asegurarse de que el esquema funcione correctamente en los bordes.
Conclusión
SGR es lo que permite pasar de un sistema que “funciona en entornos de demostración” a uno que “funciona en producción”. Se define la topología de razonamiento en Pydantic, se utiliza xgrammar para hacerla cumplir en el momento de la decodificación, y el resultado es:
- Válido en todo momento, sin bucles de intentos repetidos ni fallos de análisis.
- Auditable a nivel de campo.
- Utilizable con modelos más pequeños, ya que no es necesario que estos se encarguen solos de ajustar el formato.
- Más económico en su ejecución, al emplearse menos tokens, menos intentos y modelos de menor tamaño.
El sgr - gestor de descuentos Los cables de demostración prueban cada ejemplo de código de esta publicación contra un servidor vLLM real. Clona dicho servidor y comienza a adaptar los esquemas a tu propio flujo de trabajo.
Conclusiones clave
- El razonamiento guiado por esquema hace explícita la topología de razonamiento en lugar de confiar en que el modelo siga instrucciones redactadas en prosa.
- Constrained decoding evita la generación de JSON inválidos en el momento de la creación, lo cual resulta más eficiente que validar y volver a intentarlo posteriormente.
- Coloque los campos de análisis antes que los campos de decisión cuando el esquema debe obligar al razonamiento antes de producir la salida.
- Utilice SGR cuando el código posterior dependa de una estructura definida, y no cuando el resultado sea texto en prosa sin formato fijo.
Referencias
SGR Framework
- Razonamiento guiado por esquema (SGR) — La versión original de Rinat Abdullin framework
- SGR Patrones — Patrones de cascada, enrutamiento y ciclo
xgrammar
- XGrammar: Motor de generación estructurada flexible y eficiente para modelos de lenguaje grande — Yixin Dong y colaboradores, arXiv:2411.15100 (artículo técnico con benchmarks) xgrammar en GitHub — Biblioteca de generación estructurada rápida y flexible
- Documentación de xgrammar — Documentación oficial con guía de inicio rápido xgrammar: Guía de inicio rápido — Introducción a xgrammar
- Lograr una generación estructurada eficiente mediante XGrammar — Artículo de blog de MLC sobre los detalles internos de xgrammar
vLLM
- vLLM Structured Outputs — Documentación oficial
Proyecto de demostración
- sgr - gestor de descuentos — Demo en funcionamiento que incluye todos los ejemplos de código de esta publicación