由大语言模型(LLMs)驱动的自主智能体经历了起起伏伏。从 2023 年 AutoGPT 和 BabyAGI 的爆火演示,到如今更为成熟的框架,智能体的概念——即可以自主执行端到端任务的 LLM——既激发了人们的想象,也引发了怀疑。
为什么又重新引起关注?过去 9 个月里,LLM 取得了显著进步:更长的上下文窗口、更结构化的输出、更强的推理能力,以及更简单的工具集成。这些进展让构建可靠的智能体应用比以往任何时候都更可行。
在这篇文章中,我们将探索三种构建智能体应用的流行框架:LangGraph、CrewAI 和 OpenAI Swarm。通过一个 Agentic Finance Assistant 的动手示例,我们将突出展示每个框架的优势、劣势以及实际使用场景。
1、什么是智能体?
智能体是由大语言模型(LLMs)驱动的高级系统,能够独立与其环境交互,并实时做出决策。与传统的 LLM 应用不同,后者通常是按照固定的、预定义的流水线结构(例如 A → B → C)执行,而智能体工作流则引入了一种动态且自适应的方式。
智能体可以利用工具(即函数或 API)来与环境进行交互,并根据上下文与目标来决定下一步的行动。这种灵活性使智能体能够突破固定顺序的限制,从而实现更自主、高效的工作流,适应复杂且不断变化的任务。
然而,这种灵活性也带来了新的挑战:
- 跨任务的状态和记忆管理
- 多个子智能体之间的协调与通信机制
- 确保工具调用的可靠性,并处理复杂的错误情况
- 在大规模环境中进行推理和决策
2、为什么我们需要智能体框架?
从零开始构建智能体并非易事。像 LangGraph、CrewAI 和 OpenAI Swarm 这样的框架简化了这个过程,使开发者可以专注于应用逻辑,而不必重复造轮子去处理状态管理、流程编排和工具集成等问题。
在本质上,智能体框架提供了:
- 一种简单方式来定义智能体和工具
- 一套编排机制
- 状态管理能力
- 支持更复杂应用的附加功能,例如:持久化内存、中断处理等
我们将在接下来的章节中逐一讲解这些功能。
3、智能体框架简介
我们选择 LangGraph、CrewAI 和 OpenAI Swarm,是因为它们代表了当前智能体开发领域中三种最新的设计理念。以下是简要概览:
LangGraph:顾名思义,LangGraph 以图结构(graph architecture)为核心,认为这是定义和编排智能体工作流的最佳方式。与早期版本的 LangChain 不同,LangGraph 是一个为生产环境打造的、设计良好的框架,具备许多健壮且可自定义的特性。不过,对于某些用例来说,它有时可能过于复杂,并带来额外的学习和维护成本。
CrewAI:相比之下,CrewAI 更加简洁易用。它提供了直观的抽象方式,让你专注于任务设计,而不必过多编写复杂的编排或状态管理逻辑。但代价是:它是一个“约束性很强”的框架,在未来需要高度定制时可能不太灵活。
OpenAI Swarm:这是一个轻量级、极简主义的框架,OpenAI 将其定位为“教学用”而非“生产就绪”。它几乎可以被视为一种“反框架” —— 许多功能都由开发者自行实现,或交由强大的 LLM 自行推理完成。我们认为,它非常适合当前用例较简单的用户,或者希望将轻量智能体工作流整合进现有 LLM 流程的人群。
4、其他值得关注的框架
LlamaIndex Workflow:这是一个事件驱动的框架,从概念上讲非常适合很多智能体工作流。不过就目前而言,我们发现它仍需要开发者编写大量样板代码(boilerplate)才能运行。 LlamaIndex 团队正在积极改进该框架,我们也希望他们能尽快引入更多高级抽象。
AutoGen:由微软开发的用于多智能体对话编排的框架。AutoGen 已被用于多种智能体相关的应用场景。在吸取早期版本(如 v0.2)中存在的问题和用户反馈后,AutoGen 团队正在对其进行彻底重构(目前进入 v0.4),转向事件驱动式编排框架。
5、构建一个智能金融助手
为了对这些框架进行基准测试,我们使用每个框架构建了相同的智能金融助手应用。完整的示例代码可在此查看:Relari Agent Examples[2])。
我们希望这个智能体能够处理复杂的查询,例如:
- Spirit 航空的财务健康状况相比竞争对手如何?
- Apple 财务表现最好的产品线是什么?他们在官网上是如何宣传的?
- 请帮我找出一些市值低于 50 亿美元、且年度营收增长超过 20% 的消费类股票
以下是我们希望从助手中看到的一个完整回答片段示例:
为了实现这些目标,我们为智能体系统提供了对金融数据库的访问权限(通过 FMP[3]) API),
以及访问互联网以研究网络内容的能力。
在构建一个智能体式 AI 应用时,我们首先需要做出的关键决策之一是系统架构的选择。 目前有多种架构可选,每种架构都有其优缺点。在下图中,LangGraph 总结了几种常见的智能体架构形式 (你可以在这里阅读更多关于架构选择的内容:multi-agent architecture[4]))。
出于教学目的,我们为本应用选择了监督者架构(Supervisor Architecture)。 因此,我们将创建一个“Supervisor Agent(主管智能体)”,其职责是判断任务应交由哪个子智能体处理。
我们还将创建三个具有工具访问能力的子智能体:金融数据智能体,网页研究智能体,内容摘要智能体。
接下来我们将深入探讨每个框架在以下几个方面的实现方式:智能体的创建 ,工具的集成 ,编排机制, 状态记忆管理 ,与人类交互环节。
5.1、 定义智能体与工具
我们首先来看如何在不同框架中定义普通智能体,比如金融数据智能体、网页研究智能体和结果摘要智能体,并为它们声明相关的工具。而“Supervisor Agent(主管智能体)”是一个特殊角色,主要负责流程编排,我们将在“编排”部分单独介绍它。
LangGraph
在 LangGraph 中,创建一个具备调用工具能力的简单智能体最方便的方法,是使用预构建函数 create_react_agent
,你可以在其中提供该智能体可调用的工具及其提示词(prompt)。
from langgraph.prebuilt import create_react_agent
from langchain_openai importChatOpenAI
from langchain_core.tools import tool
# 以下是一个工具的定义示例
@tool
def get_stock_price(symbol: str)-> dict:
"""获取指定股票代码的当前股价。
参数:
symbol (str):股票代码(如"AAPL"表示苹果公司)。
返回:
dict:包含股价信息或错误消息的字典。
"""
base_url ="https://financialmodelingprep.com/api/v3/quote-short"
params={"symbol": symbol,"apikey": os.getenv("FMP_API_KEY")}
response = requests.get(base_url,params=params)
if response.status_code ==200:
data = response.json()
if data:
return{"price": data[0]["price"]}
return{"error":"无法获取股票价格。"}
# 以下是一个简单的 react 智能体示例
financial_data_agent = create_react_agent(
ChatOpenAI(model="gpt-4o-mini"),
tools=[get_stock_price, get_company_profile,...],
state_modifier="你是一个金融数据智能体,负责使用提供的 API 工具获取金融数据 ...",
)
在 LangGraph 中,一切都围绕图结构进行组织。create_react_agent
这个工具函数会创建一个简单的可执行图,其中包含智能体节点和工具节点。智能体作为决策者,会动态判断应调用哪些工具,并评估当前是否已获得足够的信息以过渡到 __end__
状态。
在图结构中,实线代表确定性边(工具节点必须返回至智能体),而虚线代表条件边,由 LLM 驱动的智能体根据当前上下文自主决定下一步走向。
节点(nodes)与边(edges)是图的基本构建单元。我们将在后面的“编排”部分看到,这个图实际上也可以作为更大、更复杂图中的一个节点存在。
CrewAI
CrewAI 的智能体定义以“智能体与任务之间的关系”为核心展开,即:每个智能体被创建是为了完成某一具体任务(task)。
对于每个智能体,我们需要定义:它的角色(role)
,它的目标(goal)
,它的背景故事(backstory)
,以及它可访问的工具(tools)
。
from crewai importAgent,Task
# 定义金融数据智能体
financial_data_agent =Agent(
role="金融数据智能体",
goal="使用 FMP API 获取完整的金融数据,以回答用户提出的问题",
backstory="""你是一名经验丰富的金融数据搜集专家,擅长获取各种金融信息。
你以精准著称,能够使用 FMP API(该接口提供美国上市公司的金融数据)
找到最相关的数据点,以满足用户需求。""",
tools=[
StockPriceTool(),
CompanyProfileTool(),
...
]
)
接下来我们需要定义任务(Task),即该智能体需要执行的具体操作。 每个任务必须包含描述(description)
和预期输出(expected_output)
。
# 定义任务:收集金融数据
gather_financial_data =Task(
description=("进行全面的金融研究,收集能够帮助解答用户问题的相关金融数据:{query}。"
"使用可用的金融工具获取准确、最新的信息。"
"重点关注股票价格、公司概况、财务比率及其他相关财务指标,以回答用户问题:{query}。"),
expected_output="一组完整的金融数据点,能够直接回应用户的问题:{query}。",
agent=financial_data_agent,
)
这种结构化的提示词构建方式为 LLM 提供了清晰一致的框架,确保智能体与任务被明确定义。
这种方法有助于保持聚焦与一致性,但在反复定义角色(role)、目标(goal)、背景故事(backstory)和任务描述时,有时会显得较为僵硬或重复。
工具的集成可以使用 @tool
装饰器,这与 LangGraph 中的方式类似。 值得一提的是,另一种可选方法是继承 BaseTool
类,这是一种更健壮的方式,能够借助 Pydantic 模型来强制执行工具的输入结构。(这种方法在 LangGraph 中同样受到支持。)
# 定义股票价格查询的输入结构
classStockPriceInput(BaseModel):
"""股票价格查询的输入结构。"""
symbol: str =Field(..., description="股票代码")
# 定义股票价格查询工具
classStockPriceTool(BaseTool):
name: str ="获取股票价格"
description: str ="获取指定股票代码的当前股价"
args_schema:Type[BaseModel]=StockPriceInput
def _run(self, symbol: str)-> dict:
# 使用 FMP API 查询指定股票的价格
OpenAI Swarm
Swarm 采用了不同的方式:它并不要求你在代码中显式定义推理流程,而是建议你在系统提示词中将流程结构化,称为“Routines(常规流程)”,即一组智能体为了完成任务所遵循的预定义步骤或指令。这种设计方式来自 OpenAI 也不难理解 —— 他们更希望开发者依赖模型自身的“指令跟随能力”,而不是用代码去显式编排一整套逻辑流程。我们发现,这种方式在与一个较强的 LLM 协作时非常简洁且高效,尤其当模型能够很好地追踪并推理这些 Routine 步骤时。
对于工具,我们可以直接作为函数传入即可:
from swarm importAgent
# 定义金融数据智能体
financial_data_agent =Agent(
name="Financial Data Agent",
instructions="""你是一名金融数据专家,负责使用提供的 API 工具获取金融数据。
你的任务:
步骤1:根据用户查询,使用合适的工具抓取相关金融数据
步骤2:读取数据并确认其是否足以回答用户问题。如不足,请修改工具输入或使用其他工具补充信息
步骤3:一旦收集到足够信息,仅返回工具获取的原始数据。不要添加解释或评论""",
functions=[
get_stock_price,
get_company_profile,
...
]
)
5.2、编排(Orchestration)
现在我们来看每个框架的核心部分 —— 它们是如何将多个子智能体组织协调在一起的。
LangGraph
LangGraph 的核心是基于图的编排机制。 我们首先创建一个主管智能体(supervisor agent), 它的职责是作为“路由器”来分析当前情境,并决定接下来由哪个子智能体执行任务。
执行型智能体本身只能将结果返回给主管智能体,不能直接互相通信。
LangGraph 要求你显式定义状态结构。 AgentState
类可用于在多个智能体之间定义统一的状态模式(schema):
classAgentState(TypedDict):
messages:Annotated[Sequence[BaseMessage],operator.add]
next: str
对于每个智能体,我们通过封装为节点的形式与状态交互, 将其输出转换为统一的消息结构:
async def financial_data_node(state):
result = await financial_data_agent.ainvoke(state)
return{
"messages":[
AIMessage(
content=result["messages"][-1].content, name="Financial_Data_Agent"
)
]
}
接下来我们就可以定义主管智能体本身了:
classRouteResponse(BaseModel):
next:Literal[OPTIONS]
def supervisor_agent(state):
prompt =ChatPromptTemplate.from_messages([
("system", ORCHESTRATOR_SYSTEM_PROMPT),
MessagesPlaceholder(variable_name="messages"),
(
"system",
"根据上方对话内容,接下来应由谁执行任务?或者是否该结束?从以下选项中选择一个:{options}",
),
]).partial(options=str(OPTIONS), members=", ".join(MEMBERS))
supervisor_chain = prompt | LLM.with_structured_output(RouteResponse)
return supervisor_chain.invoke(state)
在定义完主管智能体(Supervisor Agent)后,我们将整个智能体工作流作为一个图(graph)进行构建:每个智能体对应图中的一个节点,所有的执行逻辑通过边(edges)连接。
在定义边时,有两种方式可选:
- 普通边(regular edges):用于确定性流转。
例如:金融数据智能体完成任务后,总是返回结果给 Supervisor_Agent,由其决定下一步。 - 条件边(conditional edges):用于当我们希望 LLM 根据上下文判断下一步路径时。
例如:Supervisor Agent 可以判断是否已有足够信息,可以直接交给 Output Summarizing Agent,或者是否还需要返回 Financial Data Agent 或 Web Research Agent 继续获取数据。
from langgraph.graph importEND, START,StateGraph
def build_workflow()->StateGraph:
"""构建整个智能体工作流的状态图。"""
workflow =StateGraph(AgentState)
# 添加各个智能体节点
workflow.add_node("Supervisor_Agent", supervisor_agent)
workflow.add_node("Financial_Data_Agent", financial_data_node)
workflow.add_node("Web_Research_Agent", web_research_node)
workflow.add_node("Output_Summarizing_Agent", output_summarizing_node)
# 普通边:执行完任务后回到主管智能体
workflow.add_edge("Financial_Data_Agent","Supervisor_Agent")
workflow.add_edge("Web_Research_Agent","Supervisor_Agent")
# 条件边:由 Supervisor_Agent 决定下一步走向
conditional_map ={
"Financial_Data_Agent":"Financial_Data_Agent",
"Web_Research_Agent":"Web_Research_Agent",
"Output_Summarizing_Agent":"Output_Summarizing_Agent",
"FINISH":"Output_Summarizing_Agent",
}
workflow.add_conditional_edges(
"Supervisor_Agent",lambda x: x["next"], conditional_map
)
# 结束边与起始边
workflow.add_edge("Output_Summarizing_Agent",END)
workflow.add_edge(START,"Supervisor_Agent")
return workflow
📈 最终生成的图如下图所示。
CrewAI
与 LangGraph 相比,CrewAI 抽象掉了大部分编排逻辑。
supervisor_agent =Agent(
role="金融助手主管",
goal="利用你的团队技能来回答用户的问题:{query}。",
backstory="""你是一位金融助手团队的主管,
擅长管理不同技能的成员,并确保借助同事的帮助回答用户问题。
你总是优先通过金融数据智能体和网页抓取智能体获取数据。
获取数据之后,你必须将任务委派给内容总结智能体,
由它生成综合报告,而不是你直接回答用户问题。""",
verbose=True,
llm=ChatOpenAI(model="gpt-4o", temperature=0.5),
allow_delegation=True,
)
和 LangGraph 类似,我们首先创建主管智能体(Supervisor Agent)。注意其中的 allow_delegation
参数,它允许该智能体将任务委派给其他智能体执行。
接下来,我们使用Crew
来将所有智能体组合在一起。关键点:这里必须使Process.hierarchical
,以支持主管智能体进行任务分配。在后台,主管智能体会将用户的查询转换为任务,并自动匹配合适的智能体去完成这些任务。
如果不使用主管智能体,也可以选择Process.sequential
,以创建一个按顺序执行的确定性流程。
finance_crew =Crew(
agents=[
financial_data_agent,
web_scraping_agent,
output_summarizing_agent
],
tasks=[
gather_financial_data,
gather_website_information,
summarize_findings
],
process=Process.hierarchical,
manager_agent=supervisor_agent,
)
OpenAI Swarm
Swarm 的编排方式采用的是非常简单的策略 —— 任务移交(handoffs)。核心思想是创建一个**“转移函数”**,让一个智能体作为工具调用另一个智能体。
这无疑是最简洁的一种方法,智能体之间的关系是通过这些转移函数隐式建立的。
def transfer_to_summarizer():
return summarizing_agent
def transfer_to_web_researcher():
return web_researcher_agent
def transfer_to_financial_data_agent():
return financial_data_agent
# 定义主管智能体
supervisor_agent =Agent(
name="Supervisor",
instructions="""你是一名主管智能体,负责协调金融数据智能体、网页研究智能体和总结输出智能体。
你的任务:
1.根据用户的查询内容,决定将任务委派给哪个智能体;
2.如果查询涉及金融数据,委派给金融数据智能体;
3.如果查询涉及网络调研,委派给网页研究智能体;
4.如果已有足够信息可用于回答问题,委派给总结输出智能体生成最终结果。
请**不要自己总结数据**,最终输出必须由总结智能体提供。
""",
functions=[# 将其他智能体作为“工具”使用
transfer_to_financial_data_agent,
transfer_to_web_researcher,
transfer_to_summarizer
]
)
这种方法的一个缺点是:随着应用规模的增长,智能体之间的依赖关系变得难以追踪和维护。
5.3、记忆
记忆是有状态智能体系统中的关键组成部分。我们可以将记忆划分为两个层级:
- 短期记忆:允许智能体执行多轮对话或多步骤操作;
- 长期记忆:允许智能体跨会话学习和记住偏好。
这个话题可以非常复杂,但我们先来看看各个框架中最简单的记忆编排方法。
LangGraph
LangGraph 将记忆区分为两种:
- 线程内记忆(in-thread memory):即单个对话线程中的记忆;
- 跨线程记忆(cross-thread memory):即多个对话线程之间共享的记忆。
要保存线程内记忆,LangGraph 提供了 MemorySaver()
类,它会将图状态或对话历史记录保存到一个**检查点器(checkpointer)**中。
from langgraph.checkpoint.memory importMemorySaver
def build_app():
"""构建并编译工作流。"""
memory =MemorySaver()
workflow = build_workflow()
return workflow.compile(checkpointer=memory)
要将一次智能体执行与某个记忆线程关联起来,只需要传入一个包含 thread_id 的配置对象即可。 这表示告诉智能体使用哪一个线程的记忆检查点。
例如:
config ={"configurable":{"thread_id":"1"}}
app = build_app()
await run(app, input, config)
要保存跨线程记忆,LangGraph 允许我们将记忆保存到 **JSON 文档存储(Document Storage)**中。
from langgraph.store.memory importInMemoryStore
store =InMemoryStore()# Can be a DB-backed store in production use
user_id ="user_0"
store.put(
user_id,
"current_portfolio",
{
"portfolio":["TSLA","AAPL","GOOG"],
}
)
CrewAI
不出所料,CrewAI 采用了更简单但也更刚性的方式。
开发者只需要将 memory
设置为 True
即可。
finance_crew =Crew(
agents=[financial_data_agent, web_researcher_agent, summarizing_agent],
tasks=[gather_financial_data, gather_website_information, summarize_findings],
process=Process.hierarchical,
manager_agent=supervisor_agent,
memory=True,# 在 "CREWAI_STORAGE_DIR" 文件夹中创建记忆数据库
verbose=True,# 使用记忆时必须设置为 True
)
虽然配置简单,但其背后的实现非常复杂,它会创建几种不同的记忆存储:
- 短期记忆:使用 OpenAI 向量嵌入构建的 ChromaDB 向量库,用于存储智能体执行历史;
- 最近记忆:使用 SQLite3 数据库,保存最近一次任务执行结果;
- 长期记忆:使用 SQLite3 数据库,保存历史任务结果。注意:任务描述必须完全匹配,才能成功检索到长期记忆(限制较严格);
- 实体记忆:提取关键实体,并将实体关系存储进另一个 ChromaDB 向量库中。
OpenAI Swarm
Swarm 使用简单的无状态设计,没有内建的记忆功能。 关于 OpenAI 如何理解“记忆”的参考实现,可以看其 Assistant API。 在 Assistant API 中,每段对话拥有一个 thread_id
(对应短期记忆),每个助手拥有一个 assistant_id
(对应长期记忆)。
当然,也可以集成第三方记忆层服务(如 mem0
),或者自己实现短期与长期记忆机制。
5.4、 人类参与环节
尽管我们希望智能体能够自主运行,许多智能体依然需要与人类互动。
例如,一个客户支持智能体在执行过程中可能需要向用户询问信息;人类也可以作为审核者或指导者,帮助智能体更好地完成任务,实现更自然的人机协作。
LangGraph
LangGraph 允许我们在图中设置断点,例如下方代码展示了如何在输出摘要阶段之前加入人类确认步骤:
workflow.compile(checkpointer=checkpointer, interrupt_before=["Output_Summarizing_Agent"])
此时图会执行至断点处暂停执行,我们可以在此加入人类输入,然后再继续执行后续节点。
# Run the graph until the first interruption
foreventin graph.stream(initial_input, thread, stream_mode="values"):
print(event)
try:
user_approval = input("Do you want to go to Output Summarizer? (yes/no): ")
except:
user_approval ="yes"
if user_approval.lower()=="yes":
# If approved, continue the graph execution
foreventin graph.stream(None, thread, stream_mode="values"):
print(event)
else:
print("Operation canceled by user.")
CrewAI
CrewAI 允许人类通过在智能体初始化时设置 human_input=True
标志来提供反馈。
由 Relari 提供的图片。CrewAI 生成的消息,用于请求人类输入。
智能体在执行完任务后会暂停,并提示用户以自然语言对其操作与结果进行反馈(如下图所示)。
但目前不支持更复杂的人类参与交互方式。
OpenAI Swarm
Swarm 没有内建的人类参与功能。不过,最简单的添加方式是将人类视为一个 Tool 或 Agent,
让其他 AI 智能体通过 transfer 函数将任务转交给这个“人类代理”。
6、功能差异总结
下图总结了我们在三个框架上构建同一个应用后的功能对比:
功能对比摘要图表。
7、推荐
我们根据开发需求绘制了如下决策树,帮助你快速判断应该选择哪个智能体框架:
由 Relari 提供的图片。智能体框架选择决策树。
那么,如何系统的去学习大模型LLM?
作为一名从业五年的资深大模型算法工程师,我经常会收到一些评论和私信,我是小白,学习大模型该从哪里入手呢?我自学没有方向怎么办?这个地方我不会啊。如果你也有类似的经历,一定要继续看下去!这些问题啊,也不是三言两语啊就能讲明白的。
所以我综合了大模型的所有知识点,给大家带来一套全网最全最细的大模型零基础教程。在做这套教程之前呢,我就曾放空大脑,以一个大模型小白的角度去重新解析它,采用基础知识和实战项目相结合的教学方式,历时3个月,终于完成了这样的课程,让你真正体会到什么是每一秒都在疯狂输出知识点。
由于篇幅有限,⚡️ 朋友们如果有需要全套 《2025全新制作的大模型全套资料》,扫码获取~
👉大模型学习指南+路线汇总👈
我们这套大模型资料呢,会从基础篇、进阶篇和项目实战篇等三大方面来讲解。
👉①.基础篇👈
基础篇里面包括了Python快速入门、AI开发环境搭建及提示词工程,带你学习大模型核心原理、prompt使用技巧、Transformer架构和预训练、SFT、RLHF等一些基础概念,用最易懂的方式带你入门大模型。
👉②.进阶篇👈
接下来是进阶篇,你将掌握RAG、Agent、Langchain、大模型微调和私有化部署,学习如何构建外挂知识库并和自己的企业相结合,学习如何使用langchain框架提高开发效率和代码质量、学习如何选择合适的基座模型并进行数据集的收集预处理以及具体的模型微调等等。
👉③.实战篇👈
实战篇会手把手带着大家练习企业级的落地项目(已脱敏),比如RAG医疗问答系统、Agent智能电商客服系统、数字人项目实战、教育行业智能助教等等,从而帮助大家更好的应对大模型时代的挑战。
👉④.福利篇👈
最后呢,会给大家一个小福利,课程视频中的所有素材,有搭建AI开发环境资料包,还有学习计划表,几十上百G素材、电子书和课件等等,只要你能想到的素材,我这里几乎都有。我已经全部上传到CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
相信我,这套大模型系统教程将会是全网最齐全 最易懂的小白专用课!!