From Chaos to Clarity: How I Improved LLM Output Consistency with LangChain

Ravjot Singh
4 min readAug 16, 2024

--

Generative AI models have opened up new possibilities for creativity and problem-solving, but to get the best results, you need effective prompt engineering. In this blog, I’ll dive deep into a hands-on project where I used LangChain with Google Generative AI’s Gemini model to generate structured outputs. We’ll explore how prompt templates work, how to parse model responses using JSON, and why these choices lead to better performance and flexibility.

Overview

The goal of this project was to build a pipeline that accepts a subject (e.g., “ice cream flavors”) and returns a clean list of items using the Gemini model. The LangChain library serves as the backbone, providing both the prompt engineering and output parsing utilities.

Why Use JSON for Parsing?

JSON (JavaScript Object Notation) is a lightweight data-interchange format that’s easy for both humans and machines to read and write. In this project, JSON helps structure the output generated by the LLM, ensuring that the data is clean and easy to manipulate programmatically. By outputting structured JSON, we can easily retrieve items, apply conditions, or further process the data downstream.

Setting Up the Environment:

To start, I used the langchain_google_genai library to connect to Google’s Gemini model, specifically the "gemini-1.5-pro" version. This model is known for producing coherent and creative text outputs. The setup involved specifying the API key and loading the model:

from langchain_google_genai import GoogleGenerativeAI

api_key = "your_api_key"
llm = GoogleGenerativeAI(model="gemini-1.5-pro", google_api_key=api_key)

Designing the Prompt Template:

Prompt templates are essential in guiding the model’s output. I used LangChain’s PromptTemplate class to create a template that instructs the model to list five items based on a given subject. The output is formatted as JSON to make it more manageable and reliable:

from langchain.output_parsers import CommaSeparatedListOutputParser
from langchain_core.prompts import PromptTemplate

output_parser = CommaSeparatedListOutputParser()
format_instructions = output_parser.get_format_instructions()

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

Why JSON and LangChain’s Output Parser?

LangChain’s output parsers provide a way to enforce specific formatting rules. For instance, by using a JSON-based approach, we ensure the model returns data in a structured format that can be easily parsed and validated. The parser handles edge cases, such as inconsistent delimiters or extra whitespace, which are common issues when dealing with free-form text.

In this case, the JSON format is achieved by embedding instructions within the prompt, guiding the model to follow the specified output structure.

Chaining the Prompts, Model, and Output Parser

LangChain supports chaining, where you can link multiple steps together seamlessly. In this project, I chained the prompt, model, and output parser to ensure the generated output meets our expectations:

chain = prompt | llm | output_parser

# Invoking the chain with the subject "ice cream flavors"
output = chain.invoke({"subject": "ice cream flavors"})

Output and JSON Parsing

Once the model returns its response, the output is parsed into a JSON-friendly format. Here’s the output for the given subject:

# The output is now a structured list that can be directly used
for flavor in output:
print(flavor)
Expected Output

By ensuring the output is JSON-like, further operations, such as converting it to a dictionary or a pandas DataFrame, become straightforward.

Analyzing the Prompt and Output in JSON

{
"subject": "ice cream flavors",
"format": "Your response should be a list of comma-separated values, eg: `foo, bar, baz` or `foo,bar,baz`"
}

This design allows for scalability. If you need the model to output more complex data structures, like nested lists or key-value pairs, JSON can handle that without breaking downstream workflows.

Benefits

  • Consistency: The output parser guarantees that responses are consistent in format.
  • Scalability: JSON allows for easy scalability as the complexity of the generated data increases.
  • Flexibility: LangChain’s chaining feature simplifies the integration of multiple components, making it easy to swap out models, modify templates, or change parsing rules.

Conclusion

This project illustrates how prompt engineering and structured output generation can be optimized using tools like LangChain and Google Gen AI Models. By leveraging JSON and chaining techniques, you can build powerful, scalable solutions that produce clean, reliable outputs. As AI models evolve, these best practices will remain essential for extracting the best performance while ensuring flexibility and ease of use.

This brings us to the end of this article. I hope the concepts and code have provided you with clear insights into the world of prompt engineering using LangChain and Google Generative AI. The best way to master these techniques is through consistent practice, so keep experimenting and learning!

If you’re interested in exploring more resources related to Data Science, Machine Learning, and Generative AI, feel free to check out my GitHub repository.

I’d love to connect with like-minded professionals! You can reach out to me on LinkedIn — Ravjot Singh.

--

--

Ravjot Singh

A Tech enthusiast || Dedicated and hardworking with a passion for Data Science || Codes in Python & R.