Back to Blog
Python

Python LangChain Structured Output and Parsers

python langchain structured output and parsers: Learn how to get structured, typed output from LLMs using LangChain output parsers, including Pydantic and JSON parsers...

LangChainStructured OutputOutput ParsersPydanticJSON
Diagram showing an LLM response being parsed into a structured Pydantic object.

When you call a large language model, the response is plain text. For most applications, that is not enough. You need a typed object, a JSON document, or a validated data structure that your code can consume directly. This is where python langchain structured output and parsers come in. LangChain provides a set of output parsers that convert raw model responses into structured formats, and newer model methods can produce structured output directly.

Why Structured Output Matters

Free-text responses are unpredictable. A model might return the data you asked for, but with extra commentary, inconsistent formatting, or missing fields. When your application expects a specific schema, every deviation becomes a bug. Structured output solves this by constraining the model's response format and validating the result before it reaches your business logic.

For example, if you need a list of customer names and emails, a raw response might look like:

Here are the customers: 1. Alice - alice@example.com 2. Bob - bob@example.com

That is easy for a human to read, but parsing it reliably in code is fragile. A structured response would be:

{"customers": [{"name": "Alice", "email": "alice@example.com"}, {"name": "Bob", "email": "bob@example.com"}]}

With a parser, you can turn that JSON into a list of Pydantic objects and use them immediately.

How Output Parsers Work in LangChain

An output parser in LangChain is an object that takes the raw text from a model call and converts it into a desired structure. The typical flow is:

  1. Define the target structure (e.g., a Pydantic model or a JSON schema).
  2. Create a parser for that structure.
  3. Get format instructions from the parser and include them in the prompt.
  4. Call the model with the prompt.
  5. Pass the model's text response to the parser.

The parser's get_format_instructions() method returns a string that tells the model exactly what format to use. This is critical because the model needs explicit guidance to produce output the parser can handle.

Using PydanticOutputParser for Typed Results

Pydantic is the most common way to define structured output in LangChain. It gives you type validation, default values, and nested models. Here is a minimal example using PydanticOutputParser:

from langchain.output_parsers import PydanticOutputParser from langchain.prompts import PromptTemplate from langchain.chat_models import ChatOpenAI from pydantic import BaseModel, Field class Customer(BaseModel): name: str = Field(description="Customer's full name") email: str = Field(description="Customer's email address") class CustomerList(BaseModel): customers: list[Customer] = Field(description="List of customers") parser = PydanticOutputParser(pydantic_object=CustomerList) prompt = PromptTemplate( template="Extract all customers from the text.\n{format_instructions}\n{input_text}\n", input_variables=["input_text"], partial_variables={"format_instructions": parser.get_format_instructions()}, ) model = ChatOpenAI(model="gpt-4") user_text = "Alice (alice@example.com) and Bob (bob@example.com) are the only customers." formatted_prompt = prompt.format(input_text=user_text) response = model.invoke(formatted_prompt) parsed_result = parser.parse(response.content) print(parsed_result.customers[0].name) # Output: Alice

The parser adds format instructions to the prompt, telling the model to output JSON that matches the CustomerList schema. When the model returns text, the parser validates it against the Pydantic model and raises an error if something is missing or mistyped.

Using JSONOutputParser for Flexible Schemas

If you do not need Pydantic's validation or want to work with dynamic schemas, JSONOutputParser is a lighter alternative. It simply instructs the model to return valid JSON and parses it into a Python dictionary. You can then validate or transform the dictionary yourself.

from langchain.output_parsers import JSONOutputParser from langchain.prompts import PromptTemplate from langchain.chat_models import ChatOpenAI parser = JSONOutputParser() prompt = PromptTemplate( template="Return a JSON object with a 'customers' array. Each item must have 'name' and 'email'.\n{format_instructions}\n{input_text}\n", input_variables=["input_text"], partial_variables={"format_instructions": parser.get_format_instructions()}, ) model = ChatOpenAI(model="gpt-4") response = model.invoke(prompt.format(input_text="Alice and Bob are customers.")) data = parser.parse(response.content) print(data["customers"][0]["name"]) # Output: Alice

JSONOutputParser does not enforce a schema. It only ensures the output is valid JSON. This is useful when the structure is not known ahead of time or when you want to handle validation separately.

Handling Parse Errors and Retry Logic

Even with format instructions, models sometimes return malformed output. The parser will raise an OutputParserException when it cannot parse the response. A common strategy is to catch this exception and ask the model to fix its output by including the error message in a follow-up prompt.

from langchain.output_parsers import OutputParserException for attempt in range(3): response = model.invoke(formatted_prompt) try: parsed = parser.parse(response.content) break except OutputParserException as e: # Ask the model to correct itself correction_prompt = f"Your previous response was invalid: {e}\nPlease try again.\n{formatted_prompt}" formatted_prompt = correction_prompt else: raise RuntimeError("Failed to get valid structured output after 3 attempts")

This retry loop is simple but effective. The error message from the parser often contains specific details about what went wrong, which helps the model produce a corrected response.

Choosing Between Parsers and Structured Output Methods

LangChain also offers a more direct approach: the with_structured_output() method on chat models. Instead of using a parser, you can define a Pydantic model and pass it to the model, which returns the structured object directly.

from langchain.chat_models import ChatOpenAI model = ChatOpenAI(model="gpt-4") structured_model = model.with_structured_output(CustomerList) result = structured_model.invoke("Alice and Bob are customers.") print(result.customers[0].name)

This method uses the model's native structured output capabilities (such as function calling) and handles the parsing internally. It is often more reliable than adding format instructions to a prompt, because the model is explicitly trained to produce structured responses when invoked this way.

The tradeoff is that with_structured_output() may not be available on all models or may behave differently across providers. Output parsers, on the other hand, work with any model that can follow instructions. For maximum compatibility, parsers are the safer choice. For models that support function calling, with_structured_output() is cleaner and reduces the chance of malformed output.

Production Considerations for Structured Output

Structured output is not just about parsing; it affects the reliability and maintainability of your application. Here are some practical concerns to keep in mind.

Validation and error handling are the first line of defense. Even with a parser, you should validate the parsed data against your business rules. A Pydantic model can include custom validators, but you may also need to check for semantic correctness that the model cannot guarantee.

Retry logic is essential. Models are probabilistic, so occasional invalid output is inevitable. A retry loop with a bounded number of attempts prevents infinite loops while giving the model a chance to correct itself.

Logging and monitoring should capture parse failures. If a particular prompt consistently produces invalid output, you need to know about it. Log the raw model response and the error message to debug the issue.

Schema evolution is a maintenance concern. When you change a Pydantic model, old cached responses may no longer parse. Version your schemas and handle migration if you store structured output.

Cost and latency also matter. Adding format instructions to a prompt increases token usage, and retries multiply that cost. with_structured_output() can be more token-efficient because it uses the model's native structured output path.

Finally, consider the model's context window. Large schemas with many fields consume tokens and may push the prompt over the limit. Keep your schemas as small as possible while still capturing the required data.

Structured output is a powerful tool, but it is not a silver bullet. It requires careful design of your schemas, robust error handling, and a clear understanding of the tradeoffs between parsers and native structured output methods. By choosing the right approach for your model and use case, you can build applications that reliably consume LLM output without manual parsing or fragile string manipulation.

python langchain structured output and parsers: Practical Us | RYUSLOG DEV