LangChain cheat sheet
A scannable LangChain reference: 25 short snippets across 12 topics, each linking back to the lesson it came from.
At a glance
| Topic | What it covers | |
|---|---|---|
| Prompt templates and chains | A prompt template is a function from variables to messages. Keeping it separate from the call site means you can | lesson |
| Tools and agents | A tool is a normal function plus a description the model can read. The signature becomes the argument schema and the | lesson |
| Retrieval-augmented generation | Chunk and index documents, retrieve the right passages, and answer with citations while allowing an honest not-found | lesson |
| Models, messages and providers | init_chat_model, provider packages, message types, streaming, and swapping providers without rewriting the rest of the | lesson |
| Structured output and output parsers | with_structured_output, Pydantic and JSON schemas, plain text parsers, and handling parse failures with retries instead | lesson |
| Runnables and LangChain Expression Language in depth | RunnableLambda, RunnablePassthrough, parallel and branching runnables, fallbacks, retries, runtime configuration and | lesson |
| Document loaders and text splitters | Chunk size is a retrieval parameter, not a formatting preference. Small chunks match precise questions; large chunks | lesson |
| Embeddings and vector stores | Embedding model choice, FAISS, Chroma and pgvector, indexing and updating, and filtering on metadata before similarity | lesson |
| Retrievers in depth | Similarity search, MMR, multi-query and contextual compression, hybrid search, reranking, and writing your own | lesson |
| Conversation memory and history | The test of a good memory design: restart the service, and the next request should behave identically. Anything held | lesson |
| Observability with callbacks and LangSmith | Structured logging around each step gets you most of the value of a tracing platform in about twenty lines. Adopt a | lesson |
| Deploying LangChain apps and moving to LangGraph | Dependency pinning, streaming from an API, production error handling, and migrating a multi-step agent workflow to | lesson |
Quick snippets
Prompt templates and chains
Prompts as reusable templates
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate.from_messages([
("system", "You are a terse technical editor. Return the rewritten text only."),
("human", "Rewrite for clarity and keep every fact:\n\n{draft}"),
])
chain = prompt | ChatOpenAI(model="gpt-4o-mini", temperature=0) | StrOutputParser()
print(chain.invoke({"draft": "The system does the thing where it retries on failure."}))
Composing and branching
from langchain_core.runnables import RunnableParallel, RunnablePassthrough, RunnableLambda
clean = RunnableLambda(lambda d: d["text"].strip())
chain = RunnableParallel(
summary=clean | summary_chain,
keywords=clean | keyword_chain,
original=RunnablePassthrough(), # pass the input through unchanged
)
out = chain.invoke({"text": " Long report body ... "})
print(out.keys()) # dict_keys(['summary', 'keywords', 'original'])Full lesson: Prompt templates and chains →
Tools and agents
Turning functions into tools
from langchain_core.tools import tool
@tool
def stock_level(sku: str) -> int:
"""Return units on hand for a SKU. Call this before promising any delivery date."""
return warehouse.on_hand(sku)
@tool
def place_order(sku: str, quantity: int) -> dict:
"""Create a draft order. Does not charge the customer; the draft needs approval."""
return orders.create_draft(sku, quantity)
… 1 more lines in the full lesson.
The agent loop
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "You are a support agent. Use tools for every fact; never guess stock or prices."),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
tools = [stock_level, place_order]
agent = create_tool_calling_agent(llm, tools, prompt)
… 11 more lines in the full lesson.
Full lesson: Tools and agents →
Retrieval-augmented generation
Build the index once
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
splitter = RecursiveCharacterTextSplitter(
chunk_size=800, # characters, not tokens - measure with your embedding model
chunk_overlap=120, # keep enough context that a sentence is not cut in half
separators=["\n\n", "\n", ". ", " "],
)
chunks = splitter.split_documents(load_documents("docs/"))
store = Chroma.from_documents(chunks, OpenAIEmbeddings(model="text-embedding-3-small"))… 1 more lines in the full lesson.
Ask with the retrieved context
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_messages([
("system", "Answer using only the context below. If the answer is not present, "
"reply exactly: Not found in the provided documents."),
("human", "Context:\n{context}\n\nQuestion: {question}"),
])
def format_docs(docs):
return "\n\n".join(f"[{d.metadata['source']}] {d.page_content}" for d in docs)… 7 more lines in the full lesson.
Full lesson: Retrieval-augmented generation →
Models, messages and providers
Initialising a model
import os
from langchain.chat_models import init_chat_model
# one factory, many providers: the model string is parsed into provider + name
model = init_chat_model("gpt-4o-mini", model_provider="openai", temperature=0)
claude = init_chat_model("claude-3-5-sonnet-latest", model_provider="anthropic")
local = init_chat_model("llama3.2", model_provider="ollama", base_url="http://localhost:11434")
print(model.model_name if hasattr(model, "model_name") else type(model).__name__)
# provider packages are separate installs; a missing one fails at import time
# pip install langchain-openai langchain-anthropic langchain-ollama… 4 more lines in the full lesson.
Message types
from langchain_core.messages import (
SystemMessage, HumanMessage, AIMessage, ToolMessage, trim_messages
)
messages = [
SystemMessage("You answer in British English, in at most three sentences."),
HumanMessage("Summarise the point of idempotency in APIs."),
AIMessage("An idempotent request can be repeated without changing the outcome."),
HumanMessage("Give one concrete example."),
]
# a tool result is a distinct message type tied to a tool call id… 14 more lines in the full lesson.
Streaming and batching
# streaming: print tokens as they arrive instead of waiting for the whole reply
for chunk in model.stream("Write a haiku about deployment."):
print(chunk.content, end="", flush=True)
# async streaming for a web endpoint
import asyncio
async def stream_reply(prompt):
pieces = []
async for chunk in model.astream(prompt):
pieces.append(chunk.content)
yield chunk.content… 11 more lines in the full lesson.
Full lesson: Models, messages and providers →
Structured output and output parsers
Structured output with a schema
from typing import Literal, Optional
from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model
class Ticket(BaseModel):
"""A support ticket extracted from a customer message."""
category: Literal["billing", "technical", "account", "other"] = Field(
description="The single best matching category.")
urgency: Literal["low", "normal", "high"] = Field(
description="high only if the customer is blocked from working.")
order_id: Optional[str] = Field(default=None, description="Order reference, if present.")… 14 more lines in the full lesson.
Parsers and validation
from langchain_core.output_parsers import (
StrOutputParser, JsonOutputParser, PydanticOutputParser
)
from langchain_core.prompts import ChatPromptTemplate
str_parser = StrOutputParser()
json_parser = JsonOutputParser(pydantic_object=Ticket)
pydantic_parser = PydanticOutputParser(pydantic_object=Ticket)
prompt = ChatPromptTemplate.from_messages([
("system", "Extract the ticket.\n{format_instructions}"),
("human", "{message}"),… 14 more lines in the full lesson.
Structured output in production
from langchain_core.runnables import RunnableLambda
from pydantic import ValidationError
def safe_extract(message: str):
"""Return a validated object, or an explicit failure record. Never guess."""
try:
ticket = extractor.invoke(message)["parsed"]
if ticket is None:
raise ValueError("model returned nothing parseable")
return {"ok": True, "ticket": ticket}
except (ValidationError, ValueError) as exc:
return {"ok": False, "reason": str(exc)[:200], "input": message[:200]}… 12 more lines in the full lesson.
Full lesson: Structured output and output parsers →
Runnables and LangChain Expression Language in depth
The Runnable protocol
from langchain_core.runnables import (
RunnableLambda, RunnablePassthrough, RunnableParallel, RunnableBranch
)
# any function becomes a runnable; keep it pure and small
normalise = RunnableLambda(lambda x: x.strip().lower())
word_count = RunnableLambda(lambda x: len(x.split()))
# RunnableParallel runs its branches on the SAME input and returns a dict
enrich = RunnableParallel(text=RunnablePassthrough(), words=word_count)
print(enrich.invoke(" Hello World "))
… 12 more lines in the full lesson.
Streaming through a composed chain
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_template("Explain {topic} in three sentences.")
chain = prompt | model | StrOutputParser()
# stream the final text out of a multi-step chain
for token in chain.stream({"topic": "idempotency keys"}):
print(token, end="", flush=True)
# when intermediate steps matter, stream events instead of text
async def trace_chain(topic):… 13 more lines in the full lesson.
Full lesson: Runnables and LangChain Expression Language in depth →
Document loaders and text splitters
Loading documents
from langchain_community.document_loaders import (
PyPDFLoader, CSVLoader, UnstructuredMarkdownLoader,
WebBaseLoader, DirectoryLoader, TextLoader,
)
# a PDF per page: page number becomes metadata, which is what citations need
pdf_docs = PyPDFLoader("handbook.pdf").load()
print(pdf_docs[0].metadata)
# {'source': 'handbook.pdf', 'page': 0, ...}
# every file in a tree, dispatched by extension, with parallel workers
loader = DirectoryLoader(… 15 more lines in the full lesson.
Splitting text
from langchain_text_splitters import (
RecursiveCharacterTextSplitter, MarkdownHeaderTextSplitter, TokenTextSplitter
)
# structure-first: split on markdown headings, then on size
headers = MarkdownHeaderTextSplitter(
headers_to_split_on=[("#", "h1"), ("##", "h2"), ("###", "h3")]
)
sections = headers.split_text(markdown_text)
print(sections[0].metadata) # {'h1': 'Guide', 'h2': 'Installation'}
size_splitter = RecursiveCharacterTextSplitter(… 15 more lines in the full lesson.
Full lesson: Document loaders and text splitters →
Embeddings and vector stores
Choosing an embedding model
from langchain_openai import OpenAIEmbeddings
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_community.embeddings import OllamaEmbeddings
# hosted: strong, cheap, and a network dependency
openai_emb = OpenAIEmbeddings(model="text-embedding-3-small", dimensions=512)
# local: no per-call cost, no data leaving the machine
local_emb = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-L6-v2",
encode_kwargs={"normalize_embeddings": True, "batch_size": 64},
)… 11 more lines in the full lesson.
Updating an index
from langchain_core.documents import Document
import datetime
def reindex(store, source_path, new_chunks):
"""Replace every chunk from one source without touching the rest."""
existing = store.get(where={"source": source_path})
if existing["ids"]:
store.delete(ids=existing["ids"])
stamped = [
Document(
page_content=c.page_content,… 15 more lines in the full lesson.
Full lesson: Embeddings and vector stores →
Retrievers in depth
Retrieval modes
from langchain_community.vectorstores import FAISS
from langchain_core.runnables import RunnableLambda
store = FAISS.from_documents(chunks, local_emb)
# 1. plain similarity: top-k nearest
basic = store.as_retriever(search_kwargs={"k": 6})
# 2. MMR: relevant but mutually diverse, good for summaries over a broad question
mmr = store.as_retriever(
search_type="mmr",
search_kwargs={"k": 6, "fetch_k": 30, "lambda_mult": 0.5},… 11 more lines in the full lesson.
Multi-query, compression and hybrid
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain.retrievers import ContextualCompressionRetriever, EnsembleRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
from langchain_community.retrievers import BM25Retriever
# multi-query: the model rewrites the question several ways, results are unioned
multi = MultiQueryRetriever.from_llm(retriever=basic, llm=model)
# contextual compression: keep only the sentences that bear on the question
compressor = LLMChainExtractor.from_llm(model)
compressed = ContextualCompressionRetriever(base_compressor=compressor, base_retriever=basic)
… 11 more lines in the full lesson.
Full lesson: Retrievers in depth →
Conversation memory and history
What belongs outside the context
# per-user retrieval: never retrieve across tenants
def user_retriever(user_id: str, question: str, k: int = 6):
return store.similarity_search(
question,
k=k,
filter={"tenant_id": user_id}, # enforced in the query, not after
)
def build_messages(user_id, question, history):
profile = load_profile(user_id) # a database call, not a memory
system = (
"You are a support assistant.\n"… 10 more lines in the full lesson.
Full lesson: Conversation memory and history →
Observability with callbacks and LangSmith
Tracing with LangSmith
# enable tracing with two environment variables
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY=lsv2_...
export LANGCHAIN_PROJECT=support-assistant
# or set it in code before importing anything that reads the environment
python -c "import os; os.environ['LANGCHAIN_TRACING_V2']='true'; import langchain"
Tracing with LangSmith
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "support-assistant"
from langsmith import traceable, Client
@traceable(run_type="tool", name="lookup_order")
def lookup_order(order_id: str) -> dict:
return {"order_id": order_id, "status": "in_transit", "eta": "2026-09-21"}
@traceable(name="support_reply")
def support_reply(question: str, user_id: str) -> str:… 12 more lines in the full lesson.
Full lesson: Observability with callbacks and LangSmith →
Deploying LangChain apps and moving to LangGraph
Packaging and pinning
# LangChain moves quickly: pin exact versions and upgrade deliberately
python -m pip freeze | grep -E "langchain|langgraph|pydantic" > requirements.txt
# a minimal pinned set for a RAG service
cat > requirements.txt <<'EOF'
langchain-core==0.3.29
langchain==0.3.14
langchain-openai==0.2.14
langchain-community==0.3.14
langchain-text-splitters==0.3.5
langgraph==0.2.62
pydantic==2.10.4… 5 more lines in the full lesson.
Packaging and pinning
# fail fast at startup if a required environment variable is missing
import os
from dataclasses import dataclass
@dataclass(frozen=True)
class Settings:
openai_api_key: str
langchain_project: str
vector_store_path: str
max_concurrency: int = 4
@classmethod… 13 more lines in the full lesson.
Full lesson: Deploying LangChain apps and moving to LangGraph →
FAQ
Is this LangChain cheat sheet free to use?
Where do the examples come from?
How do I go deeper than a cheat sheet?
Related cheat sheets
AI Basics AI Agents Math for AI Machine Learning scikit-learn TensorFlow
Last refreshed 2026-09-27.