Sitemap

LangChain : A Complete Study Guide (Python)

7 min readAug 7, 2026

--

A conceptual walkthrough of LangChain — what it is, why it exists, and how each piece fits together — paired with runnable code examples for every concept.

1. What Is LangChain?

LangChain is a framework (available in Python and JavaScript) for building applications powered by Large Language Models (LLMs) like GPT, Claude, or Llama.

Think of an LLM as a very smart “brain” that can only do one thing: take text in, and give text out. It has no memory of past conversations, can’t browse the internet, can’t do math reliably, and can’t access your private files.

LangChain exists to solve exactly that problem. It gives you building blocks to connect an LLM to:

  • External data — documents, databases, PDFs
  • Tools — search engines, calculators, APIs
  • Memory — so it can remember past conversation
  • Multi-step reasoning — so it can plan and act, not just answer once

Analogy: If an LLM is an engine, LangChain is the car built around it — steering wheel, fuel line, dashboard — that lets the engine actually take you somewhere useful.

2. Core Building Blocks

a) Models

LangChain provides a standard interface so you can switch between different LLM providers without rewriting your whole application.

b) Prompts / Prompt Templates

Reusable “fill-in-the-blank” instructions sent to the LLM. Instead of hardcoding a question, you create a template with placeholders — like a mail-merge template — so the same structure can be reused with different inputs.

c) Chains

A chain connects multiple steps together, where the output of one step becomes the input of the next. For example: take user input → format it into a prompt → send to LLM → parse the response into structured data. This is the “wiring” that turns a single LLM call into a multi-step workflow.

d) Memory

Since LLMs don’t remember previous turns, LangChain’s memory components store conversation history and feed relevant parts of it back into future prompts — giving the illusion of an ongoing conversation.

e) Retrieval / RAG (Retrieval-Augmented Generation)

This lets an LLM answer questions using your own data (PDFs, internal docs, websites) instead of only what it learned during training.

The basic idea:

  1. Your documents are broken into chunks and converted into numerical representations called embeddings.
  2. These embeddings are stored in a vector database (a database optimized for finding “similar meaning” text).
  3. When a user asks a question, LangChain finds the most relevant chunks from the database.
  4. Those chunks are inserted into the prompt as context, and the LLM answers using that context.

This is why RAG is often used for “chat with your PDF” or company-knowledge-base type applications.

f) Tools

Functions the LLM can choose to use — like a web search, a calculator, a code executor, or a call to a company API. The LLM decides when a tool is needed and what input to give it.

g) Agents

An agent is an LLM that can reason step-by-step and decide which tools to use, in what order, to accomplish a goal — rather than following a fixed, pre-written sequence like a chain does.

Chain vs. Agent — the key distinction:

Get Sourim Mitra’s stories in your inbox

Join Medium for free to get updates from this writer.

Definition Analogy Chain A fixed, predetermined sequence of steps A recipe Agent The LLM dynamically decides the steps itself, based on the situation A chef improvising

3. A Typical Workflow (Conceptual, No Code)

Imagine building a “Company Policy Chatbot”:

  1. Load your company’s policy PDFs.
  2. Split them into smaller chunks (LLMs can’t read huge documents in one go).
  3. Embed each chunk into a vector representation and store it in a vector store.
  4. A user asks: “How many sick leave days do I get?”
  5. LangChain retrieves the most relevant chunks from the vector store.
  6. Those chunks + the question are combined into a prompt.
  7. The LLM generates an answer grounded in the retrieved text.
  8. If it’s a multi-turn conversation, memory keeps track of what was discussed before.

This entire pipeline — load → split → embed → store → retrieve → prompt → generate — is what LangChain helps you assemble without building each piece from scratch.

4. Related Ecosystem Terms You’ll Encounter

Term Meaning LangGraph An extension of LangChain for building more complex, stateful, multi-step agent workflows (like a flowchart of decisions) LangSmith A debugging/monitoring/testing platform for LangChain applications — lets you trace exactly what happened at each step Vector Store / Vector Database A database that stores embeddings and allows “search by meaning” instead of exact keyword match (e.g., Pinecone, Chroma, FAISS) Embedding A numerical representation of text that captures its meaning, used to compare similarity between pieces of text Token The small chunks of text (roughly word-pieces) that LLMs process; LLMs have a limit on how many tokens they can handle at once (context window)

5. When Should You Actually Use LangChain?

Good fit:

  • You need to connect an LLM to your own documents/data (RAG)
  • You need multi-step reasoning or tool use (agents)
  • You want to prototype quickly with pre-built components
  • You want to swap LLM providers easily

Might be overkill:

  • You just need a single, simple prompt → response call
  • Your use case doesn’t need memory, retrieval, or tools

6. Hands-On: Code Walkthrough

Installation

pip install langchain langchain-openai langchain-community langchain-chroma

You’ll also need an API key for whichever model provider you use (OpenAI, Anthropic, etc.), typically set as an environment variable:

export OPENAI_API_KEY="your-key-here"
# or for Anthropic
export ANTHROPIC_API_KEY="your-key-here"

Chat Models

Chat models are the entry point — you send messages, get a response.

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
model = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)messages = [
SystemMessage(content="You are a helpful assistant that explains concepts simply."),
HumanMessage(content="What is a neural network?"),
]
response = model.invoke(messages)
print(response.content)

Key idea: invoke() is the standard method across almost all LangChain components — models, chains, and retrievers all expose .invoke(), .batch(), and .stream().

Prompt Templates

Instead of hardcoding strings, use PromptTemplate to make reusable, parameterized prompts.

from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "You are an expert in {domain}."),
("human", "Explain {topic} in {num_sentences} sentences."),
])
formatted = prompt.invoke({
"domain": "biology",
"topic": "photosynthesis",
"num_sentences": 3
})
print(formatted.to_messages())

Chains — The “LCEL” Pipe Syntax

LangChain Expression Language (LCEL) lets you compose components with the | (pipe) operator, similar to Unix pipes.

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
model = ChatOpenAI(model="gpt-4o-mini")
parser = StrOutputParser()
prompt = ChatPromptTemplate.from_template(
"Write a one-paragraph summary about {subject}."
)
chain = prompt | model | parserresult = chain.invoke({"subject": "the French Revolution"})
print(result)

Flow: prompt formats the input → model generates a response → parser extracts plain text from the response object.

Output Parsers (Structured Output)

Force the model to return structured data (e.g., JSON matching a schema) using Pydantic.

from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI
class MovieReview(BaseModel):
title: str = Field(description="Movie title")
rating: int = Field(description="Rating out of 10")
summary: str = Field(description="One-sentence summary")
model = ChatOpenAI(model="gpt-4o-mini")
structured_model = model.with_structured_output(MovieReview)
result = structured_model.invoke("Review the movie Inception")
print(result.title, result.rating, result.summary)

Memory (Conversation History)

Modern LangChain manages memory via message history objects rather than the older ConversationChain class.

from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
model = ChatOpenAI(model="gpt-4o-mini")prompt = ChatPromptTemplate.from_messages([
("system", "You are a friendly tutor."),
("placeholder", "{history}"),
("human", "{input}"),
])
chain = prompt | modelstore = {}def get_history(session_id: str):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
chain_with_memory = RunnableWithMessageHistory(
chain,
get_history,
input_messages_key="input",
history_messages_key="history",
)
config = {"configurable": {"session_id": "user-1"}}r1 = chain_with_memory.invoke({"input": "My name is Priya."}, config=config)
print(r1.content)
r2 = chain_with_memory.invoke({"input": "What's my name?"}, config=config)
print(r2.content) # Should remember "Priya"

Document Loaders

Load data from files, URLs, PDFs, etc., into LangChain’s Document objects.

from langchain_community.document_loaders import TextLoader, WebBaseLoader
# From a local text file
loader = TextLoader("notes.txt")
docs = loader.load()
# From a web page
web_loader = WebBaseLoader("https://example.com/article")
web_docs = web_loader.load()
print(docs[0].page_content[:200])
print(docs[0].metadata)

Text Splitting

Large documents need to be split into chunks before embedding, so retrieval is precise.

from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
)
chunks = splitter.split_documents(docs)
print(f"Split into {len(chunks)} chunks")

Embeddings + Vector Stores

Convert text chunks into vectors and store them for similarity search.

from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db",
)
# Similarity search
results = vectorstore.similarity_search("What is the main topic?", k=3)
for r in results:
print(r.page_content[:150], "\n---")

RAG (Retrieval-Augmented Generation)

Combine retrieval with generation so the model answers using your own documents.

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
model = ChatOpenAI(model="gpt-4o-mini")
template = """Answer the question using only the following context.
If you don't know the answer, say so.
Context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
def format_docs(docs):
return "\n\n".join(d.page_content for d in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)
answer = rag_chain.invoke("What are the key findings mentioned in the document?")
print(answer)

The classic RAG pattern:

  1. Retrieve relevant chunks based on the question
  2. Stuff them into a prompt as context
  3. Ask the model to answer using only that context

Tools

Tools are functions an LLM/agent can call. Define them with the @tool decorator.

from langchain_core.tools import tool
@tool
def get_word_length(word: str) -> int:
"""Returns the length of a word."""
return len(word)
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two integers together."""
return a * b
print(get_word_length.invoke({"word": "LangChain"})) # 9
print(multiply.invoke({"a": 6, "b": 7})) # 42

Agents (Tool-Calling)

Agents let the model decide which tool(s) to call and in what order.

from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
model = ChatOpenAI(model="gpt-4o-mini")prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant. Use tools when needed."),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
tools = [get_word_length, multiply]agent = create_tool_calling_agent(model, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = executor.invoke({"input": "What is 12 multiplied by 8?"})
print(result["output"])

8. Suggested Learning Path

  1. Chat models + prompt templates
  2. LCEL chains + output parsers
  3. Memory
  4. Document loaders + splitting
  5. Embeddings + vector stores
  6. Full RAG pipeline
  7. Tools + agents
  8. Build a mini project yourself with your own text file

If you found this useful, follow for more practical breakdowns of the LLM tooling ecosystem.

--

--

Sourim Mitra
Sourim Mitra

Written by Sourim Mitra

Software Analyst - M.O.L IT PVT LTD. I have more than 13 years experience in web development.