langchain-ai/langchain
Structured output
Strategies for forcing a model's response to match a schema. Source: libs/langchain_v1/langchain/agents/structured_output.py (and BaseChatModel.with_structured_output in libs/core/langchain_core/language_models/chat_models.py).
Purpose
Plain text from a chat model is great for chat. For structured workflows — extraction, classification, agent final answers — you need typed output. LangChain offers two layers:
- Model-level —
BaseChatModel.with_structured_output(schema)returns a runnable that emits a typed value. This works without an agent and is what most users reach for first. - Agent-level —
create_agent(..., response_format=schema)constrains the agent's final response and stores it instate["structured_response"]. This composes with multi-step tool use.
Strategies
libs/langchain_v1/langchain/agents/structured_output.py defines four:
| Strategy | What it does | When to use |
|---|---|---|
AutoStrategy (default) |
Picks the best available method based on the model's profile (supports_responses_api → provider strategy; otherwise tool strategy) |
When you don't care which method is used |
ToolStrategy(schema) |
Binds a single tool whose parameters are the schema; parses the tool call args | Universally supported |
ProviderStrategy(schema) |
Uses the provider's native structured-output endpoint (OpenAI JSON Schema, Anthropic strict tools) | Best validation, lowest token overhead |
Custom ResponseFormat subclass |
Implement your own | Rare |
Schema types accepted:
- Pydantic
BaseModelsubclass - Python
@dataclass TypedDict- Raw JSON Schema dict
The dispatch is driven by _parse_with_schema in structured_output.py, which routes based on SchemaKind ("pydantic" | "dataclass" | "typeddict" | "json_schema").
How AutoStrategy decides
graph TD
Schema[Pydantic / dataclass / TypedDict / JSON schema]
Profile[Model profile]
Auto{AutoStrategy}
Provider[ProviderStrategy]
Tool[ToolStrategy]
Schema --> Auto
Profile --> Auto
Auto -->|provider supports JSON Schema| Provider
Auto -->|otherwise| ToolAutoStrategy checks model.profile.supports_native_structured_output (or a provider-specific flag). When the profile data isn't loaded, the factory falls back to a hard-coded list of model name prefixes that are known to support it (gpt-5, gpt-4.1, gpt-4o, gpt-oss, o3-pro, o3-mini, grok, …) — see FALLBACK_MODELS_WITH_STRUCTURED_OUTPUT in libs/langchain_v1/langchain/agents/factory.py.
Errors
structured_output.py defines:
StructuredOutputError— base class.MultipleStructuredOutputsError— model returned more than one structured tool call when only one was expected.StructuredOutputValidationError— the tool-call arguments failed schema validation.
When using ToolStrategy, the agent loop can recover by:
- Catching the validation error.
- Adding a tool error message to the conversation.
- Letting the model try again.
The default error template is:
Error: {error}
Please fix your mistakes.defined as STRUCTURED_OUTPUT_ERROR_TEMPLATE in factory.py.
Model-level structured output
For non-agent code paths:
from pydantic import BaseModel
from langchain_openai import ChatOpenAI
class Person(BaseModel):
name: str
age: int
model = ChatOpenAI(model="gpt-5")
typed_model = model.with_structured_output(Person, method="function_calling")
result = typed_model.invoke("Alice is 30 years old.")
# result is Person(name="Alice", age=30)Methods:
"function_calling"— bind a single tool whose schema matches the type, parse the call."json_mode"— request JSON output, parse it."json_schema"— use the provider's native JSON Schema endpoint (OpenAI'sresponse_format={"type": "json_schema"}).
Partner-specific overrides may add others (e.g. Anthropic's tool-with-input_schema).
include_raw=True returns a dict {"raw": AIMessage, "parsed": Person | None, "parsing_error": Exception | None} instead of just the parsed value, useful when you want both the typed result and the underlying message for tracing.
Agent-level structured output
from langchain.agents import create_agent
agent = create_agent(
model="openai:gpt-5",
tools=[search],
response_format=AnalysisReport, # accepts a schema or a ResponseFormat
)
result = agent.invoke({"messages": [...]})
report: AnalysisReport = result["structured_response"]Behind the scenes, the factory:
- Wraps the schema in an
AutoStrategy(or uses the provided strategy). - Adds the structured-output tool to the model's bound tools.
- Detects when the model emits the structured-output tool call and treats it as the agent's final answer.
- Stores the parsed value in
state["structured_response"]and exits the loop.
Integration points
BaseChatModel.with_structured_outputis the universal entry point at the model layer.create_agent(response_format=...)is the agent-layer entry point.- Standard tests in
libs/standard-tests/langchain_tests/integration_tests/exercise structured output across providers using a common schema. - Partner packages override
with_structured_outputto dispatch to provider-native endpoints when available.
Entry points for modification
- For a new strategy, subclass
ResponseFormatinstructured_output.pyand handle it infactory.py's strategy selection. - For a new schema kind (beyond Pydantic / dataclass / TypedDict / JSON schema), extend
SchemaKindand_parse_with_schema. - For provider-specific structured-output endpoints, implement them in the partner's
with_structured_outputoverride.
Related
- features/agents —
response_formatis one ofcreate_agent's args - primitives/language-models —
with_structured_outputlives onBaseChatModel - primitives/output-parsers — the parsers that back
function_callingmode
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.