LLM代理应用实战:构建Plotly数据可视化代理

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 构建数据可视化代理解决了LLM(大型语言模型)在理解和生成定制图表时的局限性。代理提供DataFrame信息和自定义样式工具,简化与LLM的交互。选择了Plotly而非Matplotlib,因其交互性和Web渲染能力更适合现代可视化。代理通过元数据索引了解数据集详情,并根据样式指示生成符合特定审美的图表。通过ReActAgent和Groq模型,代理能理解用户指令,生成准确的Plotly代码,从而创建定制图表,提高了数据可视化的效率和准确性。

如果你尝试过像ChatGPT这样的LLM,就会知道它们几乎可以为任何语言或包生成代码。但是仅仅依靠LLM是有局限的。对于数据可视化的问题我们需要提供一下的内容

描述数据:模型本身并不知道数据集的细节,比如列名和行细节。手动提供这些信息可能很麻烦,特别是当数据集变得更大时。如果没有这个上下文,LLM可能会产生幻觉或虚构列名,从而导致数据可视化中的错误。

样式和偏好:数据可视化是一种艺术形式,每个人都有独特的审美偏好,这些偏好因图表类型和信息而异。不断地为每个可视化提供不同的风格和偏好是很麻烦的。而配备了风格信息的代理可以简化这一过程,确保一致和个性化的视觉输出。

如果每次于LLM进行交互都附带这些内容会导致请求过于复杂,不利于用户的输入,所以这次我们构建一个数据可视化的代理,通过代理我们只需提供很少的信息就能够让LLM生成我们定制化的图表。

可视化库的选择

在构建一个数据可视化的AI代理时,选择合适的可视化工具是至关重要的。虽然存在多种工具可以用于数据可视化,但Plotly和Matplotlib是最为常用的两种。为了构建一个既功能丰富又用户友好的可视化界面,我们决定使用Plotly作为主要的可视化库。

与Matplotlib相比,Plotly提供了更加丰富的交互性功能。它支持直接在Web浏览器中的动态渲染,使得用户能够通过缩放、平移、悬停来互动式地探索数据。这种高度的交互性是Plotly的一大优势,尤其是在需要展示复杂数据集或进行深入数据分析的应用场景中。

虽然Matplotlib在科学研究和学术出版物中有广泛的应用,特别是在生成高质量的静态图像方面具有极高的灵活性和精确度,但其在交互性和Web集成方面的限制使得它在构建现代、交互式的数据可视化解决方案时可能不如Plotly那么吸引人。

所以我们选择Plotly作为构建数据可视化AI代理的工具,不仅能够满足用户对交互性的需求,还能够提供强大的数据处理能力和优秀的用户体验。这将极大地提高数据可视化的效率和效果,使得数据分析更加直观和易于理解。

下面是我使用Llama3 70B构建可视化基线。

我们执行上面的代码将得到如下的结果

要构建这个应用程序,我们需要为LLM代理配备两个工具:一个工具提供关于数据集的信息,另一个工具包含关于样式的信息。

代理提供的信息

1、DataFrame信息

这个工具目的是分析DataFrame并将其内容信息存储到索引中。要索引的数据包括列名、数据类型以及值的最小值、最大值和平均值范围。这有助于代理理解它们正在处理的变量类型。

这里我们使用layoff.fyi 的数据来进行分析。

我们这里还做了一些预处理的工作,包括将数据转换为适当的类型(例如,将数字字符串转换为整数或浮点数)并删除空值。

 #Optional pre-processing
 import pandas as pd
 import numpy as np


 df = pd.read_csv('WARN Notices California_Omer Arain - Sheet1.csv')

 #Changes date like column into datetime 
 df['Received Date'] = [pd.to_datetime(x) for x in df['Received Date']]
 df['Effective Date'] = [pd.to_datetime(x) for x in df['Effective Date']]
 #Converts numbers stored as strings into ints
 df['Number of Workers'] = [int(str(x).replace(',','')) if str(x)!='nan' else np.nan for x in df['Number of Workers']]
 # Replacing NULL values
 df = df.replace(np.nan,0)

将数据集信息存储到索引中

 from llama_index.core.readers.json import JSONReader
 from llama_index.core import VectorStoreIndex
 import json

 # Function that stores the max,min & mean for numerical values
 def return_vals(df,c):
     if isinstance(df[c].iloc[0], (int, float, complex)):
         return [max(df[c]), min(df[c]), np.mean(df[c])]
 # For datetime we need to store that information as string
     elif(isinstance(df[c].iloc[0],datetime.datetime)):
         return [str(max(df[c])), str(min(df[c])), str(np.mean(df[c]))]
     else:
 # For categorical variables you can store the top 10 most frequent items and their frequency
         return list(df[c].value_counts()[:10])

 # declare a dictionary 
 dict_ = {}
 for c in df.columns:
 # storing the column name, data type and content
   dict_[c] = {'column_name':c,'type':str(type(df[c].iloc[0])), 'variable_information':return_vals(df,c)}
 # After looping storing the information as a json dump that can be loaded 
 # into a llama-index Document

 # Writing the information into dataframe.json 

 with open("dataframe.json", "w") as fp:
     json.dump(dict_ ,fp) 


 reader = JSONReader()
 # Load data from JSON file
 documents = reader.load_data(input_file='dataframe.json')

 # Creating an Index
 dataframe_index =  VectorStoreIndex.from_documents(documents)

这样第一步就完成了。

2、自定义样式信息

表样式主要包括关于如何在plot中设置不同图表样式的自然语言说明。这里需要使用自然语言描述样式,所以可能需要进行尝试,下面是我如何创建折线图和条形图的说明!

 from llama_index.core import Document
 from llama_index.core import VectorStoreIndex

 styling_instructions =[Document(text="""
   Dont ignore any of these instructions.
         For a line chart always use plotly_white template, reduce x axes & y axes line to 0.2 & x & y grid width to 1. 
         Always give a title and make bold using html tag axis label and try to use multiple colors if more than one line
         Annotate the min and max of the line
         Display numbers in thousand(K) or Million(M) if larger than 1000/100000 
         Show percentages in 2 decimal points with '%' sign
         """
         )
         , Document(text="""
         Dont ignore any of these instructions.
         For a bar chart always use plotly_white template, reduce x axes & y axes line to 0.2 & x & y grid width to 1. 
         Always give a title and make bold using html tag axis label and try to use multiple colors if more than one line
         Always display numbers in thousand(K) or Million(M) if larger than 1000/100000. Add annotations x values
         Annotate the values on the y variable
         If variable is a percentage show in 2 decimal points with '%' sign.
         """)


        # You should fill in instructions for other charts and play around with these instructions
        , Document(text=
           """ General chart instructions
         Do not ignore any of these instructions
          always use plotly_white template, reduce x & y axes line to 0.2 & x & y grid width to 1. 
         Always give a title and make bold using html tag axis label 
         Always display numbers in thousand(K) or Million(M) if larger than 1000/100000. Add annotations x values
         If variable is a percentage show in 2 decimal points with '%'""")
          ]
 # Creating an Index
 style_index =  VectorStoreIndex.from_documents(styling_instructions)

或者直接将部分样式的代码作为示例输入给模型,这样对于固定的样式是非常好的一个方式

构建AI代理

我们上面已经构建了2个索引:DataFrame信息(元数据),表格自定义样式信息

下面就可以使用lama- index从索引构建查询引擎并将其用作代理工具使用。

 #All imports for this section
 from llama_index.core.agent import ReActAgent
 from llama_index.core.tools import QueryEngineTool
 from llama_index.core.tools import  ToolMetadata
 from llama_index.llms.groq import Groq


 # Build query engines over your indexes
 # It makes sense to only retrieve one document per query 
 # However, you may play around with this if you need multiple charts
 # Or have two or more dataframes with similar column names
 dataframe_engine = dataframe_index.as_query_engine(similarity_top_k=1)
 styling_engine = style_index.as_query_engine(similarity_top_k=1)

 # Builds the tools
 query_engine_tools = [
     QueryEngineTool(
         query_engine=dataframe_engine,
 # Provides the description which helps the agent decide which tool to use 
         metadata=ToolMetadata(
             name="dataframe_index",
             description="Provides information about the data in the data frame. Only use column names in this tool",
         ),
 \
     ),
     QueryEngineTool(
 # Play around with the description to see if it leads to better results
         query_engine=styling_engine,
         metadata=ToolMetadata(
             name="Styling",
             description="Provides instructions on how to style your Plotly plots"
             "Use a detailed plain text question as input to the tool.",
         ),
     ),
 ]

 # I used open-source models via Groq but you can use OpenAI/Google/Mistral models as well
 llm = Groq(model="llama3-70b-8192", api_key="<your_api_key>")

 # initialize ReAct agent
 agent = ReActAgent.from_tools(query_engine_tools, llm=llm, verbose=True)

为了防止幻觉,我这里稍微调整了一下提示,这步不是必须的

这里是ReAct的默认提示

修改为:

 from llama_index.core import PromptTemplate

 new_prompt_txt= """You are designed to help with building data visualizations in Plotly. You may do all sorts of analyses and actions using Python

 ## Tools

 You have access to a wide variety of tools. You are responsible for using the tools in any sequence you deem appropriate to complete the task at hand.
 This may require breaking the task into subtasks and using different tools to complete each subtask.

 You have access to the following tools, use these tools to find information about the data and styling:
 {tool_desc}


 ## Output Format

 Please answer in the same language as the question and use the following format:

Thought: The current language of the user is: (user's language). I need to use a tool to help me answer the question.
Action: tool name (one of {tool_names}) if using a tool.
Action Input: the input to the tool, in a JSON format representing the kwargs (e.g. { {"input": "hello world", "num_beams": 5}})


 Please ALWAYS start with a Thought.

 Please use a valid JSON format for the Action Input. Do NOT do this {
  
  {'input': 'hello world', 'num_beams': 5}}.

 If this format is used, the user will respond in the following format:

Observation: tool response


 You should keep repeating the above format till you have enough information to answer the question without using any more tools. At that point, you MUST respond in the one of the following two formats:

Thought: I can answer without using any more tools. I'll use the user's language to answer
Answer: [your answer here (In the same language as the user's question)]


Thought: I cannot answer the question with the provided tools.
Answer: [your answer here (In the same language as the user's question)]


 ## Current Conversation

 Below is the current conversation consisting of interleaving human and assistant messages."""

 # Adding the prompt text into PromptTemplate object
 new_prompt = PromptTemplate(new_prompt_txt)

 # Updating the prompt
 agent.update_prompts({'agent_worker:system_prompt':new_prompt})

可视化

现在让就可以向我们构建的代理发起请求了

 response = agent.chat("Give Plotly code for a line chart for Number of Workers get information from the dataframe about the correct column names and make sure to style the plot properly and also give a title")

从输出中可以看到代理如何分解请求并最终使用Python代码进行响应(可以直接构建输出解析器或复制过去并运行)。

通过运行以代码创建的图表,将注释、标签/标题和轴格式与样式信息完全一致。因为已经有了数据信息,所以我们直接提出要求就可以,不需要输入任何的数据信息

在试一试其他的图表,生成一个柱状图

结果如下:

总结

AI代理可以自动化从多个数据源收集、清洗和整合数据的过程。这意味着可以减少手动处理错误,提高数据处理速度,让分析师有更多时间专注于解读数据而不是处理数据。使用AI代理进行数据可视化能够显著提升数据分析的深度和广度,同时提高效率和用户体验,帮助企业和组织更好地利用他们的数据资产。

我们这里只是做了第一步,如果要制作一套代理工具还需要很多步骤,比如可视化代码的自动执行,优化提示和处理常见故障等等,如果你对这方面感兴趣,可以留言,如果人多的话我们会在后续的文章中一一介绍。

https://avoid.overfit.cn/post/b7250a6a029d46adb2c5948eb71b5d28

作者:Arslan Shahid

目录
相关文章
|
2月前
|
前端开发 机器人 API
前端大模型入门(一):用 js+langchain 构建基于 LLM 的应用
本文介绍了大语言模型(LLM)的HTTP API流式调用机制及其在前端的实现方法。通过流式调用,服务器可以逐步发送生成的文本内容,前端则实时处理并展示这些数据块,从而提升用户体验和实时性。文章详细讲解了如何使用`fetch`发起流式请求、处理响应流数据、逐步更新界面、处理中断和错误,以及优化用户交互。流式调用特别适用于聊天机器人、搜索建议等应用场景,能够显著减少用户的等待时间,增强交互性。
614 2
|
2月前
|
机器学习/深度学习 人工智能 运维
企业内训|LLM大模型在服务器和IT网络运维中的应用-某日企IT运维部门
本课程是为某在华日资企业集团的IT运维部门专门定制开发的企业培训课程,本课程旨在深入探讨大型语言模型(LLM)在服务器及IT网络运维中的应用,结合当前技术趋势与行业需求,帮助学员掌握LLM如何为运维工作赋能。通过系统的理论讲解与实践操作,学员将了解LLM的基本知识、模型架构及其在实际运维场景中的应用,如日志分析、故障诊断、网络安全与性能优化等。
97 2
|
12天前
|
开发框架 人工智能 安全
Promptic:轻量级 LLM 应用开发框架,提供完善的底层功能,使开发者更专注于构建上层功能
Promptic 是一个轻量级的 LLM 应用开发框架,支持通过一行代码切换不同的 LLM 服务提供商。它提供了类型安全的输出、流式支持、内置对话记忆、错误处理和重试等功能,帮助开发者专注于构建功能,而不是底层的复杂性。
48 6
Promptic:轻量级 LLM 应用开发框架,提供完善的底层功能,使开发者更专注于构建上层功能
|
10天前
|
弹性计算 自然语言处理 数据库
通过阿里云Milvus和LangChain快速构建LLM问答系统
本文介绍如何通过整合阿里云Milvus、阿里云DashScope Embedding模型与阿里云PAI(EAS)模型服务,构建一个由LLM(大型语言模型)驱动的问题解答应用,并着重演示了如何搭建基于这些技术的RAG对话系统。
|
1月前
|
JSON 数据可视化 NoSQL
基于LLM Graph Transformer的知识图谱构建技术研究:LangChain框架下转换机制实践
本文介绍了LangChain的LLM Graph Transformer框架,探讨了文本到图谱转换的双模式实现机制。基于工具的模式利用结构化输出和函数调用,简化了提示工程并支持属性提取;基于提示的模式则为不支持工具调用的模型提供了备选方案。通过精确定义图谱模式(包括节点类型、关系类型及其约束),显著提升了提取结果的一致性和可靠性。LLM Graph Transformer为非结构化数据的结构化表示提供了可靠的技术方案,支持RAG应用和复杂查询处理。
135 2
基于LLM Graph Transformer的知识图谱构建技术研究:LangChain框架下转换机制实践
|
2月前
|
监控 Kubernetes Python
Python 应用可观测重磅上线:解决 LLM 应用落地的“最后一公里”问题
为增强对 Python 应用,特别是 Python LLM 应用的可观测性,阿里云推出了 Python 探针,旨在解决 LLM 应用落地难、难落地等问题。助力企业落地 LLM。本文将从阿里云 Python 探针的接入步骤、产品能力、兼容性等方面展开介绍。并提供一个简单的 LLM 应用例子,方便测试。
157 17
|
2月前
|
存储 人工智能 算法
精通RAG架构:从0到1,基于LLM+RAG构建生产级企业知识库
为了帮助更多人掌握大模型技术,尼恩和他的团队编写了《LLM大模型学习圣经》系列文档,包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构,基于LLM+RAG构建生产级企业知识库》和《从0到1吃透大模型的顶级架构》。这些文档不仅系统地讲解了大模型的核心技术,还提供了实战案例和配套视频,帮助读者快速上手。
精通RAG架构:从0到1,基于LLM+RAG构建生产级企业知识库
|
1月前
|
人工智能 自然语言处理 算法
政务培训|LLM大模型在政府/公共卫生系统的应用
本课程是TsingtaoAI公司面向某卫生统计部门的政府职员设计的大模型技术应用课程,旨在系统讲解大语言模型(LLM)的前沿应用及其在政府业务中的实践落地。课程涵盖从LLM基础知识到智能化办公、数据处理、报告生成、智能问答系统构建等多个模块,全面解析大模型在卫生统计数据分析、报告撰写和决策支持等环节中的赋能价值。
69 2
|
2月前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。
|
2月前
|
存储 机器学习/深度学习 人工智能
文档智能与RAG技术在LLM中的应用评测
本文介绍了阿里云在大型语言模型(LLM)中应用文档智能与检索增强生成(RAG)技术的解决方案,通过文档预处理、知识库构建、高效检索和生成模块,显著提升了LLM的知识获取和推理能力,尤其在法律、医疗等专业领域表现突出。
147 1