当前位置:首页 > 技术 > 正文内容

构建基于LangChain的多智能体数据处理与可视化系统

访客 技术 2026年7月21日 1

引言

在现代复杂的业务环境中,单一的大型语言模型(LLM)往往难以满足多样化的数据处理与分析需求。为了提高系统的适应性和效率,多智能体(Multi-Agent)系统应运而生。本文将基于LangChain框架构建一个多LLM智能体系统,用于处理用户请求、收集数据、生成可视化图表并返回最终结果。我们将实现一个能够查询印度过去五年GDP数据并生成相应图表的复杂系统。

多智能体系统架构

多智能体系统主要由以下关键组件构成:

  1. 数据采集智能体(Data Collector):负责获取用户所需的数据。通过调用外部搜索引擎或数据库,收集并整理相关信息。
  2. 任务路由智能体(Task Router):根据当前状态和消息内容,决定信息流向。它是系统的核心控制器,确保各智能体之间的无缝协作。
  3. 可视化生成智能体(Visualizer):负责将收集到的数据转换为可视化图表,提升数据可理解性。
  4. 执行工具智能体(Executor):用于执行各种外部工具或脚本,如Python代码执行器,用于数据处理或图表生成。
  5. 状态管理器(State Manager):维护每个智能体的状态信息,包括消息历史、发送者等,实现跨智能体的上下文记忆。

我们选择LangChain框架来构建此系统,因为它提供了丰富的工具集和灵活的架构支持。同时,我们采用ChatOpenAI的GPT-4o-mini模型作为底层语言模型,以支持各智能体的自然语言理解和生成能力。

### 多智能体工作流程

1. 初始请求处理

用户通过系统接口提交一个请求,例如"获取印度过去五年的GDP数据,并生成可视化图表"。

2. 数据采集阶段

数据采集智能体接收请求后,开始搜集相关数据。它可能通过调用搜索引擎API(如Tavily工具),检索到印度过去五年每年的GDP数据。收集到的数据以特定格式(如JSON)返回,并添加到全局状态中。

3. 任务路由决策

任务路由智能体根据当前状态(即全局状态中的消息列表)和最新消息内容,决定下一步行动。如果数据采集智能体已收集到足够数据,且不具备直接生成图表的能力,路由智能体会将任务传递给可视化生成智能体。

4. 图表生成阶段

可视化生成智能体接收到任务后,开始将收集到的数据转换为可视化图表。它首先选择合适的图表类型(如折线图、柱状图等),然后使用Python的matplotlib库等工具生成图表。生成的图表以图片形式保存,并添加到全局状态中。

5. 工具调用与执行

在图表生成过程中,可视化生成智能体可能需要调用外部工具(如Python脚本执行器)来辅助生成图表。执行工具智能体负责执行这些外部工具,并将执行结果返回给可视化生成智能体。

6. 结果整合与呈现

当图表生成完成后,可视化生成智能体将图表和相关GDP数据整合为最终答案,通过系统接口呈现给用户。最终答案可能包含图表图片、GDP数据表格、数据来源等详细信息。

多智能体系统实现

1. 环境准备

pip install -U langchain langchain_openai langsmith pandas langchain_experimental matplotlib langgraph langchain_core

2. 智能体创建函数

from langchain_core.messages import (
    BaseMessage,
    HumanMessage,
    ToolMessage,
)
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

from langgraph.graph import END, StateGraph, START


def build_intelligent_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]))
    return prompt | llm.bind_tools(tools)

这是创建LLM智能体的通用函数,通过给定一组工具和对应智能体的描述来创建相应的智能体。

3. 工具定义

from typing import Annotated

from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.tools import tool
from langchain_experimental.utilities import PythonREPL

search_tool = TavilySearchResults(max_results=5)

# 注意:此代码在本地执行,未在沙箱环境中运行时可能存在安全风险

code_executor = PythonREPL()


@tool
def python_code_executor(
    code: Annotated[str, "要执行以生成图表的Python代码。"],
):
    """使用此函数执行Python代码。如果你想查看某个值的输出,应该使用print(...)打印出来,这对用户是可见的。"""
    try:
        result = code_executor.run(code)
    except BaseException as e:
        return f"执行失败。错误:{repr(e)}"
    result_str = f"成功执行:\n```python\n{code}\n```\n输出: {result}"
    return (
        result_str + "\n\n如果你已完成所有任务,请回复FINAL ANSWER。")


这里提供了两个工具:一个是用于搜索的工具,另一个是用于执行Python代码的工具。

4. 智能体状态设置

我们这里提到的智能体都是有状态的智能体,有状态LLM智能体会保留和更新交互中的上下文信息,从而动态调整其决策过程。这种架构有助于进行复杂推理,支持顺序任务中的长期依赖关系。

import operator
from typing import Annotated, Sequence, TypedDict

from langchain_openai import ChatOpenAI


# 定义在图中各节点之间传递的对象
# 我们将为每个智能体和工具创建不同的节点
class IntelligentAgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], operator.add]
    sender: str

5. 智能体定义

import functools

from langchain_core.messages import AIMessage


# 为特定智能体创建节点的辅助函数
def process_agent_node(state, agent, agent_name):
    result = agent.invoke(state)
    # 将智能体输出转换为适合追加到全局状态的格式
    if isinstance(result, ToolMessage):
        pass
    else:
        result = AIMessage(**result.dict(exclude={"type", "name"}), name=agent_name)
    return {
        "messages": [result],
        # 由于我们有严格的工作流程,我们可以
        # 跟踪发送者,以便知道下一步传递给谁
        "sender": agent_name,
    }


language_model = ChatOpenAI(model="gpt-4o-mini")

# 数据采集智能体和节点
data_collector_agent = build_intelligent_agent(
    language_model,
    [search_tool],
    system_message="你应该为可视化生成器提供准确的数据。",
)
data_collector_node = functools.partial(process_agent_node, agent=data_collector_agent, name="DataCollector")

# 可视化生成智能体
visualization_agent = build_intelligent_agent(
    language_model,
    [python_code_executor],
    system_message="你显示的任何图表对用户都是可见的。",
)
visualization_node = functools.partial(process_agent_node, agent=visualization_agent, name="Visualizer")


from langgraph.prebuilt import ToolNode

available_tools = [search_tool, python_code_executor]
tool_execution_node = ToolNode(available_tools)

6. 智能体循环执行逻辑

这里用来判断当前是结束调用还是继续智能体循环调用工具。

# 任一智能体都可以决定结束
from typing import Literal


def determine_next_action(state) -> Literal["execute_tool", "__end__", "continue"]:
    # 这是路由函数
    messages = state["messages"]
    last_message = messages[-1]
    if last_message.tool_calls:
        # 前一个智能体正在调用工具
        return "execute_tool"
    if "FINAL ANSWER" in last_message.content:
        # 任一智能体决定工作已完成
        return "__end__"
    return "continue"

7. 完整工作流定义

collaboration_workflow = StateGraph(IntelligentAgentState)

collaboration_workflow.add_node("DataCollector", data_collector_node)
collaboration_workflow.add_node("Visualizer", visualization_node)
collaboration_workflow.add_node("execute_tool", tool_execution_node)

collaboration_workflow.add_conditional_edges(
    "DataCollector",
    determine_next_action,
    {"continue": "Visualizer", "execute_tool": "execute_tool", "__end__": END},
)
collaboration_workflow.add_conditional_edges(
    "Visualizer",
    determine_next_action,
    {"continue": "DataCollector", "execute_tool": "execute_tool", "__end__": END},
)

collaboration_workflow.add_conditional_edges(
    "execute_tool",
    # 每个智能体节点更新"sender"字段
    # 工具调用节点不更新,这意味着
    # 此边将路由回调用原始工具的智能体
    lambda x: x["sender"],
    {
        "DataCollector": "DataCollector",
        "Visualizer": "Visualizer",
    },
)
collaboration_workflow.add_edge(START, "DataCollector")
processing_graph = collaboration_workflow.compile()

8. 系统执行

collaboration_workflow.add_edge(START, "DataCollector")
processing_graph = collaboration_workflow.compile()

processing_events = processing_graph.stream(
    {
        "messages": [
            HumanMessage(
                content="获取印度过去五年的GDP数据并绘制图表"
            )
        ],
    },
    # 图中最大执行步数
    {"recursion_limit": 150},
)
for event in processing_events:
    print(event)
    print("----")

通过构建多智能体系统,我们可以有效地将复杂任务分解为多个子任务,并由不同的LLM智能体协作完成。这不仅提高了系统的灵活性和可扩展性,还使每个智能体能专注于其擅长的领域,从而提升整体性能和效率。这种架构在处理复杂数据处理和可视化任务时尤为有用,为AI在实际应用中的落地提供了可行方案。

标签: LangChain

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。