LangChain for Beginners: Complete Guide with Examples
Welcome to your comprehensive guide to LangChain! This tutorial will walk you through every major concept in LangChain with simple, practical examples that you can try yourself.
What is LangChain?
LangChain is a powerful framework for building applications with Large Language Models (LLMs). It provides tools and abstractions to make it easier to work with AI models, manage conversations, and build complex AI-powered applications.
Core Concepts
1. Chat Models
What it is: Chat models are LLMs that process sequences of messages and return responses. Think of them as the "brain" of your AI application.
Simple Example:
from langchain_openai import ChatOpenAI
# Initialize a chat model
chat = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
# Send a simple message
response = chat.invoke("Hello! How are you?")
print(response.content)
Explanation: This creates a connection to OpenAI's GPT model and sends it a simple greeting. The temperature=0.7 makes responses somewhat creative but still focused.
📖 Read more about Chat Models →
2. Messages
What it is: Messages are the building blocks of conversations. They represent different types of communication in a chat.
Simple Example:
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
# Different types of messages
messages = [
SystemMessage(content="You are a helpful cooking assistant"),
HumanMessage(content="How do I make pasta?"),
AIMessage(content="Boil water, add pasta, cook for 8-12 minutes"),
HumanMessage(content="What about sauce?")
]
response = chat.invoke(messages)
print(response.content)
Explanation:
SystemMessage: Sets the AI's role/personalityHumanMessage: Represents user inputAIMessage: Represents AI responses
3. Chat History
What it is: A conversation represented as a sequence of messages, allowing the AI to remember context.
Simple Example:
from langchain_core.chat_history import InMemoryChatMessageHistory
# Create a conversation history
history = InMemoryChatMessageHistory()
# Add messages to history
history.add_user_message("My name is Alice")
history.add_ai_message("Nice to meet you, Alice!")
history.add_user_message("What's my name?")
# Use history in conversation
response = chat.invoke(history.messages)
print(response.content) # Should remember "Alice"
Explanation: The chat history keeps track of the entire conversation, so the AI can reference previous messages.
📖 Read more about Chat History →
4. Tools
What it is: Functions that the AI can call to perform specific tasks, like calculations or web searches.
Simple Example:
from langchain_core.tools import tool
@tool
def calculator(expression: str) -> str:
"""Calculate a mathematical expression"""
try:
result = eval(expression)
return f"The result is {result}"
except:
return "Invalid expression"
# Test the tool
print(calculator("2 + 2")) # Output: "The result is 4"
Explanation: The @tool decorator turns a regular Python function into a tool that AI models can use.
5. Tool Calling
What it is: When a chat model can automatically decide to use tools based on the conversation.
Simple Example:
from langchain_openai import ChatOpenAI
# Bind tools to the model
chat_with_tools = ChatOpenAI(model="gpt-3.5-turbo").bind_tools([calculator])
# Ask a math question
response = chat_with_tools.invoke("What is 15 * 7?")
print(response.content)
Explanation: The model can now automatically use the calculator tool when it detects a math problem.
📖 Read more about Tool Calling →
6. Structured Output
What it is: Making the AI respond in a specific format, like JSON, instead of free-form text.
Simple Example:
from pydantic import BaseModel
from langchain_openai import ChatOpenAI
class PersonInfo(BaseModel):
name: str
age: int
occupation: str
# Get structured output
chat = ChatOpenAI(model="gpt-3.5-turbo")
structured_chat = chat.with_structured_output(PersonInfo)
response = structured_chat.invoke("Tell me about a fictional character")
print(f"Name: {response.name}")
print(f"Age: {response.age}")
print(f"Job: {response.occupation}")
Explanation: Instead of free text, the AI returns data in a specific structure that your code can easily use.
📖 Read more about Structured Output →
7. Prompt Templates
What it is: Reusable templates for creating prompts with variables that can be filled in dynamically.
Simple Example:
from langchain_core.prompts import ChatPromptTemplate
# Create a template
template = ChatPromptTemplate.from_messages([
("system", "You are a {role} assistant"),
("human", "Help me with {task}")
])
# Use the template
prompt = template.format_messages(
role="cooking",
task="making pizza"
)
response = chat.invoke(prompt)
print(response.content)
Explanation: Templates let you reuse prompt structures and just change the variables, making your code more organized.
📖 Read more about Prompt Templates →
8. Runnable Interface
What it is: A standard way to run different LangChain components that makes them work together seamlessly. Many Runnables are composed of other Runnables, creating powerful chains and workflows.
Simple Example - Basic Runnable:
from langchain_core.runnables import RunnableLambda
# Create a simple runnable
def add_greeting(text):
return f"Hello! {text}"
greeting_runnable = RunnableLambda(add_greeting)
# Use it
result = greeting_runnable.invoke("How can I help you?")
print(result) # Output: "Hello! How can I help you?"
Advanced Example - Composed Runnables:
from langchain_core.runnables import RunnableLambda, RunnableParallel
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
# Create individual runnables
def format_question(text):
return f"Question: {text}"
def add_context(text):
return f"Context: You are a helpful assistant.\n{text}"
# Compose them together
format_runnable = RunnableLambda(format_question)
context_runnable = RunnableLambda(add_context)
chat = ChatOpenAI(model="gpt-3.5-turbo")
# Chain them: input -> format -> add context -> chat
composed_chain = format_runnable | context_runnable | chat
result = composed_chain.invoke("What is Python?")
print(result.content)
Parallel Composition Example:
# Run multiple runnables in parallel
def analyze_sentiment(text):
return f"Sentiment: Positive" if "good" in text.lower() else "Sentiment: Neutral"
def count_words(text):
return f"Word count: {len(text.split())}"
# Parallel execution
parallel_analysis = RunnableParallel({
"sentiment": RunnableLambda(analyze_sentiment),
"word_count": RunnableLambda(count_words),
"original": lambda x: x # Pass through original text
})
result = parallel_analysis.invoke("This is a good example")
print(result)
# Output: {
# 'sentiment': 'Sentiment: Positive',
# 'word_count': 'Word count: 5',
# 'original': 'This is a good example'
# }
Explanation: Runnables provide a consistent interface (.invoke(), .stream(), .batch()) across all LangChain components. The power comes from composing simple Runnables into complex workflows - you can chain them sequentially with | or run them in parallel with RunnableParallel. This makes building sophisticated AI pipelines as simple as connecting building blocks.
📖 Read more about Runnable Interface →
9. LangChain Expression Language (LCEL)
What it is: A syntax for chaining LangChain components together using the | operator.
Simple Example:
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# Create a chain
prompt = ChatPromptTemplate.from_template("Tell me a joke about {topic}")
parser = StrOutputParser()
# Chain them together
chain = prompt | chat | parser
# Use the chain
result = chain.invoke({"topic": "programming"})
print(result)
Explanation: LCEL lets you connect prompt → model → parser in a clean, readable way using the | operator.
10. Document Loaders
What it is: Tools to load content from various sources (files, websites, databases) into a format LangChain can work with.
Simple Example:
from langchain_community.document_loaders import TextLoader
# Load a text file
loader = TextLoader("my_document.txt")
documents = loader.load()
print(f"Loaded {len(documents)} documents")
print(f"First 100 characters: {documents[0].page_content[:100]}")
Explanation: Document loaders convert external content into LangChain Document objects that contain the text and metadata.
📖 Read more about Document Loaders →
11. Text Splitters
What it is: Tools to break large documents into smaller chunks that are easier for AI models to process.
Simple Example:
from langchain_text_splitters import CharacterTextSplitter
# Create a splitter
splitter = CharacterTextSplitter(
chunk_size=100,
chunk_overlap=20
)
# Split some text
text = "This is a very long document that needs to be split into smaller pieces for processing..."
chunks = splitter.split_text(text)
print(f"Split into {len(chunks)} chunks")
for i, chunk in enumerate(chunks):
print(f"Chunk {i}: {chunk}")
Explanation: Large documents are split into smaller pieces with some overlap to maintain context between chunks.
📖 Read more about Text Splitters →
12. Embedding Models
What it is: Models that convert text into numerical vectors that capture semantic meaning.
Simple Example:
from langchain_openai import OpenAIEmbeddings
# Create embeddings model
embeddings = OpenAIEmbeddings()
# Convert text to vectors
text = "I love programming"
vector = embeddings.embed_query(text)
print(f"Text: {text}")
print(f"Vector length: {len(vector)}")
print(f"First 5 numbers: {vector[:5]}")
Explanation: Embeddings turn text into numbers that represent meaning, allowing computers to understand semantic similarity.
📖 Read more about Embedding Models →
13. Vector Stores
What it is: Databases specialized for storing and searching through vector embeddings efficiently.
Simple Example:
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
# Create embeddings and vector store
embeddings = OpenAIEmbeddings()
texts = ["I love cats", "Dogs are great", "Python is a programming language"]
# Create vector store
vectorstore = FAISS.from_texts(texts, embeddings)
# Search for similar content
results = vectorstore.similarity_search("I like pets", k=2)
for result in results:
print(f"Found: {result.page_content}")
Explanation: Vector stores let you search for content based on meaning rather than exact keyword matches.
📖 Read more about Vector Stores →
14. Retrievers
What it is: Components that find relevant documents from a knowledge base based on a query.
Simple Example:
# Create a retriever from the vector store
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# Retrieve relevant documents
docs = retriever.invoke("animals")
for doc in docs:
print(f"Retrieved: {doc.page_content}")
Explanation: Retrievers provide a standard interface for finding relevant information from any knowledge source.
📖 Read more about Retrievers →
15. Retrieval Augmented Generation (RAG)
What it is: A technique that combines retrieving relevant information with generating responses, giving AI access to external knowledge.
Simple Example:
from langchain_core.prompts import ChatPromptTemplate
# Create RAG chain
rag_prompt = ChatPromptTemplate.from_template(
"Based on this context: {context}\n\nAnswer this question: {question}"
)
def rag_chain(question):
# Retrieve relevant docs
docs = retriever.invoke(question)
context = "\n".join([doc.page_content for doc in docs])
# Generate answer with context
prompt = rag_prompt.format_messages(context=context, question=question)
response = chat.invoke(prompt)
return response.content
# Use RAG
answer = rag_chain("What programming language is mentioned?")
print(answer)
Explanation: RAG first finds relevant information, then uses that information to generate more accurate, informed responses.
16. Agents
What it is: AI systems that can decide what actions to take and use tools to accomplish complex tasks.
Simple Example:
from langchain.agents import create_openai_tools_agent, AgentExecutor
from langchain_openai import ChatOpenAI
# Create an agent with tools
agent = create_openai_tools_agent(
llm=ChatOpenAI(model="gpt-3.5-turbo"),
tools=[calculator],
prompt=ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}")
])
)
agent_executor = AgentExecutor(agent=agent, tools=[calculator])
# The agent decides when to use tools
result = agent_executor.invoke({"input": "What's 25 * 4 + 10?"})
print(result["output"])
Explanation: Agents can think about problems, decide which tools to use, and execute multi-step solutions automatically.
17. Streaming
What it is: Receiving AI responses piece by piece as they're generated, instead of waiting for the complete response.
Simple Example:
# Stream responses
for chunk in chat.stream("Write a short poem about coding"):
print(chunk.content, end="", flush=True)
print() # New line at the end
Explanation: Streaming provides real-time responses, making your application feel more responsive and interactive.
18. Output Parsers
What it is: Components that transform raw AI output into structured formats your application can use.
Simple Example:
from langchain_core.output_parsers import CommaSeparatedListOutputParser
# Create parser
parser = CommaSeparatedListOutputParser()
# Create prompt that asks for list format
prompt = ChatPromptTemplate.from_template(
"List 3 popular programming languages.\n{format_instructions}"
).partial(format_instructions=parser.get_format_instructions())
# Use chain with parser
chain = prompt | chat | parser
result = chain.invoke({})
print(f"Parsed list: {result}") # Output: ['Python', 'JavaScript', 'Java']
Explanation: Output parsers ensure AI responses are in exactly the format your code expects.
📖 Read more about Output Parsers →
19. Few-Shot Prompting
What it is: Providing examples in your prompt to show the AI the pattern you want it to follow.
Simple Example:
from langchain_core.prompts import FewShotChatMessagePromptTemplate
# Define examples
examples = [
{"input": "happy", "output": "joyful"},
{"input": "sad", "output": "melancholy"},
]
# Create few-shot prompt
example_prompt = ChatPromptTemplate.from_messages([
("human", "{input}"),
("ai", "{output}")
])
few_shot_prompt = FewShotChatMessagePromptTemplate(
example_prompt=example_prompt,
examples=examples,
)
final_prompt = ChatPromptTemplate.from_messages([
("system", "Give a more sophisticated synonym for each word"),
few_shot_prompt,
("human", "{input}")
])
chain = final_prompt | chat
result = chain.invoke({"input": "angry"})
print(result.content) # Should output something like "furious" or "irate"
Explanation: By showing examples, you teach the AI the exact pattern or style you want it to follow.
📖 Read more about Few-Shot Prompting →
20. Callbacks
What it is: Functions that run at specific points during AI processing, useful for logging, monitoring, or custom processing.
Simple Example:
from langchain_core.callbacks import BaseCallbackHandler
class SimpleCallback(BaseCallbackHandler):
def on_llm_start(self, serialized, prompts, **kwargs):
print("🤖 AI is thinking...")
def on_llm_end(self, response, **kwargs):
print("✅ AI finished responding!")
# Use callback
response = chat.invoke("Hello!", config={"callbacks": [SimpleCallback()]})
Explanation: Callbacks let you hook into the AI processing pipeline to add custom behavior like logging or progress tracking.
Getting Started: Your First LangChain App
Here's a simple but complete example that combines several concepts:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# 1. Set up components
chat = ChatOpenAI(model="gpt-3.5-turbo")
prompt = ChatPromptTemplate.from_template("You are a helpful assistant. {question}")
parser = StrOutputParser()
# 2. Create chain
chain = prompt | chat | parser
# 3. Use it
response = chain.invoke({"question": "Explain what Python is in simple terms"})
print(response)
Next Steps
Now that you understand the core concepts, here are some ideas for practice:
- Build a simple chatbot using chat models and chat history
- Create a RAG system using document loaders, embeddings, and retrievers
- Build an agent that can use multiple tools to solve problems
- Experiment with streaming to make your apps more responsive
Key Takeaways
- Chat Models are the core AI component
- Messages and Chat History manage conversations
- Tools and Agents let AI take actions
- RAG gives AI access to external knowledge
- LCEL (the
|operator) chains components together - Prompts and Parsers control input and output format
LangChain makes it much easier to build sophisticated AI applications by providing these building blocks. Start with simple examples and gradually combine more concepts as you get comfortable!
Happy coding with LangChain! 🦜🔗