Search⌘ K
AI Features

Structured Outputs and Validation

Explore methods to improve AI workflow reliability by enforcing structured outputs and validating data in LangGraph. Learn to handle parsing errors, validate fields, and create fallback routes to maintain smooth agent operations, even when model outputs vary or fail. This lesson guides you through building robust extraction, validation, and routing nodes that safeguard your workflows from failure.

In a chat application, a sloppy model response is a UX problem. The user sees something vague or oddly formatted and moves on. The app continues working.

In a graph workflow, a sloppy model response is a system failure. If a model node returns free-form text when a downstream node expects a JSON object with a category key, that downstream node raises a KeyError. If a routing function expects the category to be one of four known values and the model returns "Feature Request" instead of "feature_request", the routing function falls through to an unhandled case. If a tool node receives a malformed input it cannot parse, the tool call silently fails or throws an exception that stops execution entirely.

The failures cascade. One unpredictable model output can break every node that runs after it.

This is why structure matters more in workflows than in chat. In a workflow, model outputs are not final answers; they are inputs to other nodes. Every downstream node is a consumer of the model’s output, and every consumer expects a specific shape.

Why models drift

Language models are probabilistic. The same prompt with the same input does not always produce the same output. On most runs, a well-written prompt reliably produces the expected format. On some runs, the model adds an explanation before the JSON object. On others, it uses slightly different field names. On rare runs, it produces something entirely unexpected.

The longer the workflow and the more nodes depend on a particular output shape, the more consequential any single drift becomes. We cannot eliminate drift entirely, but we can build a validation layer that catches it before it propagates.

What we are building

We will build a feedback classifier: a workflow that takes raw user feedback text and extracts four structured fields, a category, a sentiment, a priority level, and a one-sentence summary. Those fields then drive routing to a category-specific handler.

The workflow has two layers of protection. First, the extraction node wraps the model call and JSON parsing in a try/except block, writing a parse_error if anything goes wrong. Second, the validation node checks that the extracted fields are present and contain one of the allowed values. If either layer detects a problem, execution routes to a graceful fallback instead of crashing.

Feedback classifier workflow: a validation node sits between extraction and routing; malformed output routes to a fallback handler instead of crashing
Feedback classifier workflow: a validation node sits between extraction and routing; malformed output routes to a fallback handler instead of crashing

State design

The state schema separates the raw input from the extracted fields, and uses parse_error as the signal that travels between the extraction, validation, and routing layers.

from typing import TypedDict
class FeedbackState(TypedDict):
# Input — provided at invocation, never modified
raw_feedback: str
# Control — written by extraction and validation nodes
category: str # "bug", "feature_request", "general", or "billing"
sentiment: str # "positive", "negative", or "neutral"
priority: str # "high", "medium", or "low"
parse_error: str # non-empty string if extraction or validation failed
# Output — written by extraction and handler nodes
summary: str
response: str
State schema for the feedback classifier
  • Line 6: The only input field. All extracted fields start as empty strings at invocation.

  • Lines 9–12: Four control fields extracted from the raw text by the model. Each has a fixed set of allowed values.

  • Line 13: The error signal. An empty string means all is well. A non-empty string means ...