LangGraph 学习总结
一、这是什么?(概念解释)
LangGraph 是 LangChain 推出的用于构建有状态、多参与者(multi-actor)应用的框架。
核心概念:
- 图(Graph):将应用流程建模为节点和边的有向图
- 状态(State):在节点之间传递的数据
- 节点(Node):执行具体操作的函数
- 边(Edge):连接节点,定义执行流程
为什么需要 LangGraph?
- 传统 Agent 流程难以控制(循环、分支、并行)
- LangGraph 提供可视化、可调试、可持久化的状态管理
- 支持复杂的多智能体协作场景
二、有什么用?(应用场景)
| 场景 | 说明 |
|---|---|
| 智能Agent | 构建复杂的对话式Agent |
| 多智能体协作 | 多个Agent协同完成任务 |
| 人在环路(Human-in-the-loop) | 关键操作需要人工确认 |
| 状态持久化 | 对话历史保存和恢复 |
| 条件分支 | 根据条件动态选择执行路径 |
| 并行执行 | 多个任务并行处理 |
| 工作流自动化 | 复杂业务流程自动化 |
三、基础示例
from typing import TypedDict, Annotated, Any
import dotenv
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
dotenv.load_dotenv()
llm = ChatOpenAI(model="gpt-4o-mini")
# ============ 第一步:定义状态 ============
class State(TypedDict):
messages: Annotated[list, add_messages] # 消息列表
username: str # 用户名
# ============ 第二步:定义节点 ============
def chatbot(state: State, config: dict = None) -> Any:
"""聊天机器人节点"""
ai_message = llm.invoke(state["messages"])
return {"messages": [ai_message], "username": "chatbot"}
# ============ 第三步:构建图 ============
graph_builder = StateGraph(State)
graph_builder.add_node("llm", chatbot) # 添加节点
graph_builder.add_edge(START, "llm") # START → llm
graph_builder.add_edge("llm", END) # llm → END
# ============ 第四步:编译并调用 ============
graph = graph_builder.compile()
result = graph.invoke({
"messages": [("human", "你好,你是谁?")],
"username": "graph"
})
print(result)
四、核心概念详解
1. 状态(State)
from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages
class State(TypedDict):
# 使用 add_messages 注解,消息会追加而不是覆盖
messages: Annotated[list, add_messages]
# 普通字段,每次赋值会覆盖
username: str
count: int
2. 节点(Node)
def my_node(state: State) -> dict:
"""节点函数接收当前状态,返回要更新的字段"""
# 处理逻辑...
return {
"messages": [new_message], # 追加消息
"count": state["count"] + 1 # 更新计数
}
3. 边(Edge)
# 固定边:无条件连接
graph.add_edge("node_a", "node_b") # node_a → node_b
# 条件边:根据状态动态选择
def route_function(state: State) -> str:
if state["count"] > 5:
return "end"
return "continue"
graph.add_conditional_edges(
"node_a",
route_function,
{
"continue": "node_b",
"end": END
}
)
五、条件边示例(路由)
from typing import Literal
from langgraph.graph import StateGraph, END
class State(TypedDict):
messages: Annotated[list, add_messages]
def chatbot(state: State) -> dict:
"""LLM节点,可能产生工具调用"""
ai_message = llm_with_tools.invoke(state["messages"])
return {"messages": [ai_message]}
def tool_executor(state: State) -> dict:
"""工具执行节点"""
# 执行工具...
return {"messages": [tool_result]}
def route(state: State) -> Literal["tool_executor", "__end__"]:
"""路由函数:根据状态决定下一步"""
ai_message = state["messages"][-1]
if hasattr(ai_message, "tool_calls") and len(ai_message.tool_calls) > 0:
return "tool_executor" # 有工具调用 → 执行工具
return END # 无工具调用 → 结束
# 构建图
graph = StateGraph(State)
graph.add_node("llm", chatbot)
graph.add_node("tool_executor", tool_executor)
graph.set_entry_point("llm")
graph.add_conditional_edges("llm", route) # 条件边
graph.add_edge("tool_executor", "llm") # 固定边
app = graph.compile()
流程图:
START → llm节点 ──┬──→ route函数(条件边) ──→ tool_executor节点 ─┐
│ │
└──────────────────────────────────────┘
(有tool调用则执行工具,否则结束)
六、并行边示例
def parallel1(state: MessagesState) -> dict:
print("并行任务1")
return {"messages": [HumanMessage(content="这是并行1的结果")]}
def parallel2(state: MessagesState) -> dict:
print("并行任务2")
return {"messages": [HumanMessage(content="这是并行2的结果")]}
graph_builder = StateGraph(MessagesState)
graph_builder.add_node("chat_bot", chatbot)
graph_builder.add_node("parallel1", parallel1)
graph_builder.add_node("parallel2", parallel2)
# chat_bot 同时连接到 parallel1 和 parallel2(并行执行)
graph_builder.add_edge("chat_bot", "parallel1")
graph_builder.add_edge("chat_bot", "parallel2")
流程图:
chat_bot
│
├──→ parallel1 ──┐
│ │
├──→ parallel2 ───┴──→ 汇聚
七、人在环路(Human-in-the-loop)
from langgraph.checkpoint.memory import MemorySaver
# 创建检查点(用于保存状态)
checkpointer = MemorySaver()
# 编译时设置中断点
graph = graph_builder.compile(
checkpointer=checkpointer,
interrupt_before=["tools"] # 在执行tools之前中断
)
# 第一次调用(会中断)
config = {"configurable": {"thread_id": 1}}
state = graph.invoke(
{"messages": [("human", "搜索2024北京马拉松成绩")]},
config=config
)
# 检查是否需要人工确认
if hasattr(state["messages"][-1], "tool_calls"):
print("准备调用工具:", state["messages"][-1].tool_calls)
human_input = input("是否执行?(yes/no): ")
if human_input.lower() == "yes":
# 继续执行
result = graph.invoke(None, config)
print(result["messages"][-1].content)
else:
print("取消执行")
八、预构建 ReACT Agent
from langgraph.prebuilt import create_react_agent
# 定义工具
tools = [google_serper, generate_image]
model = ChatOpenAI(model="gpt-4o-mini")
# 创建预构建的 ReACT Agent
agent = create_react_agent(model=model, tools=tools)
# 调用
result = agent.invoke({
"messages": [("human", "帮我绘制一幅鲨鱼在天上飞的图片")]
})
九、状态持久化(MemorySaver)
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent
# 创建检查点
checkpointer = MemorySaver()
# 创建 Agent 时绑定检查点
model = ChatOpenAI(model="gpt-4o-mini")
tools = [google_serper]
agent = create_react_agent(
model=model,
tools=tools,
checkpointer=checkpointer
)
# 使用 thread_id 标识对话
config = {"configurable": {"thread_id": "user123"}}
# 第一次调用
agent.invoke({"messages": "你好,我叫慕小课"}, config)
# 第二次调用(会保留历史,记住用户名字)
result = agent.invoke({"messages": "我叫什么名字?"}, config)
print(result["messages"][-1].content)
# 输出:你叫慕小课
原理:MemorySaver 将每次对话的状态保存到内存中,通过 thread_id 区分不同会话。
十、多智能体协作(子图)
LangGraph 支持将一个图作为另一个图的节点,实现多智能体协作。
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph
from langgraph.prebuilt import ToolNode, tools_condition
# ============ 定义各智能体的状态 ============
class LiveAgentState(TypedDict):
"""直播文案智能体状态"""
query: Annotated[str, lambda x, y: y] # 原始问题
live_content: Annotated[str, lambda x, y: y] # 直播文案
messages: Annotated[list, lambda x, y: x + y] # 消息历史
class XHSAgentState(TypedDict):
"""小红书文案智能体状态"""
query: Annotated[str, lambda x, y: y]
xhs_content: Annotated[str, lambda x, y: y]
class MainAgentState(TypedDict):
"""主智能体状态(汇总所有子智能体的输出)"""
query: Annotated[str, lambda x, y: y]
live_content: Annotated[str, lambda x, y: y]
xhs_content: Annotated[str, lambda x, y: y]
# ============ 定义子图1:直播文案智能体 ============
def chatbot_live(state: LiveAgentState) -> dict:
"""直播文案生成节点"""
prompt = ChatPromptTemplate.from_messages([
("system", "你是直播文案专家,根据产品生成带货脚本文案"),
("human", "{query}")
])
chain = prompt | llm.bind_tools([google_serper])
ai_message = chain.invoke({"query": state["query"]})
return {
"messages": [ai_message],
"live_content": ai_message.content
}
# 构建直播文案子图
live_agent_graph = StateGraph(LiveAgentState)
live_agent_graph.add_node("chatbot_live", chatbot_live)
live_agent_graph.add_node("tools", ToolNode([google_serper]))
live_agent_graph.set_entry_point("chatbot_live")
live_agent_graph.add_conditional_edges("chatbot_live", tools_condition)
live_agent_graph.add_edge("tools", "chatbot_live")
# ============ 定义子图2:小红书文案智能体 ============
def chatbot_xhs(state: XHSAgentState) -> dict:
"""小红书文案生成节点"""
prompt = ChatPromptTemplate.from_messages([
("system", "你是小红书文案大师,风格活泼,多用emoji"),
("human", "{query}")
])
chain = prompt | llm | StrOutputParser()
return {"xhs_content": chain.invoke({"query": state["query"]})}
# 构建小红书文案子图
xhs_agent_graph = StateGraph(XHSAgentState)
xhs_agent_graph.add_node("chatbot_xhs", chatbot_xhs)
xhs_agent_graph.set_entry_point("chatbot_xhs")
xhs_agent_graph.set_finish_point("chatbot_xhs")
# ============ 定义主图:协调两个子智能体 ============
def parallel_node(state: MainAgentState) -> dict:
"""分发任务到子智能体"""
return state
# 构建主图
agent_graph = StateGraph(MainAgentState)
agent_graph.add_node("parallel_node", parallel_node)
agent_graph.add_node("live_agent", live_agent_graph.compile()) # 子图作为节点
agent_graph.add_node("xhs_agent", xhs_agent_graph.compile()) # 子图作为节点
agent_graph.set_entry_point("parallel_node")
# 并行执行两个子智能体
agent_graph.add_edge("parallel_node", "live_agent")
agent_graph.add_edge("parallel_node", "xhs_agent")
agent_graph.set_finish_point("live_agent")
agent_graph.set_finish_point("xhs_agent")
# ============ 编译并执行 ============
agent = agent_graph.compile()
result = agent.invoke({"query": "潮汕牛肉丸"})
print("直播文案:", result["live_content"])
print("小红书文案:", result["xhs_content"])
流程图:
parallel_node
│
┌───────────────┴───────────────┐
│ │
▼ ▼
live_agent xhs_agent
(子图1) (子图2)
│ │
┌─────┴─────┐ ┌─────┴─────┐
│ │ │ │
chatbot_live tools chatbot_xhs (结束)
│ │ │
└─────┬─────┘ │
│ │
└─────────────┬───────────┘
▼
汇聚结果
十一、消息修剪(trim_messages)
当对话历史过长时,需要修剪消息以避免超出模型的 token 限制。
from langchain_core.messages import trim_messages
from langchain_text_splitters import RecursiveCharacterTextSplitter
import tiktoken
messages = [
HumanMessage(content="你好,我叫慕小课"),
AIMessage(content="你好慕小课!"),
HumanMessage(content="我喜欢游泳"),
AIMessage(content="游泳是很好的运动"),
# ... 更多消息
]
# 自定义 token 计数器
def custom_token_counter(messages):
encoding = tiktoken.get_encoding("cl100k_base")
num_tokens = 0
for message in messages:
num_tokens += len(encoding.encode(str(message.content)))
return num_tokens
# 修剪消息
trimmed_messages = trim_messages(
messages,
max_tokens=80, # 最大 token 数
token_counter=custom_token_counter, # token 计数器
strategy="first", # 保留策略:first/last
end_on="human", # 确保最后一条是人类消息
allow_partial=False, # 是否允许部分消息
text_splitter=RecursiveCharacterTextSplitter(), # 文本分割器
)
print(f"原始消息数: {len(messages)}")
print(f"修剪后消息数: {len(trimmed_messages)}")
修剪策略:
strategy="first":保留最早的消息strategy="last":保留最新的消息end_on="human":确保最后一条是人类消息(避免截断用户的最新输入)
十二、删除和更新消息
LangGraph 支持在节点中删除或更新状态中的消息。
删除消息
from langchain_core.messages import RemoveMessage
def delete_human_message(state: MessagesState) -> dict:
"""删除状态中的第一条人类消息"""
human_message = state["messages"][0]
return {"messages": [RemoveMessage(id=human_message.id)]}
更新消息
from langchain_core.messages import AIMessage
def update_ai_message(state: MessagesState) -> dict:
"""更新AI的消息内容"""
ai_message = state["messages"][-1]
return {
"messages": [
AIMessage(
id=ai_message.id, # 使用相同ID会覆盖原消息
content="更新后的内容: " + ai_message.content
)
]
}
完整示例
from langchain_core.messages import RemoveMessage, AIMessage
from langgraph.graph import MessagesState, StateGraph
def chatbot(state: MessagesState) -> dict:
"""聊天机器人节点"""
return {"messages": [llm.invoke(state["messages"])]}
def delete_human_message(state: MessagesState) -> dict:
"""删除第一条人类消息"""
human_message = state["messages"][0]
return {"messages": [RemoveMessage(id=human_message.id)]}
def update_ai_message(state: MessagesState) -> dict:
"""为AI消息添加前缀"""
ai_message = state["messages"][-1]
return {
"messages": [
AIMessage(
id=ai_message.id,
content="更新后的AI消息: " + ai_message.content
)
]
}
# 构建图
graph_builder = StateGraph(MessagesState)
graph_builder.add_node("chatbot", chatbot)
graph_builder.add_node("delete_human_message", delete_human_message)
graph_builder.add_node("update_ai_message", update_ai_message)
graph_builder.set_entry_point("chatbot")
graph_builder.add_edge("chatbot", "delete_human_message")
graph_builder.add_edge("delete_human_message", "update_ai_message")
graph_builder.set_finish_point("update_ai_message")
graph = graph_builder.compile()
应用场景:
- 隐私保护:删除敏感信息
- 消息修正:更正错误的输出
- 数据清理:清理无关的历史消息
十三、修改图状态(人在环路)
当使用断点实现人在环路时,可以在中断后手动修改图的状态。
from langchain_core.messages import ToolMessage
from langgraph.checkpoint.memory import MemorySaver
# 编译时设置中断点
checkpointer = MemorySaver()
graph = graph_builder.compile(
checkpointer=checkpointer,
interrupt_after=["tools"] # 工具执行后中断
)
config = {"configurable": {"thread_id": 1}}
# 第一次调用(会中断)
state = graph.invoke(
{"messages": [("human", "2024年北京马拉松成绩")]},
config
)
# 获取当前状态
graph_state = graph.get_state(config)
print("当前状态:", graph_state)
# 手动修改工具执行结果
tool_message = ToolMessage(
id=graph_state.values["messages"][-1].id, # 覆盖原工具消息
tool_call_id=graph_state.values["messages"][-2].tool_calls[0]["id"],
name=graph_state.values["messages"][-2].tool_calls[0]["name"],
content="2024年北京马拉松第一名:慕小课 01:59:40" # 手动输入的结果
)
# 更新状态
graph.update_state(config, {"messages": [tool_message]})
# 继续执行(使用修改后的状态)
result = graph.invoke(None, config)
print(result["messages"][-1].content)
关键方法:
graph.get_state(config)- 获取当前状态graph.update_state(config, updates)- 更新状态graph.invoke(None, config)- 从中断处继续执行
应用场景:
- 人工审核工具调用结果
- 手动修正工具返回的错误数据
- 在继续执行前注入外部信息
流程图:
正常流程
│
▼
调用工具 ──→ 工具返回结果 ──→ 中断(interrupt_after)
│
▼
人工介入
│
┌───────────┴───────────┐
│ │
修改结果 保持原样
│ │
└───────────┬───────────┘
│
▼
graph.update_state()
│
▼
继续执行 invoke(None)
十四、CRAG(Corrective RAG)实现
CRAG(Corrective Retrieval Augmented Generation) 是一种改进的RAG方法,通过评估检索文档的质量来决定是否需要网络搜索。
核心流程
用户问题 → 检索向量库 → 评估文档相关性
│
┌───────────┴───────────┐
│ │
文档相关 文档不相关
│ │
▼ ▼
直接生成 重写查询 → 网络搜索 → 生成
完整实现
from typing import TypedDict, Any
from langchain_core.documents import Document
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI
from langchain_weaviate import WeaviateVectorStore
from langgraph.graph import StateGraph
# ============ 定义状态 ============
class GraphState(TypedDict):
question: str # 原始问题
generation: str # LLM生成的内容
web_search: str # 是否需要网络搜索
documents: list[str] # 检索到的文档列表
# ============ 定义文档评分模型 ============
class GradeDocument(BaseModel):
"""文档评分模型"""
binary_score: str = Field(description="文档与问题是否关联,回答yes或no")
# ============ 初始化组件 ============
llm = ChatOpenAI(model="gpt-4o-mini")
# 向量数据库检索器
vector_store = WeaviateVectorStore(
client=weaviate_client,
index_name="LLMOps",
text_key="text",
embedding=embeddings,
)
retriever = vector_store.as_retriever(search_type="mmr")
# 文档评估器
grade_prompt = ChatPromptTemplate.from_messages([
("system", "你是一名评估检索文档与问题相关性的评估员。给出yes或no评分。"),
("human", "检索文档: \n\n{document}\n\n用户问题: {question}"),
])
retrieval_grader = grade_prompt | llm.with_structured_output(GradeDocument)
# RAG生成链
rag_prompt = ChatPromptTemplate.from_template(
"""使用以下检索到的上下文回答问题。
问题: {question}
上下文: {context}
答案: """
)
rag_chain = rag_prompt | llm | StrOutputParser()
# 查询重写器
rewrite_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个问题重写器,将输入问题转换为优化的网络搜索版本。"),
("human", "初始问题: {question}\n\n请提出一个改进的搜索问题。")
])
question_rewriter = rewrite_prompt | llm | StrOutputParser()
# ============ 定义节点 ============
def retrieve(state: GraphState) -> dict:
"""检索节点:从向量库检索相关文档"""
question = state["question"]
documents = retriever.invoke(question)
return {"documents": documents, "question": question}
def grade_documents(state: GraphState) -> dict:
"""文档评分节点:评估每个文档的相关性"""
question = state["question"]
documents = state["documents"]
filtered_docs = []
web_search = "no"
for doc in documents:
score = retrieval_grader.invoke({
"question": question,
"document": doc.page_content
})
if score.binary_score.lower() == "yes":
filtered_docs.append(doc)
else:
web_search = "yes" # 有不相关文档,需要网络搜索
return {"documents": filtered_docs, "web_search": web_search}
def generate(state: GraphState) -> dict:
"""生成节点:基于文档生成答案"""
question = state["question"]
documents = state["documents"]
generation = rag_chain.invoke({
"context": "\n\n".join([doc.page_content for doc in documents]),
"question": question
})
return {"generation": generation}
def transform_query(state: GraphState) -> dict:
"""查询重写节点:优化问题用于网络搜索"""
question = state["question"]
better_question = question_rewriter.invoke({"question": question})
return {"question": better_question}
def web_search(state: GraphState) -> dict:
"""网络搜索节点:使用搜索引擎获取最新信息"""
question = state["question"]
documents = state["documents"]
# 调用搜索API
search_content = google_serper.invoke({"query": question})
documents.append(Document(page_content=search_content))
return {"documents": documents}
# ============ 路由函数 ============
def decide_to_generate(state: GraphState) -> str:
"""决定:直接生成 还是 重写查询后搜索"""
web_search = state["web_search"]
if web_search.lower() == "yes":
return "transform_query" # 需要网络搜索
return "generate" # 直接生成答案
# ============ 构建图 ============
workflow = StateGraph(GraphState)
# 添加节点
workflow.add_node("retrieve", retrieve)
workflow.add_node("grade_documents", grade_documents)
workflow.add_node("generate", generate)
workflow.add_node("transform_query", transform_query)
workflow.add_node("web_search_node", web_search)
# 添加边
workflow.set_entry_point("retrieve")
workflow.add_edge("retrieve", "grade_documents")
workflow.add_conditional_edges(
"grade_documents",
decide_to_generate,
{
"transform_query": "transform_query",
"generate": "generate"
}
)
workflow.add_edge("transform_query", "web_search_node")
workflow.add_edge("web_search_node", "generate")
workflow.set_finish_point("generate")
# 编译并执行
app = workflow.compile()
result = app.invoke({"question": "能介绍下什么是LLMOps吗?"})
print(result["generation"])
CRAG 流程图
┌─────────────────────────────────────────────────────────────────────────┐
│ CRAG 完整流程 │
└─────────────────────────────────────────────────────────────────────────┘
用户问题
│
▼
┌─────────────┐
│ retrieve │ 从向量库检索文档
└─────────────┘
│
▼
┌─────────────┐
│grade_docs │ 评估每个文档相关性
└─────────────┘
│
├──────────────────┐
│ │
所有文档相关 有文档不相关
│ │
▼ ▼
┌─────────────┐ ┌──────────────┐
│ generate │ │transform_qry │
└─────────────┘ └──────────────┘
│ │
│ ▼
│ ┌─────────────┐
│ │ web_search │
│ └─────────────┘
│ │
└──────────────────┤
▼
┌─────────────┐
│ generate │
└─────────────┘
│
▼
最终答案
CRAG vs 传统 RAG
| 特性 | 传统 RAG | CRAG |
|---|---|---|
| 文档评估 | 无 | 有(评估相关性) |
| 查询优化 | 无 | 有(重写查询) |
| 信息源 | 仅向量库 | 向量库 + 网络 |
| 准确性 | 依赖检索质量 | 自动纠错 |
| 适用场景 | 知识库固定 | 需要实时信息 |
十五、关键代码解析
| 代码 | 作用 |
|---|---|
StateGraph(State) | 创建状态图,指定状态类型 |
add_node(name, func) | 添加节点 |
add_edge(from, to) | 添加固定边 |
add_conditional_edges(from, route) | 添加条件边 |
set_entry_point(node) | 设置入口点 |
set_finish_point(node) | 设置结束点 |
compile() | 编译图为可运行组件 |
interrupt_before=[...] | 在指定节点前中断 |
interrupt_after=[...] | 在指定节点后中断 |
checkpointer=MemorySaver() | 启用状态持久化 |
Annotated[list, add_messages] | 消息自动追加注解 |
create_react_agent() | 创建预构建的ReACT Agent |
ToolNode(tools) | 预构建的工具节点 |
trim_messages() | 修剪过长的消息历史 |
tools_condition | 预构建的工具条件路由函数 |
RemoveMessage(id) | 删除指定ID的消息 |
AIMessage(id=..., ...) | 使用相同ID更新消息 |
graph.get_state(config) | 获取当前图状态 |
graph.update_state(config, ...) | 更新图状态 |
十六、最佳实践
1. 节点函数设计
def good_node(state: State) -> dict:
"""好:只返回需要更新的字段"""
result = process_data(state["input"])
return {"output": result}
def bad_node(state: State) -> dict:
"""差:返回整个状态(可能导致覆盖)"""
result = process_data(state["input"])
return state # 不要这样!
2. 路由函数设计
def route(state: State) -> Literal["option_a", "option_b", END]:
"""使用 Literal 类型提示,让代码更清晰"""
value = state["key"]
if value == "a":
return "option_a"
elif value == "b":
return "option_b"
else:
return END
3. 使用预构建组件
from langgraph.prebuilt import ToolNode, create_react_agent, tools_condition
# 使用预构建的Agent
agent = create_react_agent(model=llm, tools=tools)
# 使用预构建的工具节点
tool_node = ToolNode(tools)
# 使用预构建的条件路由
graph.add_conditional_edges("llm", tools_condition)
4. 状态设计建议
class State(TypedDict):
# 消息列表使用 add_messages 注解
messages: Annotated[list, add_messages]
# 其他字段根据需要选择更新策略
count: Annotated[int, lambda x, y: x + y] # 累加
latest: Annotated[str, lambda x, y: y] # 覆盖为最新值
十七、LangGraph vs 传统 Chain
| 特性 | 传统 Chain | LangGraph |
|---|---|---|
| 流程控制 | 线性 | 图状(支持循环、分支、并行) |
| 状态管理 | 隐式 | 显式(可检查、可持久化) |
| 可视化 | 困难 | 内置图可视化 |
| 调试 | 不易 | 支持断点、单步执行 |
| 多智能体 | 困难 | 原生支持 |
| 人工介入 | 不支持 | 支持人在环路 |
| 消息操作 | 有限 | 支持删除、更新、修剪 |
十八、学习建议
- 从简单开始:先理解基本的节点、边、状态概念
- 可视化流程:画图理解应用流程
- 使用预构建Agent:
create_react_agent是很好的起点 - 调试技巧:使用
interrupt_before和interrupt_after设置断点 - 消息管理:合理使用
trim_messages、RemoveMessage控制消息长度 - 阅读文档:LangGraph 文档很详细,多参考示例
十九、参考资源
- LangGraph 官方文档:langchain-ai.github.io/langgraph/
- LangGraph 教程:langchain-ai.github.io/langgraph/t…
- 概念指南:langchain-ai.github.io/langgraph/c…
- 示例代码:github.com/langchain-a…
总结一句话:LangGraph 将复杂应用流程建模为状态图,提供了可视化、可调试、可持久化的强大能力,是构建现代AI应用的首选框架!