LangGraph 基础知识

43 阅读14分钟

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

特性传统 RAGCRAG
文档评估有(评估相关性)
查询优化有(重写查询)
信息源仅向量库向量库 + 网络
准确性依赖检索质量自动纠错
适用场景知识库固定需要实时信息

十五、关键代码解析

代码作用
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

特性传统 ChainLangGraph
流程控制线性图状(支持循环、分支、并行)
状态管理隐式显式(可检查、可持久化)
可视化困难内置图可视化
调试不易支持断点、单步执行
多智能体困难原生支持
人工介入不支持支持人在环路
消息操作有限支持删除、更新、修剪

十八、学习建议

  1. 从简单开始:先理解基本的节点、边、状态概念
  2. 可视化流程:画图理解应用流程
  3. 使用预构建Agentcreate_react_agent 是很好的起点
  4. 调试技巧:使用 interrupt_beforeinterrupt_after 设置断点
  5. 消息管理:合理使用 trim_messagesRemoveMessage 控制消息长度
  6. 阅读文档:LangGraph 文档很详细,多参考示例

十九、参考资源


总结一句话:LangGraph 将复杂应用流程建模为状态图,提供了可视化、可调试、可持久化的强大能力,是构建现代AI应用的首选框架!