赞
踩
LangChain中的智能体从数据结构的角度来讲等同于一个有向无环图,也就是说,chain在推理过程中无法被循环调用.而尽管AgentExecutor(代理执行器)支持’循环’.但是缺乏精确控制能力,时常发生失控陷入死循环的情况.
使用代理执行器实现循环调用LLM的能力,其调用过程主要有两步:
AgentExecutor存在的问题是决策过程隐藏在AgentExcutor背后,过于黑盒,缺乏更精细的控制能力,在构建复杂的Agent的时候受限
在LangChain中简单的链不具备循环能力,而AgentExcutor调用Agent又过于黑盒,因此需要一个具备更精细控制能力的框架来支持复杂场景的LLM应用.LangGraph的出现宣布LangChain进入到多智能体框架领域,langGraph是基于图论运作的,他提供了一种状态机的技术,可与驱动循环代理调用,实现有向有环图. 因此,LangGraph有三个关键元素:
是LangChain的一个类,表示图的数据结构并且反应其状态,节点会更新图的状态
图中关键元素之一,每个langGraph节点都有一个名称的值,可以是LangChain表达式中的函数或者可运行项,每个节点接收一个字典类型的数据.节点返回具有相同结构的更新状态.有一个名为"END"的特殊节点,用于识别状态机的结束状态
边维系节点之间的关系,三种类型的边:开始边(没有上游节点),普通边和条件边
普通边定义上游节点应始终调用的下游节点
条件边,通过函数(路由器)来确定下游节点,条件边需要三个元素
类似于状态机(State Machine),由一组状态(State)和状态之间的转换(Transition)组成,用于表示系统在不同状态之间的转换和响应事件的行为。
python
复制代码
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages
class State(TypedDict):
# Messages have the type "list". The `add_messages` function
# in the annotation defines how this state key should be updated
# (in this case, it appends messages to the list, rather than overwriting them)
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
这个状态定义了随时间更新的核心状态对象,它接收一些操作以及属性定义以及会被节点更新;会在每一个Node之间传递不同的状态信息。然后每一个节点会根据自己定义的逻辑去更新这个状态信息
Node可以是一个langchain的runnable或者是一个可执行的函数,也可以是一个Graph,构建完成的Graph也是一个langchain的runnable,这也正是LangGraph作为langchain的扩展可以与langchain完美衔接的关键.
添加节点直接使用Graph实例中的add_node方法添加即可,当然这个节点应当有一个名字
arduino
复制代码
graph_builder.add_node("node",node)
node就是langchain的runnable对象或者可执行函数,具体在开发中定义
边(Edge)描述的是节点与节点之间的关系,可以是普通的或者是有条件的.他们都有方向,Edge描述的上游节点与下游节点的关系(开始边除外).
Edge的实现由Graph实例中的add_edge方法添加,同样这个边也有一个名字,这个名字就是节点的名字,代表的是上游节点.
arduino
复制代码
graph_builder.add_edge("node",next_node)
next_node就是node节点的下游节点.
条件边的实现由Graph实例中的add_conditional_edge进行添加
sql
复制代码
graph.add_conditional_edge(
"node",
should_continue,
{
"end": END,
"continue": "next_node"
}
)
should_continue就是条件边三个组成元素的路由函数了.确定下一个的可调用对象一个或多个节点.
到现在就完成一个图所需要的基本条件了,这也是一个最简单的LangGraph列子
编译图也是由Graph实例对象的方法实现
ini
复制代码
graph = graph_builder.compile()
编译之后的graph是一个langchain的runnable对象,同样具有.invoke.stram方法,也具备成为一个节点的能力.
python 复制代码 import os from dotenv import find_dotenv, load_dotenv load_dotenv(find_dotenv()) OPENAI_API_BASE=os.environ['OPENAI_API_BASE'] OPENAI_API_KEY=os.environ['OPENAI_API_KEY'] from typing import Annotated from typing_extensions import TypedDict from langgraph.graph import StateGraph from langgraph.graph.message import add_messages class State(TypedDict): messages: Annotated[list, add_messages] graph_builder = StateGraph(State) from langchain_openai import ChatOpenAI llm = ChatOpenAI() def chatbot(state: State): return {"messages": [llm.invoke(state["messages"])]} graph_builder.add_node("chatbot", chatbot) graph_builder.set_entry_point("chatbot") graph_builder.set_finish_point("chatbot") graph = graph_builder.compile() while True: user_input = input("User: ") if user_input.lower() in ["quit", "exit", "q"]: print("Goodbye!") break for event in graph.stream({"messages": ("user", user_input)}): for value in event.values(): print("Assistant:", value["messages"][-1].content)
想要让单个Agent干很多活儿,就必须的有极强的推理能力以及定义好工具之间的关系,和精确到控制能力.而单个Agent的执行过程过于黑盒等问题导致单个Agent很难集多种本领于一身,同时langchain却没有一个能实现多Agent的方法或者技巧.LangGraph作为langchain的扩展就可以实现多Agent(Multi-agent).当然,单个Agent有单个的好处,分开也有分开的优势
单Agent的构建较为简单,不仅编码简单,逻辑也比较清晰,LangGraph与之相比就太过于复杂了,不仅要有清晰的逻辑关系,还要有一个图的数据流向,构建一个简单的图人脑还是能应对,一旦节点,边多起来了,就需要借助工具进行设计了,在复杂的逻辑链路中抽丝剥茧.
LangGraph构建多Agent在编码的过程中或许会比较难受,但是实现效果不是单个Agent能够相比的.
AotuGen中的多Agent是基于会话实现的,有三个Agent角色,构建过程要比LangGraph简单,与LangGraph不同,LangGraph具有更清晰的逻辑条理.
当前的LangGraph还处在一个初期发展的阶段,在langchain的0.2.x版本迭代中,Agent应该会占据一个重要地位.相信在未来的LangGraph构建会更容易
作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。
但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的 AI大模型资料
包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。