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

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时计算 Flink 版,1000CU*H 3个月
简介: 构建数据可视化代理解决了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

目录
相关文章
|
3月前
|
人工智能 监控 数据可视化
BISHENG下一代企业AI应用的“全能型“LLM软件
杭州奥零数据科技有限公司成立于2023年,专注于数据中台业务,维护开源项目AllData并提供商业版解决方案。AllData提供数据集成、存储、开发、治理及BI展示等一站式服务,支持AI大模型应用,助力企业高效利用数据价值。
|
4天前
|
SQL 人工智能 监控
SLS Copilot 实践:基于 SLS 灵活构建 LLM 应用的数据基础设施
本文将分享我们在构建 SLS SQL Copilot 过程中的工程实践,展示如何基于阿里云 SLS 打造一套完整的 LLM 应用数据基础设施。
|
6天前
|
人工智能 监控 测试技术
告别只会写提示词:构建生产级LLM系统的完整架构图​
本文系统梳理了从提示词到生产级LLM产品的八大核心能力:提示词工程、上下文工程、微调、RAG、智能体开发、部署、优化与可观测性,助你构建可落地、可迭代的AI产品体系。
71 2
|
6月前
|
数据采集 算法 数据挖掘
CLIMB自举框架:基于语义聚类的迭代数据混合优化及其在LLM预训练中的应用
英伟达提出的CLIMB框架,是一种自动化优化大型语言模型(LLM)预训练数据混合的创新方法。通过语义嵌入与聚类技术,CLIMB能系统地发现、评估并优化数据混合策略,无需人工干预。该框架包含数据预处理、迭代自举及最优权重确定三大阶段,结合小型代理模型与性能预测器,高效搜索最佳数据比例。实验表明,基于CLIMB优化的数据混合训练的模型,在多项推理任务中显著超越现有方法,展现出卓越性能。此外,研究还构建了高质量的ClimbMix数据集,进一步验证了框架的有效性。
217 0
CLIMB自举框架:基于语义聚类的迭代数据混合优化及其在LLM预训练中的应用
|
7月前
|
人工智能 数据可视化 API
36.7K star!拖拽构建AI流程,这个开源LLM应用框架绝了!
`Flowise` 是一款革命性的低代码LLM应用构建工具,开发者通过可视化拖拽界面,就能快速搭建基于大语言模型的智能工作流。该项目在GitHub上线不到1年就斩获**36.7K星标**,被开发者誉为"AI时代的乐高积木"。
349 8
|
3月前
|
人工智能 自然语言处理 数据可视化
AI-Compass LLM评估框架:CLiB中文大模型榜单、OpenCompass司南、RAGas、微软Presidio等构建多维度全覆盖评估生态系统
AI-Compass LLM评估框架:CLiB中文大模型榜单、OpenCompass司南、RAGas、微软Presidio等构建多维度全覆盖评估生态系统
 AI-Compass LLM评估框架:CLiB中文大模型榜单、OpenCompass司南、RAGas、微软Presidio等构建多维度全覆盖评估生态系统
|
29天前
|
人工智能 自然语言处理 数据可视化
手把手教你用LLM图转换器构建知识图谱:从文本到知识的智能转换
本文介绍如何利用大型语言模型(LLM)自动化构建知识图谱,涵盖核心技术、实现方法、优化策略及多领域应用,助力从非结构化文本中高效提取结构化知识。
|
3月前
|
缓存 异构计算 Docker
构建高性能LLM推理服务的完整方案:单GPU处理172个查询/秒、10万并发仅需15美元/小时
本文将通过系统性实验不同的优化技术来构建自定义LLaMA模型服务,目标是高效处理约102,000个并行查询请求,并通过对比分析确定最优解决方案。
167 0
构建高性能LLM推理服务的完整方案:单GPU处理172个查询/秒、10万并发仅需15美元/小时
|
6月前
|
机器学习/深度学习 人工智能 算法
零训练成本优化LLM: 11种LLM权重合并策略原理与MergeKit实战配置
随着大语言模型快速发展,如何优化性能同时降低计算成本成为关键问题。本文系统介绍了11种零训练成本的LLM权重合并策略,涵盖线性权重平均(Model Soup)、球面插值(SLERP)、任务算术、TIES-Merging等方法,通过MergeKit工具提供实战配置示例。无论研究者还是开发者,都能从中找到高效优化方案,在有限资源下实现模型性能显著提升。
227 10
零训练成本优化LLM: 11种LLM权重合并策略原理与MergeKit实战配置