LangGraph(一)——LangGraph简介
一、LangGraph
- LangGraph官方介绍:https://blog.langchain.dev/langgraph/
1.1 简介
LangGraph 是构建在 LangChain 之上的,并且与 LangChain
生态系统完全互操作。它主要通过引入一种简单的方式创建循环图。这在创建Agent Runtimes通常非常有用。
1.2 动机
通过LCEL(LangChain Expression
Language)我们可以轻松创建chains,实际chains是有向无环图(DAG)。但是在创建更复杂的大型语言模型(LLM)应用时,常见的模式是在Runtime引入循环。
最简单的Angent的一个循环,基本上有以下两个步骤
- 调用LLM以确定(a)要执行的操作,或(b)要向用户提供什么响应
- 执行给定操作,然后返回步骤1
重复以上步骤,直到生成最终结果。AgentExecutor 和 AutoGPT都使用了上述循环。
但是在很多情况下,上述结构是一个黑盒,无法满足需要更多控制的情况。例如,始终强制Agent首先调用特定工具;更好地控制工具的调用方式;根据具体状态为Agent提供不同的Propmt。
LangChain官方将这些更受控制的流程称为state machines,认知架构的博客中找到下图

这些状态机具有循环的能力,允许处理比简单链更模糊的输入。然而,就如何构建该循环而言,仍然需要人参与。
LangGraph 是一种通过将状态机指定为图来创建这些状态机的方法。
1.3 功能性 Functionality
LangGraph 提供了一个相对狭窄的接口[1],用于创建状态机,通过图形化的方式指定。
1.3.1 StateGraph
StateGraph
是一个代表图的类。你通过传入一个state定义来初始化这个类。这个sate定义代表了一个随着时间更新的中心状态对象。这个state由图中的节点更新,这些节点返回对这个sate操作的属性(以键值存储的形式)。sate的属性有两种更新方法。第一种是一个属性可以被完全覆盖。第二种是通过向其值添加内容来更新属性。
在创建初始状态定义时,您可以指定是应该覆盖属性还是添加属性。以下是一个伪代码示例:
1 | |
1.3.2 节点 Nodes
StateGraph创建后,可以使用graph.add_node(name, value)来添加节点,name是一个string,name用来添加edges时引用node;value应该是一个function或
LCEL Runnable,function/LCEL Runnable输入参数应该和State对象的输入一样是一个字典,并输出带有要更新的State对象键的字典。
以下是一个伪代码示例:
1 | |
还有一个特殊的END节点,用于表示图的终点。你的循环最终必须能够结束!
1 | |
1.3.3 边 Edges
在添加节点后,就可以添加边来创建图了。有以下几种边。
起始边(Starting Edge)
将图形的起点连接到特定节点。这使得该节点成为在输入传递到图形时首先被调用的节点。伪代码如下:
1 | |
常规边(Normal Edges)
在这些边上,一个节点应始终在另一个节点之后被调用。例如,在基本Agent运行时,我们通常希望在调用工具后再调用模型:
1 | |
条件边(Conditional Edges)
这些边使用函数(通常由LLM提供支持)来确定首先转到哪个节点。要创建这样的边,需要传入三个参数:
- 上游节点:它查看此节点的输出以确定下一步应该做什么。
- 一个函数:该函数将被调用以确定接下来要调用哪个节点。它应该返回一个字符串。
- 映射:此映射将用于将第二个参数中函数的输出映射到另一个节点。键应该是函数可能返回的可能值。如果返回了某个值,那么这些值应该是要转到的节点的名称。
例如在调用了一个模型之后,我们要么退出图并返回给用户,要么调用一个工具——这取决于用户的决定!以下是伪代码示例:
1 | |
1.3.4 编译 Compile
在定义好graph后,可以将其编译为
runnable,这里的runnable和LangChain的一样,有.invoke,.stream,.astream_log等方法。
1 | |
1.4 Agent Executor
用 LangGraph 重新创建了标准的
LangChain AgentExecutor,这将允许您使用现有的
LangChain Agent,并且允许您更轻松地修改
AgentExecutor
的内部结构。默认情况下,此图的状态包含了一些在使用
LangChain Agent
时应该熟悉的概念:input、chat_history、intermediate_steps
和 agent_outcome。
1 | |
更详细的可参看官方notebook
1.5 Chat Agent Executor
Chat Model对消息列表进行操作,而且这些模型通常具有function calling的功能,这使得类似Agent的体验更加可行。使用这些类型的模型时,通常可以直观地将Agent的状态表示为消息列表。如下代码,输入是一个消息列表,节点只是随时间推移简单地添加到此消息列表中。
1 | |
更详细的可参看官方notebook
1.6 Modifications
LangGraph 的一个重要优势在于以更自然且可修改的方式暴露了 AgentExecutor 的逻辑。我们提供了一些我们听到过请求的修改示例:
强制调用工具:当您总是希望代理首先调用工具时使用。适用于 Agent Executor 和 Chat Agent Executor
人机交互:如何在调用工具之前添加人机交互。适用于 Agent Executor 和 Chat Agent Executor
管理
Anget步骤:用于添加处理Anget可能采取的中间步骤的自定义逻辑(在步骤较多时非常有用)。适用于 Agent Executor 和 Chat Agent Executor以特定格式返回输出:如何使用函数调用使代理以特定格式返回输出。仅适用于 Chat Agent Executor
动态直接返回工具的输出:有时您可能希望直接返回工具的输出。我们在 LangChain 中提供了一种简单的方法来实现这一点。但这会导致工具的输出始终直接返回。有时,您可能希望让 LLM 自行决定是否直接返回响应。仅适用于 Chat Agent Executor
1.7 LangGraph未来工作
期待 LangGraph
能够实现更多自定义和强大的Agent Runtimes。
- 来自学术界的更先进的
Agent Runtimes(LLM
Compiler, plan-and-solve,etc)- 有状态的工具(允许工具修改某些状态)
- 更受控的
human-in-the-loop工作流程。-
Multi-agent工作流程。
- <“一个狭窄的接口”指的是一个暴露操作数量少或模块间潜在依赖性少的接口。与之相对的是“一个宽泛的接口”,它暴露了许多操作或模块间的潜在依赖性。> ↩︎