LLM Study Diary: Comprehensive Review of LangChain — Part 1

I recently finished a project where I was deeply involved with OpenAI. After that, I spent a few months designing and developing medium-scale web and mobile services, which led to a bit of a break from LLMs. Before jumping back into LLM work, I decided to check LangChain’s version history — wow, it’s changed a lot! Realizing I needed to brush up on the basics, I’ve decided to do a thorough review of LangChain, starting from the ground up.

The LangChain CookBook

When I first dipped my toes into LangChain last year, I was pretty lost. After scouring various blogs and tutorials, I stumbled upon Greg Kamradt’s YouTube video. It turned out to be the most straightforward explanation I could find.

Greg’s explanation is lightning-fast, but his knack for explaining things is incredible. It made LangChain’s capabilities and inner workings just click for me. So, I decided to refresh my memory by rewatching Kamradt’s video and going through the tutorial below.

his video and the sample code are about a year old now, so they’re probably not compatible with the current version of LangChain. Still, the video remains valuable. I figured I’d review by watching the video and then updating Greg’s sample code to work with the latest LangChain. A good way to cover both bases.

Chat Messages

First things first, I opened a Jupyter Notebook and installed the necessary libraries.

!pip install python-dotenv
!pip install langchain
!pip install -U langchain-openai

The version of the langchain module I installed was 0.1.20. As I’ll explain later, with the latest LangChain, you need more than just the langchain module — you also need a new module called langchain-openai. That’s why I’m installing it here too.

As for loading the environment variables, the same code still works fine.

from dotenv import load_dotenv
import os

load_dotenv()

openai_api_key=os.getenv('OPENAI_API_KEY', 'your_api_key')

(Insert your OpenAI API Key where it says ‘your_api_key’)

Creating a ChatOpenAI Object

In the Cookbook, the ChatOpenAI class was imported from the langchain module. However, we now need to change this to import ChatOpenAI from the langchain_openai module instead of langchain.

from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage, AIMessage

# This it the language model we'll use. We'll talk about what we're doing below in the next section
chat = ChatOpenAI(temperature=.7, openai_api_key=openai_api_key)

The section for sending chat messages (where we send SystemMessage and HumanMessage to OpenAI’s model) now looks like this:

chat.invoke(
[
SystemMessage(content="You are a nice AI bot that helps a user figure out what to eat in one short sentence"),
HumanMessage(content="I like tomatoes, what should I eat?")
]
)

Previously, we would send a chat by calling a function of the callable object, like this:

chat(
[
HumanMessage(content="What day comes after Thursday?")
]
)

In the latest version of LangChain, we use the invoke method to send messages such as SystemMessage to the OpenAI API, as shown below:

chat.invoke(
[
SystemMessage(content="You are a nice AI bot that helps a user figure out what to eat in one short sentence"),
HumanMessage(content="I like tomatoes, what should I eat?")
]
)

(The SystemMessage serves as the system template, while the HumanMessage represents the input from us, the ‘humans’.)

Instantiating the LLM Model

In the Cookbook, the OpenAI class was imported from the langchain.llm module. However, it appears that this class has since been moved to the langchain_openai module.

from langchain_openai import OpenAI

llm = OpenAI(model_name="gpt-3.5-turbo-instruct", openai_api_key=openai_api_key)

Additionally, the model_name ‘text-ada-001’ has been deprecated. Therefore, referring to the documentation below, I selected ‘gpt-3.5-turbo-instruct’ as the model.

This output confirmed that the code is working correctly.

llm("What day comes after Friday?")

-> '\n\nSaturday'

However, upon checking the gpt-3.5-turbo-instruct model at https://platform.openai.com/docs/models/gpt-3-5-turbo, I found the following description:

‘Similar capabilities as GPT-3 era models. Compatible with legacy Completions endpoint and not Chat Completions.’

This made me realize that this model is actually compatible with the legacy ‘Completions endpoint’ of the OpenAI API, not the newer Chat API.

from langchain_openai import OpenAI

llm = OpenAI(model_name="gpt-3.5-turbo-0125", openai_api_key=openai_api_key)
llm("What day comes after Friday?")

When I tried replacing gpt-3.5-turbo-instruct with the newer gpt-3.5-turbo-0125 like this:


from langchain_openai import OpenAI

llm = OpenAI(model_name="gpt-3.5-turbo-0125", openai_api_key=openai_api_key)
llm("What day comes after Friday?")

I received the following error:

NotFoundError: Error code: 404 - {'error': {'message': 'This is a chat model and not supported in the v1/completions endpoint. Did you mean to use v1/chat/completions?', 'type': 'invalid_request_error', 'param': 'model', 'code': None}}

It appears that the OpenAI class from the langchain_openai module cannot be used with newer models.

Back to the ChatOpenAI Class

Returning to the ChatOpenAI class, I found that it works when using models like gpt-3.5-turbo-0125, gpt-4-turbo, and gpt-4o. This suggests that it's connected to the new API rather than the legacy one

chat = ChatOpenAI(model='gpt-4o', temperature=.7, openai_api_key=openai_api_key)
chat.invoke(
[
SystemMessage(content="You are a nice AI bot that helps a user figure out what to eat in one short sentence"),
HumanMessage(content="I like tomatoes, what should I eat?")
]
)

It seems that going forward, we’ll be using the ChatOpenAI class rather than the OpenAI class to interact with the OpenAI API.

Function Calling

Regarding OpenAI API’s Function Calling feature, which is used to extract specific parameter values from user chats, I found that the code from the Cookbook worked without any modifications.

import json
chat = ChatOpenAI(model='gpt-4o', temperature=1, openai_api_key=openai_api_key)

output = chat(messages=
[
SystemMessage(content="You are an helpful AI bot"),
HumanMessage(content="What’s the weather like in Tokyo right now? What degrees celsicus now?")
],
functions=[{
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"]
}
}
]
)

function_call = output.additional_kwargs.get('function_call')
if function_call:
arguments = function_call.get('arguments')
if arguments:
arguments_dict = json.loads(arguments)
print("Parsed Arguments:", arguments_dict)
else:
print("No arguments found.")
else:
print("No function_call found.", output)

I modified the latter part of the code to extract and display the parameters obtained through function calling from the output. The results look like this, showing that two parameters, ‘location’ and ‘celsius’, were successfully extracted.

Parsed Arguments: {'location': 'Tokyo, Japan', 'unit': 'celsius'}

After experimenting with function calling in various scenarios, I noticed that it doesn’t always work effectively when the HumanMessage (i.e., user input) is not in the form of a question or inquiry. It seems that the inner workings of function calling have been optimized to some extent to interpret question categories.

Since this example might be difficult for Japanese people like me to understand, I came up with the following alternative:

import json
chat = ChatOpenAI(model='gpt-4o', temperature=1, openai_api_key=openai_api_key)

output = chat(messages=
[
SystemMessage(content="You are at the customer support center of an electric appliance shop."),
HumanMessage(content="I have a question about an issue with my mobile phone: the display is blinking.")
],
functions=[{
"name": "get_product_type_and_issue",
"description": "Get the product type and the symptoms of the issue the user is experiencing.",
"parameters": {
"type": "object",
"properties": {
"product": {
"type": "string",
"description": "The type of product (e.g., mobile phone, TV, shaver)."
},
"symptom": {
"type": "string",
"description": "The symptoms of the issue the user is experiencing."
}
},
"required": ["location"]
}
}
]
)

function_call = output.additional_kwargs.get('function_call')
if function_call:
arguments = function_call.get('arguments')
if arguments:
arguments_dict = json.loads(arguments)
print("Parsed Arguments:", arguments_dict)
else:
print("No arguments found.")
else:
print("No function_call found.", output)

This is an example of function calling designed for a customer support chatbot.

As shown below, I set the description to ‘Get the product type and the symptoms of the issue the user is experiencing.’ The parameters to be extracted were set up as follows. When a HumanMessage like HumanMessage(content=’I have a question about an issue with my mobile phone: the display is blinking.’) is sent, it extracts from the inquiry:

  • The product being inquired about
  • The symptoms of the malfunction occurring with the product

It then returns a JSON response like this:

{'product': 'mobile phone', 'symptom': 'display is blinking'}

The greatest advantage of using function calling is that it makes it easier to connect the results to other APIs.

For instance, you can send the JSON above to another API in your company’s system to guide the user to a specialized troubleshooting flow (such as a web form or guided input process) designed specifically for mobile phone issues, or save it to a customer support database for later follow-up by the mobile phone department via email.

Moreover, instead of storing the entire customer response, you might only save the ‘symptom’ in a separate column, potentially enabling a quicker response system. In this way, function calling is extremely effective for connecting LLMs with your company’s existing systems or proprietary systems.

Well, up to this point, I’ve been a bit confused and unsure how to proceed, grappling with the fact that the OpenAI class is no longer compatible with the latest models. Despite this, I’ve managed to get the samples we’ve covered so far working somehow.

In the next installment, we’ll continue examining the remaining samples from Kamradt’s 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.

Read the next part of this series:

--

--

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.