LangGraph以图的方式构建语言代理官方文档地址https://langchain-ai.github.io/langgraph/LangGraph 是一个用于构建具有 LLMs 的有状态、多角色应用程序的库用于创建代理和多代理工作流。与其他 LLM 框架相比它提供了以下核心优势循环、可控性和持久性。LangGraph 允许您定义涉及循环的流程这对于大多数代理架构至关重要。作为一种非常底层的框架它提供了对应用程序的流程和状态的精细控制这对创建可靠的代理至关重要。此外LangGraph 包含内置的持久性可以实现高级的“人机交互”和内存功能。LangGraph 是 LangChain 的高级库为大型语言模型LLM带来循环计算能力。它超越了 LangChain 的线性工作流通过循环支持复杂的任务处理。状态维护计算过程中的上下文实现基于累积数据的动态决策。节点代表计算步骤执行特定任务可定制以适应不同工作流。边连接节点定义计算流程支持条件逻辑实现复杂工作流主要功能循环和分支在您的应用程序中实现循环和条件语句。持久性在图中的每个步骤之后自动保存状态。在任何时候暂停和恢复图执行以支持错误恢复、“人机交互”工作流、时间旅行等等。“人机交互”中断图执行以批准或编辑代理计划的下一个动作。流支持在每个节点产生输出时流式传输输出包括令牌流式传输。与 LangChain 集成LangGraph 与LangChain和Langsmith无缝集成但不需要它们。安装pipinstall-Ulanggraph示例LangGraph 的一个核心概念是状态。每次图执行都会创建一个状态该状态在图中的节点执行时传递每个节点在执行后使用其返回值更新此内部状态。图更新其内部状态的方式由所选图类型或自定义函数定义。让我们看一个可以使用搜索工具的简单代理示例。langgraph_hello.pyfromtypingimportLiteralfromlangchain_core.messagesimportHumanMessagefromlangchain_core.toolsimporttoolfromlangchain_deepseekimportChatDeepSeek# 导入langgraph检查点用于持久化状态fromlanggraph.checkpoint.memoryimportMemorySaver# 导入状态图和状态fromlanggraph.graphimportEND,StateGraph,MessagesState# 导入工具节点普通节点调用函数、工具节点调用工具fromlanggraph.prebuiltimportToolNode# 定义工具函数用于代理调用外部工具tooldefsearch(query:str):模拟一个搜索工具if上海inquery.lower()orShanghaiinquery.lower():return现在30度有雾return现在是30度阳光明媚。# 将工具函数放入工具列表tools[search]# 创建工具节点tool_nodeToolNode(tools)# 1. 初始化模型和工具定义并绑定工具到模型modelChatDeepSeek(modeldeepseek-chat,temperature0).bind_tools(tools)# 定义函数决定是否继续执行# 路由函数# 它不是业务计算节点而是决定下一跳的条件判断器defshould_continue(state:MessagesState)-Literal[tools,END]:messagesstate[messages]last_messagemessages[-1]# 如果llm调用了工具则转到tools节点# last_message.tool_calls: 有值说明模型这轮不是直接回答而是发起工具调用意图# 无值说明模型已经给出最终自然语言答复iflast_message.tool_calls:returntools# 否则停止回复用户returnEND# 定义调用模型的函数defcall_model(state:MessagesState):messagesstate[messages]responsemodel.invoke(messages)# 返回列表因为这将被添加到现有列表中return{messages:[response]}# 2. 用状态初始化图定义一个新的状态图# MessagesState是一个预构建的状态模式它具有一个属性一个LangChain对象列表以及将每个节点的更新合并到状态中的逻辑workflowStateGraph(MessagesState)# 3. 定义图节点定义我们将循环的两个节点workflow.add_node(agent,call_model)# agent节点负责决定采取什么如果有行动workflow.add_node(tools,tool_node)# 调用工具的tools节点如果代理决定采取行动此节点将执行该行动# 4. 定义入口点和图边# 设置入口点为agent# 这意味着这是第一个被调用的节点workflow.set_entry_point(agent)# 添加条件边# 条件边调用代理后我们应该要么如果代理说要采用行动则运行工具如果代理没有要求运行工具则完成回复用户·workflow.add_conditional_edges(# 首先定义起始节点。我们使用agent# 这意味着这些边是在调用agent节点后采取的agent,# 接下来传递决定下一个调用节点的函数should_continue,)# 添加从tools到agent的普通边# 这意味着在调用tools后接下来调用agent节点# 普通边调用工具后图应该始终返回到代理以决定下一步操作workflow.add_edge(tools,agent)# 初始化内存以在图运行之间持久化状态checkpointerMemorySaver()# 可以存Redis、Mongodb# 5. 编译图# 这将其编译成一个LangChain可运行对象# 这意味着你可以像使用其他可运行对象一样使用它# 注意我们可选的在编译图时传递内存# 编译图将图转换为可运行对象这会自动启动使用您的输入调用.invoke()、.stream()、.batch()方法# 传递检查点对象在图运行之间持久化状态并启用内存、人机交互工作流、时间旅行等等本例中使用MemorySaver将状态存储在内存中appworkflow.compile(checkpointercheckpointer)# 6. 执行图使用可运行对象final_stateapp.invoke({messages:[HumanMessage(content北京的天气怎么样)]},config{configurable:{thread_id:42}})# 从 final_state 中获取最后一条消息的内容resultfinal_state[messages][-1].contentprint(result)print(*100)final_stateapp.invoke({messages:[HumanMessage(content我问的哪个城市)]},config{configurable:{thread_id:41}})resultfinal_state[messages][-1].contentprint(result)逐步分解1. 初始化模型和工具我们使用 ChatDeepSeek 作为我们的 LLM。注意我们需要确保模型知道可以使用哪些工具。我们可以通过将 LangChain 工具转换为 ChatDeepSeek 工具调用格式来完成此操作方法是使用 .bind_tools() 方法。我们定义要使用的工具——在本例中是搜索工具。创建自己的工具非常容易——请参阅此处的文档了解如何操作2. 用状态初始化图我们通过传递状态模式在本例中为MessagesState来初始化图StateGraphMessagesState 是一个预构建的状态模式它具有一个属性一个 LangChain Message 对象列表以及将每个节点的更新合并到状态中的逻辑。3. 定义图节点我们需要两个主要节点agent节点负责决定采取什么如果有行动。调用工具的 tools 节点如果代理决定采取行动此节点将执行该行动。4. 定义入口点和图边首先我们需要设置图执行的入口点——agent节点。然后我们定义一个普通边和一个条件边。条件边意味着目的地取决于图状态MessageState的内容。在本例中目的地在代理LLM决定之前是未知的。条件边调用代理后我们应该要么a. 如果代理说要采取行动则运行工具b. 如果代理没有要求运行工具则完成回复用户。普通边调用工具后图应该始终返回到代理以决定下一步操作。5. 编译图当我们编译图时我们将其转换为 LangChain Runnable这会自动启用使用您的输入调用 .invoke()、.stream()和.batch()。我们还可以选择传递检查点对象以在图运行之间持久化状态并启用内存、“人机交互”工作流、时间旅行等等。在本例中我们使用MemorySaver——一个简单的内存中检查点。6. 执行图LangGraph 将输入消息添加到内部状态然后将状态传递给入口点节点agentagent节点执行调用聊天模型。聊天模型返回AIMessage。LangGraph 将其添加到状态中。图循环以下步骤直到AIMessage上不再有tool_calls。如果AIMessage具有tool_calls则tools节点执行agent节点再次执行并返回AIMessage执行进度到特殊的 END 值并输出最终状态。因此我们得到所有聊天消息的列表作为输出。总结循环逻辑agent-router-tools-agent…循环直到某次返回END表示图完成真实场景should_continue常会更复杂比如限制最大工具调用轮数防死循环根据工具错误状态决定重试/降级按tool_name分流到不同子图引入人工审批human-in-the-loop在决定是否继续