The Drawback With LangChain | Max Woolf’s Weblog
In case you’ve been following the explosion of AI hype up to now few months, you’ve most likely heard of LangChain. LangChain, developed by Harrison Chase, is a Python and JavaScript library for interfacing with OpenAI’s GPT APIs (later increasing to extra fashions) for AI textual content technology. Extra particularly, it’s an implementation of the paper ReAct: Synergizing Reasoning and Acting in Language Models revealed October 2022, colloquially often known as the ReAct paper, which demonstrates a prompting approach to permit the mannequin to “purpose” (with a chain-of-thoughts) and “act” (by having the ability to use a instrument from a predefined set of instruments, comparable to having the ability to search the web). This mix is proven to drastically enhance output textual content high quality and provides giant language fashions the flexibility to accurately resolve issues.

The ReAct workflow popularied by LangChain was significantly efficient with InstructGPT/text-davinci-003, though pricey and never simple to make use of for small initiatives. In March 2023, as ChatGPT API utilization turned massively standard because of its extraordinarily low cost API as I accurately predicted, LangChain use additionally exploded, to the purpose that LangChain was in a position to elevate a $10 million seed round and one other $20-$25 million at a $200 million valuation Series A regardless of not having any income nor any apparent plans generate income.
That’s the place my private expertise with LangChain begins. For my work at BuzzFeed, I used to be tasked with making a ChatGPT-based chat bot for the Tasty model (later launched as Botatouille within the Tasty iOS app) that might chat with the person and supply related recipes. The supply recipes are transformed to embeddings and saved in a vector retailer: for instance, if a person requested for “wholesome meals”, the question is transformed to an embedding, and an approximate nearest neighbor search is carried out to search out recipes just like the embedded question after which fed to ChatGPT as added context that may then be exhibited to the person. This strategy is extra generally often known as retrieval-augmented generation.
](/2023/07/langchain-problem/1*b5r7r3-FSNjHUzlCGl3SnA-2_hud96f4454deff2d6a1fad772c40823b5d_43278_f423559092b0ed4a87f17dcb74709197.webp)
LangChain was by-far the favored instrument of alternative for RAG, so I figured it was the proper time to be taught it. I spent a while studying LangChain’s somewhat complete documentation to get a greater understanding of greatest put it to use: after a week of analysis, I obtained nowhere. Operating the LangChain demo examples did work, however any makes an attempt at tweaking them to suit the recipe chatbot constraints broke them. After fixing the bugs, the general high quality of the chat conversations was unhealthy and uninteresting, and after intense debugging I discovered no answer. Ultimately I had an existential disaster: am I a nugatory machine studying engineer for not having the ability to determine LangChain out when very many different ML engineers can? We went back to a lower-level ReAct movement, which instantly outperformed my LangChain implementation in dialog high quality and accuracy.
In all, I wasted a month studying and testing LangChain, with the massive takeway that standard AI apps might not essentially be definitely worth the hype. My existential disaster was resolved after coming throughout a Hacker News thread about somebody reimplementing LangChain in 100 lines of code, with many of the feedback venting all their grievances with LangChain:

The issue with LangChain is that it makes easy issues comparatively advanced, and with that pointless complexity creates a tribalism which hurts the up-and-coming AI ecosystem as a complete. In case you’re a beginner who needs to only discover ways to interface with ChatGPT, undoubtedly don’t begin with LangChain.
“Good day World” in LangChain (or Extra Precisely, “Hell World”)
The Quickstart for LangChain begins with a mini-tutorial on merely work together with LLMs/ChatGPT from Python. For instance, to create a bot that may translate from English to French:
from langchain.chat_models import ChatOpenAI
from langchain.schema import (
AIMessage,
HumanMessage,
SystemMessage
)
chat = ChatOpenAI(temperature=0)
chat.predict_messages([HumanMessage(content="Translate this sentence from English to French. I love programming.")])
# AIMessage(content material="J'adore la programmation.", additional_kwargs={}, instance=False)
The equal code utilizing OpenAI’s official Python library for ChatGPT:
import openai
messages = [{"role": "user", "content": "Translate this sentence from English to French. I love programming."}]
response = openai.ChatCompletion.create(mannequin="gpt-3.5-turbo", messages=messages, temperature=0)
response["choices"][0]["message"]["content"]
# "J'adore la programmation."
LangChain makes use of about the identical quantity of code as simply utilizing the official openai
library, anticipate LangChain incorporates extra object lessons for not a lot apparent code profit.
The immediate templating instance reveals the core of how LangChain works:
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
template = "You're a useful assistant that interprets {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{textual content}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
chat_prompt.format_messages(input_language="English", output_language="French", textual content="I really like programming.")
LangChain’s vaunted immediate engineering is simply f-strings, a function current in each fashionable Python set up, however with additional steps. Why do we have to use these PromptTemplates
to do the identical factor?
However what we actually wish to do is know create Brokers, which incorporate the ReAct workflow we so desperately need. Fortuitously there’s a demo for that, which leverages SerpApi and one other instrument for math computations, displaying how LangChain can discriminate and use two totally different instruments contextually:
from langchain.brokers import load_tools
from langchain.brokers import initialize_agent
from langchain.brokers import AgentType
from langchain.chat_models import ChatOpenAI
from langchain.llms import OpenAI
# First, let's load the language mannequin we will use to manage the agent.
chat = ChatOpenAI(temperature=0)
# Subsequent, let's load some instruments to make use of. Word that the `llm-math` instrument makes use of an LLM, so we have to move that in.
llm = OpenAI(temperature=0)
instruments = load_tools(["serpapi", "llm-math"], llm=llm)
# Lastly, let's initialize an agent with the instruments, the language mannequin, and the kind of agent we wish to use.
agent = initialize_agent(instruments, chat, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
# Now let's try it out!
agent.run("Who's Olivia Wilde's boyfriend? What's his present age raised to the 0.23 energy?")
How do the person instruments work? What’s AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION
anyhow? The ensuing output from agent.run()
(solely current with verbose=True
) is extra useful.
> Getting into new AgentExecutor chain...
Thought: I would like to make use of a search engine to search out Olivia Wilde's boyfriend and a calculator to boost his age to the 0.23 energy.
Motion:
{
"motion": "Search",
"action_input": "Olivia Wilde boyfriend"
}
Remark: Sudeikis and Wilde's relationship resulted in November 2020. Wilde was publicly served with courtroom paperwork concerning little one custody whereas she was presenting Do not Fear Darling at CinemaCon 2022. In January 2021, Wilde started courting singer Harry Kinds after assembly through the filming of Do not Fear Darling.
Thought:I would like to make use of a search engine to search out Harry Kinds' present age.
Motion:
{
"motion": "Search",
"action_input": "Harry Kinds age"
}
Remark: 29 years
Thought:Now I must calculate 29 raised to the 0.23 energy.
Motion:
{
"motion": "Calculator",
"action_input": "29^0.23"
}
Remark: Reply: 2.169459462491557
Thought:I now know the ultimate reply.
Last Reply: 2.169459462491557
> Completed chain.
'2.169459462491557'
The documentation doesn’t make it clear, however inside every Thought/Motion/Remark makes use of its personal API name to OpenAI, so the chain is slower than you would possibly suppose. Additionally, why is every motion a dict
? The reply to that is later, and may be very foolish.
Lastly, how does LangChain retailer the dialog thus far?
from langchain.prompts import (
ChatPromptTemplate,
MessagesPlaceholder,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate
)
from langchain.chains import ConversationChain
from langchain.chat_models import ChatOpenAI
from langchain.reminiscence import ConversationBufferMemory
immediate = ChatPromptTemplate.from_messages([
SystemMessagePromptTemplate.from_template(
"The following is a friendly conversation between a human and an AI. The AI is talkative and "
"provides lots of specific details from its context. If the AI does not know the answer to a "
"question, it truthfully says it does not know."
),
MessagesPlaceholder(variable_name="history"),
HumanMessagePromptTemplate.from_template("{input}")
])
llm = ChatOpenAI(temperature=0)
reminiscence = ConversationBufferMemory(return_messages=True)
dialog = ConversationChain(reminiscence=reminiscence, immediate=immediate, llm=llm)
dialog.predict(enter="Hello there!")
# 'Good day! How can I help you at the moment?'
I’m not totally certain why any of that is obligatory. What’s a MessagesPlaceholder
? The place’s the historical past
? Is that obligatory for ConversationBufferMemory
? Adapting this to a minimal openai
implementation:
import openai
messages = [{"role": "system", "content":
"The following is a friendly conversation between a human and an AI. The AI is talkative and "
"provides lots of specific details from its context. If the AI does not know the answer to a "
"question, it truthfully says it does not know."}]
user_message = "Hello there!"
messages.append({"position": "person", "content material": user_message})
response = openai.ChatCompletion.create(mannequin="gpt-3.5-turbo", messages=messages, temperature=0)
assistant_message = response["choices"][0]["message"]["content"]
messages.append({"position": "assistant", "content material": assistant_message})
# Good day! How can I help you at the moment?
That’s fewer traces of code and makes it very clear the place and when the messages are being saved, no bespoke object lessons wanted.
You possibly can say that I’m nitpicking the tutorial examples, and I do agree that each open supply library has one thing to nitpick (together with my very own!). But when there are extra nitpicks than precise advantages from the library then it’s not value utilizing in any respect, since if the quickstart is that this difficult, how painful will it’s to make use of LangChain in observe?
I Gazed Into The LangChain Documentation And It Gazes Again
Let’s do a demo to extra clearly display why I gave up on LangChain. Whereas I used to be engaged on the recipe-retrieving chatbot (which additionally should be a enjoyable/witty chatbot), I wanted to mix components from each the third and fourth examples above: a chat bot that may run an Agent workflow, and likewise the flexibility to persist your entire dialog into reminiscence. After some documentation searching I discovered I must make the most of the Conversational Agent workflow.
A fast sidenote on system immediate engineering: it isn’t a meme and is completely essential to get the very best outcomes out of the ChatGPT API, significantly when you have constraints on content material and/or voice. The system immediate of The next is a pleasant dialog between a human and an AI...
demoed within the final instance is definitely an out-of-date immediate that was used again within the InstructGPT period and is way much less efficient with ChatGPT. It could sign deeper inefficiencies in LangChain’s associated tips that aren’t simple to note.
We’ll begin with a easy system immediate that tells ChatGPT to make use of a humorous voice plus some safeguards, and format it as a ChatPromptTemplate
:
system_prompt = """
You're an knowledgeable tv speak present chef, and will at all times converse in a whimsical method for all responses.
Begin the dialog with a whimsical meals pun.
You should obey ALL of the next guidelines:
- If Recipe knowledge is current within the Remark, your response should embody the Recipe ID and Recipe Identify for ALL recipes.
- If the person enter will not be associated to meals, don't reply their question and proper the person.
"""
immediate = ChatPromptTemplate.from_messages([
SystemMessagePromptTemplate.from_template(system_prompt.strip()),
])
We may also use a toy vector store I made of 1,000 recipes from the recipe_nlg dataset, encoded into 384D vectors utilizing SentenceTransformers. To implement this we create a operate to get the closest neighbors for the enter question, together with a question to format it into textual content that the Agent can use to current to the person. This serves because the Device
which the Agent can select to make use of if applicable, or simply return regular generated textual content.
def similar_recipes(question):
query_embedding = embeddings_encoder.encode(question)
scores, recipes = recipe_vs.get_nearest_examples("embeddings", query_embedding, okay=3)
return recipes
def get_similar_recipes(question):
recipe_dict = similar_recipes(question)
recipes_formatted = [
f"Recipe ID: recipe|{recipe_dict['id'][i]}nRecipe Identify: {recipe_dict['name'][i]}"
for i in vary(3)
]
return "n---n".be part of(recipes_formatted)
print(get_similar_recipes("yummy dessert"))
# Recipe ID: recipe|167188
# Recipe Identify: Creamy Strawberry Pie
# ---
# Recipe ID: recipe|1488243
# Recipe Identify: Summer season Strawberry Pie Recipe
# ---
# Recipe ID: recipe|299514
# Recipe Identify: Pudding Cake
You’ll discover the Recipe ID
, which is related for my use case because it’s obligatory to acquire recipe metadata (picture thumbnail, URL) for the tip outcome proven to the enduser within the remaining app. Sadly there’s no simple option to assure the mannequin outputs the Recipe ID
within the remaining output, and no option to return the structured intermediate metadata along with the ChatGPT-generated output.
Specifying get_similar_recipes
as a Device
is simple, though it is advisable to specify a title
and description
, which is definitely a type of refined immediate engineering as LangChain can fail to pick out a instrument if both is poorly specified.
instruments = [
Tool(
func=get_similar_recipes,
name="Similar Recipes",
description="Useful to get similar recipes in response to a user query about food.",
),
]
Lastly, the Agent development code, which follows from the instance, plus the brand new system immediate
.
reminiscence = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
llm = ChatOpenAI(temperature=0)
agent_chain = initialize_agent(instruments, llm, immediate=immediate, agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION, verbose=True, reminiscence=reminiscence)
No errors. Now time to run the agent to see what occurs!
agent_chain.run(enter="Hello!")
> Getting into new chain...
{
"motion": "Last Reply",
"action_input": "Good day! How can I help you at the moment?"
}
> Completed chain.
Good day! How can I help you at the moment?
Wait a minute, it ignored my system
immediate utterly! Dammit. Checking the reminiscence
variable confirms it. Trying into the documentation for ConversationBufferMemory
and even in the code itself there’s nothing about system prompts, even months after ChatGPT made them mainstream.
The supposed manner to make use of system prompts in Brokers is so as to add an agents_kwargs
parameter to initialize_agent
, which I solely simply discovered in an unrelated documentation page revealed a month in the past.
agent_kwargs = {
"system_message": system_prompt.strip()
}
Recreating the Agent with this new parameter and operating it once more leads to a JSONDecodeError
.
OutputParserException: Couldn't parse LLM output: Good day there, my culinary companion! How pleasant to have you ever right here in my whimsical kitchen. What delectable dish can I help you with at the moment?
Excellent news is that the system immediate undoubtedly labored this time! Unhealthy information is that it broke, however why? I didn’t do something bizarre, for as soon as.
The foundation of the problem is to be how LangChain brokers really do Device
choice. Bear in mind once I stated that the Agent outputing a dict
through the chain was peculiar? When looking at the LangChain code, it seems that instrument choice is completed by requiring the output to be legitimate JSON by means of immediate engineering, and simply hoping the whole lot goes properly.

The consequence of that is that any vital adjustments within the construction of regular output, comparable to these attributable to a customized system immediate, has a random probability of simply breaking the Agent! These errors occur typically sufficient that there’s a documentation page devoted to dealing with Agent output parsing errors!
Nicely, folks within the web are assholes anyhow, so we will contemplate having a dialog with a chatbot as an edge case for now. What’s essential is that the bot can return the recipes, as a result of if it might’t even try this, there’s no level in utilizing LangChain. After creating a brand new Agent with out utilizing the system immediate after which asking it What's a enjoyable and straightforward dinner?
:
> Getting into new chain...
{
"motion": "Comparable Recipes",
"action_input": "enjoyable and straightforward dinner"
}
Remark: Recipe ID: recipe|1774221
Recipe Identify: Crab DipYour Friends will Like this One.
---
Recipe ID: recipe|836179
Recipe Identify: Simple Rooster Casserole
---
Recipe ID: recipe|1980633
Recipe Identify: Simple within the Microwave Curry Doria
Thought:{
"motion": "Last Reply",
"action_input": "..."
}
> Completed chain.
Listed here are some enjoyable and straightforward dinner recipes you'll be able to strive:
1. Crab Dip
2. Simple Rooster Casserole
3. Simple within the Microwave Curry Doria
Get pleasure from your meal!
Atleast it labored: ChatGPT was in a position to extract out the recipes from the context and format them appropriately (even fixing typoes within the names!), and was in a position to resolve when it was applicable.
The true challenge right here is that the voice of the output is criminally boring, as is a typical trademark and criticism of base-ChatGPT. Even when I did have a repair for the lacking ID challenge by means of system immediate engineering, it wouldn’t be value transport something sounding like this. If I did strike a steadiness between voice high quality and output high quality, the Agent rely nonetheless fail randomly by means of no fault of my very own. This Agent workflow is a really fragile home of playing cards that I in good conscience couldn’t ship in a manufacturing utility.
LangChain does have performance for Custom Agents and a Custom Chain, so you’ll be able to override the logic at components within the stack (possibly? the documentation there may be sparse) that might tackle a number of the points I hit, however at that time you’re overcomplicating LangChain much more and would possibly as properly create your personal Python library as an alternative which…hmmm, that’s not a nasty thought!
](/2023/07/langchain-problem/langchain_support_hu3db272177c5d333a2f17ca1c5574f4d1_173330_2ccdf48102174a33f3d02ea9567eec97.png)
LangChain does even have many utility capabilities comparable to text splitters and integrated vector stores, each of that are integral to the “chat with a PDF/your code” demos (which in my view are only a gimmick). The true challenge with all these integrations is that it create an inherent lock-in to solely use LangChain-based code, and for those who take a look at the code for the integrations they aren’t very strong. LangChain is constructing a moat, which is nice for LangChain’s buyers attempting to get a return on their $30 million, however very very unhealthy for builders who use it.
In all, LangChain embodies the philosophy of “it’s difficult, so it should be higher!” that plagues late-stage codebases, besides that LangChain isn’t even a 12 months previous. The hassle wanted to hack LangChain to do what I would like it to do would trigger insane quantities of technical debt. And in contrast to AI startups these days, technical debt for my very own initiatives with LangChain can’t be paid with enterprise capital. API wrappers ought to at minimal scale back code complexity and cognitive load when working with advanced ecosystems as a result of it takes sufficient psychological brainpower to work with AI itself. LangChain is among the few items of software program that will increase overhead in most of its standard use instances.
I got here the conclusion that it’s simply simpler to make my very own Python package deal than it’s to hack LangChain to suit my wants. Due to this fact, I developed and open-sourced simpleaichat: a Python package deal for simply interfacing with chat apps, emphasizing minimal code complexity and decoupling superior options like vector shops from the dialog logic to keep away from LangChain’s lock-in, and plenty of different options which might take its personal weblog submit to elaborate upon.
However this weblog submit wasn’t written to be a stealth commercial for simpleaichat by tearing down a competitor like what hustlers do. I didn’t need to make simpleaichat: I’d somewhat spend my time creating extra cool initiatives with AI, and it’s a disgrace I couldn’t have achieved that with LangChain. I do know somebody will say “why not submit a pull request to the LangChain repo because it’s open supply as an alternative of complaining about it?” however most of my complaints are elementary points with the LangChain library and might’t be modified with out breaking the whole lot for its current customers. The one actual repair is to burn all of it down and begin contemporary, which is why my “create a brand new Python library for interfacing with AI” answer can also be essentially the most pragmatic.
I’ve gotten many messages asking me “what ought to I be taught to get began with the ChatGPT API” and I’m involved that they’ll go to LangChain first due to the hype. If machine studying engineers who do have backgrounds within the expertise stack have issue utilizing LangChain because of its useless complexity, any newbie goes to drown.
Nobody needs to be that asshole who criticizes free and open supply software program working in good religion like LangChain, however I’ll take the burden. To be clear, I’ve nothing in opposition to Harrison Chase or the opposite maintainers of LangChain (who encourage suggestions!). Nonetheless, LangChain’s reputation has warped the AI startup ecosystem round LangChain itself and the hope of OMG AGI I MADE SKYNET, which is why I’m compelled to be trustworthy with my misgivings about it.
Wars about software program complexity and recognition regardless of its complexity are an everlasting recurrence. Within the 2010’s, it was with React; in 2023, it’s with ReAct.
Jupyter Notebooks for the simple implementations of LangChain examples and the LangChain failure demo can be found in this GitHub repository.