深度剖析 Agent 框架:以 LangGraph 为例,探索 AI 开发新范式
❝
Agent 系列第四篇,后续持续更新 。 Agent 框架正在彻底改变人工智能系统的运行方式,使智能、自主的 Agent 能够动态推理、计划和交互。在文章中,我们探讨了 Agent 框架的重要性,介绍了 8 个 Agent 框架,并比较了它们的优势。然后,我们深入研究了 LangGraph,了解了它基于图的架构、状态管理和现实世界的应用程序。动手部分展示了如何使用 LangGraph 构建具有内存、人在回路功能和可扩展工作流的人工智能 Agent。
更多 LLM 架构文章点击查看:LLM 架构专栏
大模型架构专栏文章阅读指南
Agent系列 1W字用Python从零搭建AI智能体
欢迎加入大模型交流群:加群链接[1] https://docs.qq.com/doc/DS3VGS0NFVHNRR0Ru#
公众号【柏企阅文】
1. 介绍
Agent 框架让自主系统能够动态感知、推理和行动,彻底革新了人工智能领域。本节将深入探究 Agent 框架的核心概念,并着重强调开源解决方案在现代 AI 开发中,对于创新和可扩展性的重要意义。
1.1 什么是 Agent 框架?
Agent 框架代表着人工智能系统设计模式的重大转变。与依赖静态、预定义工作流程的传统 AI 应用程序不同,Agent 框架引入了动态自适应系统,该系统具备自主感知、推理和行动的能力。这些框架可以把复杂任务拆解成多个小子任务,交给专门的 Agent 协作完成,以实现更宏大的目标。借助大型语言模型(LLM),Agent 框架能够管理工作流程、做出决策,还能无缝集成各种工具,这使得它成为动态决策、实时问题解决等高级应用的理想之选。
关键参考:像 LangGraph 和 CrewAI 这样的 Agent 框架,就是这种动态方法的典型代表,它们帮助开发者突破单 Agent、线性工作流程的局限,进入多 Agent 协作系统的全新领域。
1.2 为什么它们很重要?
从头开始构建 Agent 绝非易事。LangGraph、CrewAI 和 OpenAI Swarm 等框架大大简化了这个过程,让开发者能够把精力集中在应用程序逻辑上,而不用在状态管理、编排和工具集成这些方面重复造轮子。
Agent 框架的核心优势体现在:
-
定义 Agent 和工具的简便方式:提供简单直观的方法来定义 Agent 和工具,降低开发门槛。 -
编排机制:具备高效的编排机制,能够合理安排任务执行顺序。 -
状态管理:实现可靠的状态管理,确保系统在运行过程中状态的稳定和准确。 -
附加工具:拥有一系列附加工具,可支持更复杂的应用开发,比如持久层(内存)、中断处理等功能。
接下来的章节,我们将详细介绍这些内容。
2. 流行的 Agent 框架和库
现在,让我们深入了解当下一些最知名的 AIAgent 框架和工具:
2.1 Langchain
LangChain 是一个强大且适应性很强的框架,它让开发由大型语言模型(LLM)驱动的应用程序变得更加轻松。凭借丰富的工具集和抽象概念,开发者利用它可以设计出功能强大的人工智能 Agent,这些 Agent 具备复杂推理、任务执行能力,还能与外部数据源和 API 进行交互。
从根本上讲,在长时间对话中保持上下文连贯性、整合外部信息以及协调多步骤项目,是开发者在与 LLM 合作时面临的几个难题,而 LangChain 恰好能解决这些问题。得益于其模块化架构,该框架可以很方便地由各种组件组合而成,满足不同的开发需求。
**langchain github** [2]
**langchain 文档链接**[3]
2.2 LangGraph
LangGraph 是 LangChain 的扩展框架,它支持使用大型语言模型(LLM)创建有状态的多参与者应用程序。在构建涉及规划、反思、思考以及多 Agent 协作的复杂交互式 AI 系统时,LangGraph 特别有用。
GitHub 链接:LangGraph [4]
文档链接:LangGraph 文档[5]
2.3 CrewAI
CrewAI 是一个用于编排角色扮演 AIAgent 的框架。借助它,开发者能够创建一个 AIAgent“团队”,团队中的每个 Agent 都有明确的角色和职责,共同协作完成复杂任务。对于构建那些需要多种专业知识协同合作,以解决多方面问题的协作 AI 系统而言,这个框架非常实用。
GitHub 链接:CrewAI GitHub[6]文档:CrewAI 文档[7]
2.4 微软语义内核(Microsoft Semantic Kernel)
微软语义内核旨在缩小传统软件开发和人工智能能力之间的差距,尤其专注于将大型语言模型(LLM)集成到现有的应用程序中。该框架为开发者提供了一系列工具,使得他们无需彻底修改现有代码库,就能轻松融入人工智能功能。
SDK 的轻量级特性以及对多种编程语言的支持,让它能很好地适应各种开发环境。其编排器可以管理复杂的多步骤人工智能任务,帮助开发者在应用程序内创建复杂的 AI 驱动工作流。
GitHub 链接:Microsoft Semantic Kernel github[8]
文档链接:Microsoft 语义内核 documentation [9]
2.5 微软 AutoGen(Microsoft AutoGen)
Microsoft AutoGen 是一个开源框架,主要用于构建高级 AIAgent 和多 Agent 系统。它由微软研究院开发,为创建对话式和任务完成型的 AI 应用程序,提供了一套灵活且强大的工具包。该框架强调模块化、可扩展性和易用性,能帮助开发者高效构建复杂的 AI 系统。
**AutoGen 文档**[10]GitHub 链接:Microsoft Autogen[11]
2.6 Smolagents
Smolagent 是一个处于前沿的开源框架,旨在彻底变革人工智能 Agent 的开发方式。它为开发者提供了一套全面的工具包,用于构建智能、协作的多 Agent 系统。该框架注重灵活性和模块化,所创建的复杂人工智能系统既可以独立运行,也能在人类监督下协同工作。
**Smolagents 文档**[12]**Smolagents GitHub 链接**[13]
2.7 AutoGPT
AutoGPT 基于强大的 GPT-4 语言模型,通过语言输入就能执行目标导向的任务,它标志着自主人工智能 Agent 领域取得了重大进展。这款先进的人工智能助手将决策能力提升到了新高度,超越了基础的反射 Agent,集成了众多复杂功能,使其在各类应用场景中都极具价值。
**AutoGPT 文档**[14]**AutoGPT GitHub 链接**[15]
2.8 Agno(Phidata)
我们要讨论的最后一个 AIAgent 框架是 Phidata。这是一个多模态 Agent 框架,可用于开发协作执行任务的 Agent 系统。它还能与内存、工具等组件协同工作,助力 Agent 自主、稳定地运行。
默认情况下,PhidataAgent 支持文本、图像、音频等多模态数据,这使得它无需依赖外部工具就具备很高的价值。该框架还提供了 Agent 用户界面,如果您喜欢通过可视化方式与 Agent 交互,这个界面就能派上用场。此外,他们还是 Agent 检索增强生成(Agentic RAG)技术的先驱,Agent 可以利用该技术搜索知识库。
**Phidata 文档**[16]**Phidata GitHub 链接**[17]
3. Agent 框架的比较
下面的图表对本文讨论的关键 AIAgent 框架进行了高层次的对比。通过这种对比,我们可以清楚地看到每个框架的独特优势和重点应用领域,方便开发者和研究人员根据自身具体需求,选择最合适的工具。
4. 深入了解 LangGraph
LangGraph 是 LangChain 团队开发的一个库,目的是帮助开发者创建基于图的单 Agent 或多 AgentAI 应用程序。作为底层框架,LangGraph 赋予开发者控制 Agent 交互方式、工具选择以及应用程序内信息流的能力。
4.1 什么是图?
想象一下,有一组数据可以用网络来表示,其中每个数据或实体都与其他数据或实体存在某种关系,而且这种关系可以是一对一、一对多、多对多等多种类型。图主要由两个部分组成:节点和边。
交通数据、社交媒体网络数据就是这类数据的典型例子。在社交媒体网络中,每个用户与其他用户之间都存在关联关系,使用图结构能够很直观地将这种数据可视化呈现出来。
图主要分为两种类型:
-
有向图:在有向图中,边是有方向的,它表示节点之间的流向或关系。比如在社交媒体上的“关注”关系,就可以用有向图来表示。 -
无向图:无向图中的边没有方向,代表着对称关系。像领英上的“连接”关系,就是无向图的体现。
4.2 关键概念
4.2.1 图结构
LangGraph 设计的核心,是用基于图的方式来表示应用程序的工作流程。这个图主要包含两个基本元素:
-
节点——工作的基本单元:LangGraph 中的每个节点,都代表着应用程序中一个独立的工作或操作单元。这些节点本质上是用 Python 编写的函数,封装了特定的任务。这些任务涵盖范围很广,例如: -
与 LLM 直接通信,进行文本生成、摘要提取或其他基于语言的任务。 -
与外部工具和 API 交互,获取数据或在现实场景中执行操作。 -
通过格式化、过滤、转换等操作处理数据。 -
与用户进行交互,收集用户输入或展示信息。 -
边——信息流和控制的引导者:边在 LangGraph 中就像连接组织一样,为信息流构建路径,并决定操作的执行顺序。LangGraph 支持多种类型的边: -
简单边:简单边表示从一个节点到另一个节点的直接、无条件的信息流。前一个节点的输出会直接作为后一个节点的输入,形成线性的处理流程。 -
条件边:条件边为工作流程引入了动态特性,它能让工作流根据特定节点的操作结果进行分支。比如,根据用户的回复内容,图结构可以决定是终止交互,还是继续调用某个工具。这种决策能力对于开发能够适应不同场景的应用程序至关重要。
4.2.2 状态管理
管理多 Agent 系统时,确保所有 Agent 对任务当前状态有一致的理解是非常关键的。LangGraph 通过自动状态管理机制解决了这个问题。这意味着,当 Agent 执行任务时,该库会自动对中央状态对象进行跟踪和更新。
这个状态对象就像是一个信息仓库,存储着工作流程中不同节点都可能需要访问的关键信息,主要包括:
-
对话历史:在聊天机器人应用里,状态可以记录用户和机器人之间的实时对话内容,这样机器人就能根据上下文给出更合适的回复。 -
上下文数据:与当前任务相关的信息,比如用户偏好、过往行为数据,或者相关的外部数据等,都可以存储在状态中,供 Agent 在决策时参考。 -
内部变量:Agent 可以利用状态来记录内部标志、计数器或其他变量,这些变量会影响 Agent 的行为和决策。
5. 动手使用 LangGraph
5.1 安装
要开始使用 LangGraph,首先需要进行安装。在终端或命令提示符中,输入以下命令:
pip install -U langgraph
这个命令会下载并安装最新版本的 LangGraph。其中,-U
参数用于确保安装的是最新版。
5.2 在 LangGraph 中创建基本聊天机器人
这个示例是帮助大家理解 LangGraph 基本概念的绝佳起点。
-
导入必要的库:首先,从 LangGraph 和其他相关库中导入所需的类和模块。
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
-
定义状态结构:创建一个类,用于定义状态对象的结构。这个状态对象将存储图中节点之间需要共享和更新的信息。
class State(TypedDict):
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
-
初始化 LLM:实例化你选择的 LLM 模型,并提供必要的 API 密钥或配置参数。这个 LLM 将为聊天机器人的回复提供支持。
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-3-5-sonnet-20240620")
-
创建聊天机器人节点:定义一个 Python 函数,封装聊天机器人节点的逻辑。该函数以当前状态作为输入,并根据 LLM 的输出生成回复。
def chatbot(state: State):
response = llm.invoke(state["messages"])
return {"messages": [response]}
graph_builder.add_node("chatbot", chatbot)
-
定义入口和终点:在图中明确工作流程的起始点和结束点。
graph_builder.add_edge(START, "chatbot")
graph_builder.add_edge("chatbot", END)
-
编译图形:通过编译,创建图的可运行实例。
graph = graph_builder.compile()
-
可视化图形:运行一段简单的 Python 代码,就能将包含节点和边的图可视化展示出来。
from IPython.display import Image, display
try:
display(Image(graph.get_graph().draw_mermaid_png()))
except Exception:
pass
-
运行聊天机器人:实现一个循环,用于与用户交互。将用户输入传递给图,并展示聊天机器人的回复。
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)
这段代码为 LangGraph 聊天机器人搭建了一个基础框架。你可以在此基础上进一步扩展,比如引入更复杂的状态管理机制、更换不同的 LLM 模型,或者连接外部工具和 API。关键在于,要为不同任务定义清晰的节点,并通过边来设定聊天机器人内部的信息流和控制流程。
5.3 高级图形技术
工具集成:将工具集成到 LangGraph 聊天机器人中,可以让它按照你的需求访问和处理信息,从而显著提升其功能。使用工具集成增强我们的基本聊天机器人:我们对上一节创建的基本聊天机器人进行修改,添加一个能在网络上搜索信息的工具。这里我们使用langchain_community.tools.tavily_search
中的TavilySearchResults
工具,使用这个示例需要 Tavily API 密钥。
from typing import Annotated
from langchain_anthropic import ChatAnthropic
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import BaseMessage
from typing_extensions import TypedDict
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
class State(TypedDict):
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
tool = TavilySearchResults(max_results=2)
tools = [tool]
llm = ChatAnthropic(model="claude-3-5-sonnet-20240620")
llm_with_tools = llm.bind_tools(tools)
def chatbot(state: State):
return {"messages": [llm_with_tools.invoke(state["messages"])]}
graph_builder.add_node("chatbot", chatbot)
tool_node = ToolNode(tools=[tool])
graph_builder.add_node("tools", tool_node)
graph_builder.add_conditional_edges(
"chatbot",
tools_condition,
graph_builder.add_edge("tools", "chatbot")
)
graph_builder.set_entry_point("chatbot")
graph = graph_builder.compile()
解释:
-
导入工具:导入所需的工具类,在这个例子里是 TavilySearchResults
。 -
定义和绑定工具:创建工具实例,并使用 llm.bind_tools()
将其绑定到 LLM 上。这样 LLM 就能知道有哪些可用工具以及如何使用它们。 -
创建 ToolNode:实例化一个 ToolNode
,并传入可用工具列表。 -
将 ToolNode 添加到图中:使用 graph_builder.add_node()
把ToolNode
添加到 LangGraph 中。 -
条件路由:利用 graph_builder.add_conditional_edges()
,根据 LLM 是否决定调用工具来设置路由逻辑。tools_condition
函数会检查 LLM 的回复中是否包含工具调用指令。 -
循环返回:工具执行完成后,使用 graph_builder.add_edge()
将流程引导回聊天机器人节点,以便对话能够继续进行。
现在,当你运行这个聊天机器人,并提出一个需要外部信息的问题时,LLM 可以选择调用网络搜索工具,获取相关数据,并将其融入到回复中。
6. 为聊天机器人添加 memory
记忆对于创建聊天机器人至关重要,这些聊天机器人可以通过记住过去的互动来进行有意义的对话。
LangGraph 的检查点系统
-
检查指针:当你编译你的 LangGraph 时,你可以提供一个检查指针对象。该对象负责保存图在不同时间点的状态。 -
线程 ID:每次调用图时,都提供一个 thread_id。检查指针使用此 ID 来跟踪不同的对话线程。 -
自动保存和加载:LangGraph 自动保存给定 thread_id 的图执行的每一步后的状态。当您再次使用相同的 thread_id 调用图时,它会自动加载保存的状态,使聊天机器人能够从中断的地方继续对话。
使用检查点实现内存
在前面代码的基础上,以下是如何使用 LangGraph 的检查点添加内存:
from langgraph.checkpoint.memory import MemorySaver
memory = MemorySaver()
graph = graph_builder.compile(checkpointer=memory)
解释:
-
导入 MemorySaver:从 langgraph.checkpoint.memory
导入MemorySaver
类。 -
创建一个 MemorySaver 对象:实例化一个 MemorySaver 对象,它将处理保存和加载图的状态。 -
**传递给 compile()**:编译图时,将 memory 对象作为 checkpointer 参数传递。
现在,当您运行聊天机器人时,首先,使用 thread_id 作为此对话的密钥:
config = {"configurable": {"thread_id": "1"}}
每个唯一的 thread_id 都将存储其对话历史记录。
现在开始对话:
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)]}, config):
for value in event.values():
print("Assistant:", value["messages"][-1].content)
注意:调用我们的图时,配置作为第二个位置参数提供。
Human in the Loop
对于希望将人工监督、验证或决策纳入 AI 应用程序的情况,人在回路工作流至关重要。
使用中断实现人在环
下面的代码说明了使用 LangGraph 的interrupt_before
或interrupt_after
功能的人在循环实现。
from typing import Annotated
from langchain_anthropic import ChatAnthropic
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import BaseMessage
from typing_extensions import TypedDict
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
class State(TypedDict):
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
tool = TavilySearchResults(max_results=2)
tools = [tool]
llm = ChatAnthropic(model="claude-3-5-sonnet-20240620")
llm_with_tools = llm.bind_tools(tools)
def chatbot(state: State):
return {"messages": [llm_with_tools.invoke(state["messages"])]}
graph_builder.add_node("chatbot", chatbot)
tool_node = ToolNode(tools=[tool])
graph_builder.add_node("tools", tool_node)
graph_builder.add_conditional_edges(
"chatbot",
tools_condition,
graph_builder.add_edge("tools", "chatbot")
)
graph_builder.set_entry_point("chatbot")
memory = MemorySaver()
graph = graph_builder.compile(
checkpointer=memory,
interrupt_before=["tools"],
)
解释:
在此特定示例中,图表将在执行 tools 节点之前暂停。此 tools 节点负责运行 LLM 在轮到它时可能请求的任何工具。通过在这一点上中断,您基本上可以允许人类:
-
批准工具调用:人类可以查看 LLM 想要进行的工具调用及其输入。如果他们认为合适,他们可以简单地允许图形继续,并且工具将被执行。 -
修改工具调用:如果人类看到需要调整 LLM 的工具调用(例如,细化搜索查询),他们可以修改图的状态,然后恢复执行。 -
绕过工具调用:人类可能会决定不需要该工具。也许他们有 LLM 试图查找的答案。在这种情况下,他们可以用适当的信息更新图形状态,LLM 将收到它,就好像工具已经返回了该信息一样。
资源:https://github.com/langchain-ai/langgraph/blob/main/docs/docs/how-tos/human_in_the_loop/review-tool-calls.ipynb
LangGraph 的实际用途
LangGraph 通过管理状态、协调多个 Agent 并允许人工反馈,让您可以构建比简单的问答机器人更复杂和更具交互性的 AI 系统。以下是可以使用 LangGraph 的一些方式:
-
更聪明的客户服务:想象一个在线购物聊天机器人,它可以记住你过去的订单和偏好。它可以回答有关产品的问题,跟踪您的货物,甚至在需要时将您与人类代表联系起来。 -
AI 研究助手:研究项目需要帮助?支持 LangGraph 的助手可以搜索大量学术论文和文章,总结关键发现,甚至帮助您组织笔记。 -
个性化学习:LangGraph 可以为下一代教育平台提供动力。想象一个系统,它能适应你的学习风格,识别你需要额外帮助的领域,并推荐个性化资源。 -
精简的业务:许多业务流程涉及多个步骤和人员。LangGraph 可以自动化这些工作流程的一部分,例如路由文档以供批准、分析数据或管理项目。
这些示例突出了 LangGraph 如何帮助弥合 AI 功能与现实世界情况的复杂性之间的差距。
结论
Agent 框架正在彻底改变人工智能系统的运行方式,使智能、自主的 Agent 能够动态推理、计划和交互。在文章中,我们探讨了 Agent 框架的重要性,介绍了一些最流行的库,并比较了它们的优势。然后,我们深入研究了 LangGraph,了解了它基于图的架构、状态管理和现实世界的应用程序。动手部分展示了如何使用 LangGraph 构建具有内存、人在回路功能和可扩展工作流的人工智能 Agent。