A systematic approach to mastering the LangChain ecosystem's open-source agent frameworks, guided by the Feynman Technique, Simon Learning Method, SQ3R Reading Method, and Cornell Note-Taking System.
2026-06-02Technology, LangChain, LangGraph, DeepSeek, AI
1. Overview & Questions (SQ3R: Survey & Question)
SQ3R Step 1: Survey the big picture and formulate key questions.
What Are LangChain and LangGraph?
LangChain is an open-source platform for agent engineering. It provides the core abstractions for building AI agents: a unified model interface (Model), tools (Tool), prompts (Prompt), and middleware (Middleware). Through create_agent, it offers a minimal yet highly configurable agent harness — compose exactly the agent your use case needs from model, tools, prompt, and middleware.
LangGraph is the low-level orchestration framework and runtime within the LangChain ecosystem, designed for building, managing, and deploying long-running, stateful agents. It models agent workflows as graphs — composed of nodes, edges, and state — providing production-grade capabilities like durable execution, human-in-the-loop, and streaming. Inspired by Google's Pregel system and Apache Beam, LangGraph is trusted by companies like Klarna, Uber, and J.P. Morgan.
Understanding the product hierarchy:
Product
Role
When to Use
Deep Agents
High-level agent harness ("batteries included")
Quickly build agents with planning, subagents, and filesystem tools
LangChain
Agent framework (core abstractions)
Custom agent harness with flexible model/tools/middleware composition
Tracing, debugging, evaluating, and deploying agents
DeepSeek's Position in the AI Ecosystem
DeepSeek is a Chinese AI company offering high-performance, ultra-low-cost large language model APIs. As of 2026, its core models include:
DeepSeek-V4-Pro / V4-Flash: Flagship general-purpose models, rivaling GPT-5.5 and Claude Opus 4.7 at roughly 1/10th the cost
DeepSeek-R1: A reasoning model supporting chain-of-thought "Thinking Mode" for superior performance on complex reasoning tasks
DeepSeek Coder: A model specialized for programming tasks
Key advantages of the DeepSeek API:
OpenAI SDK compatible: Simply change base_url to switch
Anthropic interface support: Also compatible with the Anthropic API format
Extremely low pricing: As low as $0.0028 per million tokens (cache hit)
Thinking Mode: Built-in chain-of-thought reasoning with controllable reasoning_effort
Key Questions
What is the relationship between LangChain and LangGraph? — LangChain provides high-level agent abstractions; LangGraph provides the low-level graph orchestration runtime. LangChain's agents are built on top of LangGraph.
When should I use LangChain vs. LangGraph directly? — Use LangChain's create_agent for simple agents; use LangGraph when you need fine-grained workflow control, state persistence, or human-in-the-loop.
How does DeepSeek integrate with the LangChain ecosystem? — Through the OpenAI-compatible interface, just set base_url to the DeepSeek API endpoint.
What is the core programming model of StateGraph? — Define State, add Nodes, add Edges, compile, invoke.
2. Explaining in Plain Language (Feynman Technique)
Feynman Technique: If you can't explain it in simple terms, you don't truly understand it.
Core Concepts Explained
LLM (Large Language Model)
An LLM is like a super-brain that has read millions of books. You give it text (a prompt), and it predicts what should come next. DeepSeek, GPT, and Claude are all LLMs.
from openai import OpenAI# Using DeepSeek API (OpenAI-compatible format)client = OpenAI( api_key="your-deepseek-api-key", base_url="https://api.deepseek.com")response = client.chat.completions.create( model="deepseek-v4-flash", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What is an Agent?"} ])print(response.choices[0].message.content)
Agent
An Agent = LLM + Tools + Loop. Think of it as an assistant that can use tools: it doesn't just answer questions — it decides "I need to look this up" or "I need to calculate this," calls the appropriate tool, and delivers the final answer.
from langchain.agents import create_agentdef search_web(query: str) -> str: """Search the web for information.""" return f"Search results: information about {query}..."def calculate(expression: str) -> str: """Evaluate a mathematical expression.""" return str(eval(expression))agent = create_agent( model="openai:deepseek-v4-flash", tools=[search_web, calculate], system_prompt="You are a helpful assistant that can search and calculate.")result = agent.invoke({ "messages": [{"role": "user", "content": "Calculate 3^10 for me"}]})
Chain
A Chain links multiple steps together. For example: extract user intent, call a search engine, then summarize the results with an LLM. In LangChain v1, create_agent has replaced the legacy Chain concept as the primary way to build agents.
Tool
Tools are functions the agent can call. Any Python function can become a tool — LangChain automatically generates tool descriptions from the function signature and docstring, telling the LLM when to use it.
def get_weather(city: str) -> str: """Get weather information for a given city.""" # In production, this would call a real weather API return f"It's sunny in {city}, 22°C"# Pass directly to create_agentagent = create_agent( model="openai:deepseek-v4-flash", tools=[get_weather], system_prompt="You are a weather assistant.")
Memory
Memory lets the agent remember previous conversations. Just like humans, if every conversation starts from scratch, you can't handle context references in multi-turn dialogs. LangGraph implements short-term and long-term memory through State and Checkpointer.
State
State is LangGraph's core data structure. It records all information during graph execution — conversation history, intermediate results, user inputs, etc. Each Node reads the state, executes logic, and returns updates.
from typing import Annotatedfrom typing_extensions import TypedDictfrom operator import addclass AgentState(TypedDict): messages: Annotated[list, add] # Message list; new messages are appended current_step: str # Current step
Graph
A Graph is LangGraph's core programming model. You draw your workflow as a "flowchart" — each node is a processing step, each edge determines where to go next.
from langgraph.graph import StateGraph, MessagesState, START, ENDdef chatbot(state: MessagesState): """A node that processes user messages.""" return {"messages": [{"role": "ai", "content": "Hello! I'm your assistant."}]}graph = StateGraph(MessagesState)graph.add_node(chatbot)graph.add_edge(START, "chatbot")graph.add_edge("chatbot", END)graph = graph.compile()result = graph.invoke({"messages": [{"role": "user", "content": "Hello!"}]})
Analogies
Concept
Analogy
LLM
A knowledgeable consultant who can't take action
Agent
A versatile assistant who can both think and act
Tool
The assistant's toolbox (calculator, search engine, database...)
Chain
An assembly line — step one, step two, step three
State
The assistant's notebook — recording all intermediate info and conversation history
Graph
The complete workflow diagram — which path to take under what conditions
Middleware
Quality checkpoints in the workflow — intercept, inspect, modify each step
LangSmith
A surveillance camera — recording every move the agent makes
Common Misconceptions Clarified
Misconception: LangChain is an LLM. Reality: LangChain is an orchestration framework. It doesn't contain an LLM — it provides a unified interface to call various LLMs.
Misconception: LangGraph only works with LangChain. Reality: LangGraph can be used standalone, without any LangChain dependency.
Misconception: DeepSeek is a competitor to LangChain. Reality: DeepSeek is an LLM provider, complementary to LangChain — LangChain provides the framework, DeepSeek provides the model.
Misconception: Agents must be complex. Reality: LangChain's create_agent can create a working agent in just a few lines of code.
3. Cone-Shaped Deep Dive (Simon Learning Method)
Simon Learning Method: Focused, layered progression from basics to mastery.
Layer 1: Core Fundamentals
LangChain Core Components
Models
LangChain provides a unified model interface so you can seamlessly swap providers without changing business code. DeepSeek integrates through the OpenAI-compatible interface:
# pip install -qU langchain "langchain[openai]"from langchain.agents import create_agent# Using a DeepSeek modelagent = create_agent( model="openai:deepseek-v4-flash", system_prompt="You are a helpful assistant.")
LangChain standardizes API differences across providers, supporting OpenAI, Anthropic, Google, DeepSeek, and many more.
Tools
Tools are the bridge between agents and the outside world. Any Python function can become a tool:
def lookup_database(query: str) -> str: """Query the database for information. Args: query: SQL query string """ # In production, connect to a real database return f"Query results: 3 matching records found"def send_email(to: str, subject: str, body: str) -> str: """Send an email. Args: to: Recipient email address subject: Email subject line body: Email body content """ return f"Email sent to {to}"
The function's docstring and type annotations are automatically parsed by LangChain, telling the LLM what the tool does and what parameters it needs.
Middleware
Middleware is a key concept introduced in LangChain v1 for intercepting and modifying agent behavior during execution. Each middleware handles one concern and composes freely:
from langchain.agents import create_agentagent = create_agent( model="openai:deepseek-v4-flash", tools=[get_weather], system_prompt="You are an assistant.", # Add prebuilt or custom middleware here)
LangGraph Basics: StateGraph
LangGraph's core programming model is StateGraph — build a graph with three elements:
State: Shared state defining the graph's "memory"
Node: Node functions executing specific logic
Edge: Edges determining the next destination
from langgraph.graph import StateGraph, MessagesState, START, END# 1. Define node functionsdef greet(state: MessagesState): """A greeting node.""" return {"messages": [{"role": "ai", "content": "Hello! How can I help you?"}]}# 2. Build the graphgraph = StateGraph(MessagesState)graph.add_node(greet)graph.add_edge(START, "greet") # From START to greet nodegraph.add_edge("greet", END) # From greet to END# 3. Compile and executeapp = graph.compile()result = app.invoke({"messages": [{"role": "user", "content": "Hello"}]})
DeepSeek API: Basic Usage
The DeepSeek API is fully compatible with the OpenAI format — switching requires only a base_url change:
from openai import OpenAIclient = OpenAI( api_key="your-api-key", base_url="https://api.deepseek.com")# Basic chatresponse = client.chat.completions.create( model="deepseek-v4-flash", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Explain quantum computing"} ], stream=False)print(response.choices[0].message.content)# Streaming outputstream = client.chat.completions.create( model="deepseek-v4-flash", messages=[{"role": "user", "content": "Write a poem about spring"}], stream=True)for chunk in stream: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="")
Layer 2: Advanced Usage
Custom Agents and Tool Integration
from langchain.agents import create_agentdef search_knowledge_base(query: str) -> str: """Search the knowledge base for relevant documents. Args: query: Search keywords """ # In production, connect to a vector database return f"Found documents related to '{query}': LangGraph is a..."def create_summary(text: str, max_words: int = 100) -> str: """Generate a summary for the given text. Args: text: Original text max_words: Maximum word count for the summary """ return f"Summary ({max_words} words max): {text[:50]}..."agent = create_agent( model="openai:deepseek-v4-flash", tools=[search_knowledge_base, create_summary], system_prompt="You are a research assistant. Search the knowledge base first, then summarize.")result = agent.invoke({ "messages": [{"role": "user", "content": "Look up LangGraph's core features and summarize them"}]})
RAG Pipeline (Retrieval-Augmented Generation)
from langchain.agents import create_agentdef retrieve_documents(query: str) -> str: """Retrieve relevant documents from a vector database. Args: query: User query """ # In production, use LangChain's retriever return f"Retrieved 3 relevant documents: [Doc1...], [Doc2...], [Doc3...]"rag_agent = create_agent( model="openai:deepseek-v4-flash", tools=[retrieve_documents], system_prompt="""You are a RAG assistant. 1. First, use the retrieve_documents tool to fetch relevant documents 2. Answer the user's question based on the retrieved content 3. If no relevant information is found, honestly tell the user""")
LangGraph Conditional Edges and Loops
Conditional edges give the graph branching decision capabilities — the key to implementing complex agent logic:
from typing import Literalfrom langgraph.graph import StateGraph, MessagesState, START, ENDdef agent_node(state: MessagesState): """Agent thinking node.""" return {"messages": [{"role": "ai", "content": "I need to use a tool"}]}def tool_node(state: MessagesState): """Tool execution node.""" return {"messages": [{"role": "tool", "content": "Tool execution result"}]}def should_continue(state: MessagesState) -> Literal["tools", "__end__"]: """Routing function: decide whether to continue using tools or end.""" last_message = state["messages"][-1] if hasattr(last_message, "tool_calls") and last_message.tool_calls: return "tools" return "__end__"# Build an Agent graph with a loopbuilder = StateGraph(MessagesState)builder.add_node("agent", agent_node)builder.add_node("tools", tool_node)builder.add_edge(START, "agent")builder.add_conditional_edges("agent", should_continue)builder.add_edge("tools", "agent") # After tool execution, return to agent — forming a loopapp = builder.compile()
This is the classic ReAct pattern: Agent thinks, calls a tool, observes the result, thinks again, and so on until reaching a final answer.
Human-in-the-Loop Interrupts
LangGraph's interrupt mechanism lets you pause execution at critical nodes and wait for human approval:
from langgraph.checkpoint.memory import InMemorySaverfrom langgraph.graph import StateGraph, MessagesState, START, ENDfrom langgraph.types import Command, interruptdef human_review(state: MessagesState): """Pause execution and wait for human approval.""" answer = interrupt("Please review the agent's action. Continue?") return {"messages": [{"role": "user", "content": answer}]}builder = StateGraph(MessagesState)builder.add_node("review", human_review)builder.add_edge(START, "review")builder.add_edge("review", END)checkpointer = InMemorySaver()app = builder.compile(checkpointer=checkpointer)config = {"configurable": {"thread_id": "review-1"}}# First invocation — pauses at the interruptstream = app.invoke({"messages": []}, config)# After human review, resume executionresult = app.invoke(Command(resume="Continue"), config)
DeepSeek Reasoning Model (Thinking Mode)
DeepSeek's "Thinking Mode" outputs a chain-of-thought reasoning trace before producing the final answer, significantly improving accuracy on complex tasks:
from openai import OpenAIclient = OpenAI( api_key="your-api-key", base_url="https://api.deepseek.com")# Enable thinking moderesponse = client.chat.completions.create( model="deepseek-v4-pro", messages=[ {"role": "user", "content": "Prove that the square root of 2 is irrational"} ], reasoning_effort="high", # Control reasoning effort: high or max extra_body={"thinking": {"type": "enabled"}},)# Access the reasoning process and final answerreasoning = response.choices[0].message.reasoning_content # CoT reasoning traceanswer = response.choices[0].message.content # Final answerprint("=== Reasoning Process ===")print(reasoning)print("=== Final Answer ===")print(answer)
Key points about Thinking Mode:
reasoning_content contains the chain-of-thought reasoning process
temperature, top_p, and similar parameters are not supported (setting them won't cause errors but has no effect)
In multi-turn conversations, reasoning_content from turns without tool calls can be omitted; turns with tool calls must include it
Multi-Agent Collaboration
LangGraph supports multi-agent collaboration through subgraphs:
from langgraph.graph import StateGraph, MessagesState, START, ENDdef research_agent(state: MessagesState): """Research agent: responsible for information gathering.""" return {"messages": [{"role": "ai", "content": "Research complete. Here's the gathered info..."}]}def writer_agent(state: MessagesState): """Writer agent: responsible for content generation.""" return {"messages": [{"role": "ai", "content": "Based on the research, generating the article..."}]}def reviewer_agent(state: MessagesState): """Reviewer agent: responsible for quality checks.""" return {"messages": [{"role": "ai", "content": "Review passed."}]}# Build the collaboration pipelinebuilder = StateGraph(MessagesState)builder.add_node("researcher", research_agent)builder.add_node("writer", writer_agent)builder.add_node("reviewer", reviewer_agent)builder.add_edge(START, "researcher")builder.add_edge("researcher", "writer")builder.add_edge("writer", "reviewer")builder.add_edge("reviewer", END)app = builder.compile()
Layer 3: Deep Dive
How LangGraph's Graph Execution Engine Works
LangGraph's underlying algorithm is based on message passing, inspired by Google's Pregel system. Execution proceeds in discrete "super-steps":
All nodes start in an inactive state
A node becomes active when it receives a new message (state update)
Active nodes execute their function and send updates
Nodes with no incoming messages vote to halt and become inactive
Execution terminates when all nodes are inactive and no messages are in transit
Parallel nodes belong to the same super-step; sequential nodes belong to separate super-steps. This model supports both parallel execution and determinism.
Persistent State Management
LangGraph implements state persistence through Checkpointers. A checkpoint is saved at the end of every super-step, which means:
Agents can resume after failures, continuing from where they left off
Time travel: return to any historical state and fork to explore alternative paths
Long-running tasks can span multiple sessions
from langgraph.checkpoint.memory import InMemorySaver# Use an in-memory Checkpointer (for development)checkpointer = InMemorySaver()# For production, use PostgreSQL, MongoDB, or other persistent storageapp = builder.compile(checkpointer=checkpointer)# Each invoke uses a different thread_id to isolate stateconfig = {"configurable": {"thread_id": "user-123"}}result = app.invoke({"messages": [...]}, config)
Agent Architecture Design Patterns
ReAct Pattern (Reasoning + Acting)
The classic agent pattern: think, act, observe, loop. LangGraph's conditional edges + loop edges natively support this pattern.
Plan-and-Execute Pattern
First create a complete plan, then execute step by step. Ideal for complex multi-step tasks:
from typing import Literalfrom langgraph.graph import StateGraph, START, ENDfrom typing_extensions import TypedDictclass PlanState(TypedDict): goal: str plan: list[str] current_step: int results: list[str]def planner(state: PlanState): """Create an execution plan.""" plan = ["Step 1: Gather information", "Step 2: Analyze data", "Step 3: Generate report"] return {"plan": plan, "current_step": 0, "results": []}def executor(state: PlanState): """Execute the current step.""" step = state["plan"][state["current_step"]] return { "results": state["results"] + [f"Completed: {step}"], "current_step": state["current_step"] + 1 }def should_continue(state: PlanState) -> Literal["executor", "__end__"]: """Are there more steps to execute?""" if state["current_step"] < len(state["plan"]): return "executor" return "__end__"builder = StateGraph(PlanState)builder.add_node("planner", planner)builder.add_node("executor", executor)builder.add_edge(START, "planner")builder.add_edge("planner", "executor")builder.add_conditional_edges("executor", should_continue)app = builder.compile()
Multi-Agent Pattern
Multiple specialized agents collaborate through a router that distributes tasks. LangGraph implements cross-graph navigation through subgraphs and Command.
Production Deployment and Observability
LangSmith is the observability platform in the LangChain ecosystem, providing:
Tracing: Visualize every execution step, state transition, and runtime metric of your agents
Evaluation: Test and score agent behavior on production or offline datasets
Prompt Engineering: Version control, collaborative optimization, A/B testing
One-Click Deployment: Deploy agents via LangSmith Deployment
LangSmith Engine: Automatically detect issues in traces and propose fixes
# Enable LangSmith tracing (just set environment variables)import osos.environ["LANGSMITH_TRACING"] = "true"os.environ["LANGSMITH_API_KEY"] = "your-langsmith-key"# All agent executions are now automatically logged to LangSmith
4. Key Notes (Cornell Note-Taking System)
Cornell Method: Cues/keywords on the left, detailed notes on the right, summary at the bottom.
Quick Reference Table
Cue/Keyword
Detailed Notes
create_agent
LangChain's core API; accepts model + tools + prompt + middleware, returns an invocable agent
StateGraph
LangGraph's main graph class, parameterized by a user-defined State object
State
The graph's shared data structure, typically defined with TypedDict; supports Reducer functions
Node
A function in the graph; receives state + config + runtime, returns state updates
Edge
Connects nodes: normal edges (fixed path) or conditional edges (dynamic routing)
Reducer
Defines how State updates are applied. Default is overwrite; use Annotated[list, add] for append
MessagesState
Prebuilt State with a messages field and add_messages Reducer
Checkpointer
State persistence component; supports InMemorySaver, PostgreSQL, MongoDB
interrupt
Pauses graph execution, waiting for external input (Human-in-the-Loop)
Command
Multi-purpose primitive: update + goto + resume — unifies state updates and control flow
Thinking Mode
DeepSeek's chain-of-thought mode, outputting CoT via reasoning_content
Middleware
Behavior interception mechanism introduced in LangChain v1; each middleware handles one concern
The LangChain ecosystem provides a complete toolchain for agent engineering: LangChain offers the create_agent high-level abstraction, LangGraph provides the StateGraph low-level orchestration, and DeepSeek delivers cost-effective LLM capabilities. All three can be used independently or seamlessly combined. The core programming model is the graph: State defines data, Nodes define logic, Edges define flow, and after compilation you invoke to execute.
5. Review & Practice (SQ3R: Recite & Review)
SQ3R Final Steps: Recite key points and consolidate understanding through practice.
Core Points Review
LangChain is an agent framework — create_agent is the core API, composing agents from model + tools + prompt + middleware
LangGraph is an orchestration runtime — models complex workflows with StateGraph (State + Node + Edge), supporting persistence, interrupts, and streaming
DeepSeek integrates via the OpenAI-compatible interface — just change base_url; supports Thinking Mode (CoT reasoning)
LangChain's agents are built on top of LangGraph — they are layered, not competing, technologies
Hands-On Exercises
Exercise 1: Create a Simple DeepSeek Agent
from langchain.agents import create_agentdef get_time() -> str: """Get the current time.""" from datetime import datetime return datetime.now().strftime("%Y-%m-%d %H:%M:%S")agent = create_agent( model="openai:deepseek-v4-flash", tools=[get_time], system_prompt="You are a time assistant.")result = agent.invoke({ "messages": [{"role": "user", "content": "What time is it now?"}]})
Exercise 2: Build a LangGraph with Conditional Routing
from typing import Literalfrom langgraph.graph import StateGraph, MessagesState, START, ENDdef classifier(state: MessagesState): """Classify user intent.""" return {"messages": [{"role": "ai", "content": "Classification result: weather query"}]}def weather_handler(state: MessagesState): """Handle weather queries.""" return {"messages": [{"role": "ai", "content": "Sunny today, 25°C"}]}def general_handler(state: MessagesState): """Handle general questions.""" return {"messages": [{"role": "ai", "content": "I'm your assistant. How can I help?"}]}def route(state: MessagesState) -> Literal["weather", "general"]: last = state["messages"][-1].content if hasattr(state["messages"][-1], "content") else "" if "weather" in str(last).lower(): return "weather" return "general"builder = StateGraph(MessagesState)builder.add_node("classifier", classifier)builder.add_node("weather", weather_handler)builder.add_node("general", general_handler)builder.add_edge(START, "classifier")builder.add_conditional_edges("classifier", route, { "weather": "weather", "general": "general"})builder.add_edge("weather", END)builder.add_edge("general", END)app = builder.compile()
Exercise 3: DeepSeek Thinking Mode + Tool Calls
from openai import OpenAIimport jsonclient = OpenAI( api_key="your-api-key", base_url="https://api.deepseek.com")tools = [ { "type": "function", "function": { "name": "get_population", "description": "Get population data for a city", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "City name"} }, "required": ["city"] } } }]def get_population(city: str) -> str: populations = {"New York": "8.3M", "London": "9.0M", "Tokyo": "14.0M"} return populations.get(city, "Data not available")# Tool calling with thinking moderesponse = client.chat.completions.create( model="deepseek-v4-pro", messages=[{"role": "user", "content": "Which city has more people: New York or London?"}], tools=tools, reasoning_effort="high", extra_body={"thinking": {"type": "enabled"}},)# Handle tool callsif response.choices[0].message.tool_calls: for tool_call in response.choices[0].message.tool_calls: args = json.loads(tool_call.function.arguments) result = get_population(**args) print(f"Tool call {tool_call.function.name}({args}) = {result}")
Common Pitfalls
Forgetting to compile: StateGraph must be .compile()d before invocation — calling invoke directly will raise an error
Incorrect State update strategy: The default Reducer is overwrite; to append to a list, use Annotated[list, add]
Not returning reasoning_content in DeepSeek Thinking Mode: When tool calls are involved, reasoning_content must be passed back to the API, or it returns a 400 error
Exceeding recursion limits: LangGraph's default recursion limit is 1000 steps. Complex agents may exceed this — use RemainingSteps for proactive detection
Confusing LangChain and LangGraph responsibilities: LangChain handles "what an agent is"; LangGraph handles "how an agent runs"
Non-idempotent side effects in Nodes: LangGraph re-runs nodes when resuming from checkpoints. Ensure node logic is idempotent