[!NOTE] Automatische Übersetzung Dieser Artikel wurde automatisch aus der englischen Originalversion übersetzt.

Schema-gestütztes Reasoning auf vLLM: Structured Outputs mithilfe von xgrammar und Pydantic

Ein erneuter Aufruf von LLM garantiert keine gültigen JSON. Das nächste Beispiel kann auf dieselbe Weise fehlschlagen, und wiederholte Aufrufe führen zu zusätzlichem Latency sowie zu höheren Kosten.

Schema-gestütztes Reasoning (SGR) stellt sicher, dass ein Schema eingehalten wird, während der Model jeweils einen Token erzeugt. Die erforderlichen Felder werden mithilfe von Pydantic definiert, wobei der Inference-Motor solche Tokens blockiert, die diese Struktur verletzen. Dadurch entstehen von vornherein syntaktisch korrekte Objekte, anstatt dass wiederholt Versuche unternommen werden müssen.

Zusammenfassung. SGR nutzt Constrained Decoding, um die Ausgabe eines LLM an ein von Ihnen kontrolliertes Pydantic-Schema zu binden. In Kombination mit dem xgrammar Backend von vLLM ergeben sich somit stets gültige JSON-Objekte bei nahezu vernachlässigbarem Latency-Aufwand.


Was ist ein schema-gesteuerter Reasoning?

Schema-gestütztes Reasoning ist eine Technik, die Rinat Abdullin im Jahr 2024 verfasst. Anstatt es dem Model zu überlassen, den Text frei zu vervollständigen – was zu Inkonsistenzen oder Mehrdeutigkeiten führen kann – wird ihm ein strenges Template zur Verfügung gestellt, das Folgendes definiert:

Betrachten Sie es als eine kognitive Checkliste, der der Model folgen muss.

SGR Übersicht

Was durch das Schema gesteuert wird

Felder wie zum Beispiel churn_analysis, margin_math, und max_discount_percent Stellen Sie die erwarteten Zwischenergebnisse ausdrücklich dar. Der Model muss die erforderliche Struktur vor dem Erstellen der endgültigen Rabattentscheidung vollständig füllen.

Das liefert Ihnen:


SGR im Vergleich zur Gedankenkette und zur Prompt-Entwicklung

Die drei Ansätze unterscheiden sich hauptsächlich darin, inwieweit sie die Model stark einschränken.

SGR Vergleich

FunktionPrompt IngenieurwesenKettendenkprozessSchema-gestütztes Reasoning
AusgabestrukturVariable TexteFreiformprosastarres JSON/Pydantic
SteuermechanismusSemantische Überzeugungskraft („Bitte geben Sie JSON aus“)heuristische Anleitung („Lassen Sie uns Schritt für Schritt darüber nachdenken“)Constrained Decoding (grammatikbasiert)
Reasoning FlussModel bestimmtModel bestimmtDer Entwickler bestimmt die (Schema-Topologie).
AuditorierbarkeitNiedrig (erfordert Parsing)Niedrig (erfordert Lesen des Textes)Hohe Prüfgenauigkeit (Ebene der Feldprüfung)
IntegrationSchwierig (variabler Format)Trivial (Serialisierung von nativen Objekten)
FehlerrateHoch (Formatvielfalt)Moderieren (Hallucination des Formats)
Model AnforderungStarke BefehlsbefolgungStarke Reasoning-FunktionalitätEs funktioniert auch mit kleineren Models.

Prompt Engineering: semantische Überzeugungskraft

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!

Sie hoffen, dass das Verständnis des Model für „Ausgabe JSON” seine Neigung zur konversativen Kommunikation überwiegt. Ein Update des Model, eine Änderung der Temperatur oder ein anderes Few-Shot-Beispiel können Ihren Parser lahmlegen.

Gedankenkette: bessere Reasoning, dasselbe Strukturproblem

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 erhöht die Genauigkeit von Reasoning, verschlechtert jedoch die Struktur erheblich. Das Ergebnis sind unvorhersehbare Texte, die nahezu unmöglich zuverlässig解析bar sind. In der Regel muss man eine zweite Aufrufung von LLM durchführen, um die strukturierten Daten extrahieren zu können.

SGR: strukturierte Gedankenkette

SGR bewahrt die Intuition von CoT, dass mittlere Reasoning-Werte die Genauigkeit verbessern. Es formalisiert lediglich die jeweiligen Schritte:

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

Der Model kann keine Ausgabe generieren. max_discount_percent bis churn_analysis, financial_analysis, und margin_math Sie werden mit Inhalten befüllt. Das Schema stellt die Reihenfolge von Reasoning sicher.


SGR-Muster

SGR weist drei Kernmuster auf, aus denen größere Workflows zusammengesetzt werden.

SGR Muster

1. Cascade: sequenzielle Reasoning-Schritte

Cascade stellt eine strikte Reihenfolge nach Reasoning sicher. Jedes Feld muss vor dem nächsten ausgefüllt werden.

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"]

Gute Anwendungsfälle: Bewertung von Kandidaten, Klassifizierung von Dokumenten, Konformitätsanalyse, medizinische Diagnose.

Der Model muss schreiben brief_candidate_summary Bevor ein Agent bewerten kann, muss er zunächst bewertet werden, und bevor er empfehlen kann, muss er zuvor bewertet worden sein. Es gibt keinen Abkürzungsweg.


2. Routing: ein semantisches Switch-Spruchteil

Routing zwingt den Model dazu, sich aus einer Menge von Optionen für einen bestimmten Pfad zu entscheiden, wobei dies mithilfe von … implementiert wird. Union Typen.

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]

Gute Anwendungsfälle sind die Intent-Klassifizierung, die Auswahl von Tools, die Priorisierung von Supportanfragen sowie die multi-agent-Verteilung.

Der Literal Diskriminierertool_name) lässt den Model einen einzigen Branch auswählen und füllt lediglich die Felder aus, die dieser Branch benötigt.


3. Zyklus: wiederholte Ausführung von Reasoning mit Listen

Cycle zwingt den Model dazu, mehrere Elemente zu erzeugen, wobei die Anzahl durch Grenzwerte begrenzt wird.

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)]

Gute Anwendungsfälle sind die Risikobewertung, die Extraktion von Problemen, paralleler Tool Calls-Ablauf sowie mehrstufige Planning-Prozesse.

Der MinLen und MaxLen Die Grenzwerte erzwingen mindestens 2 und höchstens 4 Elemente. In Kombination mit Routing ist dies die Methode, um einen fest definierten Satz an Tool Calls zu verarbeiten.


SGR in die Praxis umsetzen: Constrained Decoding

Die obigen Muster sind lediglich Pydantic-Schemata. Was sie bindend macht, ist Constrained Decoding (auch als Structured Output bezeichnet).

Constrained Decoding ändert den Generierungsprozess von Token. Anstelle zu ermöglichen, dass die Model-Beispiele frei aus ihrem Wortschatz wählen, wendet das Engine eine Grammatikmaske an, die solche Tokens-Elemente blockiert, die gegen das Schema verstoßen würden. Dies findet im Inference-Engine statt und nicht im Code Ihrer Anwendung.

[!TIP] SGR benötigt nicht wie o1 oder DeepSeek-R1 „Reasoning Models@“. Er funktioniert einwandfrei mit instruction-tuned Models und insbesondere hervorragend mit aus Reasoning abgeleiteten Models.

Cloud-Anbieter, die dies unterstützen

Die meisten modernen LLM-Anbieter stellen Structured Outputs über Constrained Decoding bereit:

AnbieterUnterstützung
OpenAIStructured Outputs (einschließlich Azure). GPT-5 verwendet JSON Schema über llguidance.
Google/GeminiJSON Schema Support seit November 2025 (Pydantic und Zod)
MistralEingestellte Structured Output
GrokStructured Outputs für mehrere Models
Feuerwerkseffekte AIJSON Schema
CerebrasStructured Outputs
OpenRouterHängt vom nachgelagerten Anbieter ab und entspricht JSON Schema

Inference-Engineer, die diese unterstützen

Für selbst gehostete Models verfügen alle gängigen Engine über einen Constrained Decoding Backend:

MotorBackend
vLLMxGrammar oder Leitfaden
SGLangÜbersichten, XGrammar, oder LL-Guidance
TensorRT-LLMGuidedDecoding
OllamaStructured Outputs

Warum sich dieser Artikel auf vLLM und xgrammar konzentriert

Einige Gründe:

Im nächsten Abschnitt wird erläutert, wie xgrammar tatsächlich eine Schema-Verifizierung auf der Ebene von Token durchführt.


Wie xgrammar Schemata durchsetzt

Dieser Abschnitt ist genau zu verstehen, da er die Art und Weise verändert, wie man SGR Workflows debuggt und optimiert.

xgrammar-Einhaltung

Wo die Maskierung stattfindet

xgrammar modifiziert die Ausgabelogits nach dem Forward-Pass des Model und vor der Stichprobenziehung. Es ändert den Model selbst nicht; stattdessen filtert es aus, welche Tokens ausgewählt werden dürfen.

Eine Standard-Inference-Schleife sieht wie folgt aus:

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 gerät zwischen den Schritten 1 und 2 ins Stocken:

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

Der Model berechnet weiterhin seine vollständige Wahrscheinlichkeitsverteilung auf der GPU. Anschließend wird xgrammar auf der CPU ausgeführt und wendet vor dem Sampling einen Bitmask auf diese Logits an. Ungültige Tokens erhalten dabei ihre Logits gesetzt auf -∞, wodurch ihre Wahrscheinlichkeit nach der Softmax-Berechnung exakt 0 wird.

Zwei Phasen

xgrammar teilt die Arbeit in eine Kompilierzeitphase sowie Runtime auf, und genau das sorgt für seine hohe Geschwindigkeit.

Phase 1: Grammatik-Kompilierung, einmal pro Schema

# 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)

Während der Kompilierung: xgrammar:

  1. Wandelt den JSON Schema in eine kontextfreie Grammatik um.
  2. Erstellt einen Stapelautomaten (PDA), der ein State Machine mit einem Stack ist, um damit verschachtelte Strukturen verarbeiten zu können. {"a": {"b": {"c": ...}}}.
  3. Es wird im Voraus berechnet, welche Tokens an jeder Grammatikposition gültig sind. Das Ergebnis ist der „adaptive Token-Masken-Cache“.
  4. Tokens werden als „kontextunabhängig“ (kann im Cache gespeichert werden) oder als „kontextabhängig“ (muss bei Runtime anhand des Stack-Zustands überprüft werden) kategorisiert.

[!NOTE] Etwa 99 % von Tokens weisen sich als kontextunabhängig heraus und werden schließlich im Cache gespeichert.Der XGrammar-Artikel). Die meisten Gültigkeitsprüfungen bei Runtime bestehen lediglich aus Cache-Aufrufen, weshalb xgrammar so schnell ist.

Phase 2: Erstellung der Runtime-Maske, für jeden Token

In jedem Generierungsschritt:

  1. Der GrammarMatcher Es verfolgt die aktuelle Position innerhalb der Grammatik.
  2. Es ruft die im Voraus berechnete Maske für kontextunabhängige Tokens ab.
  3. Es führt einen PDA-Ablauf durch, um die verbleibenden kontextabhängigen Tokens zu überprüfen.
  4. Es kombiniert diese Ergebnisse zu einer endgültigen Bitmaske und wendet sie auf die Logits an.

Warum Pushdown-Automaten und nicht reguläre Ausdrücke?

Wegen der Verkettung. Eine reguläre Ausdruckskonstruktion (ein endlicher State Machine) kann Strukturen wie diese nicht zuverlässig abgleichen:

{ "user": { "profile": { "settings": { "theme": "dark" } } } }

Der schwierige Teil sind die schließenden Klammern. }}}: Man muss sich merken, wie viele Elemente man geöffnet hat. Ein Pushdown-Automat verfügt über einen Stack, der dies überwacht, wodurch er beliebige Nesttiefe bewältigen kann. Genau deshalb kann xgrammar Union-Typen, verschachtelte Objekte sowie rekursive Schemata durchsetzen – Dinge, bei denen herkömmliche regex-basierte Ansätze an ihre Grenzen stoßen.

Ein konkretes Beispiel: Erstellung eines Float-Felds

Wenn der Model generiert "max_discount_percent":, xgrammar erkennt aus dem Schema, dass ein float folgt nun. Die Maske:

Der Vorwärtslauf könnte dem Wort eine hohe Wahrscheinlichkeit zugewiesen haben. "fifteen"Nach der Maskierung durch xgrammar beträgt die Wahrscheinlichkeit für Token 0. Model muss Ziffern ausgeben.

Warum „nahe null Overhead“

Drei Gründe:

  1. Parallelverarbeitung. Maskenberechnung auf dem CPU überschneidet sich mit dem nächsten Vorwärtslauf GPU. Während der GPU werden Logits für die Berechnung erzeugt Token N+1-Problem, das CPU berechnet gerade das Masken-Objekt für Token N.
  2. Caching. Der größte Teil der Gültigkeitsprüfungen erfolgt bereits zur Kompilierzeit. Runtime Es handelt sich größtenteils um Cache-Aufrufe.
  3. C++-Implementierung. Der Hot Path wird in C++ und nicht in Python ausgeführt, wobei die Maske direkt auf die Logits angewendet wird.

In Benchmarks xgrammar ist der Overhead nahezu vernachlässigbar, und die strukturierte Generierung kann gelegentlich schneller sein als die unbeschränkte Generierung, da das eingeschränkte Vokabular das Sampling erschwert.


Praktische Implementierung mit vLLM

Der Referenzwert ist der sgr – Rabattmanager Ein Projekt, eine kleine Demo, die SGR zur dynamischen Preiskalkulation verwendet.

Agent Workflow

Projektstruktur

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

Schritt 1: Definition der Schemata

# 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.")

Schritt 2: Ein LLM-Client, der xgrammar aktiviert

# 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)

[!HINWEIS] > guided_json nimmt ein JSON Schema-Diktum entgegen. Mit guided_decoding_backend: "xgrammar"Der LLM kann ausschließlich Tokens erzeugen, die gültige JSON-Objekte darstellen, die mit Ihrem Schema übereinstimmen.

Schritt 3: Die Agent orchestrieren

# 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}")

Schritt 4: Ausführung von vLLM mit 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

Beispielausgabe

🤖 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.

Das Audit-Log zeigt die tatsächliche Arbeitsweise des Model: Er berechnete den Margebetrag (40 beieinemWarenwertvon200 bei einem Warenwert von 200  bei 20 %) und legte eine Obergrenze für den Rabatt fest, damit das Angebot weiterhin innerhalb der Gewinnvorgaben bleibt.


Empfehlungen für die Praxis

Schema-Design

  1. Ordnen Sie die Felder nach dem Reasoning-Fluss. Analysefelder kommen vor Entscheidungsfeldern.
  2. Verfassen Sie beschreibende Texte. Field Beschreibungen. Sie leiten die Attention des Model genauso stark wie der Feldname selbst.
  3. Einschränkungen durch Anwendung von Literal und Annotated. Verwenden Sie Literal["a", "b"] für Enumerationen und Annotated[int, Ge(1), Le(10)] für die Grenzen.
  4. Halten Sie die Schemata fokussiert. Ein Schema pro Reasoning-Phase und anschließende Kombination durch mehrere Aufrufe.

vLLM-Konfiguration

  1. Verwenden Sie eine niedrige Temperatur (0,1–0,3), um eine deterministische Reasoning zu erzielen.
  2. Überlassen Sie es xgrammar, die Struktur zu verwalten. Konfrontieren Sie es nicht mit Formatierungsanweisungen in den Prompt.
  3. Achten Sie auf die Nutzung von Token. SGR verwendet in der Regel weniger Tokens als CoT, da dort keine ausführlichen Beschreibungen enthalten sind.

Produktionsaspekte

  1. Versionieren Sie Ihre Schemata auf dieselbe Weise wie APIs.
  2. Auch bei Verwendung von SGR sind fehlerfreie Handhabungsmechanismen für Netzwerk- und Serverfehler weiterhin erforderlich.
  3. Protokollieren Sie die rohen Ausgaben von SGR zur Einhaltung von Vorgaben sowie zum Debugging.
  4. Testen Sie mit Randfällen, damit das Schema an den Grenzbereichen weiterhin funktioniert.

Fazit

SGR ist es, das es ermöglicht, den Übergang von einer Funktionalität im Demo-Zustand zu einer stabilen Implementierung in der Produktion zu schaffen. Man definiert die Reasoning-Topologie in Pydantic, lässt xgrammar diese zu Decode Zeit überprüfen, und das Ergebnis ist:

Der sgr – Rabattmanager Demo verbindet jedes Codebeispiel aus diesem Beitrag mit einem echten vLLM-Server. Klonen Sie diesen Server und beginnen Sie damit, die Schemata an Ihre eigenen Workflow anzupassen.


Wichtige Erkenntnisse

  1. Die durch das Schema gesteuerte Reasoning-Methodik macht die Reasoning-Topologie explizit, anstatt darauf zu vertrauen, dass der Model den darin enthaltenen Anweisungen folgt.
  2. Constrained Decoding verhindert bereits zur Erstellung Zeit ungültige JSON-Werte, was sauberer ist als eine anschließende Validierung mit erneutem Versuch.
  3. Setzen Sie Analysefelder vor Entscheidungsfelder ein, wenn das Schema vorschreibt, dass Reasoning vor der Ausgabe erfolgen muss.
  4. Verwenden Sie SGR dann, wenn der nachgeschaltete Code von einer bestimmten Struktur abhängt – und nicht, wenn das Endergebnis aus freier Formulierung besteht.

Referenzen

SGR Framework

xgrammar

vLLM

Demo-Projekt