LangGraph 基础知识

LangGraph 学习总结

一、这是什么?(概念解释)

LangGraph 是 LangChain 推出的用于构建有状态多参与者(multi-actor)应用的框架。

核心概念

  • 图(Graph):将应用流程建模为节点和边的有向图
  • 状态(State):在节点之间传递的数据
  • 节点(Node):执行具体操作的函数
  • 边(Edge):连接节点,定义执行流程

为什么需要 LangGraph?

  • 传统 Agent 流程难以控制(循环、分支、并行)
  • LangGraph 提供可视化、可调试、可持久化的状态管理
  • 支持复杂的多智能体协作场景

二、有什么用?(应用场景)

场景 说明
智能Agent 构建复杂的对话式Agent
多智能体协作 多个Agent协同完成任务
人在环路(Human-in-the-loop) 关键操作需要人工确认
状态持久化 对话历史保存和恢复
条件分支 根据条件动态选择执行路径
并行执行 多个任务并行处理
工作流自动化 复杂业务流程自动化

三、基础示例

python 复制代码
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)

python 复制代码
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)

python 复制代码
def my_node(state: State) -> dict:
    """节点函数接收当前状态,返回要更新的字段"""
    # 处理逻辑...
    return {
        "messages": [new_message],  # 追加消息
        "count": state["count"] + 1  # 更新计数
    }

3. 边(Edge)

python 复制代码
# 固定边:无条件连接
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
    }
)

五、条件边示例(路由)

python 复制代码
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()

流程图

scss 复制代码
START → llm节点 ──┬──→ route函数(条件边) ──→ tool_executor节点 ─┐
                    │                                      │
                    └──────────────────────────────────────┘
                         (有tool调用则执行工具,否则结束)

六、并行边示例

python 复制代码
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")

流程图

markdown 复制代码
    chat_bot
       │
       ├──→ parallel1 ──┐
       │                │
       ├──→ parallel2 ───┴──→ 汇聚

七、人在环路(Human-in-the-loop)

python 复制代码
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

python 复制代码
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)

python 复制代码
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 支持将一个图作为另一个图的节点,实现多智能体协作。

python 复制代码
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"])

流程图

scss 复制代码
                    parallel_node
                          │
          ┌───────────────┴───────────────┐
          │                               │
          ▼                               ▼
    live_agent                      xhs_agent
    (子图1)                          (子图2)
          │                               │
    ┌─────┴─────┐                   ┌─────┴─────┐
    │           │                   │           │
chatbot_live tools              chatbot_xhs   (结束)
    │           │                   │
    └─────┬─────┘                   │
          │                         │
          └─────────────┬───────────┘
                        ▼
                     汇聚结果

十一、消息修剪(trim_messages)

当对话历史过长时,需要修剪消息以避免超出模型的 token 限制。

python 复制代码
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 支持在节点中删除或更新状态中的消息。

删除消息

python 复制代码
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)]}

更新消息

python 复制代码
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
            )
        ]
    }

完整示例

python 复制代码
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()

应用场景

  • 隐私保护:删除敏感信息
  • 消息修正:更正错误的输出
  • 数据清理:清理无关的历史消息

十三、修改图状态(人在环路)

当使用断点实现人在环路时,可以在中断后手动修改图的状态。

python 复制代码
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) - 从中断处继续执行

应用场景

  • 人工审核工具调用结果
  • 手动修正工具返回的错误数据
  • 在继续执行前注入外部信息

流程图

scss 复制代码
  正常流程
     │
     ▼
  调用工具 ──→ 工具返回结果 ──→ 中断(interrupt_after)
                                  │
                                  ▼
                             人工介入
                                  │
                     ┌───────────┴───────────┐
                     │                       │
                  修改结果                保持原样
                     │                       │
                     └───────────┬───────────┘
                                 │
                                 ▼
                          graph.update_state()
                                 │
                                 ▼
                          继续执行 invoke(None)

十四、CRAG(Corrective RAG)实现

CRAG(Corrective Retrieval Augmented Generation) 是一种改进的RAG方法,通过评估检索文档的质量来决定是否需要网络搜索。

核心流程

markdown 复制代码
用户问题 → 检索向量库 → 评估文档相关性
                                │
                    ┌───────────┴───────────┐
                    │                       │
                文档相关                文档不相关
                    │                       │
                    ▼                       ▼
               直接生成               重写查询 → 网络搜索 → 生成

完整实现

python 复制代码
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 流程图

markdown 复制代码
┌─────────────────────────────────────────────────────────────────────────┐
│                        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. 节点函数设计

python 复制代码
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. 路由函数设计

python 复制代码
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. 使用预构建组件

python 复制代码
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. 状态设计建议

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

十八、学习建议

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

十九、参考资源


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

相关推荐
Java编程爱好者2 小时前
MyBatis-mybatis入门与增删改查
后端
神奇小汤圆2 小时前
并发编程进阶:volatile、内存屏障与 CPU 缓存机制详解
后端
神奇小汤圆2 小时前
Redis实现 IP 维度滑动窗口限流实践
后端
程序员清风2 小时前
小红书二面:Spring Boot的单例模式是如何实现的?
java·后端·面试
Lee川3 小时前
深入浅出JavaScript事件机制:从捕获冒泡到事件委托
前端·javascript
光影少年3 小时前
async/await和Promise的区别?
前端·javascript·掘金·金石计划
树獭叔叔3 小时前
19-为什么AI工程这么喜欢"创造名词":从Prompt到Skill的造词运动
后端·aigc·openai
恋猫de小郭3 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
天朝八阿哥3 小时前
使用Docker+vscode搭建离线的go开发调试环境
后端·docker·visual studio code