Language models are probabilistic — they do not guarantee that their output will be well-formed JSON, contain all required fields, or respect the value constraints your application depends on. Guardrails AI solves this by wrapping LLM calls with a validation layer built on JSON Schema and Python validators, automatically retrying when the model produces non-conforming output. This guide explains exactly how it works and how to set up a reliable structured output pipeline from scratch.
What is Guardrails AI?
Guardrails AI is an open-source Python library designed to make LLM outputs reliable and predictable. It wraps any LLM API call — OpenAI, Anthropic, Cohere, local models — with a validation pipeline that checks the model's response against a user-defined schema and a set of field-level validators before returning the result to your application code.
The core abstraction is the `Guard` object. You construct a Guard from a Pydantic model or a JSON Schema definition, optionally attach validators to individual fields, then call the Guard instead of calling the LLM directly. The Guard handles prompt construction, response parsing, validation, and automatic re-prompting when validation fails — all in a single, auditable pipeline.
Where Guardrails AI fits in the LLM stack
Guardrails sits between your application code and the LLM provider. It does not replace the model or change how the model is called — it adds a contract enforcement layer around the call. Think of it as a schema validator for API responses, except the "API" is a language model that produces natural language, and the "response" needs to be parsed into structured data before it can be validated.
- Guard: The main interface — wraps an LLM call and applies schema + validators.
- ValidationOutcome: The result object returned by a Guard call — contains validated output, pass/fail status, and field errors.
- Validator: A callable attached to a schema field that enforces a specific rule (type, range, regex, external check).
- reask: The retry mechanism — when validation fails, Guardrails re-prompts the model with error context.
- Hub: The Guardrails validator registry — a curated collection of community-contributed validators installable via `guardrails hub install`.
Note
Why LLM output needs validation
The fundamental problem is that language models are trained to produce plausible text — not to respect programmatic contracts. Even when you instruct a model to return JSON, it can produce output with missing fields, wrong value types, extra fields your downstream code does not expect, hallucinated values outside allowed ranges, or text fragments wrapped around the JSON block that break parsing entirely.
The five failure modes of unvalidated LLM output
- Parse failure: The model wraps the JSON in markdown code fences, adds commentary before or after, or produces malformed JSON that cannot be parsed.
- Missing required fields: The model omits a field it was asked to populate, causing a KeyError or null reference error in downstream code.
- Type violations: A field expected to be a number arrives as a string, or a boolean arrives as the string "true" rather than the literal `true`.
- Value constraint violations: A rating field returns 11 when the allowed range is 1–10, or an enum field returns a value not in the defined list.
- Hallucinated structure: The model invents additional fields or nests objects differently than the schema specifies.
Any of these failures can silently corrupt downstream data, cause runtime exceptions, or allow bad values to propagate into business logic. For low-stakes prototypes, optimistic parsing is acceptable. For production pipelines — invoice extraction, clinical data parsing, fraud detection signals, customer record enrichment — every field violation is a data quality problem that needs to be caught and handled.
The contract between your application and the LLM is only as strong as the validation you enforce around every response. Hope is not a validation strategy.
Warning
JSON Schema as the validation contract
JSON Schema is the language Guardrails AI uses to describe what a valid LLM response looks like. A JSON Schema definition specifies the expected object structure — which fields exist, their types, which are required, and what constraints apply to their values. This schema serves two purposes: it tells Guardrails how to validate the parsed response, and Guardrails uses it to construct the prompt instruction that tells the model what shape to produce.
What JSON Schema covers for LLM validation
For structured output use cases, the most useful JSON Schema keywords are type enforcement, required field lists, enum values, string formats, and numeric ranges. Together these cover the majority of field-level rules an extraction or generation task needs to enforce.
{
"$schema": "https://json-schema.org/draft-07/schema",
"type": "object",
"required": ["product_name", "rating", "sentiment", "summary"],
"additionalProperties": false,
"properties": {
"product_name": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"rating": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"sentiment": {
"type": "string",
"enum": ["positive", "neutral", "negative"]
},
"summary": {
"type": "string",
"minLength": 20,
"maxLength": 500
},
"pros": {
"type": "array",
"items": { "type": "string" },
"maxItems": 5
},
"cons": {
"type": "array",
"items": { "type": "string" },
"maxItems": 5
}
}
}This schema tells Guardrails to reject any response where `rating` is outside 1–5, `sentiment` is not one of the three allowed values, or `summary` is shorter than 20 characters. Fields listed in `required` must be present. `additionalProperties: false` rejects any extra fields the model adds spontaneously.
Generating a schema from a sample response
When designing a new extraction task, getting the initial schema right takes time. A practical shortcut: run your prompt once with no validation, examine the raw JSON the model returns, then use the JSON Schema Generator to automatically infer a Draft-07 schema from that sample. The generated schema captures types, required fields, and nested structure. You then refine it — tightening string lengths, adding enum constraints, setting numeric bounds — rather than writing every keyword from scratch.
JSON Schema Generator
Paste any JSON payload and get a complete Draft-07 or Draft 2020-12 schema automatically — browser-local, no upload, no signup.
Tip
How Guardrails AI validates output
Understanding the validation pipeline helps you debug failures and configure the right response strategy for each field. The pipeline runs in a fixed order for every Guard call: prompt injection, response parsing, JSON Schema validation, field-level validator execution, and outcome assembly.
Prompt injection
Before sending the prompt to the LLM, Guardrails appends a structured instruction block derived from your schema. This block describes the expected output format, lists required fields with their types and constraints, and (when reask is active) includes any validation errors from the previous attempt. The injection is transparent — you write your task prompt normally and Guardrails handles the formatting instructions.
Response parsing
After the model responds, Guardrails extracts the JSON from the output. It handles common model formatting habits: stripping markdown code fences, trimming prose before or after the JSON block, and correcting minor syntax issues. If the output cannot be parsed into a Python dict, the Guard immediately triggers a reask with a parse error message rather than raising an exception.
JSON Schema validation
The parsed dict is validated against your JSON Schema using a standards-compliant validator. Type violations, missing required fields, enum mismatches, and range violations all produce structured error objects at this stage. You can test your schema against a candidate payload independently using the JSON Schema Validator before wiring it into a Guard.
Field-level validator execution
After the JSON Schema check passes, each field's registered validators run in order. Built-in validators include `ValidChoices`, `ValidRange`, `ValidURL`, `NoRefusal`, `ToxicLanguage`, `PIIFilter`, and dozens more from the Hub. Custom validators are plain Python functions decorated with `@register_validator`. Each validator returns a `PassResult` or `FailResult` with a human-readable error message.
Outcome assembly and reask
Guardrails assembles a `ValidationOutcome` containing the validated output dict, a `validation_passed` boolean, and a list of field errors. If validation failed and `num_reasks` is greater than zero, the pipeline loops back to Step 1 with the validation errors injected into the prompt, giving the model a chance to correct its output. Each reask round decrements the retry counter.
| on_fail action | What it does | Best for |
|---|---|---|
| exception | Raises ValidationError immediately | Hard requirements — fail fast |
| reask | Re-prompts the model with error context | Most structured output use cases |
| fix | Applies a correction function automatically | Normalisation (trim, lowercase, cast) |
| filter | Removes the failing field from the output | Optional enrichment fields |
| refrain | Returns None for the entire Guard call | Conservative fallback workflows |
| noop | Records the failure but continues | Logging and observability pipelines |
Rail specs and Pydantic integration
Guardrails AI supports two schema definition styles: the legacy Rail spec format and the modern Pydantic model approach. Understanding both is useful because you will encounter Rail specs in older codebases and community examples, while Pydantic is the recommended path for all new projects as of Guardrails v0.4+.
Pydantic models as Guard schemas
The cleanest way to define a Guardrails output schema in Python is a Pydantic `BaseModel` subclass. Pydantic models have native JSON Schema export, IDE type checking, and familiar Python syntax. You attach Guardrails validators using Pydantic's `Field()` with custom metadata, or by importing validator classes directly from `guardrails`.
from pydantic import BaseModel, Field
from guardrails import Guard
from guardrails.hub import ValidRange, ValidChoices
class ProductReview(BaseModel):
product_name: str = Field(description="Name of the product reviewed")
rating: int = Field(
description="Rating from 1 to 5",
validators=[ValidRange(min=1, max=5, on_fail="reask")]
)
sentiment: str = Field(
description="Overall sentiment of the review",
validators=[ValidChoices(
choices=["positive", "neutral", "negative"],
on_fail="reask"
)]
)
summary: str = Field(description="One paragraph summary of the review")
# Build the Guard from the Pydantic model
guard = Guard.from_pydantic(ProductReview)
# Call the LLM through the Guard
outcome = guard(
openai.chat.completions.create,
model="gpt-4o",
messages=[{"role": "user", "content": f"Extract a review from: {raw_text}"}],
num_reasks=2,
)
if outcome.validation_passed:
review: ProductReview = outcome.validated_output
else:
print(outcome.error)The Pydantic-to-JSON Schema pipeline
Under the hood, Guardrails calls `model.model_json_schema()` to export your Pydantic model as a JSON Schema, then uses that schema for both prompt injection and response validation. This means every Pydantic model you can write is automatically a valid Guardrails contract. You can inspect the generated schema yourself — paste a sample response into the JSON Schema Generator to see the equivalent schema, then compare it against your Pydantic model's output.
If your application is TypeScript-based but calls a Python Guardrails service, the JSON to Zod Schema converter generates a matching Zod schema from the same sample JSON — useful for validating the same contract on the client side without duplicating the schema definition manually.
Rail specs — the legacy format
Rail specs are XML files where each `<output>` element describes a field with a `type` attribute and one or more `<validator>` child elements. They predate the Pydantic integration and are less ergonomic for Python developers, but they are still fully supported. If you inherit a Guardrails codebase using `.rail` files, you can migrate each spec to a Pydantic model incrementally — the validation behaviour is equivalent.
Note
Practical workflow and toolchain
A reliable Guardrails workflow combines offline schema design, local testing, and production monitoring. The schema design phase — where you define what valid output looks like — is the most important step and benefits most from dedicated tooling.
Step 1: Design the schema offline
Before writing any Guardrails code, define your output schema as a standalone JSON Schema document. Working in JSON Schema first lets you iterate on the contract independently of the LLM call — you can validate sample payloads, adjust constraints, and confirm the schema is correct before spending API credits on testing.
The JSON Schema Validator on Quasar Tools lets you paste a JSON Schema and a candidate payload, then see field-level validation errors immediately. Use it to confirm that your `required` arrays, enum lists, and numeric ranges behave as expected before translating the schema into a Pydantic model. The JSON Formatter & Validator is useful for checking that your schema file itself is syntactically valid JSON before referencing it.
Step 2: Generate Pydantic from JSON
If you have collected sample LLM responses during prototyping, the JSON to Python Dataclass / Pydantic converter generates a Pydantic model from a sample JSON payload in one step. The tool infers field types, handles nested objects, and applies `Optional` where fields may be absent. Use the output as a starting point and add Guardrails validators to each field based on the constraints in your JSON Schema.
Step 3: Test locally with mock responses
Guardrails Guards can be called with any Python callable, not just live LLM APIs. During development, pass a mock function that returns a fixed string response to test the validation pipeline without any API calls. This makes it fast and free to iterate on schema changes, validator configurations, and reask prompts before connecting to a paid model endpoint.
Recommended Quasar Tools schema workflow
- JSON Schema Generator — infer a starting schema from a sample LLM response.
- JSON Schema Validator — validate candidate payloads against your schema offline.
- JSON Formatter & Validator — check schema files are valid JSON before use.
- JSON to Python Dataclass — generate a Pydantic model from a sample payload.
- JSON to Zod Schema — generate a TypeScript-side contract for client validation.
JSON Schema Validator
Validate any JSON payload against a schema with field-level error reporting — browser-local, no upload, instant results.
Edge cases and limitations
Guardrails AI improves structured output reliability significantly, but it is not a guarantee of correctness. Understanding the limitations helps you design your pipeline with appropriate fallbacks rather than trusting the Guard unconditionally.
Reask loops do not always converge
When a model consistently fails a specific validator, adding more reask retries does not help — it just costs more API credits for the same result. Some failure modes are systematic: the model genuinely does not understand a constraint, or the constraint is too strict for the model to reliably satisfy given the input. Audit your validator failure rates and treat high-failure validators as signals to revisit either the constraint definition or the prompt.
JSON Schema does not catch semantic errors
A schema can confirm that `sentiment` is one of `["positive", "neutral", "negative"]` but cannot verify that the assigned sentiment is actually correct for the input text. JSON Schema and validators enforce structural and syntactic contracts — they cannot replace human review or downstream quality checks for content accuracy. Use Guardrails to enforce the format and structure of the output, and apply separate evaluation metrics for content correctness.
Latency and cost overhead
Each reask attempt is an additional LLM API call at full token cost. For a Guard configured with `num_reasks=3`, a worst-case extraction can trigger four LLM calls before failing. In high-throughput pipelines, this overhead is significant. Profile your Guard's reask rate in staging before deploying to production, and set `num_reasks=0` for non-critical fields where the `filter` or `noop` on_fail actions are acceptable alternatives to retrying.
| Limitation | Impact | Mitigation |
|---|---|---|
| Reask loops do not converge | Wasted API credits on known failures | Audit validator failure rates; simplify constraints |
| Semantic errors uncaught | Wrong values that pass structural checks | Apply separate content evaluation metrics |
| Latency from reasks | Up to 4× the cost per failed call | Profile reask rate; use filter/noop for non-critical fields |
| No cross-field validation | Cannot enforce field A > field B | Use a post-validation Python function for cross-field rules |
| Provider prompt sensitivity | Injection format affects model compliance | Test multiple prompt formats; use native structured output modes |
Warning
Tip
Key takeaways
- Guardrails AI wraps LLM calls with a JSON Schema validation layer and field-level validators, automatically re-prompting the model when output fails validation.
- JSON Schema defines the structural contract — field types, required fields, enum values, and numeric ranges. Generate a starting schema from a sample payload using the JSON Schema Generator.
- The reask mechanism re-prompts the LLM with structured error context — configurable per Guard call with `num_reasks`. High reask rates signal overly strict constraints or a misaligned prompt.
- Pydantic models are the recommended schema format in Guardrails v0.4+: they export to JSON Schema automatically and integrate with Python type checking and IDE tooling.
- Use `additionalProperties: false` in every schema to prevent the model from adding invented fields that silently pass validation but corrupt your data model.
- JSON Schema enforces structure, not semantic correctness — apply separate evaluation metrics for content accuracy alongside Guardrails schema validation.
- Validate your JSON Schema and candidate payloads offline with the JSON Schema Validator before wiring any Guard into a live LLM pipeline.