← Writing
AI & Generative AI

Unpacking Output Parsers with LangChain

Data Mastery Series — Episode 33: LangChain Website (Part 8)

24 Nov 202412 min readLangChainDashboard
LangChain Series · Part 12 of 19

Unpacking Output Parsers with LangChain

Data Mastery Series — Episode 33: LangChain Website (Part 8)

Connect with me and follow our journey: Linkedin, Facebook


Welcome to Episode 33 of the Data Mastery Series, where we continue our journey exploring LangChain, a powerful tool for integrating AI into real-world applications. If you’ve been following along, you’ve seen how LangChain can elevate your data workflows. Here’s a quick recap of what we’ve covered so far:

Note:This post is a reflection on my learning journey to better understand LangChain. The content is based on resources found link. I hope you find it insightful and useful!

In today’s episode, we’re diving into Output Parsers. These tools are essential for transforming AI-generated outputs into structured formats like JSON, CSV, or even custom models. Whether you’re integrating with an API, running analyses, or preparing data for visualization, Output Parsers are your go-to solution.

What Are Output Parsers?

LLMs are excellent at generating human-like text, but applications often require more than plain text. Output Parsers help bridge the gap by converting unstructured AI outputs into structured data formats such as JSON, CSV, or custom data structures. This ensures seamless integration into workflows while maintaining data integrity and usability.

Exploring Output Parsers in LangChain

LangChain provides a variety of Output Parsers, each tailored for specific use cases. Here’s a breakdown of some key parsers:

1. OpenAI Tools:

OpenAI Tools Parsers enable LLMs to interact with predefined functions, returning structured data. For instance, they can extract arguments, filter specific keys, or validate outputs using a schema.

  • JsonOutputToolsParser: Converts function call outputs into JSON.

Example - OpenAI Tools (JsonOutputToolsParser)

Define a simple data structure

class Joke(BaseModel):
"""Joke to tell user."""

setup: str = Field(description="question to set up a joke")  
punchline: str = Field(description="answer to resolve the joke")  

Create a prompt

prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant"),
("user", "{input}")
])

Initialize the LLM and bind the Joke tool

model = ChatOpenAI(api_key=OPENAI_API_KEY, model="gpt-3.5-turbo", temperature=0).bind_tools([Joke])

Use JsonOutputToolsParser to initialize the parser and chain

parser = JsonOutputToolsParser()
chain = prompt | model | parser

Get the result

result = chain.invoke({"input": "เล่าเรื่องตลกให้ฟังที ภาษาไทย"}) # Tell me a joke in Thai
print(result)

Output:

'''
[{'args': {'setup': 'เป็นคนที่ชอบนอนเป็นเวลานานมาก', 'punchline': 'เรียกว่าคนนอนยาว'}, 'type': 'Joke'}]
'''

  • JsonOutputKeyToolsParser: Extracts specific keys from the output.

Example - OpenAI Tools (JsonOutputKeyToolsParser)

Above is same example 1

Use JsonOutputKeyToolsParser to parse the output

parser = JsonOutputKeyToolsParser(key_name="Joke")

Creating a chain

chain = prompt | model | parser

Get the result

result = chain.invoke({"input": "เล่าเรื่องตลกให้ฟังที ภาษาไทย ขอเรื่องใหม่ๆ"}) # Tell me a new joke in Thai.
print(result)

Output:

'''
[{'setup': 'เป็นไงถ้าเสียงของคุณเป็นเสียงของเสือ?', 'punchline': 'คนที่อยู่ข้างๆคงรู้สึกเหมือนอยู่ในสวนสัตว์'}]
'''

  • PydanticToolsParser: Validates and formats outputs into custom data models using Pydantic.

Example - OpenAI Tools (PydanticToolsParser)

class Joke(BaseModel):
"""Joke to tell user."""

setup: str = Field(description="question to set up a joke")  
punchline: str = Field(description="answer to resolve the joke")  

# Ensure the setup ends with a question mark  
@Field.validator("setup")  
def question_ends_with_question_mark(cls, value: str, info: FieldValidationInfo):  
    if not value.endswith("?"):  
        raise ValueError("Badly formed question! Setup must end with a question mark.")  
    return value  

Set up the chain

parser = PydanticToolsParser(tools=[Joke]) # Parse output using the Joke model
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant"),
("user", "{input}")
])
model = ChatOpenAI(api_key=OPENAI_API_KEY, model="gpt-3.5-turbo", temperature=0).bind_tools([Joke])
chain = prompt | model | parser

Get a joke from the AI

result = chain.invoke({"input": "Tell me a joke"})
print(result)

Output:

'''
[Joke(setup="Why couldn't the bicycle stand up by itself?", punchline='Because it was two tired!')]
'''

2. OpenAI Functions:

Similar to OpenAI Tools Parsers, these parsers format data returned by OpenAI’s function-calling capabilities. You can extract structured data or validate it using schemas. Examples include:

  • JsonOutputFunctionsParser: Formats outputs as JSON.

Example - OpenAI Functions (JsonOutputFunctionsParser)

class Joke(BaseModel):
"""Joke to tell user."""

setup: str = Field(description="question to set up a joke")  
punchline: str = Field(description="answer to resolve the joke")  

openai_functions = [convert_pydantic_to_openai_function(Joke)]
model = ChatOpenAI(api_key=OPENAI_API_KEY, temperature=0)
prompt = ChatPromptTemplate.from_messages(
[("system", "You are helpful assistant"), ("user", "{input}")]
)

Use JsonOutputFunctionsParser to parse the output

parser = JsonOutputFunctionsParser()

Bind OpenAI functions to the model

chain = prompt | model.bind(functions=openai_functions) | parser

Invoke the chain

result = chain.invoke({"input": "Tell me a joke."})
print(result) # Outputs the joke in JSON format

Output:

'''
{'setup': "Why couldn't the bicycle stand up by itself?", 'punchline': 'Because it was two tired!'}
'''

  • JsonKeyOutputFunctionsParser: Extracts specific keys from JSON outputs.

Example - OpenAI Functions (JsonKeyOutputFunctionsParser)

class Jokes(BaseModel):
joke: List[Joke]
funniness_level: int

Extract only the "joke" key

parser = JsonKeyOutputFunctionsParser(key_name="joke")
openai_functions = [convert_pydantic_to_openai_function(Jokes)]
chain = prompt | model.bind(functions=openai_functions) | parser
result = chain.invoke({"input": "tell me two jokes"})
print(result)

Output:

'''
[{'setup': "Why couldn't the bicycle stand up by itself?", 'punchline': 'It was two tired.'},
{'setup': 'What do you call a fish wearing a crown?', 'punchline': 'A kingfish.'}]
'''

  • PydanticOutputFunctionsParser: Combines validation and formatting for more reliable outputs.

Example - OpenAI Functions (PydanticOutputFunctionsParser)

Define a Joke schema

class Joke(BaseModel):
"""Joke to tell user."""

setup: str = Field(..., description="Question to set up a joke.")  
punchline: str = Field(..., description="Answer to resolve the joke.")  

# Custom validation logic using `field_validator` in Pydantic v2  
@field_validator("setup")  
def question_ends_with_question_mark(cls, field):  
    if not field.endswith("?"):  
        raise ValueError("Setup must be a question ending with a question mark!")  
    return field  

PydanticOutputFunctionsParser with updated schema

parser = PydanticOutputFunctionsParser(pydantic_schema=Joke)

Convert the Pydantic schema to OpenAI functions

openai_functions = [convert_pydantic_to_openai_function(Joke)]

Create a chain using LangChain utilities

chain = prompt | model.bind(functions=openai_functions) | parser

Example usage

result = chain.invoke({"input": "tell me a joke"})
print(result)

Output:

'''
setup="Why couldn't the bicycle stand up by itself?" punchline='It was two tired!'
'''

3. JSON**:**

JSON is one of the most versatile data formats for APIs and storage. LangChain’s JsonOutputParser ensures LLM outputs conform to predefined JSON schemas, with optional integration into Pydantic for validation.

Example - JSON (with Pydantic)

Define the data structure

class Joke(BaseModel):
setup: str = Field(description="question to set up a joke")
punchline: str = Field(description="answer to resolve the joke")

Initialize the model

model = ChatOpenAI(api_key=OPENAI_API_KEY, temperature=0)

Create a JSON parser with the defined schema

parser = JsonOutputParser(pydantic_object=Joke)

Define a prompt template

prompt = PromptTemplate(
template="Answer the user query.\n{format_instructions}\n{query}\n",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)

Combine prompt, model, and parser into a chain

chain = prompt | model | parser

Generate a joke

joke_query = "Tell me a joke."
result = chain.invoke({"query": joke_query})
print(result)

Output:

'''

{'setup': "Why couldn't the bicycle stand up by itself?", 'punchline': 'Because it was two tired!'}

'''

Example - JSON (without Pydantic)

parser = JsonOutputParser()

result = chain.invoke({"query": "Tell me a joke."})
print(result)

Output:

'''

{'response': "Why couldn't the bicycle stand up by itself? Because it was two tired!"}

'''

4. CSV:

When working with tabular data, LangChain’s CommaSeparatedListOutputParser simplifies the creation of structured lists. This parser is ideal for generating CSV-like outputs for spreadsheets or database

Example - CSV

Initialize the output parser

output_parser = CommaSeparatedListOutputParser()

Get formatting instructions

format_instructions = output_parser.get_format_instructions()

Create a prompt template

prompt = PromptTemplate(
template="List five {subject}.\n{format_instructions}",
input_variables=["subject"],
partial_variables={"format_instructions": format_instructions},
)

Initialize the model

model = ChatOpenAI(api_key=OPENAI_API_KEY, temperature=0)

Combine prompt, model, and parser into a chain

chain = prompt | model | output_parser

Generate a list of ice cream flavors

result = chain.invoke({"subject": "ice cream flavors"})
print(result)

Output:

'''

['Vanilla', 'Chocolate', 'Strawberry', 'Mint Chocolate Chip', 'Cookies and Cream']

'''

5. Pandas DataFrame:

For Python users, Pandas DataFrame Output Parser is a game-changer. It allows LLMs to interact directly with tabular data, enabling dynamic queries, calculations, and seamless integration into data analysis workflows.

Example - Pandas DataFrame

Query 1: Retrieve a specific column

Create a DataFrame

df = pd.DataFrame({
"num_legs": [2, 4, 8, 0],
"num_wings": [2, 0, 0, 0],
"num_specimen_seen": [10, 2, 1, 8],
})

Create format_parser_output function

def format_parser_output(parser_output: Dict[str, Any]) -> None:
for key in parser_output.keys():
parser_output[key] = parser_output[key].to_dict()
return pprint.PrettyPrinter(width=4, compact=True).pprint(parser_output)

Initialize the parser

parser = PandasDataFrameOutputParser(dataframe=df)

Define a query

df_query = "Retrieve the num_wings column."

Create a prompt

prompt = PromptTemplate(
template="Answer the user query.\n{format_instructions}\n{query}\n",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)

Initialize the model

model = ChatOpenAI(api_key=OPENAI_API_KEY, temperature=0)

Combine prompt, model, and parser into a chain

chain = prompt | model | parser

Execute the query

parser_output = chain.invoke({"query": df_query})
format_parser_output(parser_output)

Output:

'''
{'num_wings': {0: 2,
1: 0,
2: 0,
3: 0}}
'''

Example - Pandas DataFrame

Query 2: Retrieve a specific row

df_query = "Retrieve the first row."
parser_output = chain.invoke({"query": df_query})
format_parser_output(parser_output)

Output:

'''
{'0': {'num_legs': 2,
'num_specimen_seen': 10,
'num_wings': 2}}
'''

Example - Pandas DataFrame

Query 3: Perform a calculation

df_query = "Retrieve the average of the num_legs column from rows 1 to 3."
parser_output = chain.invoke({"query": df_query})
print(parser_output)

Output:

'''
{'mean': 4.0}
'''

6. Datetime

LangChain’s DatetimeOutputParser converts LLM outputs into Python datetime objects. This is particularly useful for applications requiring precise date and time data for further processing or analysis.

Example - Datetime

Initialize the parser

output_parser = DatetimeOutputParser()

Create a prompt

template = """Answer the users question:

{question}

{format_instructions}"""

prompt = PromptTemplate.from_template(
template,
partial_variables={"format_instructions": output_parser.get_format_instructions()},
)

Combine prompt, model, and parser into a chain

chain = prompt | OpenAI(api_key=OPENAI_API_KEY) | output_parser

Ask a datetime-related question

output = chain.invoke({"question": "When was Bitcoin founded?"})
print(output)

Output:

'''
2009-01-03 18:15:05
'''

7. Enum: Categorizing Outputs

Enums are perfect for categorizing outputs into predefined values, such as color codes or status levels. The EnumOutputParser ensures LLM outputs conform to a specified set of valid categories.

Example - Datetime

Define an Enum

class Colors(Enum):
RED = "red"
GREEN = "green"
BLUE = "blue"

Initialize the parser

parser = EnumOutputParser(enum=Colors)

Create a prompt

prompt = PromptTemplate.from_template(
"""What color eyes does this person have?

Person: {person}

Instructions: {instructions}"""
).partial(instructions=parser.get_format_instructions())

Combine prompt, model, and parser into a chain

chain = prompt | ChatOpenAI(api_key=OPENAI_API_KEY) | parser

Query the chain

result = chain.invoke({"person": "Frank Sinatra"})
print(result)

Output:

'''
<Colors.BLUE: 'blue'>
'''

Why Output Parsers Are Essential

Output Parsers unlock a world of possibilities for AI applications by offering:

  • Structured Data Integration: Convert raw text into actionable formats like JSON or CSV for seamless downstream processing.
  • Validation: Use schemas to enforce data integrity, reducing errors in workflows.
  • Customization: Tailor outputs to specific needs using tools like Pydantic models or Enums.
  • Flexibility: Support for real-time data streaming, enabling interactive applications.

In this episode, we explored how LangChain’s Output Parsers transform unstructured AI outputs into usable formats. From JSON to Pandas DataFrames, these tools are essential for building robust, data-driven applications.

Stay tuned for the next episode, where we’ll delve into even more advanced features of LangChain, helping you master this incredible framework step by step. 🚀


Data Science Explore the world of data science with Donato_Story

Dashboard Discover the power of data visualization with Donato_Story

Donato_Journey Join me on my journey (Thai version)

Course_Review Discover the training courses with Donato_Story (Thai version)

Let’s Connect!

Your feedback is invaluable. Feel free to share your thoughts or questions in the comments below. You can also connect with me on:

Originally published on Medium

Related