Introduction to LangChain¶
1. Why this matters¶
Without LangChain, every LLM app re-invents the same plumbing: prompt templating, model API calls, conversation memory, document loading, embedding + vector search, tool calling, retry logic, output parsing.
LangChain replaces all of that glue with a modular, model-agnostic layer. You write one chain that works against OpenAI, Anthropic, Gemini, or a local Ollama model with a single line change.
Where you'll actually use it:
- Chatbots with memory.
- Document Q&A / RAG over PDFs, web pages, databases.
- Autonomous agents that pick the right tool to solve a task.
- Pipelines: summarize → classify → route → respond.
2. Mental model¶
Think of LangChain like a circuit-board for LLM apps:
- Components are the chips: a Prompt template, a Chat model, an Output parser, a Retriever, a Tool.
- Each component is a
Runnable— it has.invoke(),.stream(),.batch(),.ainvoke(). - You wire them together with the
|pipe (LCEL — LangChain Expression Language). - Data (a dictionary, a string, a
Messagelist) flows from left to right through the wires. - Swap any chip for another (OpenAI → Claude) without rewiring the rest.
If you already know Unix pipes (cat | grep | wc -l), LCEL feels identical — just with LLM-aware components.
3. Architecture / Flow¶
flowchart LR
U[User Query] --> P[PromptTemplate]
P --> M[Chat Model<br/>OpenAI / Claude / Gemini]
M --> O[Output Parser]
O --> R[Response]
subgraph Optional Add-ons
MEM[Memory] -.-> P
RET[Retriever<br/>+ Vector DB] -.-> P
TOOLS[Tools / Agents] -.-> M
end
style P fill:#e8f0fe
style M fill:#fff4e5
style O fill:#e8f5e9
Every LangChain app is some variation of this. RAG adds the retriever path. Agents add the tools path. Chatbots add the memory path.
4. Core concepts¶
- Component — a reusable building block (Prompt, Model, Parser, Retriever, Tool, Memory).
- Runnable — the universal interface every component implements (
.invoke,.stream,.batch, async variants). - LCEL (LangChain Expression Language) — the pipe-based composition syntax (
prompt | model | parser). - Chain — any composition of Runnables.
- Agent — a chain that lets the LLM decide which tool to call next, in a loop.
- Document — LangChain's standard wrapper:
Document(page_content, metadata). - Message — chat-style I/O:
SystemMessage,HumanMessage,AIMessage,ToolMessage.
5. Code — minimal working example¶
The "hello world" of LangChain — three components piped together:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from dotenv import load_dotenv
load_dotenv() # loads OPENAI_API_KEY
prompt = PromptTemplate.from_template("Explain {topic} in one sentence.")
model = ChatOpenAI(model="gpt-4o-mini")
parser = StrOutputParser()
chain = prompt | model | parser
print(chain.invoke({"topic": "vector embeddings"}))
That's the entire pattern. Every LangChain app — no matter how big — is this shape with more pieces wired in.
6. Code — real-world pattern¶
A small RAG-flavored pipeline showing how the same | composes with retrieval, error handling, and structured output:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
# 1. Vector store (built once, queried many times)
vectorstore = FAISS.load_local("./index", OpenAIEmbeddings(),
allow_dangerous_deserialization=True)
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
# 2. Prompt with retrieved context injected
prompt = ChatPromptTemplate.from_template(
"""Answer using only the context. If the answer isn't there, say "I don't know."
Context: {context}
Question: {question}
"""
)
# 3. Compose: question -> {context, question} -> prompt -> model -> string
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| ChatOpenAI(model="gpt-4o-mini", temperature=0)
| StrOutputParser()
)
answer = chain.invoke("What's our refund policy?")
Notice nothing about the shape changed — still prompt | model | parser. Retrieval just feeds the prompt.
7. Common pitfalls¶
- ❗ Mixing v0.1 and v0.3 syntax. The old
LLMChain(llm=..., prompt=...)andchain.run(...)style is deprecated. Always use LCEL (prompt | model | parser) and.invoke(). - ❗ Confusing
langchainvslangchain_corevslangchain_community. Core abstractions live inlangchain_core; integrations live in provider packages (langchain_openai,langchain_anthropic); community contrib lives inlangchain_community. The umbrellalangchainpackage mostly re-exports. - ❗ Forgetting to load
.env. API keys must be in the environment before instantiating models. Usepython-dotenvand callload_dotenv()at the top. - ❗ Calling
.invoke()with a string when the chain expects a dict. If your prompt has variables{topic}, you must pass{"topic": "..."}— not just"...".
8. When to use vs not use¶
| Use LangChain when | Don't use LangChain when |
|---|---|
| You need to swap LLM providers easily | You're making one simple OpenAI call (just use the SDK) |
| Building RAG / agents / multi-step pipelines | You need maximum control over every prompt/token |
| You want the ecosystem (loaders, retrievers, integrations) | The abstraction overhead hurts more than it helps |
| Prototyping fast | You're building infra that needs to be lean and dependency-light |
For graph/state machine workflows (loops, branching, human-in-the-loop), reach for LangGraph instead — it's the same team, designed for that.
9. Cheatsheet¶
| Package | What's in it |
|---|---|
langchain_core |
Runnable, BaseMessage, base classes for prompts/parsers/retrievers |
langchain_openai |
ChatOpenAI, OpenAIEmbeddings, OpenAI (legacy completions) |
langchain_anthropic |
ChatAnthropic |
langchain_google_genai |
ChatGoogleGenerativeAI |
langchain_community |
Document loaders, vector stores, retrievers from the community |
langchain |
Umbrella package — chains, agents, helpers |
langgraph |
Stateful, graph-based orchestration (separate library) |
langsmith |
Tracing + evals (separate library) |
| Runnable method | What it does |
|---|---|
.invoke(input) |
Run synchronously, return output |
.ainvoke(input) |
Run asynchronously |
.stream(input) |
Yield tokens / chunks as they arrive |
.batch([in1, in2, ...]) |
Run many inputs in parallel |
.with_retry(...) |
Add retry logic |
.with_fallbacks([...]) |
Fall back to alternate chains on failure |
10. Q&A — recall test¶
-
Q: What does the
|operator do in LangChain? A: It composes twoRunnables into a sequential chain — output of the left becomes input of the right. It's LCEL syntax sugar forRunnableSequence(left, right). -
Q: Why is everything a
Runnable? A: Uniform interface. Any component can be.invoked,.streamed,.batched, retried, parallelized, or piped — without each component needing to implement all that itself. -
Q: Difference between
langchain_coreandlangchain_community? A:langchain_core= abstract base classes + a few core implementations, no heavy deps.langchain_community= 100s of third-party integrations (loaders, vector stores) contributed by the community. -
Q: When would you choose raw OpenAI SDK over LangChain? A: Single-call apps where you don't need retrieval, memory, tool-calling orchestration, or provider swappability — the SDK is leaner and gives you direct control.
Practice¶
What does this print?
Expected: Hello, Alice!
Substitute the placeholder using .format()
Expected: Welcome Bob
Quiz — Quick check¶
What you remember
Q1. What's the core abstraction that makes LangChain components composable?
- LLMChain
- Runnable — invocable, streamable, pipe-able
- Pipeline
- Agent
Why: LCEL pipes Runnables together:
prompt | model | parser. Every component (model, prompt, parser, tool) implements the same interface.
Q2. When should you use LangChain vs the raw OpenAI SDK?
- Always use LangChain
- LangChain for multi-step apps (retrieval, memory, tool-calling); raw SDK for simple single-call apps
- LangChain is deprecated
- Only for OpenAI
Why: LangChain shines for orchestration. For a single API call, the raw SDK is leaner. Use LangChain when you have 3+ components to wire together.
Q3. What's the main benefit of LangChain's model abstraction?
- Faster API calls
- Swap providers (OpenAI → Anthropic → Mistral) without rewriting application code
- Cheaper costs
- Built-in safety
Why: Same
.invoke()/.stream()/.batch()interface across providers — change one import line.
Common doubts¶
Is LangChain over-engineered for simple apps?
For a single LLM call, yes — use the raw SDK. LangChain shines when you have multiple components (retrieval + prompt + model + parser + memory). For real-world workflows it pays off.
What's the difference between LangChain and LangGraph?
LangChain builds linear pipelines. LangGraph builds stateful graphs with loops, branches, and human-in-the-loop. Use LangChain for chatbots and Q&A; LangGraph for agents that retry, branch, or pause for approval.
Should I learn LangChain in 2026?
Yes — the patterns are universal: prompt templates, output parsing, retrieval, tool calling, agents. The patterns transfer even if libraries change. LangChain is still the most-used framework in production LLM apps.