微信扫码
添加专属顾问
我要投稿
告别手动编程,实现数据可视化的智能对话助手。 核心内容: 1. 利用Dify、数据库和Echarts搭建智能数据可视化助手 2. 通过自然语言指令自动查询数据库并生成图表 3. 详细步骤与实例,从数据准备到图表生成全流程拆解
你是否曾幻想过,
面对复杂的数据,
不再需要手动编写繁琐的SQL,
不再需要费力选择图表类型,
只需像和助手对话一样,
轻松说出你的数据分析需求,
精美的图表便能自动呈现在眼前?
使用效果如下:
上一篇文章,我们探讨了dify中数据库及Echarts图表的基础用法,但当时的SQL语句是预设的,灵活性稍显不足。
也有很多人评论想知道如何使用自然语言生成sql然后自动生成Echarts图表的方式。
这次满足大家的需求,我将手把手带你利用dify的工作流编排能力和大型语言模型(LLM),搭建一个能“听懂”我们自然语言指令,自动查询数据库、判断图表类型,并最终生成酷炫Echarts图表的数据可视化助手!
忘记那些写死的SQL和固定的图表吧,是时候让数据分析变得如此智能和随心所欲了!
核心思路很简单: 用户用大白话提问 -> 工作流智能判断是否需要图表及图表类型 -> 将用户问题转化为SQL语句 -> 执行SQL查询数据库 -> 将查询结果处理成图表所需格式 -> 调用相应的Echarts图表插件生成图表 -> (如果不需要图表)LLM总结数据并回复。
听起来很酷?让我们一步步拆解这个工作流是如何搭建的。
还是用中国历史票房红榜的数据了,使用Mysql数据库。
你可以根据自己的实际业务数据进行替换。
我们选取其中的年份、电影名称、评分、导演、票房来新建数据表。
新建数据库test。
新建数据库表boxoffice结构如下:
-- ----------------------------
-- Table structure for boxoffice
-- ----------------------------
DROPTABLE IF EXISTS `boxoffice`;
CREATETABLE `boxoffice` (
`years` varchar(64) CHARACTERSET utf8 COLLATE utf8_unicode_ci NULLDEFAULTNULL,
`movie_name` varchar(255) CHARACTERSET utf8 COLLATE utf8_unicode_ci NULLDEFAULTNULL,
`score` floatNULLDEFAULTNULL,
`director` varchar(64) CHARACTERSET utf8 COLLATE utf8_unicode_ci NULLDEFAULTNULL,
`box_office` floatNULLDEFAULTNULL
) ENGINE = MyISAM CHARACTERSET= utf8 COLLATE= utf8_unicode_ci ROW_FORMAT =Dynamic;
数据如下:
这次用到了两个插件,需要提前安装一下。
1、插件市场搜索“db”,找到【rookie_text2data】插件进行安装。
2、插件市场搜索“Echarts”,找到【ECharts图表生成】插件进行安装。
新建一个对话流,这次稍微复杂一点点,整体流程如下:
这里无需特殊配置,它将作为接收用户自然语言提问的入口。
这是我们工作流的第一个“智能大脑”。
它负责分析用户的原始问题,判断是否需要图表,并初步确定合适的图表类型(柱状图、折线图、饼图,或不需要图表)。
模型选择: DeepSeek-ai/DeepSeek-V3
完整提示词如下:
你是一个智能助手,需要根据用户的问题判断是否需要用图表展示数据,并判断适合的图表类型。
请严格按照如下JSON格式输出,不要输出多余内容:
{
"need_chart": true/false, // 是否需要图表
"chart_type": "bar/line/pie/none" // 推荐的图表类型,bar=柱状图,line=折线图,pie=饼图,none=不需要图表
}
判断标准:
- 如果用户问题中包含“趋势”、“变化”、“对比”、“分布”、“比例”、“占比”、“增长”等词,通常需要图表。
- 如果用户问题中有“每年”、“历年”、“随时间”、“随年份”等,推荐折线图(line)。
- 如果用户问题中有“对比”、“排行”、“最多”、“最少”等,推荐柱状图(bar)。
- 如果用户问题中有“占比”、“比例”、“分布”等,推荐饼图(pie)。
- 如果用户只是问具体数值、详情、描述,不需要图表,chart_type 填 none。
示例:
用户问题:“请用图表展示历年票房变化”
输出:{"need_chart": true, "chart_type": "line"}
用户问题:“各导演的票房占比是多少?”
输出:{"need_chart": true, "chart_type": "pie"}
用户问题:“哪吒之魔童降世的票房是多少?”
输出:{"need_chart": false, "chart_type": "none"}
现在请判断下面这个问题:
{{#sys.query#}}
这个节点是实现“自然语言对话数据库”的核心。它会将用户的原始问题(sys.query)和我们预设的数据库表结构信息结合,智能地生成可执行的SQL语句。
输入变量:
数据库配置: 正确填写数据库类型、IP、端口、库名、用户名、密码。
大模型:我这里就用DeepSeek V3了。
返回数据格式为TEXT,就是自然语言转成的SQL语句。
自定义提示词:
表名:boxoffice
字段说明:
- years:年份,int
- movie_name:电影名,string
- score:评分,float
- director:导演,string
- box_office:票房,int
注意事项:
- 如有分组统计,请使用SUM、AVG等聚合函数,不要直接用原始字段。
- 所有非聚合字段必须出现在GROUP BY中。
- 只输出SQL语句,不要解释。
示例查询:
1. 查询每个导演的总票房:SELECT director, SUM(box_office) FROM boxoffice GROUP BY director;
2. 查询每年票房最高的电影:SELECT years, movie_name, MAX(box_office) FROM boxoffice GROUP BY years;
之所以选择这个插件,因为支持自定义提示词,这样就可以把表结构及注意事项都写在提示词中。
此节点负责连接数据库,并执行上一步生成的SQL语句。
这是一个逻辑判断节点,它会根据第一个LLM节点【判断用户问题】的输出,决定工作流是走向“生成图表”的分支,还是走向“无需图表,直接文字回答”的分支。
上一个条件分支走到需要图表,工作流会进入这个LLM节点。
它的核心任务是将SQL查询结果(目前是TEXT格式)和第一个LLM判断出的图表类型(target_chart_type),转换为后续代码节点或图表插件所需的格式化数据。
完整提示词如下:
SYSTEM
你是一个数据格式化专家。你的核心任务是根据已执行的SQL查询结果和用户指定的图表类型,将数据转换为特定图表工具所需的输入格式。
## 上下文变量说明:
*`target_chart_type`: (String) 用户期望生成的图表类型,值为 "bar"、"pie" 或 "line"。此信息来源{{#1746780564950.text#}}。
*`sql_execution_result`: (JSON Array) SQL查询的执行结果,来源于{{#context#}}例如 `[{"category": "A", "value": 10}, {"category": "B", "value": 20}]`。
*`user_original_query`: (String) 用户最原始的自然语言查询,可用于辅助生成图表标题,,来源于{{#sys.query#}}。
## 图表工具输入规范:
1.**柱状图 (bar):**
* 标题 (String)
* 数据 (String): 数字用 ";" 分隔 (例如:"150;280;200")
* x轴 (String): 文本用 ";" 分隔 (例如:"一月;二月;三月")
2.**饼图 (pie):**
* 标题 (String)
* 数据 (String): 数字用 ";" 分隔 (例如:"30;50;20")
* 分类 (String): 文本用 ";" 分隔 (例如:"类型A;类型B;类型C")
3.**线性图表 (line):**
* 标题 (String)
* 数据 (String): 数字用 ";" 分隔 (例如:"10;15;13;18")
* x轴 (String): 文本用 ";" 分隔 (例如:"周一;周二;周三;周四")
## 任务指令:
1.**解析核心数据**:
* 将输入的 `sql_json_string_result` (它是一个字符串) **作为 JSON 进行解析**。解析后的结果可能是单个 JSON 对象(如果SQL只返回一行)或一个 JSON 对象数组(如果SQL返回多行)。我们将其称为 `core_sql_data`。
* 例如,如果 `sql_json_string_result` 是字符串 `"[{\"colA\": \"val1\", \"colB\": 10}]"`,那么 `core_sql_data` 就是实际的数组 `[{"colA": "val1", "colB": 10}]`。
* 如果 `sql_json_string_result` 是字符串 `"{\"colA\": \"val1\", \"colB\": 10}"`,那么 `core_sql_data` 就是实际的对象 `{"colA": "val1", "colB": 10}`。为了统一处理,如果它是单个对象,请将其视为只包含一个元素的数组。
2.**生成图表标题**: 参考 `user_original_query`,生成一个简洁明了的 `chart_tool_title`。
3.**数据提取与格式化 (基于 `core_sql_data`)**:
* 分析 `core_sql_data`。数组中的每个对象代表一个数据点。你需要从中识别出用作标签/类别/x轴的字段(通常是文本或日期类型)和用作数值/数据的字段(通常是数字类型)。
***根据 `target_chart_type` 指示的类型进行处理:**
***若为 "bar"**:
* 从 `core_sql_data` 中提取所有对象的数值字段值,用 ";" 连接成 `chart_tool_data_string`。
* 提取所有对象的标签字段值,用 ";" 连接成 `chart_tool_label_string` (对应x轴)。
***若为 "pie"**:
* 从 `core_sql_data` 中提取所有对象的数值字段值,用 ";" 连接成 `chart_tool_data_string`。
* 提取所有对象的标签字段值,用 ";" 连接成 `chart_tool_label_string` (对应分类)。
***若为 "line"**:
* 从 `core_sql_data` 中提取所有对象的数值字段值,用 ";" 连接成 `chart_tool_data_string`。
* 提取所有对象的标签字段值,用 ";" 连接成 `chart_tool_label_string` (对应x轴).
* 确保 `core_sql_data` 中至少有一个标签/类别字段和一个数值字段可供提取。如果字段不明确(例如,多个数字列),优先选择第一个文本/日期字段作为标签,第一个数字字段作为数据,或根据 `user_original_query` 中的暗示选择。
4.**构建输出**:
* 以严格的JSON对象格式输出以下字段:
*`chart_tool_title` (String)
*`chart_tool_data_string` (String)
*`chart_tool_label_string` (String)
*`chart_type_final` (String, 其值应等于输入的 `target_chart_type`)
## 示例(假设变量已按上述说明传入):
* 若 `target_chart_type` = "bar"
* 若 `sql_json_string_result` (字符串) = `"[{\"product_name\": \"产品A\", \"total_sales\": 5500}, {\"product_name\": \"产品B\", \"total_sales\": 7200}]"`
* 若 `user_original_query` = "查询产品销售额柱状图"
期望的输出JSON:
```json
{
"chart_tool_title": "产品销售额柱状图",
"chart_tool_data_string": "5500;7200",
"chart_tool_label_string": "产品A;产品B",
"chart_type_final": "bar"
}
功能就是提取LLM的数据,作为图表节点的输入。
完整代码如下:
import json
import re # 导入正则表达式模块
defmain(llm_data_input):
llm_data_str = llm_data_input
# 1. 清理 Markdown 代码块标记 (保持你现有的健壮清理逻辑)
llm_data_str = llm_data_str.strip()
if llm_data_str.startswith("```json"):
llm_data_str = llm_data_str[len("```json"):]
elif llm_data_str.startswith("```"):
llm_data_str = llm_data_str[len("```"):]
if llm_data_str.endswith("```"):
llm_data_str = llm_data_str[:-len("```")]
llm_data_str = llm_data_str.strip()
data = {}
try:
data = json.loads(llm_data_str)
except json.JSONDecodeError as e:
return {
"unpacked_title": f"Error: Invalid JSON - {e}",
"unpacked_data": "",
"unpacked_labels": "",
"chart_type": "error_invalid_json"
}
title = data.get("chart_tool_title", "无标题")
original_data_string = data.get("chart_tool_data_string", "") # 获取原始数据字符串
label_string = data.get("chart_tool_label_string", "")
chart_type = data.get("chart_type_final")
if chart_type isNone:
chart_type = "unknown_type_from_llm"
# 2. 清理和验证 data_string (这是关键的修改部分)
cleaned_data_parts = []
if original_data_string: # 只有当原始数据字符串非空时才处理
parts = original_data_string.split(';')
for part in parts:
part = part.strip() # 移除每个部分前后的空格
if part: #确保部分不是空字符串
try:
# 尝试转换为 float 来验证它是否是有效数字
# 我们仍然以字符串形式保存,因为插件期望分号分隔的字符串
float(part) # 如果这里失败,会抛出 ValueError
cleaned_data_parts.append(part)
except ValueError:
cleaned_data_parts.append("0") # 方案 b: 替换为 "0"
# print(f"Warning: Invalid data part '{part}' replaced with '0'.")
else:
# 如果部分是空字符串 (例如来自 ";;"),也替换为 "0" 或跳过
cleaned_data_parts.append("0") # 方案 b: 替换为 "0"
# print(f"Warning: Empty data part replaced with '0'.")
unpacked_data = ";".join(cleaned_data_parts)
return {
"unpacked_title": title,
"unpacked_data": unpacked_data, # 使用清理过的数据字符串
"unpacked_labels": label_string, # 标签字符串通常不需要转为数字,所以保持原样
"chart_type": chart_type
}
判断代码节点的chart_type类型,给到不同的图表插件。
这些是你预设的、能够接收格式化数据并(理想情况下)输出可渲染Echarts图表的工具。
如果最初判断用户问题不需要图表,工作流会进入这个分支。
这里我们用一个LLM节点,根据用户的问题和“执行SQL”节点返回的(TEXT格式)查询结果,用自然语言生成一段简洁的文字回答。
提示词如下:
请根据用户问题和查询结果,用简洁的中文自然语言回答。
用户问题:{{#sys.query#}}
查询结果:{{#context#}}
注意查询结果中票房数据不用换算,原数据展示,单位为万元
这是工作流的终点,负责将生成的结果(无论是图表还是文字回答)展示给用户。
你需要配置此节点,使其能够正确接收并展示来自不同分支的输出。
在Dify应用的“提示词编排”或“开场白”设置中,你可以设计一个友好的欢迎语和一些示例问题,引导用户开始提问。
点击预览按钮,找到右下角“管理”:
点击编写开场白。
设置开场白和开场问题。
测试生成3种格式的图表及无需生成图表的问题。
1、饼图测试。测试问题:各导演的票房占比是多少?
可以看一下工作流具体是怎么工作的?
自然语言转SQL:
转换数据:最后给图表插件传递的参数。
2、折线图测试。测试问题:各导演的票房占比是多少?
3、柱形图测试。测试问题:评分最高的五部电影。
4、普通问题测试,无需生成图表,直接回答。
通过Dify工作流的巧妙搭建,我们成功地让数据可视化助手学会了“聆听”。
自然语言转SQL,再到Echarts图表,一切都那么自然而高效。
技术的进步,是为了更好地服务于人。
从此,你可以更专注于数据背后的洞察。
把重复的任务,交给智能的助手。
开口即图,让想法快速验证。
享受这份,由简驭繁的从容。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-10-14
2024-10-09
2024-06-20
2025-02-04
2024-06-14
2024-06-16
2024-06-14
2025-02-09
2024-05-31
2024-07-24
2025-05-12
2025-05-09
2025-04-17
2025-04-14
2025-04-10
2025-04-05
2025-03-24
2025-03-11