Migrating from LangChain 1.x to 2.0
LangChainMigrationTutorial
Complete guide to migrating your LangChain application to version 2.0 with 10x performance improvements.
Migrating from LangChain 1.x to 2.0
Overview
LangChain 2.0 represents a complete architectural overhaul with significant performance improvements and a simplified API. This tutorial guides you through migrating your existing LangChain 1.x code to version 2.0.
By the end of this tutorial, you'll understand the key changes, have migrated a sample application, and know how to leverage the new features.
Prerequisites
- Existing LangChain 1.x code
- Python 3.10+ or Node.js 18+
- Understanding of your current chain architecture
Step 1: Understand the Key Changes
What's Different?
| Aspect | LangChain 1.x | LangChain 2.0 |
|---|---|---|
| Core Paradigm | Class-based chains | LCEL (functional composition) |
| Performance | Baseline | 10x faster |
| Streaming | Added on | Native throughout |
| TypeScript | Good | Excellent |
| Parallel Execution | Manual | Built-in |
| Debugging | Basic | Enhanced tracing |
Why Migrate?
- Performance: 10x faster for common operations
- Simplicity: Less boilerplate, more intuitive
- Streaming: Native at every layer
- Type Safety: Better TypeScript support
- Future-Proof: 1.x is in maintenance mode
Step 2: Update Dependencies
Python
# Remove old packages
pip uninstall langchain langchain-core langchain-community -y
# Install 2.0
pip install langchain==2.0.0
pip install langchain-core==2.0.0
pip install langchain-community==2.0.0
pip install langchain-openai==2.0.0
pip install langchain-anthropic==2.0.0
Node.js
npm uninstall @langchain/core @langchain/community
npm install @langchain/core@2.0.0
npm install @langchain/community@2.0.0
npm install @langchain/openai@2.0.0
Step 3: Update Imports
Common Import Changes
# OLD (1.x)
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain, RetrievalQA
from langchain.agents import initialize_agent, Tool
from langchain.memory import ConversationBufferMemory
# NEW (2.0)
from langchain_openai import OpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains import RetrievalQA # Some still exist, but prefer LCEL
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.chat_history import InMemoryChatMessageHistory
Import Migration Guide
| 1.x Import | 2.0 Import |
|---|---|
langchain.llms.OpenAI | langchain_openai.OpenAI |
langchain.llms.Anthropic | langchain_anthropic.Anthropic |
langchain.prompts.PromptTemplate | langchain_core.prompts.PromptTemplate |
langchain.prompts.ChatPromptTemplate | langchain_core.prompts.ChatPromptTemplate |
langchain.chains.LLMChain | Use LCEL: prompt | llm | parser |
langchain.agents.initialize_agent | langchain.agents.create_tool_calling_agent |
langchain.memory.ConversationBufferMemory | langchain_core.chat_history.InMemoryChatMessageHistory |
Step 4: Convert Chains to LCEL
Simple LLM Chain
# OLD (1.x)
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
prompt = PromptTemplate.from_template("Tell me a joke about {topic}")
llm = OpenAI()
chain = LLMChain(llm=llm, prompt=prompt)
result = chain.run(topic="cats")
# NEW (2.0)
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_template("Tell me a joke about {topic}")
llm = OpenAI()
parser = StrOutputParser()
chain = prompt | llm | parser
result = chain.invoke({"topic": "cats"})
RAG Chain
# OLD (1.x)
from langchain.chains import RetrievalQA
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever
)
result = qa_chain.run("What is the return policy?")
# NEW (2.0)
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
qa_prompt = ChatPromptTemplate.from_template("""
Answer the question based only on the following context:
{context}
Question: {input}
""")
rag_chain = (
{"context": retriever, "input": lambda x: x["input"]}
| qa_prompt
| llm
| StrOutputParser()
)
result = rag_chain.invoke({"input": "What is the return policy?"})
Chain with Multiple Steps
# OLD (1.x)
from langchain.chains import TransformChain, LLMChain
first_chain = LLMChain(llm=llm, prompt=first_prompt)
second_chain = LLMChain(llm=llm, prompt=second_prompt)
# Combined manually
intermediate = first_chain.run(input)
result = second_chain.run(input=intermediate)
# NEW (2.0)
chain = (
first_prompt | llm | StrOutputParser()
| lambda x: second_prompt.format(input=x)
| llm
| StrOutputParser()
)
result = chain.invoke({"input": "text"})
Step 5: Update Memory Usage
Conversation Memory
# OLD (1.x)
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
memory = ConversationBufferMemory()
chain = ConversationChain(llm=llm, memory=memory)
response1 = chain.run("Hello, my name is John")
response2 = chain.run("What's my name?")
# NEW (2.0)
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate
store = InMemoryChatMessageHistory()
chain = (
ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant."),
("human", "{input}"),
("placeholder", "{chat_history}"),
])
| llm
| StrOutputParser()
)
response1 = chain.invoke(
{"input": "Hello, my name is John"},
config={"configurable": {"chat_history": store.messages}}
)
response2 = chain.invoke(
{"input": "What's my name?"},
config={"configurable": {"chat_history": store.messages}}
)
Step 6: Update Agents
Tool-Calling Agent
# OLD (1.x)
from langchain.agents import initialize_agent, Tool, AgentType
from langchain.tools import DuckDuckGoSearchRun
tools = [
Tool(
name="Search",
func=DuckDuckGoSearchRun().run,
description="Search the web"
)
]
agent = initialize_agent(
tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION
)
result = agent.run("What's the weather in Tokyo?")
# NEW (2.0)
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain.tools import DuckDuckGoSearchRun
from langchain_core.prompts import ChatPromptTemplate
tools = [DuckDuckGoSearchRun()]
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant."),
("placeholder", "{agent_scratchpad}"),
("human", "{input}"),
])
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools)
result = executor.invoke({"input": "What's the weather in Tokyo?"})
Step 7: Add Streaming
# OLD (1.x) - Limited streaming support
for token in chain.stream("What is AI?"):
print(token, end="", flush=True)
# NEW (2.0) - Native streaming
for chunk in chain.stream({"input": "What is AI?"}):
print(chunk, end="", flush=True)
# Event-based streaming (2.0)
for event in chain.astream_events(
{"input": "What is AI?"},
version="v2"
):
kind = event["event"]
if kind == "on_chain_stream":
print(event["data"]["chunk"], end="", flush=True)
Step 8: Add Parallel Execution
# NEW (2.0) - Parallel execution
from langchain_core.runnables import RunnableParallel
parallel_chain = RunnableParallel({
"summary": summary_chain,
"keywords": keyword_extractor,
"sentiment": sentiment_analyzer
})
results = parallel_chain.invoke({"text": document})
# All three run in parallel!
print(results["summary"])
print(results["keywords"])
print(results["sentiment"])
Step 9: Add Error Handling
# NEW (2.0) - Built-in retry
chain = base_chain.with_retry(
max_retries=3,
wait_exponential_multiplier=1000,
wait_exponential_max=10000
)
# Fallbacks
chain = primary_chain.with_fallbacks([
ChatAnthropic(),
ChatGoogleGenerativeAI()
])
Step 10: Test Your Migration
Create a Test Suite
import pytest
class TestMigratedChain:
def test_simple_query(self):
result = chain.invoke({"topic": "cats"})
assert len(result) > 0
def test_streaming(self):
chunks = list(chain.stream({"topic": "cats"}))
assert len(chunks) > 0
def test_error_handling(self):
# Test with invalid input
result = chain.invoke({"topic": ""})
# Should handle gracefully
Run Tests
pytest tests/ -v
Complete Migration Example
Before (1.x)
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
from langchain.memory import ConversationBufferMemory
class QASystem:
def __init__(self):
self.llm = OpenAI()
self.memory = ConversationBufferMemory()
self.qa_chain = RetrievalQA.from_chain_type(
llm=self.llm,
chain_type="stuff",
retriever=self.retriever
)
def ask(self, question: str) -> str:
return self.qa_chain.run(question)
After (2.0)
from langchain_openai import OpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.chat_history import InMemoryChatMessageHistory
class QASystem:
def __init__(self):
self.llm = OpenAI()
self.history = InMemoryChatMessageHistory()
self.qa_chain = self._create_chain()
def _create_chain(self):
prompt = ChatPromptTemplate.from_template("""
Answer based on context:
{context}
Question: {input}
""")
return (
{"context": self.retriever, "input": lambda x: x["input"]}
| prompt
| self.llm
| StrOutputParser()
)
def ask(self, question: str) -> str:
return self.qa_chain.invoke(
{"input": question},
config={"configurable": {"chat_history": self.history.messages}}
)
Common Issues and Solutions
Issue: Import Errors
Solution: Make sure you've installed all required packages:
pip install langchain langchain-core langchain-community langchain-openai
Issue: Chain Not Working
Solution: Check that you're using the correct LCEL syntax:
# Correct
chain = prompt | llm | parser
# Incorrect (old style won't work)
chain = LLMChain(llm=llm, prompt=prompt) # Deprecated
Issue: Memory Not Persisting
Solution: Pass memory through config:
chain.invoke(input, config={"configurable": {"chat_history": messages}})
Best Practices
- Test Incrementally: Migrate one chain at a time
- Use LCEL: Prefer functional composition over classes
- Add Streaming: Take advantage of native streaming
- Use Parallel: Where appropriate, use parallel execution
- Add Error Handling: Use built-in retry and fallbacks
