目录
一、导读
环境:OpenEuler、Windows 11、WSL 2、Python 3.12.3 langchain 0.3 langgraph 0.2
背景:前期忙碌的开发阶段结束,需要沉淀自己的应用知识,过一遍LangGraph
时间:20250226
说明:技术梳理,langgraph的基础原理以及为什么使用langgraph
二、LangGrah介绍
1、基础介绍
LangGraph是LangChain生态系统中的一个新成员,它提供了一个基于图(Graph)的框架来构建复杂的LLM应用。通过将应用逻辑组织成有向图的形式,LangGraph使得构建复杂的对话流程变得更加直观和灵活。
2、LangChain各版本图示
LangChain 0.1版本的图示
LangChain 0.2版本的图示
LangChain 0.3版本的图示
从LangChain官网的图示即可看出,现在核心功能均在向LangGraph偏移。可以这样理解,核心框架使用LangGraph,而其代码语法使用LangChain实现。
三、为什么使用LangGraph
1、链(Chain)的局限性
在LangChain中,链(Chain)是一种基本的构建块,用于将多个LLM(语言模型)调用和工具调用链接在一起。然而,链在处理复杂、动态的对话流程时存在一些局限性:
线性流程:链通常是线性的,这意味着它们只能按照预定义的顺序执行步骤。这种线性结构限制了在对话中进行动态路由和条件分支的能力。
状态管理:链在处理多轮对话时,状态管理变得复杂。每次调用链时,都需要手动传递和更新状态,这增加了代码的复杂性和出错的可能性。
工具集成:虽然链可以调用外部工具,但在链的结构中集成和协调多个工具的使用并不直观,尤其是在需要根据对话上下文动态选择工具时。
2、AgentExecutor的局限性
AgentExecutor是LangChain中用于执行代理(Agent)的组件,它允许代理根据输入动态选择工具和操作。尽管AgentExecutor提供了一定的灵活性,但它仍然存在一些局限性:
复杂性:AgentExecutor的配置和使用相对复杂,尤其是在处理复杂的对话流程和多轮对话时。需要手动管理代理的状态和工具调用,这增加了开发的难度。
动态路由:AgentExecutor虽然支持动态选择工具,但在处理复杂的条件分支和动态路由时,仍然不够灵活。缺乏一种直观的方式来定义和执行复杂的对话流程。
状态持久性:AgentExecutor在处理长时间运行的对话时,缺乏内置的状态持久性机制。每次对话重启时,都需要从头开始,无法恢复之前的对话状态。
3、LangGraph解决的问题
面对链和AgentExecutor的局限性,LangGraph应运而生。LangGraph的设计目标是解决这些局限性,提供一个更灵活、更强大的框架来构建复杂的智能体应用:
图结构:LangGraph采用图(Graph)结构来表示对话流程,允许开发者定义复杂的非线性流程和条件分支。这种图结构提供了更大的灵活性,使得动态路由和条件分支变得直观和简单。
状态管理:LangGraph内置了强大的状态管理机制,可以无缝地管理多轮对话的状态。开发者无需手动传递和更新状态,LangGraph会自动处理状态的持久化和恢复。
工具集成:LangGraph简化了工具的集成和使用,开发者可以轻松地将多个工具集成到对话流程中,并根据对话上下文动态选择和调用工具。
持久性:LangGraph提供了内置的状态持久性机制,支持长时间运行的对话。开发者可以随时暂停和恢复对话,无需担心状态丢失。
通过这些特性,LangGraph使得构建复杂、可扩展的智能体应用变得更加容易和高效。
四、LangGraph核心思想
LangGraph 受 Pregel 和 Apache Beam 的启发,其公共接口借鉴了 NetworkX。LangGraph 由 LangChain Inc 创建,该公司也是 LangChain 的创建者,但 LangGraph 可以独立于 LangChain 使用。
chain是链,而graph是图,图具备连通性,对于LangGraph而言,最重要的概念是state、edge、node,如果这三个概念尚未弄明白,不建议写代码,否则会有N多的坑
1、核心概念
(1)state 状态
状态是LangGraph应用的基础,它可以是一个简单的字典或者Pydantic模型。状态包含了应用运行时需要的所有信息以及模型生成的信息
(2)node 节点
节点通常是Python函数,用于处理状态并返回更新后的状态
(3)edge 边
边定义了节点之间的连接关系和路由逻辑
2、流程说明
程序运行后,用户输入信息以及相关参数保存在state中,state起始在开始节点,按照代码逻辑沿着edge进入下一个节点;每一个节点(基本)都是函数,按照需求的逻辑进行处理,并更新state中的数据,一直到end节点。
以上是LangGraph最基础的理念,一定要明白,下图是一个LangGraph实现的代理RAG
上图使用的技术有tool和RAG两种技术,其起始node为__start__,结束node为__end__。state中存储的数据在start中,下一步到agent中,接下来是条件边(edge分为normal和conditional,conditional称之为条件边),一般情况下,实线代表普通边,虚线代表条件边。条件边根据当前的具体条件而选择那一条边执行,选择不同的边,则到达的节点不同。所以,agent下一步可能是结束,也可能是retrieve。retrieve节点下一步可能rewrite或是generate,rewrite下一个node必然抵达agent;而generate下一个node必然是__end__。图中可见,agent、retrieve、rewrite三个节点可能存在死循环,可以通过设置循环次数来避免这个bug。
上图实现的功能是:用户提问,如果检测该问题较为模糊,无法准确回答,则走retrieve节点,反之则结束。如果在retrieve中确认需要重写问题,则是rewrite,然后agent,最后__end__;如果找到相关答案,则将retrieve的输出,输入到generate中,并在generate中生成答案,结束
五、代码实战
下面使用最简单的逻辑实现一个graph,熟悉其基础组件概念以及使用方法
1、代码实现
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import MessagesState
llm = ChatOpenAI(
base_url="https://lxxxxx.enovo.com/v1/",
api_key="sxxxxxxxwW",
model_name="qwen2.5-instruct"
)
# 创建graph
graph_builder = StateGraph(MessagesState)
# 创建节点函数
def chatbot(state: MessagesState):
return {"messages": [llm.invoke(state["messages"])]}
# 添加节点,命名为chatbot
graph_builder.add_node("chatbot", chatbot)
# 添加起始边
graph_builder.add_edge(START, "chatbot")
# 添加结束边
graph_builder.add_edge("chatbot", END)
# 代码编译为图
graph = graph_builder.compile()
# 生成图的流程图片,写到当前目录下
qa_async_png = graph.get_graph().draw_mermaid_png()
with open("chatbot.png", "wb") as f:
f.write(qa_async_png)
# 流式调用大模型
for event in graph.stream({"messages": [{"role": "user", "content": "中国最好的大学是哪所?"}]}):
for value in event.values():
print("Assistant:", value["messages"][-1].content)
2、输出
Assistant: 中国有很多优秀的大学,每一所在其特定领域都有卓越的表现。如果要提及最知名的几所,人们往往会提到清华大学和北京大学。这两所学校在中国以及国际上都享有很高的声誉,分别在工科和文科方面有着出色的表现。
当然,除了清华和北大之外,还有许多其他优秀的高等教育机构,比如复旦大学、浙江大学、上海交通大学等,它们在各自的领域内也有很高的成就。选择哪所学校最好,往往取决于个人的专业兴趣和职业规划。
3、生成图片
生成图片访问的网址需要科学上网(之前不记得需要,今天不清楚啥情况)
解决方案(前提是Windows可以科学上网):Linux子系统固定IP和代理设置-CSDN博客