深入浅出LangGraph AI Agent智能体开发教程(六)—LangGraph 底层API入门

前言

本系列前五篇文章:

通过以上文章的分享我们学习了LangGraph高级预构建图API create_react_agent的使用技巧,掌握了LangGraph Agent开发全生态核心工具的开发方法。从本期分享开始我们就深入到LangGraph底层API进行学习。

本系列分享是笔者结合自己学习工作中使用LangChain&LangGraph经验倾心编写的,力求帮助大家体系化快速掌握LangChain&LangGraph AI Agent智能体开发的技能!笔者的LangChain系列教程暂时更完,后面也会实时补充工作实践中的额外知识点,建议大家在学习LangGraph分享前先学习LangChain的基本使用技巧。大家感兴趣可以关注笔者掘金账号和系列专栏。更可关注笔者同名微信公众号: 大模型真好玩 , 每期分享涉及的代码均可在公众号私信: LangChain智能体开发获得。

一、为什么要学习LangGraph底层API?

在整个系列分享的一开始我们绘制过如下的LangGraph核心设计的层级结构图。

第一层 是预构建图的API,也就是预定义的图结构图模板,比如我们一直使用的create_react_agent表示使用一行命令创建基于预构建ReACT图的智能体,通过它我们可以方便的接入外部工具函数或者MCP服务。其它的图结构模板API与create_react_agent类似所以我们没有去深入讲解。

第二层是一些AgentNode API,有时我们并不会简单的使用ReACT等图模板,往往还需要添加一些组件。AgentNode API就是方便我们快速封装节点并引入图结构的API,例如一些规定模型如何调度,工具如何封装的节点API。

第三层是最底层的API,借助底层API,开发者可以更加灵活的完成各类智能体的开发,将任意的函数,大模型都编排成节点和边封装到图结构中。在很多场景下,比如人在环中(必须有人类参与协助的Agent结构,例如一些模型输出结果后要经过人类审核才能生成最终答案)或者搭建多智能体协作系统时,必须使用更加底层的图结构API才能完成,因此这也使得掌握底层API是目前大模型开发人员进阶的必备技巧。

这里也要说明底层API学习起来还是有些难度(可以想象一个图既有节点又有边,还是一个有向有环图,内部还有条件判别、循环等结构,肯定不是一行create_react_agent命令能完成的)

二、LangGraph图结构对象创建方法与核心语法

2.1 LangGraph图结构概念说明

在介绍API之前,我们先梳理一下LangGraph 底层 API的基本语法与设计理念,LangGraph的宗旨是创建一个图结构,该图结构包含大模型、外部工具等,通过点线间的连接构成灵活的处理链路。基于该宗旨,LangGraph定义了一套由点、边、状态组成的有向有环的结构图语法。

节点(Nodes)

任何可执行的功能包括大语言模型API,工具,甚至Agent都可以作为LangGraph图的点。

边(Edges)

边通常负责传递数据,也有一些边负责进行逻辑控制,例如if-else的判断和选择,从而让整个图状结构更加丰富。

State(状态)

LangGraph通过组合点和边去创建复杂的循环工作流程,节点产生的消息通过边传递给别的节点从而形成通路。为了维持节点和边之间的消息传递,LangGraph势必要对所有的消息进行统一管理,这就引出了概念"State(状态)"。在LangGraph构建的流程中,每次执行都会启动一个状态,图中的节点在处理时会传递和修改该状态。这个状态不仅仅是一组静态数据,而是由每个节点的输出动态更新,然后影响循环内的后续操作,确保图通路顺畅。

2.2 手动创建图流程

具备理论基础后接下来我们通过代码实战来理解LangGraph的设计原理。为了方便大家理解,我们先在不接入大模型的情况下构建一个加减法图工作流。

  1. LangGraph图结构构建的第一步是创建State, 构建state的方法非常简单,我们可以将图的状态设计为一个字典,用于在不同节点间共享和修改数据,然后使用StateGraph类进行图的实例化。代码如下, 需要注意的是builder也是后面要用到的图构建器(Graph Builder)对象,用于逐步添加节点、边、控制流逻辑,最终编译成可执行的图。
python 复制代码
from langgraph.graph import StateGraph

# 创建一个字典类型的State
builder = StateGraph(dict)
  1. 接下来使用代码定义图结构的两个节点,对LangGraph来说,图结构节点的类型包括很多种,可以是大语言模型,工具函数等等,简而言之可以顺序式处理数据的节点都可以作为图节点。我们这里自定义两个简单函数:一个是加法函数接收当前State并将其中的x值加1,另一个是减法函数接收当前State并将其中的x值减2,代码如下:
python 复制代码
def addition(state):
    print(f'加法节点收到的初始值:{state}')
    return {"x": state["x"] + 1}

def subtraction(state):
    print(f'减法节点收到的初始值:{state}')
    return {"x": state["x"] - 2}
  1. 接下来进行图结构的设计,添加名为additionsubtraction的节点,并关联到两个函数上。 对于LangGraph来说有两个名为STARTEND的特殊节点,这两个节点没有明确功能,只是起到标识开始和结束的作用。
python 复制代码
from langgraph.graph import START, END

# 向图中添加两个节点
builder.add_node("addition", addition)
builder.add_node("subtraction", subtraction)

# 构建节点之间的边
builder.add_edge(START, "addition")
builder.add_edge("addition", "substraction")
builder.add_edge("subtraction", END)

上述的代码语义非常明确,我们可以构建出如下图:

我们也可以通过builder.nodesbuilder.edges查看图的节点和边的相关情况:

  1. 执行图的编译,需要通过调用compile()方法将编排后的builder编译成一个可执行的图,添加如下代码:
python 复制代码
graph = builder.compile()

编译后的图也支持可视化效果展示,笔者喜欢ascii风格的展示效果。我们首先在anaconda虚拟环境langgraphenv中执行pip install grandalf安装依赖环境,然后在代码中添加 graph.get_graph().print_ascii()打印字符风格的图,效果如下:

2.3 LangGraph图对象运行

当我们通过builder.compile()方法编译图后,编译后的graph对象提供了invoke方法,该方法用于启动图的执行。在图执行前我们需要通过invoke方法传递一个初始状态,这个状态作为图执行的起始输入:

python 复制代码
initial_state={"x": 10}

result = graph.invoke(initial_state)

print('最后的结果:', result)

可以看到最后的输出和我们的预期相符合,x初始值为10, 首先经过加法节点变为11后传递给减法节点,减法节点减去2后变为9输出为最终结果。

三、借助Pydantic构建稳定的State

以上的写法虽然灵活但有一个致命缺陷,我们的State状态缺乏预定义的模式,节点可以在没有严格类型约束的情况下自由地读取和写入状态,这样的灵活性虽然有利于动态数据处理,但这也要求开发者在整个图的执行过程中保持对键和值的一致性管理(例如我们在加减法函数中返回的都是只包含键值对x的字典对象)。因为在任何节点中尝试访问State中不存在的键,会直接中断整个图的运行状态。

3.1 Pydantic基本使用方法

通过集成pydantic中的BaseModel抽象类来定义状态State, 定义后的状态可以对键值对属性进行自动校验,我们编写如下代码,对x和y键定义不同的类型,错误的类型会报错。

python 复制代码
from pydantic import BaseModel

class MyState(BaseModel):
    x: int
    y: str = "default"   # 设置默认值

# 自动校验
state = MyState(x=1)
print(state.x)       # 输出 1
print(state.y)       # 输出 default

# 错误类型会报错
state = MyState(x="abc")  

3.2 Pydantic应用于StateGraph

下面我们使用Pydantic对第2节的代码进行修改,采用如下方法编写的代码可以对状态键内容和属性进行约束,代码健壮性更强。

python 复制代码
from pydantic import BaseModel
from langgraph.graph import StateGraph, START, END

# 1. 定义结构化状态模型
class CalcState(BaseModel):
    x: int

# 2. 定义节点函数,接收并返回 CalcState
def addition(state: CalcState) -> CalcState:
    print(f"[addition] 初始状态: {state}")
    return CalcState(x=state.x + 1)

def subtraction(state: CalcState) -> CalcState:
    print(f"[subtraction] 接收到状态: {state}")
    return CalcState(x=state.x - 2)

# 3. 构建图
builder = StateGraph(CalcState)

builder.add_node("addition", addition)
builder.add_node("subtraction", subtraction)

builder.add_edge(START, "addition")
builder.add_edge("addition", "subtraction")
builder.add_edge("subtraction", END)

graph = builder.compile()

# 4. 执行图:传入结构化状态对象
initial_state = CalcState(x=10)
final_state = graph.invoke(initial_state)

# 5. 打印最终结果
print("\n[最终结果] ->", final_state)

四、总结

本期内容分享了LangGraph底层自定义图API点、边、状态State的设计理念,并通过简单的加减法串联结构图演示了LangGraph底层API的使用方法,同时介绍了如何使用Pydantic约束State使代码更健壮的基本方法。当然我们使用LangGraph构建的图不可能仅仅是串行关系这么简单,下期分享我们将介绍如何使用底层API构建条件判断图和循环结构图,大家敬请期待~

本系列分享预计会有20节左右的规模,保证大家看完一定能够掌握LangChain&LangGraph的开发能力,大家感兴趣可关注笔者掘金账号和专栏,更可关注笔者的同名微信公众号:大模型真好玩 , 本系列分享的全部代码均可在微信公众号私信笔者: LangChain智能体开发 免费获得。

相关推荐
飞哥数智坊3 小时前
从界面崩塌到功能完整:CodeBuddy + uniapp 小程序生成实录
人工智能·ai编程
IT_陈寒3 小时前
Vue3性能优化:掌握这5个Composition API技巧让你的应用快30%
前端·人工智能·后端
黎燃15 小时前
人工智能在法律文书自动生成中的深度实践:从语言模型到审判逻辑的可解释对齐
人工智能
站大爷IP18 小时前
Python operator模块的methodcaller:一行代码搞定对象方法调用的黑科技
python
哔哩哔哩技术18 小时前
TextFlux重磅发布:告别复杂控制信号!多语种高保真场景文本编辑新时代
人工智能
小白狮ww18 小时前
LAMMPS 教程:移动原子演示
人工智能·深度学习·机器学习
聚客AI19 小时前
⭐超越CNN与RNN:为什么Transformer是AI发展的必然选择?
人工智能·llm·掘金·日新计划
快手技术19 小时前
可灵AI数字人来了!快手重磅发布Kling-Avatar,面向多模态指令理解与控制的数字人长视频生成新范式
人工智能
GarrettGao20 小时前
Frida常见用法
javascript·python·逆向