You have learned about LangChain, now let’s understand the soul architecture of LangGraph.
Why "Build a Diagram"? What does this have to do with Agent and LLM?
You have learned LangChain and already know how to call LLM, splice Chain, and use Tool.The core model of LangChain is "pipeline": Input → Processing step A → Processing step B → Output, going down linearly.
| Dimensions | LangChain (Chain) | LangGraph (Graph) |
|---|---|---|
| Execution process | linear/sequential | Graph structure, can branch, loop, and roll back |
| Status management | Relying on developers to manually pass variables | Built-in State object, automatic transfer |
| Conditional judgment | Need to write if/else manually in the code | Conditional Edge, native support for graph structures |
| loop / iteration | Complex implementation and prone to bugs | Graphs naturally support loops, and Agent loops are first-class citizens |
| Suitable for the scene | Simple questions and answers, RAG, fixed step tasks | Complex Agent, multi-step reasoning, human-machine collaboration, dialogue with memory |
LangGraph is a "superset" of LangChain: It does not replace LangChain, but provides aControlled, stateful execution engine. You can still call LangChain's Chain, LLM, and Tool in LangGraph's Node.
LangChain solves the problem of "how to call LLM", and LangGraph solves the problem of "how to call LLM".process controlandStatus management" problem. When your AI application needs to "determine what to do next based on the results of the previous step", you need LangGraph.
What is a "picture"? In computer science, graph is represented byNodeandEdgecomposition. LangGraph borrows this concept:
Imagine you are planning a journey:
This is the notebook of Module 1complete logic: After node_1 is executed, it decides whether to go to node_2 or node_3 based on a certain condition (random/weather/user input), and finally reaches END.
When your Agent needsLoop call tool(Search → judge whether it is enough → search again),Parallel execution(Check multiple data sources at the same time), orManual intervention interruption(Human-in-the-loop), writing code with if/else can quickly turn into spaghetti. Graph structures allow these complex processes toVisual, testable, maintainable。
State is a Python dictionary (TypedDict), which is used during the execution of the entire graph.always exist, from START to END, each Node can read it and modify it. You can think of it as a "sticky note" or a "shared whiteboard" passed between nodes.
from typing_extensions import TypedDict
# 定义 State 的"模板":图里有哪些共享数据
class State(TypedDict):
graph_state: str # 这张图只有一个字段:graph_state
In this simplest example, State has only one fieldgraph_state, type is string. But in a real Agent, State can include:
Each Node receives the current State and returns aPartially updated dictionary, LangGraph will automatically merge this update into State:
By default, the value returned by Node will becoverRemove the old value of the corresponding field in State. if you wantAppend(such as messages list), you need to use reducer. This will be discussed in Module 2 later.
from langchain_core.messages import BaseMessage
from typing import Annotated, List
from langgraph.graph.message import add_messages
class AgentState(TypedDict):
# Annotated + add_messages 表示"追加"而不是"覆盖"
messages: Annotated[List[BaseMessage], add_messages]
# 其他字段可以根据需要添加
user_query: str
search_results: list
iteration_count: int
This is one of the most elegant designs of LangGraph: NodeJust a regular Python function, without any magic. It has only one convention:
# 这就是一个完整的 Node!
def node_1(state):
print("---Node 1---")
# 读取 State 中的值
current = state['graph_state']
# 返回要更新的字段
return {"graph_state": current + " I am"}
def node_2(state):
print("---Node 2---")
return {"graph_state": state['graph_state'] + " happy!"}
def node_3(state):
print("---Node 3---")
return {"graph_state": state['graph_state'] + " sad!"}
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini")
def call_llm(state):
# 从 State 里取消息历史
messages = state["messages"]
# 调用 LLM(这里就用到了 LangChain!)
response = llm.invoke(messages)
# 把 LLM 回复追加到 messages
return {"messages": [response]}
from langchain_community.tools import TavilySearchResults
search_tool = TavilySearchResults()
def search_web(state):
query = state["user_query"]
results = search_tool.invoke(query)
return {"search_results": results}
Node is "pure business logic", ithave no ideaI am part of the picture and alsohave no ideaWhere to go next. It only reads State, does things, and updates State.Edge decides who goes where.
Edge connects to Node and tells the graph "where to go next after executing this node." LangGraph has two types of Edge:
alwaysGo from A to B without conditional judgment.
# 总是从 node_2 走到 END
builder.add_edge("node_2", END)
builder.add_edge("node_3", END)
# 总是从 START 走到 node_1
builder.add_edge(START, "node_1")
according to arouting functionThe return value determines which Node to go to next. The routing function accepts State and returns the name of the next Node.
import random
from typing import Literal
# 路由函数:根据 State 决定下一步
def decide_mood(state) -> Literal["node_2", "node_3"]:
# 可以根据 state 里的任何信息来决定
if random.random() < 0.5:
return "node_2" # 走 happy 路线
return "node_3" # 走 sad 路线
# 把路由函数挂到 node_1 之后
builder.add_conditional_edges("node_1", decide_mood)
def should_continue(state) -> Literal["tools", "__end__"]:
messages = state["messages"]
last_message = messages[-1]
# 如果 LLM 要调用工具 → 去 tools 节点
if last_message.tool_calls:
return "tools"
# 否则 LLM 已经给出最终答案 → 结束
return "__end__"
# 这就构成了 Agent 的"思考→工具→思考→工具→…→结束"循环
builder.add_conditional_edges("agent", should_continue)
What you used in LangChainAgentExecutor, the bottom layer of which is such a loop: LLM node → conditional judgment (whether to call the tool) → tool node (if so) → return to the LLM node. LangGraph makes this loopTransparent, controllable, customizable。
StateGraphis the core class of LangGraph, which is a"Graph Builder"(Builder Pattern). You "tell" it all the definitions of Node and Edge, and finallycompile()Generate a graph that can be run.
StateGraph(State)— This determines the data structure template shared by all nodes in the graph
builder.add_node("名字", 函数)— "Name" is the identifier that refers to this node in the graph, and "Function" is the actual execution logic
Ordinary side useadd_edge, use it for routes that need to judge conditions.add_conditional_edges
LangGraph does basic correctness checks in this step (such as whether there are orphan nodes) and returns aCompiledGraphobject
graph.invoke({"graph_state": "输入"})— Pass in the initial State, the graph starts execution from START, and returns the final State
STARTandENDare two special nodes built into LangGraph:
invoke()When , execution starts from the first Node connected by START. it allows you to useadd_edge(START, "my_first_node")to clearly state "where to start"Now let’s analyze the code in the notebook that you are “completely confused about” line by line:
from IPython.display import Image, display
from langgraph.graph import StateGraph, START, END
# ① 创建一个图的"蓝图",使用 State 作为共享数据结构
builder = StateGraph(State)
# ② 注册三个节点("标识符名" → Python函数)
builder.add_node("node_1", node_1) # node_1 函数处理第一步
builder.add_node("node_2", node_2) # node_2 = happy 路线
builder.add_node("node_3", node_3) # node_3 = sad 路线
# ③ 定义固定边:START → node_1(图从 node_1 开始)
builder.add_edge(START, "node_1")
# ④ 定义条件边:node_1 执行完后,调用 decide_mood() 决定去 node_2 还是 node_3
builder.add_conditional_edges("node_1", decide_mood)
# ⑤ 定义固定边:无论走哪条路,最终都到 END
builder.add_edge("node_2", END)
builder.add_edge("node_3", END)
# ⑥ 编译:校验图的结构,生成可执行的 CompiledGraph
graph = builder.compile()
# ⑦ 可视化(仅用于学习/调试,生产代码里不需要)
display(Image(graph.get_graph().draw_mermaid_png()))
After executing this code, the shape of the graph is as follows:
# 传入初始 State,运行图
result = graph.invoke({"graph_state": "Hi, this is Lance."})
# 可能的输出 1(走 node_2):
# ---Node 1---
# ---Node 2---
# {'graph_state': 'Hi, this is Lance. I am happy!'}
# 可能的输出 2(走 node_3):
# ---Node 1---
# ---Node 3---
# {'graph_state': 'Hi, this is Lance. I am sad!'}
The complete evolution of State:
| stage | The value of graph_state | what happened |
|---|---|---|
| when invoke is called | "Hi, this is Lance." | The initial State you passed in |
| After node_1 is executed | "Hi, this is Lance. I am" | node_1 appended "I am" |
| decide_mood route | (Do not modify State) | Return "node_3" (assuming sad is randomly reached this time) |
| After node_3 is executed | "Hi, this is Lance. I am sad!" | node_3 added "sad!" |
| Arrive at END | "Hi, this is Lance. I am sad!" | After the graph is executed, the final State is returned. |
This is not just an example. The pattern of StateGraph + Node + Edge is the entire basis of LangGraph.From the simplest chatbot to the most complex multi-agent system, they are all built using this model.
Module 1 uses "randomly select happy/sad" just toShielding the complexity of LLM, let you first understand the flow control mechanism of the graph. In the subsequent Module, you will see:
| Module | What was added to the picture? | Corresponding scene |
|---|---|---|
| Module 1 | LLM as Node; Tool as Node; conditional Edge determines whether to call the tool | Complete ReAct Agent |
| Module 2 | State adds messages list; reducer appends rather than overwrites | Memorized conversation chatbot |
| Module 3 | Figure execution is suspended midway, waiting for manual approval | Human-in-the-loop |
| Module 4 | Parallel execution of multiple Nodes; sub-graph (Sub-graph) | Research assistant, check multiple data sources at the same time |
| Module 5 | Figure connects external memory storage (Memory Store) | Long-term memory across conversations Agent |
LangGraph’s StateGraph pattern is used in production systems by AI teams at LinkedIn, Elastic, Uber, and more. This introductory example teaches you about these production systemscommon skeleton。
Now upgrade the simple example of Module 1 to an Agent that actually calls LLM and tools, you will find that the structureexactly the same:
from langchain_openai import ChatOpenAI
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import HumanMessage
from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import ToolNode
from typing_extensions import TypedDict, Annotated
from langgraph.graph.message import add_messages
from typing import Literal
# ─── Step 1: 定义 State(比 Module 1 更丰富)───
class AgentState(TypedDict):
messages: Annotated[list, add_messages] # 追加而非覆盖
# ─── Step 2: 准备 LLM 和工具 ───
tools = [TavilySearchResults(max_results=2)]
llm = ChatOpenAI(model="gpt-4o-mini")
llm_with_tools = llm.bind_tools(tools) # 告诉 LLM 有哪些工具可用
# ─── Step 3: 定义 Nodes(和 Module 1 结构完全一样!)───
def call_llm(state: AgentState):
# Node:调用 LLM,LLM 会决定是直接回答还是调用工具
response = llm_with_tools.invoke(state["messages"])
return {"messages": [response]}
# ─── Step 4: 定义路由函数(就是 Module 1 的 decide_mood)───
def should_continue(state: AgentState) -> Literal["tools", END]:
last_msg = state["messages"][-1]
if last_msg.tool_calls: # LLM 决定要调用工具
return "tools"
return END # LLM 给出了最终答案
# ─── Step 5: 构建图(和 Module 1 完全一样的模式!)───
builder = StateGraph(AgentState)
builder.add_node("agent", call_llm)
builder.add_node("tools", ToolNode(tools)) # 内置的工具执行节点
builder.add_edge(START, "agent")
builder.add_conditional_edges("agent", should_continue)
builder.add_edge("tools", "agent") # 工具执行完回到 LLM!这就是循环
agent = builder.compile()
# ─── Step 6: 运行 ───
result = agent.invoke({
"messages": [HumanMessage(content="2024年奥运会在哪里举行?")]
})
Noticeadd_edge("tools", "agent")This line: It connects the output of the tools node back to the agent node, forming acycle. This is the mechanism by which the Agent repeatedly "thinks→tools→thinks→tools" until it reaches the answer. LangChain's AgentExecutor has this diagram under the hood, but you couldn't see it before.
The learning focus of Module 1 is not the code details, but building this mental model:
This "simple graph" of Module 1 is what you will use for all future LangGraph codeskeleton. No matter how complex the Agent is, it is just: define State → write Node function → connect it with Edge → compile → invoke. Understand this pattern and you understand the entire basis of LangGraph.