LangGraph大体简介
| 概念 | 入门理解 | 适合解决什么问题 |
| LangChain | LLM 应用开发组件库,提供模型接入、Prompt、Parser、Tools、Retriever、Agent 等能力 | 模型接入、线性链、RAG 管道、快速搭 Agent |
| Chain / LCEL | 把多个 Runnable 按固定数据流串起来的链式写法和链式流程 | Prompt → Model → Parser 这种线性、声明式流程 |
| Agent | 一种由模型根据上下文动态决定下一步动作的应用形态 | 任务路径不完全固定,需要模型自己判断是否调工具、是否继续推理 |
| Workflow | 工作流 / 固定流程,整体步骤由开发者提前设计,只在部分节点做条件判断 | 流程边界明确、要求稳定可控、希望更容易复现和审计 |
| LangGraph | 用“状态 + 节点 + 边”把 Workflow 或 Agent 编排成一张可执行图 | 分支、循环、并行、持久化、人机介入、多智能体调度 |
这里有三个边界点特别值得说清楚:
- LangGraph 可以配合 LangChain 使用,但不是“必须依赖 LangChain 才能用”。 官方文档明确说过,LangGraph 可以独立使用;只是实际项目里,图里的节点常常会调用 LangChain 的模型、工具和 Prompt,所以两者经常搭配出现。
- LangGraph 不是 Chain 的替代品,而是更适合“非线性控制流 + 状态管理”的编排方式。 如果你的任务本来就是一条固定直线,用 LCEL 反而更简单;如果流程开始出现循环、分支、暂停、恢复,就更适合切到 LangGraph。
- LangChain v1 的
create_agent底层就是构建在 LangGraph runtime 之上的。 所以你可以把 LangGraph 理解成“更底层、更可控的 Agent / Workflow 编排层”。如果只是想快速搭一个标准工具调用 Agent,可以先用create_agent;如果想把每一步流程拆开、显式控制状态和边,就自己写 LangGraph。
四个核心概念
| 概念 | 中文解释 | 入门理解 | 代码里通常对应什么 |
| State | 状态 | 这张图当前保存了哪些数据 | TypedDict / dict / Pydantic schema |
| Nodes | 节点 | 每一步真正干活的函数 | 普通 Python 函数、异步函数、内部调用 LLM/工具的函数 |
| Edges | 边 | 当前节点跑完后,下一步去哪 | add_edge、条件边、START、END |
| Graph | 图 | 由状态、节点、边组成的完整工作流 | StateGraph(...) 构建器,compile() 后得到可执行 app |
有几个很容易误解的点,建议提前记住:
- 节点不一定非得是大模型调用。 节点本质上就是函数,它可以调 LLM,也可以只是做加减法、查数据库、调用 API、做格式转换。
- 边不一定只是固定顺序。
A → B是最简单的普通边,后面第 24 章还会讲条件边、动态分发、Command等更灵活的控制方式。 - 状态更新通常是“节点返回局部字段更新”,不是每次手动拼完整状态。 比如节点只返回
{"greeting": "你好,z3"},框架会按规则合并回全局 State。 - 如果某个字段要“追加”而不是“覆盖”,就要考虑 Reducer。
使用场景
| 更适合用 LangGraph 的场景 | 更适合先用 LangChain / 普通代码 / Coze / Dify 的场景 |
| 流程里有明显的 条件分支、循环、回退、并行 | 只是一次模型调用,或者固定 Prompt → Model → Parser 线性链 |
| 需要 长期运行、断点续跑、失败后从中间恢复 | 只是做一个轻量验证型 Demo,不需要状态持久化 |
| 需要 人在环审核,关键节点必须暂停等待人工确认 | 不需要人工干预,只是自动生成一段文本 |
| 需要 多智能体协作 或多个子流程调度 | 单 Agent 或单工作流已经够用 |
| 需要更强的 可观测、可调试、可追踪 | 项目还在早期快速试错阶段,低代码平台更快 |
LangGraph技术架构
- 预构建 Agent API:更偏“直接拿来用”,适合快速搭标准 Agent。
- Agent Node API:更偏“围绕 Agent 节点做一些中间层封装”。
- 构建图语法与 API:更底层,也更适合我们系统学习 State、Node、Edge、Graph 这些核心机制。
Graph最小构建流程
- 定义 State:说明这张图里要流转哪些字段。
- 定义 Node:把每一步逻辑写成函数,函数接收当前
state,返回要更新的字段。 - 定义 Edge:用
add_edge把节点连起来,并用START/END指定入口和出口。 - 编译 Graph:调用
compile(),把图构建器编译成一个真正可运行的应用对象。 - 执行 Graph:调用
invoke(initial_state)传入初始状态,拿到最终状态结果。
骨架代码:
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
class MyState(TypedDict):
value: str
# 定义节点
def node_a(state: MyState):
return {"value": state["value"] + " A"}
def node_b(state: MyState):
return {"value": state["value"] + " B"}
# 初始化
builder = StateGraph(MyState)
# 添加节点
builder.add_node("node_a", node_a)
builder.add_node("node_b", node_b)
# 添加边
builder.add_edge(START, "node_a")
builder.add_edge("node_a", "node_b")
builder.add_edge("node_b", END)
# 创建应用
app = builder.compile()
result = app.invoke({"value": "start"})
print(result)
先搭图,再编译,最后才能运行
怎么看图结构
- ASCII 文本图:适合直接在终端快速看结构。
- Mermaid 代码:适合复制到 Mermaid Live Editor 或 ProcessOn Mermaid 编辑器 里查看和二次编辑。
- PNG 图片:适合导出成文档配图,但
draw_mermaid_png()可能依赖在线渲染服务或本地浏览器渲染环境,偶尔会不稳定。
案例1
# State:用 TypedDict 定义状态字段(如 name、greeting),表示这张图运行过程中会保存哪些数据。
# Nodes:每个节点本质上都是一个函数,接收当前 state,返回“本节点要更新的字段字典”,不需要手动拼完整状态。
# Edges:add_edge 定义执行顺序;START / END 为虚拟起止节点。
# Graph API 入门主流程:定义 State → 定义节点函数 → StateGraph(State) → add_node / add_edge → compile() → invoke(initial_state)。
# 可视化:compile() 之后可通过 get_graph().print_ascii() 和 draw_mermaid() 查看图结构;输出里的 __start__、__end__ 是 LangGraph 内置虚拟节点名,不要自定义同名节点
from typing import TypeDict
from langgrap.graph import StateGraph, START, END
import uuid
# 1. 定义 State(状态):声明图中要传递的字段及类型(可选)
class HelloState(TypedDict):
name: str
greeting: str
# 2. 定义节点函数 Node:接收当前 state,返回对 state 的「部分更新」字典
def greet(helloState: HelloState) -> dict:
name = helloState["name"]
return {"greeting":f"你好,{name}"}
def add_emoji(helloState: HelloState) -> dict:
greeting = helloState["greeting"]
return {"greeting": greeting + " 。。。😄"}
# 3. 构建图 Graph:初始化 StateGraph,添加节点与边
graph = StateGraph(HelloState)
graph.add_node("greeting", greet)
graph.add_node("add_emoji", add_emoji)
graph.add_edge(START, "greeting")
graph.add_edge("greeting", "add_emoji")
graph.add_edge("add_emoji", END)
# 4. 编译图,得到可执行的 app
app = graph.compile()
# 5. 运行:invoke 只接收一个核心参数——初始状态字典
result = app.invoke({"name": "z3"})
print(result)
print(result["greeting"])
# 6. 可视化:ASCII 和 Mermaid 两种方式最适合入门阶段快速看图结构
print(app.get_graph().print_ascii())
print("=" * 50)
print(app.get_graph().draw_mermaid())
print("=" * 50)
把大模型接入LangGraph中
import json
import os
from typing import Annotated, List, TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langchain.chat_models import init_chat_model
from langchain_core.messages import BaseMessage, HumanMessage, message_to_dict
from dotenv import load_dotenv
load_dotenv(encoding="utf-8")
# 1. 定义状态 State:messages 使用 add_messages 规约器,节点返回的每条新消息会自动追加到列表
class DiliState(TypedDict):
# 含义:该字段不是「覆盖」更新,而是「追加」——节点只返回新增的消息
# 若不用 add_messages,节点返回 {"messages": [reply]} 会直接覆盖掉之前的对话历史
messages: Annotated[List, add_messages]
# 2. 初始化大模型
llm = init_chat_model(
model="qwen-plus",
model_provider="openai",
api_key=os.getenv("aliQwen-api"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 3. 定义节点 Nodes:将当前消息列表交给模型,返回新消息字典(add_messages 会追加到 state)
def model_node(state: DiliState):
replay = llm.invoke(state['messages'])
return {"messages": {replay}}
# 4. 构建图:单节点 model,START → model → END
graph = StateGraph(DiliState)
graph.add_node("model", model_node)
graph.add_edge(START,"model")
graph.add_edge("model", END)
# 5. 编译并执行
app = graph.compile()
# 传入初始消息(HumanMessage 或字符串均可,视模型封装而定)
result = app.invoke(
{"messages": [HumanMessage(content="请用一句话解释什么是 LangGraph。")]}
)
print("模型回答:", result["messages"][-1].content)
print("\n--- result 格式化输出 ---")
print(
json.dumps(
result,
ensure_ascii=False,
indent=2,
default=lambda o: message_to_dict(o) if isinstance(o, BaseMessage) else str(o),
)
)
并行检索:
真实项目里,LangGraph 更常见的价值,往往体现在多个分支并行执行,再把结果汇总到一个后续节点。
比如一个企业问答助手,收到用户问题后,可以同时走两条分支:
- 一条分支做 知识库检索(RAG Search),拿企业内部资料;
- 一条分支做 联网搜索(Web Search),补充实时信息;
- 两路结果都回来后,再交给 最终回答节点 做融合总结。
from typing import TypedDict
from langgraph.constants import START, END
from langgraph.graph import StateGraph
class QAState(TypedDict):
query: str
rag_result: str
web_search_result: str
final_answer: str
# 定义节点
def rag_search_node(state: QAState):
return {"rag_result": f"关于 {state['query']} 的知识库检索结果"}
def web_search_node(state: QAState):
return {"web_search_result": f"关于 {state['query']} 的联网搜索结果"}
def final_answer_node(state: QAState):
return {
"final_answer": (
f"基于知识库结果:{state['rag_result']};"
f"结合联网结果:{state['web_search_result']};"
"生成最终回答"
)
}
# 初始化
builder = StateGraph(state_schema=QAState)
# 添加节点
builder.add_node("rag_search_node", rag_search_node)
builder.add_node("web_search_node", web_search_node)
builder.add_node("final_answer_node", final_answer_node)
# 添加边
builder.add_edge(START, "rag_search_node")
builder.add_edge(START, "web_search_node")
builder.add_edge("rag_search_node", "final_answer_node")
builder.add_edge("web_search_node", "final_answer_node")
builder.add_edge("final_answer_node", END)
graph = builder.compile()
result = graph.invoke({"query": "如何使用 LangGraph"})
print(result["final_answer"])
print(graph.get_graph().print_ascii())

浙公网安备 33010602011771号