Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

LangChain & LangGraph

Overview

LangChain is the most widely-used framework for building LLM applications. LangGraph, its companion for agent workflows, provides a graph-based architecture for complex, stateful agent systems. Together, they handle tool integration, memory, retrieval, and orchestration.

LangChain Core Concepts

graph TD
    LC[LangChain]
    LC --> MODELS[LLM/Chat Models]
    LC --> PROMPTS[Prompt Templates]
    LC --> CHAINS[Chains]
    LC --> AGENTS[Agents]
    LC --> TOOLS[Tools]
    LC --> MEMORY_LC[Memory]
    LC --> RETRIEVERS[Retrievers]

Chains

Sequential operations:

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# Simple chain
prompt = ChatPromptTemplate.from_template(
    "Explain {topic} in simple terms."
)
model = ChatOpenAI(model="gpt-4")
parser = StrOutputParser()

chain = prompt | model | parser
result = chain.invoke({"topic": "quantum computing"})

LCEL (LangChain Expression Language)

Pipe-based composition:

# Complex chain with retrieval
retriever = vectorstore.as_retriever()
prompt = ChatPromptTemplate.from_template("""
Answer based on context:
{context}
Question: {question}
""")

chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | model
    | parser
)

LangGraph

LangGraph models agent workflows as state graphs:

graph TD
    START((Start)) --> AGENT[Agent Node]
    AGENT --> TOOL_CALL{Tool Call?}
    TOOL_CALL -->|Yes| TOOLS[Tool Node]
    TOOL_CALL -->|No| END((End))
    TOOLS --> AGENT

Basic Agent

from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import ToolNode

# Define tools
tools = [search_tool, calculator_tool]

# Create agent
model = ChatOpenAI(model="gpt-4").bind_tools(tools)

def agent_node(state: MessagesState):
    response = model.invoke(state["messages"])
    return {"messages": [response]}

def should_use_tools(state: MessagesState):
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tools"
    return END

# Build graph
graph = StateGraph(MessagesState)
graph.add_node("agent", agent_node)
graph.add_node("tools", ToolNode(tools))
graph.add_edge(START, "agent")
graph.add_conditional_edges("agent", should_use_tools)
graph.add_edge("tools", "agent")

app = graph.compile()
result = app.invoke({"messages": [("user", "What's the weather?")]})

Stateful Agent with Custom State

from typing import TypedDict, Annotated
from langgraph.graph import StateGraph

class AgentState(TypedDict):
    messages: list
    plan: list
    completed_steps: list
    current_step: str

def planner_node(state: AgentState):
    plan = create_plan(state["messages"][-1].content)
    return {"plan": plan, "current_step": plan[0]}

def executor_node(state: AgentState):
    result = execute_step(state["current_step"])
    return {
        "completed_steps": state["completed_steps"] + [result],
        "current_step": get_next_step(state["plan"], state["completed_steps"])
    }

# Build graph
graph = StateGraph(AgentState)
graph.add_node("planner", planner_node)
graph.add_node("executor", executor_node)
graph.add_edge(START, "planner")
graph.add_edge("planner", "executor")
graph.add_conditional_edges("executor", should_continue)

Human-in-the-Loop

from langgraph.checkpoint.memory import MemorySaver

# Add checkpointing for human-in-the-loop
checkpointer = MemorySaver()
app = graph.compile(
    checkpointer=checkpointer,
    interrupt_before=["tools"]  # Pause before tool execution
)

# Run until interrupt
config = {"configurable": {"thread_id": "1"}}
result = app.invoke(input_data, config)

# Human reviews and approves
# Resume execution
result = app.invoke(None, config)

Key LangGraph Features

FeatureDescription
State managementTyped state objects passed between nodes
Conditional edgesDynamic routing based on state
CyclesLoops for iterative agent behavior
CheckpointingSave/restore state for long-running tasks
Human-in-the-loopPause execution for human approval
StreamingStream tokens and state updates
PersistenceSQLite/PostgreSQL for state storage

Interview Questions

Q1: What is the difference between LangChain and LangGraph?

Answer:

  • LangChain: Higher-level abstractions (chains, agents, tools). Good for simple sequential workflows. LCEL for composing operations.
  • LangGraph: Lower-level graph-based architecture. Models workflows as state machines with nodes and edges. Supports cycles, conditional routing, human-in-the-loop.
  • LangGraph is better for complex agents with state. LangChain is better for simple chains and retrieval.

Q2: How does LangGraph handle state?

Answer: LangGraph uses TypedDict for state definition. State is passed between nodes, and each node returns partial state updates. The graph merges updates automatically. This enables:

  • Tracking conversation history
  • Maintaining plans and progress
  • Sharing data between agent steps
  • Checkpointing for persistence

Q3: What is LCEL?

Answer: LCEL (LangChain Expression Language) is a pipe-based composition syntax:

chain = prompt | model | parser

It creates a RunnableSequence. Benefits: automatic async support, streaming, batch processing, and fallbacks. It replaces the older LLMChain class.

Common Mistakes

  • ❌ Using LangChain for simple tasks (overhead not worth it)
  • ❌ Not understanding LangGraph’s state management
  • ❌ Ignoring checkpointing (lose state on failures)
  • ❌ Over-complicating graphs (keep them simple)

Summary

LangChain provides building blocks for LLM applications. LangGraph models agent workflows as state graphs with nodes, edges, and conditional routing. Key features: state management, checkpointing, human-in-the-loop, and streaming. Use LangGraph for complex agents, LangChain for simple chains.

Cross-References