学习如何使用 LangGraph 和一组专门化 AI 智能体构建自主研究助手
距离 GPT 研究员 初始发布仅一年,但构建、测试和部署 AI 智能体的方法已经显著发展。这就是当前 AI 进展的本质和速度。从最初的简单 零次示范 或 少次示范,迅速演变为智能体 函数调用、RAG,最终到 智能工作流(又称为 "流工程")。
Andrew Ng 最近表示:"我认为 AI 智能体工作流将推动今年的大规模 AI 进展 - 甚至可能比下一代基础模型更多。这是一个重要趋势,我敦促所有从事 AI 的人关注它。"
在本文中,您将了解为什么多智能体工作流是当前的最佳标准,以及如何使用 LangGraph 构建最佳自主研究多智能体助手。
要跳过本教程,请随时查看 GPT 研究员 x LangGraph 的最终代码实现 这里。
介绍 LangGraph
LangGraph 是 LangChain 的扩展,旨在创建智能体和多智能体流。它增加了创建循环流的能力,并内置了记忆 - 这两个对于创建智能体至关重要的属性。
LangGraph 为开发人员提供了高度的可控性,对于创建自定义智能体和流至关重要。几乎所有生产中的智能体都针对它们试图解决的特定用例进行了定制。LangGraph 为您提供了创建任意定制智能体的灵活性,同时为此提供了直观的开发人员体验。
不再闲聊,让我们开始构建吧!
构建终极自主研究助手
通过利用 LangGraph,研究过程可以通过利用具有专业技能的多个智能体显着提高深度和质量。使每个智能体专注并专门化于仅一个特定技能,可以更好地分离关注点、可定制性,并在项目增长时进一步开发规模。
受最近的 STORM 论文启发,此示例展示了一个 AI 智能体团队如何共同研究给定主题,从规划到发布。此示例还将利用领先的自主研究智能体 GPT 研究员。
研究智能体团队
研究团队由七个 LLM 智能体组成:
-
首席编辑 - 监督研究过程并管理团队。这是协调其他智能体使用 LangGraph 的 "主" 智能体。此智能体充当主要的 LangGraph 接口。
-
GPT 研究员 - 专门的自主智能体,对给定主题进行深入研究。
-
编辑 - 负责规划研究大纲和结构。
-
审阅员 - 根据一组标准验证研究结果的正确性。
-
修订员 - 根据审阅员的反馈修订研究结果。
-
撰稿人 - 负责编写最终报告。
-
发布者 - 负责以各种格式发布最终报告。
架构
如下所示,自动化流程基于以下阶段:规划研究、数据收集和分析、审查和修订、撰写报告,最后是发布:
具体流程如下:
-
浏览器(gpt-researcher) - 浏览互联网以获取基于给定研究任务的初始研究。这一步对于根据最新和相关信息规划研究过程至关重要,而不仅仅依赖于给定任务或主题的预训练数据。
-
编辑 - 根据初始研究规划报告大纲和结构。编辑还负责根据规划的大纲触发并行研究任务。
-
对于每个大纲主题(并行):
-
研究员(gpt-researcher) - 对子主题进行深入研究并撰写草稿。此智能体在底层利用 GPT 研究员 Python 包,以进行优化、深入和事实性研究报告。
-
审阅员 - 根据一组准则验证草稿的正确性,并向修订员提供反馈(如果有)。
-
修订员 - 根据审阅员的反馈修订草稿,直到满意为止。
-
撰稿人 - 编写最终报告,包括介绍、结论和参考文献部分,根据给定研究结果。
-
发布者 - 将最终报告发布为 PDF、Docx、Markdown 等多种格式。
我们不会深入所有代码,因为代码量很大,但主要关注我发现值得分享的有趣部分。
定义图状态
LangGraph 中我最喜欢的功能之一是 状态管理。LangGraph 中的状态通过一种结构化方法实现,开发人员定义了一个封装了整个应用程序状态的 GraphState。图中的每个节点都可以修改此状态,从而根据交互的不断演变的上下文提供动态响应。
就像在每个技术设计的开始一样,考虑应用程序中的数据模式是关键。在这种情况下,我们将定义一个 ResearchState 如下:
class ResearchState(TypedDict):
task: dict
initial_research: str
sections: List[str]
research_data: List[dict]
# 报告布局
title: str
headers: dict
date: str
table_of_contents: str
introduction: str
conclusion: str
sources: List[str]
report: str
如上所示,状态分为两个主要区域:研究任务和报告布局内容。随着数据在图智能体之间流动,每个智能体将依次生成新数据,基于现有状态生成新数据,并更新它以供后续处理。
然后我们可以使用以下方式初始化图:
from langgraph.graph import StateGraph
workflow = StateGraph(ResearchState)
使用 LangGraph 初始化图
如上所述,多智能体开发的一个很棒之处是构建每个智能体具有专业化和范围化技能。让我们以使用 GPT 研究员 Python 包的研究员智能体为例:
from gpt_researcher import GPTResearcher
class ResearchAgent:
def __init__(self):
pass
async def research(self, query: str):
# 初始化研究员
researcher = GPTResearcher(parent_query=parent_query, query=query, report_type=research_report, config_path=None)
# 对给定查询进行研究
await researcher.conduct_research()
# 撰写报告
report = await researcher.write_report()
return report
如上所示,我们创建了一个研究员智能体的实例。现在让我们假设我们为团队的每个智能体都做了同样的事情。创建所有智能体后,我们将使用 LangGraph 初始化图:
def init_research_team(self):
# 初始化智能体
editor_agent = EditorAgent(self.task)
research_agent = ResearchAgent()
writer_agent = WriterAgent()
publisher_agent = PublisherAgent(self.output_dir)
# 使用 ResearchState 定义 Langchain StateGraph
workflow = StateGraph(ResearchState)
# 为每个智能体添加节点
workflow.add_node("browser", research_agent.run_initial_research)
workflow.add_node("planner", editor_agent.plan_research)
workflow.add_node("researcher", editor_agent.run_parallel_research)
workflow.add_node("writer", writer_agent.run)
workflow.add_node("publisher", publisher_agent.run)
workflow.add_edge('browser', 'planner')
workflow.add_edge('planner', 'researcher')
workflow.add_edge('researcher', 'writer')
workflow.add_edge('writer', 'publisher')
# 设置起始和结束节点
workflow.set_entry_point("browser")
workflow.add_edge('publisher', END)
return workflow
如上所示,创建 LangGraph 图非常直接,由三个主要函数组成:add_node、add_edge 和 set_entry_point。通过这些主要函数,您可以首先向图中添加节点,连接边缘,最后设置起始点。
重点检查:如果您一直在正确地跟踪代码和架构,您会注意到审阅员和修订员智能体在上面的初始化中缺失。让我们深入了解一下!
支持有状态并行化的图中的图这是我在与 LangGraph 合作中最激动人心的部分!这个自主助手的一个令人兴奋的特点是针对每个研究任务都有一个并行运行,根据一组预定义的准则进行审查和修订。
在流程中如何利用并行工作是优化速度的关键。但是如果所有代理都报告给相同的状态,你将如何触发并行代理工作呢?这可能会导致竞争条件和最终数据报告中的不一致性。为了解决这个问题,你可以创建一个子图,该子图将从主 LangGraph 实例触发。这个子图将为每个并行运行保留自己的状态,从而解决了提出的问题。
就像以前做过的那样,让我们定义一下 LangGraph 的状态和其代理。由于这个子图基本上是审查和修订研究草案,我们将用草案信息来定义状态:
class DraftState(TypedDict):
task: dict
topic: str
draft: dict
review: str
revision_notes: str
如 DraftState 中所示,我们主要关心讨论的主题,以及评审人和修订说明,因为它们在彼此之间进行沟通,以完成子主题研究报告。为了创建循环条件,我们将利用 LangGraph 的最后一个重要部分,即条件边缘:
async def run_parallel_research(self, research_state: dict):
workflow = StateGraph(DraftState)
workflow.add_node("researcher", research_agent.run_depth_research)
workflow.add_node("reviewer", reviewer_agent.run)
workflow.add_node("reviser", reviser_agent.run)
# 设置边缘研究员->评审员->修订者->评审员...
workflow.set_entry_point("researcher")
workflow.add_edge('researcher', 'reviewer')
workflow.add_edge('reviser', 'reviewer')
workflow.add_conditional_edges('reviewer',
(lambda draft: "accept" if draft['review'] is None else "revise"),
{"accept": END, "revise": "reviser"})
通过定义条件边缘,如果评审人存在评审说明,图将指向修订者,否则循环将以最终草案结束。如果你回到我们构建的主图,你会看到这个并行工作是在一个名为“研究员”的节点下由首席编辑代理调用的。
运行研究助手
在完成代理、状态和图之后,现在是时候运行我们的研究助手了!为了更容易定制,助手会使用给定的 task.json 文件运行:
{
"query": "AI 是否处于炒作周期中?",
"max_sections": 3,
"publish_formats": {
"markdown": true,
"pdf": true,
"docx": true
},
"follow_guidelines": false,
"model": "gpt-4-turbo",
"guidelines": [
"报告必须按照 APA 格式编写",
"每个子部分必须包含使用超链接的支持来源。如果没有,删除子部分或将其重写为上一部分的一部分",
"报告必须用西班牙语编写"
]
}
任务对象相当简单明了,但请注意,如果 follow_guidelines 为 false,图将忽略修订步骤和定义的准则。此外,max_sections 字段定义了要研究的子标题数量。数量较少将生成较短的报告。
运行助手将生成诸如 Markdown、PDF 和 Docx 等格式的最终研究报告。
要下载并运行示例,请查看GPT 研究员 x LangGraph开源页面。
接下来是什么?
展望未来,这里有一些非常令人兴奋的事情值得思考。人在循环中对于优化 AI 体验至关重要。让人类助手帮助修订并专注于恰到好处的研究计划、主题和大纲,将提升整体质量和体验。此外,一般来说,依赖人类干预整个 AI 流程,可以确保正确性、控制感和确定性结果。很高兴看到 LangGraph 已经支持这一点,正如在这里所见。
此外,支持关于网络和本地数据的研究对于许多类型的业务和个人用例至关重要。
最后,可以做更多的努力来提高检索到的来源质量,并确保最终报告按照最佳故事情节构建。