Skip to content

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 Message list) 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=...) and chain.run(...) style is deprecated. Always use LCEL (prompt | model | parser) and .invoke().
  • Confusing langchain vs langchain_core vs langchain_community. Core abstractions live in langchain_core; integrations live in provider packages (langchain_openai, langchain_anthropic); community contrib lives in langchain_community. The umbrella langchain package mostly re-exports.
  • Forgetting to load .env. API keys must be in the environment before instantiating models. Use python-dotenv and call load_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 two Runnables into a sequential chain — output of the left becomes input of the right. It's LCEL syntax sugar for RunnableSequence(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_core and langchain_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!

template = "Hello, {name}!"
print(template.format(name="Alice"))

Substitute the placeholder using .format()

Expected: Welcome Bob

template = "Welcome {user}"
user = "Bob"
print(template)                       # bug: forgot .format(user=user)

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.