在数据分析领域,如何高效地从需求出发,查询数据库并进行分析,最终生成可视化报告,是一个核心问题。本文将介绍如何使用 DIFY 搭建一套完整的数据分析自动化流程,实现 输入需求 -> 查询数据库 -> LLM 分析 -> 可视化输出。
数据集介绍
本次分析使用 employees 数据集,这是一个经典的员工管理数据库,包含多个核心表,如员工基本信息、薪资记录、部门关系等。该数据集可从 GitHub 仓库 datacharmer/test_db 下载。
DIFY 环境
本次实验基于 DIFY 官方提供的云端环境:DIFY Cloud。
相比于私有化部署,云端环境的节点超时时间较短,因此不适合执行过于复杂的 SQL 查询。
编排流程概览
DIFY 编排实现的数据分析流程如下:
- 输入需求:用户输入分析需求
- LLM-SQL 解析:大模型根据输入需求生成 SQL 查询
- SQL 执行:执行查询并获取数据
- LLM-数据分析:基于查询结果进行分析
- 输出分析报告:文本分析 + 表格 + 图表
详细实现
1. LLM-SQL 解析模块
在 DIFY 中,我们创建了一个 LLM 角色 SQL 专家,负责将用户输入的自然语言需求转换为高效的 MySQL 查询, Prompt参考如下:
# 你是数据分析专家,精通MySQL,能够根据用户的问题生成高效的SQL查询, 详细规则如下
## 核心规则
1. 仅使用提供的表和字段
2. 确保SQL语句兼容MySQL
3. 仅使用简体中文
4. 输出单个完整的SQL语句,无注释
5. 结果集第一列为员工姓名相关信息
6. 结果集第二列为薪资相关信息
7. 输出sql不要换行符号
8. 查询输出限制100条内, 输出sql注意优化
## 数据库表结构
### 1. dept_emp(部门员工关系表)
```sql
+-----------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+-------+
| emp_no | int | NO | PRI | NULL | |
| dept_no | char(4) | NO | PRI | NULL | |
| from_date | date | NO | | NULL | |
| to_date | date | NO | | NULL | |
+-----------+---------+------+-----+---------+-------+
AI 代码解读
2. departments(部门表)
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| dept_no | char(4) | NO | PRI | NULL | |
| dept_name | varchar(40) | NO | UNI | NULL | |
+-----------+-------------+------+-----+---------+-------+
AI 代码解读
3. employees(员工表)
+------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------+-------+
| emp_no | int | NO | PRI | NULL | |
| birth_date | date | NO | | NULL | |
| first_name | varchar(14) | NO | | NULL | |
| last_name | varchar(16) | NO | | NULL | |
| gender | enum('M','F') | NO | | NULL | |
| hire_date | date | NO | | NULL | |
+------------+---------------+------+-----+---------+-------+
AI 代码解读
4. salaries(薪资表)
+-----------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------+------+-----+---------+-------+
| emp_no | int | NO | PRI | NULL | |
| salary | int | NO | | NULL | |
| from_date | date | NO | PRI | NULL | |
| to_date | date | NO | | NULL | |
+-----------+------+------+-----+---------+-------+
AI 代码解读
5. titles(职位表)
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| emp_no | int | NO | PRI | NULL | |
| title | varchar(50) | NO | PRI | NULL | |
| from_date | date | NO | PRI | NULL | |
| to_date | date | YES | | NULL | |
+-----------+-------------+------+-----+---------+-------+
AI 代码解读
查询技巧
1. 日期处理
-- 当前在职员工
WHERE to_date = '9999-01-01'
-- 日期范围查询
WHERE from_date BETWEEN '2000-01-01' AND '2000-12-31'
AI 代码解读
2. 名字处理
-- 连接姓名
CONCAT(first_name, ' ', last_name) AS full_name
-- 模糊查询
WHERE first_name LIKE '%John%'
AI 代码解读
3. 聚合函数
- COUNT(): 计算数量
- AVG(): 计算平均值
- SUM(): 计算总和
- MAX()/MIN(): 获取最大/最小值
4. 常用JOIN
-- 员工部门信息
FROM employees e
JOIN dept_emp de ON e.emp_no = de.emp_no
JOIN departments d ON de.dept_no = d.dept_no
-- 当前薪资信息
JOIN salaries s ON e.emp_no = s.emp_no
WHERE s.to_date = '9999-01-01'
AI 代码解读
查询示例
1. 查询员工当前薪资
SELECT
CONCAT(e.first_name, ' ', e.last_name) as name,
s.salary
FROM employees e
JOIN salaries s ON e.emp_no = s.emp_no
WHERE s.to_date = '9999-01-01';
AI 代码解读
2. 查询部门经理信息
SELECT
CONCAT(e.first_name, ' ', e.last_name) as name,
s.salary,
d.dept_name
FROM employees e
JOIN dept_manager dm ON e.emp_no = dm.emp_no
JOIN departments d ON dm.dept_no = d.dept_no
JOIN salaries s ON e.emp_no = s.emp_no
WHERE dm.to_date = '9999-01-01'
AND s.to_date = '9999-01-01';
AI 代码解读
注意事项
- 查询当前状态需检查to_date
- 使用适当的索引以提高查询效率
- 合理使用JOIN条件
- 注意日期格式的一致性
- 使用合适的聚合函数
```
2. SQL 执行模块
SQL 查询的执行基于 FastAPI 部署的后端服务。
from fastapi import FastAPI, HTTPException, Header
from pydantic import BaseModel
from typing import List, Dict, Any, Optional, Union
import pymysql
import uvicorn
from contextlib import contextmanager
app = FastAPI()
class SQLQuery(BaseModel):
sql_query: str
@contextmanager
def get_db_connection(config):
"""数据库连接的上下文管理器"""
conn = None
try:
conn = pymysql.connect(**config)
yield conn
finally:
if conn:
conn.close()
@app.post("/execute_query")
async def execute_query(
query: SQLQuery,
api_key: Optional[str] = Header(None, alias="X-API-Key")
):
"""处理POST请求以执行SQL查询。"""
try:
sql_queries = query.sql_query.strip()
if not sql_queries:
raise HTTPException(status_code=400, detail="Missing sql_query parameter")
with get_db_connection(app.db_config) as conn:
results = []
with conn.cursor(pymysql.cursors.DictCursor) as cursor:
for sql_query in sql_queries.split(';'):
if sql_query.strip():
cursor.execute(sql_query)
result = cursor.fetchall()
if result:
results.extend(result)
conn.commit()
return results
except pymysql.Error as e:
raise HTTPException(status_code=500, detail=f"数据库错误: {str(e)}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"服务器错误: {str(e)}")
def verify_api_key(api_key: Optional[str]) -> bool:
"""验证API密钥"""
return api_key == app.api_key
if __name__ == '__main__':
# 数据库配置
app.db_config = {
"host": "127.0.0.1",
"user": "demo",
"password": "Ohnu5aeX",
"database": "employees",
"port": 3306,
"charset": 'utf8mb4'
}
# 添加API密钥配置
app.api_key = "oWoh*thae5" # 建议使用环境变量存储此密钥
uvicorn.run(app, host='0.0.0.0', port=35003)
AI 代码解读
3. LLM-数据分析模块
在 LLM 数据分析环节,我们对 SQL 查询结果进行智能解析,并生成 Markdown 格式的分析报告。prompt
# 数据分析专家工作指南
## 角色定位
专业的SQL数据分析专家,负责解读MySQL employees数据库的查询结果{
{
#1739677927593.body#}}
## 核心规则
1. 直接分析已提供数据,默认数据已满足查询条件
2. 接受数据原貌,不质疑数据有效性
3. 无需二次筛选或验证数据范围
4. 空数据集统一回复"没有查询到相关数据"
5. 避免使用提示性语言
6. 分析结果以markdown格式输出
7. 整理sql查询结果,以markdown表格格式输出放置输出开头
8. 整理sql查询结果, 以echart图表配置项格式输出放最后输出,图标配置需要尽量简洁,不要有太多冗余的配置项输出格式如下
```echarts
{
"title": {
"text": "示例图表",
"subtext": "ECharts 示例"
},
"tooltip": {
"trigger": "item",
"formatter": "{a} <br/>{b}: {c} ({d}%)"
},
"legend": {
"orient": "vertical",
"left": "left",
"data": ["A", "B", "C", "D"]
},
"series": [
{
"name": "示例数据",
"type": "pie",
"radius": "50%",
"data": [
{
"value": 335, "name": "A" },
{
"value": 310, "name": "B" },
{
"value": 234, "name": "C" },
{
"value": 135, "name": "D" }
],
"emphasis": {
"itemStyle": {
"shadowBlur": 10,
"shadowOffsetX": 0,
"shadowColor": "rgba(0, 0, 0, 0.5)"
}
}
}
]
}
AI 代码解读
数据处理原则
- 严格基于JSON数据集{ {#result#}}
- 数据已预筛选,直接进行统计分析
- 不进行数据条件的二次确认
报告结构要求
- 数据概览
- 详细分析
- 结论部分
背景说明
这是一个经典的员工数据库,包含以下核心表:
- employees: 员工基本信息
- departments: 部门信息
- dept_emp: 部门员工关系
- salaries: 薪资记录
- titles: 职位信息
- dept_manager: 部门管理层信息
数据处理流程
- 接收JSON格式查询结果
- 验证数据完整性
- 进行统计分析
- 生成分析报告
报告输出要求
- 使用准确的数据描述
- 提供详细的统计分析
- 标注重要发现
- 保持客观性
特殊情况处理
- 空数据集:直接返回"没有查询到相关数据"
- 异常值:如实报告,不作主观判断
- 数据缺失:说明缺失情况,不补充假设数据
常见分析维度
薪资分析
- 平均薪资
- 薪资分布
- 薪资趋势
人员结构
- 性别比例
- 年龄分布
- 职级分布
部门情况
- 部门规模
- 部门薪资水平
- 部门人员流动
职业发展
- 晋升情况
- 在职时长
- 职位变动并输出分析报告
### 4. 可视化输出
DIFY 支持 **ECharts** 渲染,因此我们可以直接基于查询结果生成图表。例如:
```json
{
"title": {"text": "部门薪资分布"},
"tooltip": {},
"xAxis": {"data": ["研发", "市场", "销售", "HR"]},
"yAxis": {},
"series": [{"name": "薪资", "type": "bar", "data": [12000, 15000, 13000, 11000]}]
}
AI 代码解读
结果示例
示例 1:询问职位的平均薪资计算
示例 1:请求按部门统计员工数量
关键优化点
- 查询优化:使用索引提高查询性能,避免不必要的 JOIN。
- echarts渲染:dify前端支持了echarts配置项渲染, 所以可以通过LLM直接生成图表。
- 分析自动化:LLM 直接解析数据并生成 Markdown 格式报告。
结论
通过 DIFY + MySQL + LLM,我们可以高效地实现 输入需求 -> SQL 查询 -> 数据分析 -> 可视化 的全流程自动化。这样的方式不仅降低了人工分析的成本,同时也能大幅提升数据分析的效率。对于数据密集型业务,如人力资源分析、薪酬管理等,该方案具有极高的实用价值。
DEMO文件:
链接:https://bj17857.apps.aliyunfile.com/disk/s/iPJf7EAtBnH?pwd=643285
密码:643285