LLM Study Diary: Comprehensive Review of LangChain — Part 3

Today, I’d like to continue working through the remaining recipes from Greg Kamradt’s YouTube video, “The LangChain Cookbook — 7 Core Concepts”, using the latest version of LangChain!

Output Parsers Method 1: Prompt Instructions & String Parsing

For this sample as well, since the OpenAI class isn’t compatible with the latest model, I first commented out the part where we import the OpenAI class and initialize the LLM object. Then, I executed the code up to the point where we generate the StructuredOutputParser object.

from langchain.output_parsers import StructuredOutputParser, ResponseSchema
from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
# from langchain.llms import OpenAI
# llm = OpenAI(model_name="text-davinci-003", openai_api_key=openai_api_key)
response_schemas = [
ResponseSchema(name="bad_string", description="This a poorly formatted user input string"),
ResponseSchema(name="good_string", description="This is your response, a reformatted response")
]

output_parser = StructuredOutputParser.from_response_schemas(response_schemas)

format_instructions = output_parser.get_format_instructions()
print (format_instructions)

When we output the result of StructuredOutputParser’s get_format_instructions(), we can see that it looks like this:

The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":

```json
{
"bad_string": string // This a poorly formatted user input string
"good_string": string // This is your response, a reformatted response
}
```

We’ll embed this into the prompt below using PromptTemplate.

template = """
You will be given a poorly formatted string from a user.
Reformat it and make sure all the words are spelled correctly

{format_instructions}

% USER INPUT:
{user_input}

YOUR RESPONSE:
"""

prompt = PromptTemplate(
input_variables=["user_input"],
partial_variables={"format_instructions": format_instructions},
template=template
)

If we create a promptValue by inserting a sentence with spelling mistakes and uncapitalized first letters into user_input, like this:


promptValue = prompt.format(user_input="welcom to califonya!")

print(promptValue)

The contents of the promptValue output by print() look like this:

You will be given a poorly formatted string from a user.
Reformat it and make sure all the words are spelled correctly

The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":

```json
{
"bad_string": string // This a poorly formatted user input string
"good_string": string // This is your response, a reformatted response
}
```

% USER INPUT:
welcom to califonya!

YOUR RESPONSE:

In the sample, this promptValue was passed to the callable object function of the OpenAI object. However, I rewrote it to pass it to the invoke function of the ChatOpenAI class, like this:

from langchain_openai import ChatOpenAI
chat = ChatOpenAI(model_name="gpt-4o", openai_api_key=openai_api_key)
result = chain.invoke(promptValue)
print(result)

With this, we obtained the following result in result:

content='```json\n{\n\t"bad_string": "welcom to califonya!",\n\t"good_string": "Welcome to California!"\n}\n```' response_metadata={'token_usage': {'completion_tokens': 29, 'prompt_tokens': 176, 'total_tokens': 205}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_729ea513f7', 'finish_reason': 'stop', 'logprobs': None} id='run-49fa9f41-3d8c-4be8-93dc-f48ad46c35a8-0'

Unlike the sample, if we pass this directly to the parser, it won’t work. The return value structure differs between the callable object function of the OpenAI class and the invoke method of the ChatOpenAI class. The LLM’s response is contained in a variable called content, so we’ll pass this to the parser.

output_parser.parse(result.content)

Then, we got the same result as in the tutorial, like this:

{'bad_string': 'welcom to califonya!', 'good_string': 'Welcome to California!'}

By using StructuredOutputParser, we can specify multiple output formats with ResponseSchema and receive the results in JSON format. When creating systems where the output format changes dynamically, it seems that we can design the parser with a modular structure. I think this will likely be very useful for us many times in the future.

Output Parsers Method 2: OpenAI Fuctions

Next, we’ll look at a formidable sample that directly converts user input into a Pydantic model. The code defining the Pydantic model doesn’t require any particular changes.

from langchain.pydantic_v1 import BaseModel, Field
from typing import Optional

class Person(BaseModel):
"""Identifying information about a person."""

name: str = Field(..., description="The person's name")
age: int = Field(..., description="The person's age")
fav_food: Optional[str] = Field(None, description="The person's favorite food")

This sample uses the ChatOpenAPI class, but since create_structured_output_chain was deprecated, I did the same thing using the with_structured_output method of the ChatOpenAPI object, as shown below. Also, I rewrote it to call invoke() instead of run() on the resulting chain.

# from langchain.chains.openai_functions import create_structured_output_chain

llm = ChatOpenAI(model='gpt-4-0613', openai_api_key=openai_api_key)

# chain = create_structured_output_chain(Person, llm, prompt)
# chain.run(
# "Sally is 13, Joey just turned 12 and loves spinach. Caroline is 10 years older than Sally."
# )
chain = llm.with_structured_output(Person)
chain.invoke(
"Sally is 13, Joey just turned 12 and loves spinach. Caroline is 10 years older than Sally."
)

The result is like this:

Person(name='Sally', age=13, fav_food=None)

In the above sample, although the user’s input contained information for three people — Sally, Joey, and Caroline — the generated Pydantic model only included Sally. Next, we’ll look at a sample that generates multiple Pydantic model instances for cases like this. We can use the same Pydantic definition for this.

from typing import Sequence

class People(BaseModel):
"""Identifying information about all people in a text."""

people: Sequence[Person] = Field(..., description="The people in the text")

Just like before, we’ll create a chain using with_structured_output, but this time we’ll pass the People class instead of the Person class. Then we’ll call the invoke method.

chain = llm.with_structured_output(People)
chain.invoke(
"Sally is 13, Joey just turned 12 and loves spinach. Caroline is 10 years older than Sally."
)

With this, we were able to extract information for all three people — Sally, Joey, and Caroline — as shown below.

People(people=[
Person(name='Sally', age=13, fav_food=''),
Person(name='Joey', age=12, fav_food='spinach'),
Person(name='Caroline', age=23, fav_food='')
])

This is quite an interesting demo. By using with_structured_output, we can connect natural language and REST APIs quite directly.

There’s one more sample that converts to a Pydantic model with Enum type member variables, but it works the same way by just rewriting it using with_structured_output and invoke, so I’ll skip the explanation.

LangChain allows us to do many things quickly, but it might be too quick for the memory to settle. I realized that even though I’ve worked with it before, I hardly remember most of it 💦.

In the next post, we’ll go through all the remaining samples in the Cookbook.

To be continued.

Thank you for reading. I hope you found this post informative. Your interest motivates me to continue sharing my knowledge in AI and language technologies.

For any questions about this blog or to inquire about OpenAI API, LLM, or LangChain-related development projects with our company (Goldrush Computing), feel free to reach out to me directly at:

mizutori@goldrushcomputing.com

As a Japanese company with native speakers, my company specializes in creating prompts and RAG systems optimized for Japanese language and culture. If you’re looking for expertise in tailoring AI solutions for the Japanese market or Japanese-language applications, we’re ideally positioned to assist. Please don’t hesitate to reach out for collaborations or projects requiring Japan-specific AI optimization.

--

--

Taka Mizutori
LLM Study Diary: A Beginner’s Path Through AI

Founder and CEO of Goldrush Computing Inc (https://goldrushcomputing.com). Keep making with Swift, Kotlin, Java, C, Obj-C, C#, Python, JS, and Assembly.