DS DevShelfHub Projects · AI tools
Cheatsheets / LangChain
Cheatsheet · AI frameworks

LangChain Cheatsheet: LCEL, Agents, RAG and LangGraph

By DevShelfHub

LangChain is a Python/JS framework for composing LLM-powered applications: it provides a unified interface across model providers, a composable LCEL pipe syntax, and pre-built chains for RAG, agents, and memory. This cheatsheet covers the core imports, Chat and Embedding model wrappers, LCEL runnables, prompt templates, retrievers, agents, tools, LangGraph state, and full minimal RAG and agent examples.

75 items 7 min Chains LCEL LangGraph RAG

LangChain is a Python and JavaScript framework that provides a unified interface for building LLM-powered applications. Its core insight is that most LLM applications follow the same structural patterns — retrieve context, format a prompt, call a model, parse the output — so LangChain abstracts each step behind composable primitives. The LangChain Expression Language (LCEL) lets you chain these primitives with the pipe operator (|), producing a lazy, streaming-capable runnable that can be invoked, batched, or streamed with the same API surface.

The framework is organised into several packages: langchain-core holds the base abstractions (Runnable, BaseMessage, BasePromptTemplate), langchain ships the high-level chains and agents, and langchain-community or provider packages (e.g. langchain-openai, langchain-anthropic) provide concrete model integrations. Pinning to provider packages rather than langchain-community gives you faster upgrades and smaller dependency footprints in production.

Agents in LangChain follow the ReAct (Reason + Act) loop: the model decides which tool to call, the framework executes it and feeds the result back, and the loop continues until the model emits a final answer. LangGraph extends this model to multi-node stateful graphs, enabling cycles, parallel branches, and human-in-the-loop checkpoints — essential for production agentic workflows. This cheatsheet covers the full daily surface: imports, model wrappers, LCEL chains, retrievers, agents, memory, callbacks, and end-to-end RAG and agent patterns.

Start hereQuick start · 6 you’ll reach for daily

Call a modelllm.invoke("…")
Build a chainprompt | llm | parser
Stream tokenschain.stream(input)
Structured outputllm.with_structured_output(Schema)
Bind toolsllm.bind_tools([tool_a, tool_b])
Build an agentcreate_agent(model, tools)

Target versions · paceVersions

Targets: langchain ≥ 0.3 langchain-core ≥ 0.3 langgraph ≥ 0.2 python ≥ 3.10

LangChain moves fast — module paths and class names shift between minor versions (e.g. langchain.chat_modelslangchain_openai, LLMChain → LCEL, classic memory → LangGraph checkpointers). If an import errors, check the official docs at python.langchain.com for the current path. This sheet pins to the names current as of May 2026.

Install · envSetup

bash
# pip — install only what you need; provider packages are split out
pip install langchain langchain-core langchain-community langgraph
pip install langchain-openai langchain-anthropic   # providers
pip install langchain-chroma langchain-pinecone    # vector stores

# env
export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-...
export LANGSMITH_API_KEY=ls-...   # optional, for tracing

Where things liveCommon imports

Provider integrations live in their own packages — langchain-openai, langchain-anthropic, etc. Core abstractions stay in langchain-core. Old from langchain import … paths still work but are mostly re-exports.

from langchain_openai import ChatOpenAI, OpenAIEmbeddingsOpenAI chat + embeddings.
from langchain_anthropic import ChatAnthropicAnthropic chat.
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, ToolMessageMessage classes.
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate, MessagesPlaceholderPrompt templates.
from langchain_core.output_parsers import StrOutputParser, JsonOutputParserOutput parsers.
from langchain_core.runnables import RunnablePassthrough, RunnableParallel, RunnableLambdaLCEL building blocks.
from langchain_core.tools import toolThe @tool decorator.
from langchain.agents import create_agent, before_model, after_model, wrap_model_call, wrap_tool_callAgent factory + 4 middleware decorators.
from langgraph.graph import StateGraph, MessagesState, START, ENDGraph primitives.
from langgraph.checkpoint.memory import MemorySaverIn-memory checkpointer (dev).
from langgraph.checkpoint.sqlite import SqliteSaverSQLite checkpointer (prod).
from langchain_community.document_loaders import WebBaseLoader, PyPDFLoaderDocument loaders.
from langchain_text_splitters import RecursiveCharacterTextSplitterText splitter (own package).
from langchain_chroma import ChromaLocal vector store.
from langchain_pinecone import PineconeVectorStoreManaged vector store.

Chat models · messagesModels

Chat models

ChatOpenAI(model="gpt-4o-mini", temperature=0)OpenAI chat model.
ChatAnthropic(model="claude-sonnet-4-6")Anthropic chat model.
llm.invoke("hi")Single sync call → AIMessage.
await llm.ainvoke("hi")Async variant. Use in FastAPI / asyncio.
llm.batch(["q1", "q2"])Parallel calls. Faster than a Python loop.
for chunk in llm.stream("hi"): …Stream tokens as they arrive.

Message types

SystemMessage("You are a tutor.")Sets behavior / persona.
HumanMessage("What is RAG?")User input.
AIMessage("RAG is…")Model response. Has .content and .tool_calls.
ToolMessage(content, tool_call_id)Tool execution result fed back to the model.
Pass a list[BaseMessage] to .invoke() for multi-turn — strings are auto-wrapped as HumanMessage.

Templates · placeholdersPrompts

PromptTemplate.from_template("Tell me a {topic} joke")Plain string template.
ChatPromptTemplate.from_messages([("system","…"),("human","{q}")])Multi-turn template.
MessagesPlaceholder("history")Slot to inject prior messages at runtime.
prompt.format(topic="cats")Render to string.
prompt.invoke({"q":"hi"})Render to PromptValue (chainable).
prompt.partial(role="tutor")Pre-fill some variables.

Few-shot

python
from langchain_core.prompts import (
    ChatPromptTemplate,
    FewShotChatMessagePromptTemplate,
)

examples = [{"q": "2+2", "a": "4"}, {"q": "3+3", "a": "6"}]
ex_prompt = ChatPromptTemplate.from_messages([("human", "{q}"), ("ai", "{a}")])
few_shot = FewShotChatMessagePromptTemplate(
    example_prompt=ex_prompt,
    examples=examples,
)

Coerce model outputOutput parsers

StrOutputParser().content as a plain string. 90% of chains.
JsonOutputParser()Parses model JSON; tolerates fences.
PydanticOutputParser(pydantic_object=Schema)Legacy Validates by regex-parsing model output. Fragile on format drift.
llm.with_structured_output(Schema)Preferred Uses the model’s native tool/JSON mode. No parsing, no drift.

The pipe operatorLCEL · Runnables

Composition

chain = prompt | llm | StrOutputParser()Classic 3-step chain.
chain.invoke({"q":"hi"})Run it.
RunnablePassthrough()Identity. Use to fork inputs into a parallel branch.
RunnableParallel(a=ra, b=rb)Run multiple runnables in parallel; output is a dict.
RunnableLambda(fn)Wrap a Python function so it composes with |.
chain.with_config({"tags":["prod"]})Attach run metadata for tracing.

Async & streaming

.invoke(x) / .ainvoke(x)Sync / async single call.
.batch([x1, x2]) / .abatch(…)Parallel.
.stream(x) / .astream(x)Yield chunks.
.astream_events(x, version="v2")Stream intermediate events (token, tool call, etc).

Parallel RAG pattern

python
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

rag = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

Function callingTools

@tool
def add(a: int, b: int) -> int: …
Decorate a Python function into a tool. Docstring + type hints become the schema.
llm_with_tools = llm.bind_tools([add, search])Give the model tools it can call.
resp.tool_callsList of {name, args, id} the model wants to invoke.
add.invoke(call["args"])Execute the tool yourself with the model’s args.
TavilySearchResults(max_results=3)Prebuilt web-search tool.

Reason + act loopAgents

from langchain.agents import create_agentHigh-level agent factory.
agent = create_agent(model, tools=[…])Build a tool-using agent.
agent.invoke({"messages":[("user","…")]})Run; returns final state.
create_agent(…, middleware=[hook])Inject pre/post hooks.

Middleware decorators

@before_modelRuns before each model call. Inject context, redact, rate-limit.
@after_modelRuns after each model call. Log, filter, transform.
@wrap_model_callWrap entire model call. Add retry / fallback logic.
@wrap_tool_callWrap tool invocations. Sandbox, audit, mock.

Persist across turnsMemory & state

Modern path: memory has moved from chain-attached ConversationBufferMemory / RunnableWithMessageHistory to graph-level checkpointers in LangGraph. State is keyed by thread_id and persisted via a Saver. Use the legacy classes only if you’re maintaining old code.

Current — LangGraph checkpointers Preferred

MemorySaver()In-process checkpointer. Drop-in for dev.
SqliteSaver.from_conn_string("checkpoints.db")Durable checkpointer for single-node prod.
PostgresSaver.from_conn_string("postgresql://…")Durable, multi-node prod.
graph.compile(checkpointer=saver)Make a graph stateful.
config = {"configurable":{"thread_id":"u1"}}Identify a conversation thread. Required when checkpointer is set.
graph.get_state(config)Inspect current state of a thread.
graph.update_state(config, {"messages":[…]})Patch state (e.g., human-in-the-loop edit).

Legacy — chain-attached memory Legacy

InMemoryChatMessageHistory()Per-session message store. Use a checkpointer instead.
RunnableWithMessageHistory(chain, get_history)Wraps a chain to add memory. Superseded by graph state.
ConversationBufferMemory()Pre-LCEL memory class. Avoid in new code.

Load → split → embed → store → retrieveRAG pipeline

1 · Load

WebBaseLoader(web_paths=["https://…"])Scrape URLs.
PyPDFLoader("file.pdf")PDF → Documents (one per page).
loader.load()Eager — returns list[Document].
loader.lazy_load()Iterator — for huge corpora.

2 · Split

RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=150)Default choice. Splits on ¶ → sent → word.
splitter.split_documents(docs)Chunks preserving metadata.
MarkdownHeaderTextSplitter([("#","h1"),("##","h2")])Split markdown by headers.

3 · Embed

OpenAIEmbeddings(model="text-embedding-3-small")Strong default.
HuggingFaceEmbeddings(model_name="…")Local / OSS.
OllamaEmbeddings(model="nomic-embed-text")Local via Ollama.
emb.embed_query("text")→ list[float] (one vector).
emb.embed_documents(["a","b"])→ list[list[float]] (batched).

4 · Store

Chroma.from_documents(docs, emb)Local persistent vector DB.
PineconeVectorStore.from_documents(docs, emb, index_name="…")Managed cloud.
QdrantVectorStore.from_documents(docs, emb, url="…", collection_name="…")Self-host or cloud.
store.add_documents([…])Append more docs.

5 · Retrieve

store.similarity_search("q", k=4)Top-k by cosine.
store.similarity_search_with_score("q")Same, plus distance.
store.max_marginal_relevance_search("q", k=4)Diverse top-k. Beats plain similarity for breadth.
retriever = store.as_retriever(search_kwargs={"k":4})Make it composable in LCEL.

State machines for agentsLangGraph

graph = StateGraph(MessagesState)Define a graph with a state schema.
graph.add_node("model", node_fn)A node is any callable: state → state.
graph.add_edge("model", "tools")Static transition.
graph.add_conditional_edges("model", router_fn)Dynamic — router returns next node name.
graph.set_entry_point("model")Where execution starts.
app = graph.compile(checkpointer=MemorySaver())Compile to a Runnable.
app.invoke({"messages":[…]}, config)Run a turn.
add_messagesReducer that appends instead of replacing the message list.

Full pipeline · ~25 linesEnd-to-end · Minimal RAG

Loads a web page, chunks it, embeds into Chroma, retrieves top-k, and answers a question. Replace the URL and you have a working RAG bot.

python
from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# 1 · Load + split
docs = WebBaseLoader(["https://example.com/about"]).load()
chunks = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=150,
).split_documents(docs)

# 2 · Embed + store
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
store = Chroma.from_documents(chunks, embeddings)
retriever = store.as_retriever(search_kwargs={"k": 4})

# 3 · Compose chain
prompt = ChatPromptTemplate.from_messages([
    ("system", "Answer using only the context.\n\n{context}"),
    ("human", "{question}"),
])
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

rag_chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

# 4 · Run
print(rag_chain.invoke("What does this company do?"))

Minimal agent

A tool-using agent in 12 lines. create_agent builds a LangGraph state machine under the hood — checkpointer optional.

python
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain.agents import create_agent
from langgraph.checkpoint.memory import MemorySaver

@tool
def multiply(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b

agent = create_agent(
    ChatOpenAI(model="gpt-4o-mini"),
    tools=[multiply],
    checkpointer=MemorySaver(),
)

config = {"configurable": {"thread_id": "demo"}}
result = agent.invoke({"messages": [("user", "What is 21 * 2?")]}, config)
print(result["messages"][-1].content)

LangSmithTracing & evaluation

os.environ["LANGSMITH_TRACING"] = "true"Auto-trace every LangChain call.
@traceableTrace any plain Python function.
chain.with_config({"run_name":"myrun","tags":["v2"]})Tag a run for filtering in LangSmith.
Client().create_dataset("…")Create an eval dataset.
evaluate(chain, data="ds", evaluators=[…])Run an eval over a dataset.

Best practiceGood to know

Prefer with_structured_output over PydanticOutputParser. The latter regex-parses model output and fails on minor format drift; the former uses the model’s native JSON/tool mode.
RunnablePassthrough() in a dict is a fork, not a no-op. {"context": retriever, "question": RunnablePassthrough()} sends the same input to both branches.
Chunk size matters more than embedding model. Most bad-RAG diagnoses are really bad chunking. Start at chunk_size=800–1200, overlap=120–200.

Common trapsWatch out for

Don’t call .invoke() inside an async event loop. It blocks. Use .ainvoke() in FastAPI / asyncio. The error is silent latency, not a crash.
Always set a thread_id when using a checkpointer. Missing thread_id silently makes every turn a fresh conversation — no memory.
.batch() isn’t magic. It parallelizes I/O but provider rate limits still apply. Tune max_concurrency in RunnableConfig.

Go deeperSee also

LangChain FAQ

What is LangChain?

LangChain is a Python (and JavaScript) framework for building LLM-powered applications. It provides abstractions for model calls, prompt templates, output parsers, retrieval chains, tool-using agents, and memory. Since v0.3, the recommended way to compose these components is through LCEL (LangChain Expression Language), which uses the pipe operator.

What is LCEL in LangChain?

LCEL (LangChain Expression Language) is LangChain v0.2+ syntax for composing chains using the pipe operator. Each component (prompt, model, parser, retriever) implements a Runnable interface with invoke(), stream(), and batch() methods. Chains are built as prompt | model | parser, and the resulting chain is itself a Runnable.

How do LangChain agents work?

A LangChain agent binds tools to a model and runs a loop: the model receives the task and tool descriptions, chooses a tool and arguments, observes the result, and repeats until it produces a final answer. Modern agents use the model's native tool-calling API rather than ReAct text parsing. LangGraph is now the recommended framework for complex multi-step agents.

How do I build a RAG pipeline with LangChain?

Load documents with a document loader, split them with a text splitter, embed and store chunks in a vector store, then create a retriever. Build a chain as retriever | format_docs | prompt | model | parser. LangChain includes built-in integrations for Chroma, Pinecone, pgvector, and Weaviate so you can swap stores without rewriting the chain.

What is the difference between LangChain and LangGraph?

LangChain provides the building blocks: model wrappers, prompt templates, retrievers, and simple sequential chains. LangGraph adds a stateful graph execution engine on top for orchestrating cyclic, branching, and multi-agent workflows with explicit state management and checkpointing. Most new agent work starts with LangGraph rather than legacy LangChain AgentExecutor.