使用LangGraph构建多Agent系统

使用LangGraph构建多代理系统

0.完整工作流

在这里插入图片描述

1.开发代码

环境变量

# open ai的相关环境变量
OPENAI_API_KEY=xxx
OPENAI_BASE_URL=https://api.openai-hk.com/v1

# LangSmith的环境变量,方便去LangSmith看执行过程
LANGCHAIN_TRACING_V2=xxx
LANGCHAIN_ENDPOINT=xxx
LANGCHAIN_API_KEY=xxx
LANGCHAIN_PROJECT=xxx

# 搜索用的
TAVILY_API_KEY=xxx 环境变量

构建通用的agent

# 导入基本消息类、用户消息类和工具消息类
from langchain_core.messages import (
    HumanMessage
)
# 导入聊天提示模板和消息占位符
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

# 定义一个函数,用于创建代理
def create_agent(llm, tools, system_message: str):
    """创建一个代理。"""
    # 创建一个聊天提示模板
    prompt = ChatPromptTemplate.from_messages(
        [
            (
                "system",
                "你是一个有帮助的AI助手,与其他助手合作。"
                " 使用提供的工具来推进问题的回答。"
                " 如果你不能完全回答,没关系,另一个拥有不同工具的助手"
                " 会接着你的位置继续帮助。执行你能做的以取得进展。"
                " 如果你或其他助手有最终答案或交付物,"
                " 在你的回答前加上FINAL ANSWER,以便团队知道停止。"
                " 你可以使用以下工具: {tool_names}。\n{system_message}",
            ),  # 系统消息
            # 消息占位符 
            MessagesPlaceholder(variable_name="messages"),
        ]
    )
    # 传递系统消息参数
    prompt = prompt.partial(system_message=system_message)
    # 传递工具名称参数
    prompt = prompt.partial(tool_names=", ".join([tool.name for tool in tools]))

    # 返回RunnableSequence,先用消息messages填充提示词,再llm_with_tools进行调用 (类型是:langchain_core.runnables.base.RunnableSequence)
    return prompt | llm.bind_tools(tools)

构建通用的agent节点

# 辅助函数,用于为给定的代理创建节点
from langchain_core.messages import ToolMessage, AIMessage

"""
图的agent节点。决定做什么操作(也就是调用下llm)
1.把历史消息放入提示词,然后让llm回答。(此时的state里就有历史消息,也就是messages,而sender再字典里,也无关紧要,虽然传入进去了,但是底层没用)
2.返回消息和发送方
"""

def agent_node(state, agent, name):
    # 调用代理
    result = agent.invoke(state)
    # 将代理输出转换为适合附加到全局状态的格式
    if isinstance(result, ToolMessage):
        pass
    else:
        # 先result.dict(exclude={"type", "name"}) 返回一个去除type和name的字典,然后通过**变成关键字参数,最后把name传进去
        # 相当于曲线救国,把消息的name改成了。
        result = AIMessage(**result.dict(exclude={"type", "name"}), name=name)

    return {
        "messages": [result],  # 会追加到消息后边
        # 由于我们有一个严格的工作流程,我们可以
        # 跟踪发送者,以便知道下一个传递给谁。
        "sender": name,
    }

构建tool

# 导入注解类型
from typing import Annotated

# 导入Tavily搜索工具
from langchain_community.tools.tavily_search import TavilySearchResults
# 导入工具装饰器
from langchain_core.tools import tool
# 导入Python REPL工具
from langchain_experimental.utilities import PythonREPL

# 创建Tavily搜索工具实例,设置最大结果数为5
tavily_tool = TavilySearchResults(max_results=5)

# 警告:这会在本地执行代码,未沙箱化时可能不安全
# 创建Python REPL实例
repl = PythonREPL()

# 定义一个工具函数,用于执行Python代码
@tool
def python_repl(
        code: Annotated[str, "要执行以生成图表的Python代码。并保存到本地plt.png。"],
):
    """使用这个工具来执行Python代码。如果你想查看某个值的输出,
    应该使用print(...)。这个输出对用户可见。"""
    try:
        # 尝试执行代码
        result = repl.run(code)
    except BaseException as e:
        # 捕捉异常并返回错误信息
        return f"执行失败。错误: {repr(e)}"
    # 返回执行结果
    result_str = f"成功执行:\n```python\n{code}\n```\nStdout: {result}"
    return (
            result_str + "\n\n如果你已完成所有任务,请回复FINAL ANSWER。"
    )

构建agent路由

from typing import Literal

# 定义路由器函数
def router(state) -> Literal["call_tool", "__end__", "other_agent"]:
    # 这是路由器
    messages = state["messages"]
    last_message = messages[-1]
    if last_message.tool_calls:
        # 上一个代理正在调用工具
        return "call_tool"
    if "FINAL ANSWER" in last_message.content:  # 刚开始的提示词里指定了以FINAL ANSWER为结束标志
        # 任何代理决定工作完成
        return "__end__"
    return "other_agent"

核心代码

from dotenv import load_dotenv

# 先加载环境变量,默认是找当前目录下的.env文件
load_dotenv()

# 导入操作符和类型注解
import functools
import operator
from typing import Annotated, Sequence, TypedDict
from langchain_core.messages import BaseMessage, HumanMessage
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph

from build_agent import create_agent
from build_tool import tavily_tool, python_repl
from build_agent_node import agent_node
from build_router import router
from langgraph.prebuilt import ToolNode
from langgraph.graph import END, START

# 定义一个对象,用于在图的每个节点之间传递
# 我们将为每个代理和工具创建不同的节点
class AgentState(TypedDict):
    # 添加operator.add注解,相当于每次把消息列表加起来。变相的追加而已。
    messages: Annotated[Sequence[BaseMessage], operator.add]
    sender: str

# 创建OpenAI聊天模型实例
llm = ChatOpenAI(model="gpt-4o-mini")

# 查询的agent,用的时候给他送入消息就行
research_agent = create_agent(
    llm,
    [tavily_tool],
    system_message="你应该提供准确的数据供chart_generator使用。",
)

# 创建查询节点,指定对应的agent   functools.partial是会生成一个函数,函数为agent_node,指定参数agent和name
research_node = functools.partial(agent_node, agent=research_agent, name="Researcher")

# 图表生成的agent
chart_agent = create_agent(
    llm,
    [python_repl],
    system_message="你展示的任何图表都将对用户可见。",
)

# 创建图表生成节点,指定对应的agent
chart_node = functools.partial(agent_node, agent=chart_agent, name="chart_generator")

# 定义工具列表
tools = [tavily_tool, python_repl]
# 创建工具节点
tool_node = ToolNode(tools)

# -------------创建图---------------

# 创建状态图实例
workflow = StateGraph(AgentState)

# 添加搜索节点
workflow.add_node("Researcher", research_node)
# 添加图表生成器节点
workflow.add_node("chart_generator", chart_node)
# 添加工具调用节点
workflow.add_node("call_tool", tool_node)

# 添加起始边
workflow.add_edge(START, "Researcher")

# 添加条件边 (三种情况,结束,调用工具,调用其他代理)
workflow.add_conditional_edges(
    "Researcher",
    router,
    {"other_agent": "chart_generator", "call_tool": "call_tool", "__end__": END},
)
workflow.add_conditional_edges(
    "chart_generator",
    router,
    {"other_agent": "Researcher", "call_tool": "call_tool", "__end__": END},
)

# 添加条件边,工具调用结束后,需要返回到哪里。
workflow.add_conditional_edges(
    source="call_tool",
    # 每个代理节点更新'sender'字段
    # 工具调用节点不更新,这意味着
    # 该边将路由回调用工具的原始代理
    path=lambda x: x["sender"],  # 发送方是谁,就返回到哪里

    path_map={  # 根据path进行路由,防止sender和具体的节点名字不一样的情况
        "Researcher": "Researcher",
        "chart_generator": "chart_generator",
    },
)

# 编译工作流图
graph = workflow.compile()

# 将生成的图片保存到文件
graph_png = graph.get_graph().draw_mermaid_png()
with open("build_graph.png", "wb") as f:
    f.write(graph_png)

# 事件流
events = graph.stream(
    {
        "messages": [
            HumanMessage(
                content="获取过去5年AI软件市场规模,"
                        " 然后绘制一条折线图。"
                        " 一旦你编写好代码,完成任务。"
            )
        ],
    },
    # 图中最多执行的步骤数
    {"recursion_limit": 150},
)
# 打印事件流中的每个状态
for s in events:
    print(s)
    print("----")

2.LangGraph执行图

在这里插入图片描述

  • 1)开始先到检索的agent,调用大模型,根据结果看需要走哪个分支(调用工具、调用其他agent、直接结束)
  • 2)如果是到调用工具,则调用检索的工具,进行检索,然后把结果返回给检索的agent,这里是原路返回
  • 3)到了检索的agent,再次调用大模型,根据结果看需要走哪个分支
  • 4)如果是到图表生成的agent,进入agent后,调用大模型,根据结果看需要走哪个分支
  • 5)如果是调用工具,则调用生成图表的工具,生成最后的图表,然后把结果原路返回给对应的agent
  • 6)agent收到结果后,再次调用大模型,通过大模型的结果进行判断,如果完成任务了则直接结束。
  • 7)综上,调用结束,其中至少调用四次大模型。
3.LangSmith执行图

在这里插入图片描述

NOTE:和LangGraph执行图对应着看。以及注意自己环境的matplotlib的版本,可能和llm生成的代码版本不一致,导致运行报错。

4.最终执行结果

让Agent系统获取过去5年AI软件市场规模,然后绘制一条折线图的结果如下图所示, 整体表现为自己查询数据,自己生成代码,自己展示并保存结果图片。

在这里插入图片描述

如何学习AI大模型?

大模型时代,火爆出圈的LLM大模型让程序员们开始重新评估自己的本领。 “AI会取代那些行业?”“谁的饭碗又将不保了?”等问题热议不断。

不如成为「掌握AI工具的技术人」,毕竟AI时代,谁先尝试,谁就能占得先机!

想正式转到一些新兴的 AI 行业,不仅需要系统的学习AI大模型。同时也要跟已有的技能结合,辅助编程提效,或上手实操应用,增加自己的职场竞争力。

但是LLM相关的内容很多,现在网上的老课程老教材关于LLM又太少。所以现在小白入门就只能靠自学,学习成本和门槛很高

那么我作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,希望可以帮助到更多学习大模型的人!至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

👉 福利来袭CSDN大礼包:《2025最全AI大模型学习资源包》免费分享,安全可点 👈

全套AGI大模型学习大纲+路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

👉学会后的收获:👈
基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

👉 福利来袭CSDN大礼包:《2025最全AI大模型学习资源包》免费分享,安全可点 👈

img

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值