• 微信:WANCOME
  • 扫码加微信,提供专业咨询
  • 服务热线
  • 13215191218
    13027920428

  • 微信扫码访问本页
desc-2
环企首页

LangGraph 详细讲解

LangGraph 是 LangChain 生态中用于构建有状态、多步骤的 AI Agent 应用的图框架。它的核心思想是将 Agent 的推理过程建模为一个状态机,其中节点(Node)执行操作,边(Edge)控制流程,状态(State)在节点间传递。

📦 安装

pip install langgraph langchain langchain-openai

🏗️ 核心概念

概念 说明
State (状态) 在节点间共享的数据,用 TypedDict 定义,可指定 Reducer
Node (节点) 一个函数或 Runnable,接收状态,返回部分状态更新
Edge (边) 连接节点,决定执行顺序
Conditional Edge (条件边) 根据状态内容动态选择下一个节点
Graph (图) 节点和边的集合,定义整个工作流
Reducer (归约器) 定义如何合并多个节点对同一状态字段的更新

🔧 核心 API 详解

1. StateGraph - 创建图

from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, add_messages
from langchain_core.messages import AnyMessage

# 定义状态结构
class MessagesState(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]
    user_name: str
    
# 创建图
graph = StateGraph(MessagesState)

2. add_node - 添加节点

# 添加节点函数
def my_node(state: MessagesState) -> dict:
    # 处理逻辑...
    return {"messages": [AIMessage(content="回复内容")]}

graph.add_node("node_name", my_node)

3. add_edge / add_conditional_edges - 添加边

# 普通边:顺序执行
graph.add_edge("node_a", "node_b")

# 条件边:根据函数返回动态选择
def router(state: MessagesState) -> str:
    if "需要工具" in state["messages"][-1].content:
        return "tool_node"
    return "end"

graph.add_conditional_edges("assistant", router)

4. set_entry_point / set_finish_point - 设置入口和出口

graph.set_entry_point("assistant")      # 起始节点
graph.set_finish_point("assistant")     # 终止节点

5. compile - 编译图

app = graph.compile()

6. invoke / stream - 执行图

# 同步执行,返回最终状态
result = app.invoke({"messages": [HumanMessage(content="你好")]})

# 流式执行,返回每一步的更新
for chunk in app.stream(
    {"messages": [HumanMessage(content="你好")]},
    stream_mode="updates"  # 'values', 'updates', 'debug'
):
    print(chunk)

📋 MessageState 与 add_messages

from typing import Annotated, TypedDict
from langgraph.graph import add_messages
from langchain_core.messages import AnyMessage

class MessagesState(TypedDict):
    # add_messages 会自动追加新消息到列表末尾
    messages: Annotated[list[AnyMessage], add_messages]
    # 没有 reducer 的字段会被直接覆盖
    step_count: int

🛠️ 内置工具节点 - ToolNode

from langgraph.prebuilt import ToolNode
from langchain.tools import tool

@tool
def get_weather(city: str) -> str:
    """获取城市天气"""
    return f"{city} 天气晴朗"

tools = [get_weather]
tool_node = ToolNode(tools)

graph.add_node("tools", tool_node)

🤖 预置 Agent - create_react_agent / create_agent

from langchain.agents import create_agent  # 推荐使用
from langchain_openai import ChatOpenAI

agent = create_agent(
    model=ChatOpenAI(model="gpt-3.5-turbo"),
    tools=[get_weather],
    system_prompt="你是一个有用的助手"
)

result = agent.invoke({"messages": [{"role": "user", "content": "北京天气如何?"}]})

💡 完整示例:计算器 Agent

from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, add_messages
from langgraph.prebuilt import ToolNode
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage

# 1. 定义工具
@tool
def add(a: float, b: float) -> float:
    """计算两个数的和"""
    return a + b

@tool
def multiply(a: float, b: float) -> float:
    """计算两个数的乘积"""
    return a * b

# 2. 定义状态
class CalculatorState(TypedDict):
    messages: Annotated[list, add_messages]
    result: float

# 3. 初始化模型和工具
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
tools = [add, multiply]
llm_with_tools = llm.bind_tools(tools)

# 4. 定义节点函数
def assistant(state: CalculatorState):
    sys_msg = SystemMessage(content="你是一个计算器助手,根据用户请求计算数学表达式")
    response = llm_with_tools.invoke([sys_msg] + state["messages"])
    return {"messages": [response]}

def should_continue(state: CalculatorState) -> str:
    last_message = state["messages"][-1]
    if hasattr(last_message, "tool_calls") and last_message.tool_calls:
        return "tools"
    return "end"

# 5. 构建图
graph = StateGraph(CalculatorState)
graph.add_node("assistant", assistant)
graph.add_node("tools", ToolNode(tools))

graph.set_entry_point("assistant")
graph.add_conditional_edges("assistant", should_continue, {
    "tools": "tools",
    "end": "__end__"
})
graph.add_edge("tools", "assistant")

# 6. 编译
app = graph.compile()

# 7. 执行
result = app.invoke({"messages": [HumanMessage(content="(3+4)*2等于多少?")]})
for msg in result["messages"]:
    msg.pretty_print()

🔄 stream_mode 详解

模式 输出内容
"values" 每次更新后的完整状态
"updates" 每个节点的局部更新
"debug" 调试信息,包括执行细节
for chunk in app.stream(input, stream_mode="updates"):
    print(chunk)  # 例如: {'assistant': {'messages': [...]}}

⚙️ 高级配置

设置递归限制

config = {"recursion_limit": 50}
result = app.invoke(input, config=config)

Checkpoint 持久化(状态保存)

from langgraph.checkpoint import MemorySaver

memory = MemorySaver()
app = graph.compile(checkpointer=memory)

# 多轮对话保持状态
config = {"configurable": {"thread_id": "user123"}}
app.invoke(input, config=config)

📊 图结构对比

类型 说明 适用场景
StateGraph 通用状态图 需要自定义状态和流程
MessageGraph 专门处理消息 对话类应用
create_agent 预置 Agent 标准 ReAct Agent

⚠️ 常见错误与解决

错误 原因 解决方案
InvalidUpdate 状态更新包含未定义的键 确保返回的字典键在 State 中定义
GraphRecursionError 超过递归限制 增加 recursion_limit
tool 缺少 docstring @tool 装饰的函数无文档 添加文档字符串或 description
Model Not Exist 模型名称错误 检查模型 ID 格式

💎 总结

  • StateGraph 是最核心的构建块,定义状态和节点
  • add_messages 自动管理消息历史
  • ToolNode 简化工具调用执行
  • 条件边 实现智能路由(如是否需要调用工具)
  • checkpointer 支持多轮对话持久化

掌握这些后,你可以构建从简单对话到复杂多步推理的各种 Agent 应用。