How to Use Zod to Get Structured Data with LangChain

Struggling with structured output from LLMs? Frustrated by LangChain's vague documentation on data parsing? Hitting roadblocks when trying to use non-OpenAI models? You're not alone.

Many developers face these challenges:

  • Inconsistent and unpredictable LLM responses

  • Difficulty in parsing complex, nested data structures

  • Limited portability across different LLM providers

  • Lack of robust type checking and validation for LLM outputs

But what if there was a way to guarantee structured output from your LLMs, regardless of the provider? A method that works seamlessly with LangChain while providing rock-solid data validation?

Enter the powerful combination of LangChain and Zod – a dynamic duo that can transform your AI development experience.

In this comprehensive guide, we'll explore:

  1. How to leverage Zod's TypeScript-first schema validation with LangChain

  2. Techniques for ensuring consistent, structured output across different LLMs

  3. Practical examples that work beyond just OpenAI's models

  4. Advanced strategies for handling complex data structures with ease

By the end of this article, you'll have a clear roadmap for tackling structured data in your AI projects, armed with tools and techniques that will make your development process smoother and more reliable.

Understanding the Basics

What is LangChain?

LangChain is an innovative framework designed to streamline the development of AI-driven applications. Its modular architecture allows for flexible integration with various components, including large language models (LLMs), datasets, and external tools. Here are some of its key features:

  • Prompt Engineering: Crafting prompts to elicit desired responses from language models.

  • LLM Integration: Seamless integration with models like GPT-4 for robust AI capabilities.

  • Data Source Connectivity: Connecting to databases, APIs, and other data sources.

  • Tool Interactions: Enabling interactions with various tools for comprehensive solutions.

What is Zod?

Zod is a TypeScript-first schema declaration and validation library. It allows developers to define schemas for their data and validate it at runtime. This ensures that the data conforms to the expected structure, reducing the likelihood of errors and inconsistencies. Key features of Zod include:

  • Schema Declaration: Easy-to-define schemas for various data structures.

  • Runtime Validation: Validates data even after TypeScript code has been transpiled to JavaScript.

  • Type Inference: Automatically infers TypeScript types from schemas.

  • Composability: Schemas can be composed to create complex data validation rules.

  • Integration: Works seamlessly with TypeScript and other JavaScript libraries.

Comparing Zod to other validation libraries like Yup or Joi, Zod stands out for its TypeScript-first approach, providing better type safety and developer experience.

Setting Up Your Environment

Before diving into the examples, let's set up the environment. This involves installing the necessary packages and configuring your project.

Installing Necessary Packages

First, install LangChain and Zod in your Node.js project:

npm install langchain zod

Or, if you're using yarn:

yarn add langchain zod

Setting Up Environment Variables

Ensure you have the necessary API keys for the services you'll be using. For instance, if you are using OpenAI's GPT models, set your API key as an environment variable:

OPENAI_API_KEY=your-api-key

Implementing Zod with LangChain

With the environment set up, we can now look at how to implement Zod with LangChain. This section covers the basic setup, defining schemas, and using these schemas with LangChain models, complete with detailed code examples.

Basic Setup and Configuration

Importing Dependencies

To start, you need to import the necessary dependencies, including LangChain, Zod, and any other utility libraries you plan to use in your project.

import { ChatOpenAI } from 'langchain/chat_models/openai';
import { z } from 'zod';
Initializing Models

Next, instantiate the ChatOpenAI model from LangChain. This model will be used to interact with OpenAI's GPT models.

const chatModel = new ChatOpenAI({
  modelName: 'gpt-4o-mini',
  temperature: 0 // For best results with the output fixing parser
});

Defining Schemas with Zod

Defining schemas with Zod is straightforward. You declare the structure of your data using schema objects. Here are some example schemas for different use cases.

Example 1: Joke Schema

This schema defines the structure for a joke, including the setup, punchline, and an optional rating.

const jokeSchema = z.object({
  setup: z.string().describe('The setup of the joke'),
  punchline: z.string().describe('The punchline to the joke'),
  rating: z.number().optional().describe('How funny the joke is, from 1 to 10')
});
Example 2: User Profile Schema

This schema can be used to validate a user profile, including the name, age, and list of interests.

const userProfileSchema = z.object({
  name: z.string().describe('The name of the user'),
  age: z.number().describe('The age of the user'),
  interests: z.array(z.string()).describe('List of user interests')
});

Using Zod Schema with LangChain

Once your schemas are defined, you can use them with LangChain models to ensure that the data you receive from the models conforms to the expected structure.

Connecting Zod with LangChain Models

Use the withStructuredOutput method from LangChain to connect your Zod schema with the model. This ensures that the output from the language model adheres to the schema you've defined.

Example: Creating and Using Zod Schemas for Structured Data
const structuredLlm = chatModel.withStructuredOutput(jokeSchema);

async function getJoke() {
  const result = await structuredLlm.invoke('Tell me a joke about cats');
  console.log(result);
  // Result: { setup: "Why don't cats play poker in the wild?", punchline: "Too many cheetahs.", rating: 7 }
}

getJoke();

In this example, the invoke method is used to send a prompt to the language model. The result is a structured object that adheres to the jokeSchema defined earlier.

Advanced Techniques with Zod and LangChain

Structuring Complex Data

For more complex data structures, you can compose Zod schemas. This is useful when your data model consists of nested objects or arrays.

const addressSchema = z.object({
  street: z.string(),
  city: z.string(),
  postalCode: z.string()
});

const userSchema = z.object({
  name: z.string(),
  age: z.number(),
  address: addressSchema
});

const structuredLlm = chatModel.withStructuredOutput(userSchema);

async function getUser() {
  const result = await structuredLlm.invoke('Provide details about a user named John Doe');
  console.log(result);
  // Result: { name: "John Doe", age: 30, address: { street: "123 Main St", city: "Anytown", postalCode: "12345" } }
}

getUser();

This example shows how to define and use nested schemas with LangChain. The addressSchema is nested within the userSchema, illustrating how to handle more complex data structures.

Error Handling and Output Fixing

LangChain provides mechanisms to handle errors and fix outputs that do not match the expected schema. The OutputFixingParser can be used to handle such scenarios.

const outputFixingParser = OutputFixingParser.fromLLM(chatModel, userSchema);

async function getUserWithFix() {
  try {
    const result = await outputFixingParser.invoke('Provide details about a user named John Doe');
    console.log(result);
  } catch (error) {
    console.error('Output did not match schema:', error);
  }
}

getUserWithFix();

The OutputFixingParser tries to fix the output if it doesn't conform to the schema, ensuring that the final result is valid.

Conclusion

In this article, we explored how to use Zod with LangChain to get structured data. We covered the basics of LangChain and Zod, set up the environment, and provided practical examples of defining and using schemas. We also discussed advanced techniques and best practices for handling complex data structures.

By integrating Zod with LangChain, you can leverage the power of both tools to create robust, error-resistant applications. Whether you're extracting data from unstructured text or validating user inputs, this combination offers a reliable solution for managing structured data.

Raymond Yeh

Raymond Yeh

Published on 28 October 2024

Get engineers' time back from marketing!

Don't let managing a blog on your site get in the way of your core product.

Wisp empowers your marketing team to create and manage content on your website without consuming more engineering hours.

Get started in few lines of codes.

Choosing a CMS
Related Posts
Validating TypeScript Types in Runtime using Zod

Validating TypeScript Types in Runtime using Zod

TypeScript enhances JavaScript by adding static types, but lacks runtime validation. Enter Zod: a schema declaration and validation library. Learn how to catch runtime data errors and ensure robustness in your TypeScript projects.

Read Full Story
Validating API Response with Zod

Validating API Response with Zod

Learn why validating API responses with Zod is indispensable for TypeScript apps, especially when handling unexpected data formats from third-party APIs in production.

Read Full Story
How to Use Zod Validation for React Hook Forms with ShadCN's Form Component

How to Use Zod Validation for React Hook Forms with ShadCN's Form Component

Streamline React form validation with Zod & react-hook-form! Learn how to integrate schema validation using ShadCN’s component, ensuring robust and user-friendly forms.

Read Full Story