Alpha Notice: These docs cover the v1-alpha release. Content is incomplete and subject to change.For the latest stable version, see the current LangChain Python or LangChain JavaScript docs.

Overview

Structured output allows agents to return data in a specific, predictable format. Instead of parsing natural language responses, you get typed structured data. LangChain’s prebuilt ReAct agent createReactAgent handles structured output automatically. The user sets their desired structured output schema, and when the model generates the structured data, it’s captured, validated, and returned in the structuredResponse key of the agent’s state.
type ResponseFormat = (
    | ZodSchema<StructuredResponseT> // a Zod schema
    | Record<string, unknown> // a JSON Schema
)

const agent = createReactAgent({
    // ...
    responseFormat: ResponseFormat | ResponseFormat[]
})
responseFormat
Controls how the agent returns structured data. You can provide either a Zod object or JSON schema. By default, the agent uses a tool calling strategy, in which the output is created by an additional tool call. Certain models support native structured output, in which case the agent will use that strategy instead.You can control the behavior by wrapping ResponseFormat in a toolStrategy or providerStrategy function call:
import { toolStrategy, providerStrategy } from "langchain/agents";

const agent = createReactAgent({
    // use a provider strategy if supported by the model
    responseFormat: providerStrategy(z.object({ ... }))
    // or enforce a tool strategy
    responseFormat: toolStrategy(z.object({ ... }))
})
The structured response is returned in the structuredResponse key of the agent’s final state.

Provider strategy

Some model providers support structured output natively through their APIs (currently only OpenAI and Grok). This is the most reliable method when available. To use this strategy, configure a ProviderStrategy:
function providerStrategy<StructuredResponseT>(
  schema: ZodSchema<StructuredResponseT> | JsonSchemaFormat
): ProviderStrategy<StructuredResponseT>
schema
required
The schema defining the structured output format. Supports:
  • Zod Schema: A zod schema
  • JSON Schema: A JSON schema object
LangChain automatically uses ProviderStrategy when you pass a schema type directly to createReactAgent.responseFormat and the model supports native structured output:
import { z } from "zod";
import { createReactAgent, providerStrategy } from "langchain";

const ContactInfo = z.object({
    name: z.string().describe("The name of the person"),
    email: z.string().describe("The email address of the person"),
    phone: z.string().describe("The phone number of the person"),
});

const agent = createReactAgent({
    model: "openai:gpt-5",
    tools: tools,
    responseFormat: providerStrategy(ContactInfo)
});

const result = await agent.invoke({
    messages: [{"role": "user", "content": "Extract contact info from: John Doe, john@example.com, (555) 123-4567"}]
});

result.structuredResponse;
// { name: "John Doe", email: "john@example.com", phone: "(555) 123-4567" }
Provider-native structured output provides high reliability and strict validation because the model provider enforces the schema. Use it when available.
If the provider natively supports structured output for your model choice, it is functionally equivalent to write responseFormat: contactInfoSchema instead of responseFormat: toolStrategy(contactInfoSchema). In either case, if structured output is not supported, the agent will fall back to a tool calling strategy.

Tool calling strategy

For models that don’t support native structured output, LangChain uses tool calling to achieve the same result. This works with all models that support tool calling, which is most modern models. To use this strategy, configure a ToolStrategy:
function toolStrategy<StructuredResponseT>(
  responseFormat: 
    | JsonSchemaFormat
    | ZodSchema<StructuredResponseT>
    | (ZodSchema<StructuredResponseT> | JsonSchemaFormat)[]
  options?: ToolStrategyOptions
): ToolStrategy<StructuredResponseT>
schema
required
The schema defining the structured output format. Supports:
  • Zod Schema: A zod schema
  • JSON Schema: A JSON schema object
options.toolMessageContent
Custom content for the tool message returned when structured output is generated. If not provided, defaults to a message showing the structured response data.
options.handleError
Options parameter containing an optional handleError parameter for customizing the error handling strategy.
  • true: Catch all errors with default error template (default)
  • False: No retry, let exceptions propagate
  • (error: ToolStrategyError) => string | Promise<string>: retry with the provided message or throw the error
import { z } from "zod";
import { createReactAgent, toolStrategy } from "langchain";

const ProductReview = z.object({
    rating: z.number().min(1).max(5).optional(),
    sentiment: z.enum(["positive", "negative"]),
    keyPoints: z.array(z.string()).describe("The key points of the review. Lowercase, 1-3 words each."),
});

const agent = createReactAgent({
    model: "openai:gpt-5",
    tools: tools,
    responseFormat: toolStrategy(ProductReview)
})

result = agent.invoke({
    "messages": [{"role": "user", "content": "Analyze this review: 'Great product: 5 out of 5 stars. Fast shipping, but expensive'"}]
})

console.log(result.structuredResponse);
// { "rating": 5, "sentiment": "positive", "keyPoints": ["fast shipping", "expensive"] }

Custom tool message content

The toolMessageContent parameter allows you to customize the message that appears in the conversation history when structured output is generated:
import { z } from "zod";
import { createReactAgent, toolStrategy } from "langchain";

const MeetingAction = z.object({
    task: z.string().describe("The specific task to be completed"),
    assignee: z.string().describe("Person responsible for the task"),
    priority: z.enum(["low", "medium", "high"]).describe("Priority level"),
});

const agent = createReactAgent({
    model: "openai:gpt-5",
    tools: [],
    responseFormat: toolStrategy(MeetingAction, {
        toolMessageContent: "Action item captured and added to meeting notes!"
    })
});

const result = await agent.invoke({
    messages: [{"role": "user", "content": "From our meeting: Sarah needs to update the project timeline as soon as possible"}]
});

console.log(result);
/**
 * {
 *   messages: [
 *     { role: "user", content: "From our meeting: Sarah needs to update the project timeline as soon as possible" },
 *     { role: "assistant", content: "Action item captured and added to meeting notes!", tool_calls: [ { name: "MeetingAction", args: { task: "update the project timeline", assignee: "Sarah", priority: "high" }, id: "call_456" } ] },
 *     { role: "tool", content: "Action item captured and added to meeting notes!", tool_call_id: "call_456", name: "MeetingAction" }
 *   ],
 *   structuredResponse: { task: "update the project timeline", assignee: "Sarah", priority: "high" }
 * }
 */
Without tool_message_content, we’d see:
# console.log(result);
/**
 * {
 *   messages: [
 *     ...
 *     { role: "tool", content: "Returning structured response: {'task': 'update the project timeline', 'assignee': 'Sarah', 'priority': 'high'}", tool_call_id: "call_456", name: "MeetingAction" }
 *   ],
 *   structuredResponse: { task: "update the project timeline", assignee: "Sarah", priority: "high" }
 * }
 */

Error handling

Models can make mistakes when generating structured output via tool calling. LangChain provides intelligent retry mechanisms to handle these errors automatically.

Multiple structured outputs error

When a model incorrectly calls multiple structured output tools, the agent provides error feedback in a ToolMessage and prompts the model to retry:
import { z } from "zod";
import { createReactAgent, toolStrategy } from "langchain";

const ContactInfo = z.object({
  name: z.string().describe("Person's name"),
  email: z.string().describe("Email address"),
});

const EventDetails = z.object({
  event_name: z.string().describe("Name of the event"),
  date: z.string().describe("Event date"),
});

const agent = createReactAgent({
  model: "openai:gpt-5",
  tools: [],
  responseFormat: toolStrategy([ContactInfo, EventDetails]),
});

const result = await agent.invoke({
  messages: [
    {
      role: "user",
      content:
        "Extract info: John Doe (john@email.com) is organizing Tech Conference on March 15th",
    },
  ],
});

console.log(result);

/**
 * {
 *   messages: [
 *     { role: "user", content: "Extract info: John Doe (john@email.com) is organizing Tech Conference on March 15th" },
 *     { role: "assistant", content: "", tool_calls: [ { name: "ContactInfo", args: { name: "John Doe", email: "john@email.com" }, id: "call_1" }, { name: "EventDetails", args: { event_name: "Tech Conference", date: "March 15th" }, id: "call_2" } ] },
 *     { role: "tool", content: "Error: Model incorrectly returned multiple structured responses (ContactInfo, EventDetails) when only one is expected.\n Please fix your mistakes.", tool_call_id: "call_1", name: "ContactInfo" },
 *     { role: "tool", content: "Error: Model incorrectly returned multiple structured responses (ContactInfo, EventDetails) when only one is expected.\n Please fix your mistakes.", tool_call_id: "call_2", name: "EventDetails" },
 *     { role: "assistant", content: "", tool_calls: [ { name: "ContactInfo", args: { name: "John Doe", email: "john@email.com" }, id: "call_3" } ] },
 *     { role: "tool", content: "Returning structured response: {'name': 'John Doe', 'email': 'john@email.com'}", tool_call_id: "call_3", name: "ContactInfo" }
 *   ],
 *   structuredResponse: { name: "John Doe", email: "john@email.com" }
 * }
 */

Schema validation error

When structured output doesn’t match the expected schema, the agent provides specific error feedback:
import { z } from "zod";
import { createReactAgent, toolStrategy } from "langchain";

const ProductRating = z.object({
  rating: z.number().min(1).max(5).describe("Rating from 1-5"),
  comment: z.string().describe("Review comment"),
});

const agent = createReactAgent({
  model: "openai:gpt-5",
  tools: [],
  responseFormat: toolStrategy(ProductRating),
});

const result = await agent.invoke({
  messages: [
    {
      role: "user",
      content: "Parse this: Amazing product, 10/10!",
    },
  ],
});

console.log(result);

/**
 * {
 *   messages: [
 *     { role: "user", content: "Parse this: Amazing product, 10/10!" },
 *     { role: "assistant", content: "", tool_calls: [ { name: "ProductRating", args: { rating: 10, comment: "Amazing product" }, id: "call_1" } ] },
 *     { role: "tool", content: "Error: Failed to parse structured output for tool 'ProductRating': 1 validation error for ProductRating\nrating\n  Input should be less than or equal to 5 [type=less_than_equal, input_value=10, input_type=int].\n Please fix your mistakes.", tool_call_id: "call_1", name: "ProductRating" },
 *     { role: "assistant", content: "", tool_calls: [ { name: "ProductRating", args: { rating: 5, comment: "Amazing product" }, id: "call_2" } ] },
 *     { role: "tool", content: "Returning structured response: {'rating': 5, 'comment': 'Amazing product'}", tool_call_id: "call_2", name: "ProductRating" }
 *   ],
 *   structuredResponse: { rating: 5, comment: "Amazing product" }
 * }
 */

Error handling strategies

You can customize how errors are handled using the handleErrors parameter: Custom error message:
const responseFormat = toolStrategy(ProductRating, {
  handleError: "Please provide a valid rating between 1-5 and include a comment."
)

// Error message becomes:
// { role: "tool", content: "Please provide a valid rating between 1-5 and include a comment." }
Handle specific exceptions only:
import { ToolInputParsingException } from "@langchain/core/tools";

const responseFormat = toolStrategy(ProductRating, {
  handleError: (error: ToolStrategyError) => {
    if (error instanceof ToolInputParsingException) {
      return "Please provide a valid rating between 1-5 and include a comment.";
    }
    return error.message;
  }
)

// Only validation errors get retried with default message:
// { role: "tool", content: "Error: Failed to parse structured output for tool 'ProductRating': ...\n Please fix your mistakes." }
Handle multiple exception types:
const responseFormat = toolStrategy(ProductRating, {
  handleError: (error: ToolStrategyError) => {
    if (error instanceof ToolInputParsingException) {
      return "Please provide a valid rating between 1-5 and include a comment.";
    }
    if (error instanceof CustomUserError) {
      return "This is a custom user error.";
    }
    return error.message;
  }
)
No error handling:
const responseFormat = toolStrategy(ProductRating, {
  handleError: false  // All errors raised
)