智能体+MCP+NL2SQL构建一个智能数据分析应用(一)

通过Dify智能体,结合MCP工具能力,可以很轻松的构建基于数据库的查询问答,对用户输出的问题,通过Dify的Agent节点,自动调用合适的工具来获取数据并回答问题。下面以一个具体的数据例子来介绍如何完成。

创建示例数据库

首先准备一些示例数据,这里以一个数字音乐商店的数据为例,可以在Github仓库GitHub - lerocha/chinook-database: Sample database for SQL Server, Oracle, MySQL, PostgreSQL, SQLite, DB2上下载相应的数据库创建脚本,创建数据库。这个数据库有以下的数据表,其结构如下图。

以Postgresql数据库为例,首先通过docker启动postgres服务。

bash 复制代码
docker run -d \
  --name postgres \
  -e POSTGRES_PASSWORD=abc123 \
  -p 5432:5432 \
  -v /home/abc/docker/volumes/postgres:/var/lib/postgresql \
  postgres:latest

将Github仓库下载的sql脚本通过docker cp拷贝到容器中,然后连接到数据库。

bash 复制代码
docker exec -it postgres psql -U postgres

运行sql脚本创建数据库

bash 复制代码
\i /Chinook_PostgreSql.sql

创建完成后,可以通过命令\dt查看导入的数据表, \d tablename查看具体某个表的结构。

通过以下命令导出所有的表结构数据。

bash 复制代码
docker exec -it postgres pg_dump -U postgres -d chinook -s -f /datatables.sql

然后将其保存到宿主机

bash 复制代码
docker cp postgres:/datatables.sql ./

保存好的sql文件后续可以在智能体工作流中传入给大模型,帮助大模型理解数据库的结构,从而按照用户的提问生成相应的SQL查询语句。

除了用sql格式来描述数据库结构,也可以采用M-Schema规范来描述数据库结构,这是一种用于自然语言转SQL(NL2SQL)​ 任务的、半结构化的数据库模式表示规范。它由阿里巴巴的团队提出,是其 XiYan-SQL 框架的核心组成部分,旨在解决大模型在理解复杂、专业的数据库结构时面临的挑战,具体介绍可以参见https://github.com/XGenerationLab/XiYan-DBDescGen.git

通过以下代码自动生成M-Schema文件。

python 复制代码
import os
from sqlalchemy import create_engine

database_url = 'postgresql://postgres:abc123@localhost:5532/chinook'
engine = create_engine(database_url)

from schema_engine import SchemaEngine

db_name = 'chinook'
schema_engine = SchemaEngine(engine=engine, db_name=db_name)
mschema = schema_engine.mschema
mschema_str = mschema.to_mschema()
print(mschema_str)
mschema.save(f'./{db_name}.json')

创建MCP服务

数据库创建完成后,需要对外提供一个MCP服务,使得大模型可以调用该服务进行数据库的查询。这里采用fastmcp这个库来构建MCP服务,如以下代码。

python 复制代码
from fastmcp import FastMCP
from sqlalchemy import create_engine, text

database_url = 'postgresql://postgres:roy2000@localhost:5532/chinook'

app = FastMCP("Database Query Server") 

def execute_safe_query(sql):
    """执行SQL并返回结果,包含基础安全校验"""
    # 1. 安全检查:禁止执行非SELECT语句或包含危险关键词的操作
    #sql_upper = sql.replace("\n", "").strip().upper()
    sql_upper = sql.strip().upper()
    if not sql_upper.startswith('SELECT'):
        raise ValueError("Only SELECT queries are allowed for safety.")
    if any(keyword in sql_upper for keyword in ['DROP', 'DELETE', 'INSERT', 'UPDATE', ';--']):
        raise ValueError("Potentially dangerous operation detected and blocked.")

    # 2. 连接数据库并执行查询
    with engine.connect() as connection:
        try:
            result = connection.execute(text(sql))
            data = result.mappings().all()
            serializable_result = [dict(row) for row in data]
            return {"status": "success", "data": serializable_result}
        except Exception as e:
            return {"status": "error", "message": str(e)}

# 使用装饰器将函数注册为MCP工具
@app.tool()
def query_database(sql_query: str) -> dict:
    """
    根据提供的SQL查询语句,从数据库中检索信息。
    参数:
        sql_query (str): 要执行的SELECT查询语句。
    """
    print(f"Sql execute code: {sql_query}")
    return execute_safe_query(sql_query)

if __name__ == "__main__":
    engine = create_engine(database_url)
    # 以标准输入输出(stdio)模式运行服务器,这是最常见的与客户端通信的方式
    app.run(transport="sse", host="127.0.0.1", port=8000)

运行该Python脚本,即可启动一个MCP服务,提供数据库查询服务。

创建智能体

在Dify中,单击"工具"菜单,然后选择"MCP",最后单击"添加一个MCP服务",在设置中填入MCP服务的URL,之前启动的MCP服务的URL是http://127.0.0.1:8000/sse,因为我的Dify是在容器中运行的,所以这里的URL设置为http://host.docker.internal:8000/sse,设置后如下图。

现在可以创建Dify智能体了,在新建一个Chatflow工作流,并按如下方式编排节点。

这里面的文档提取器节点用于对上传的数据库sql格式的文件进行解析,以获取文档的内容。Agent节点在工具列表中添加之前配置的MCP服务,并设置指令,如下图。

设置完成后,单击预览,进行测试。

在对话窗口中上传之前创建的数据库格式的sql文件,然后询问"当前有多少首歌曲",Agent节点将基于数据库的格式,自动生成对应的SQL查询语句,然后进行回复。从MCP服务打印出的SQL语句"SELECT COUNT(*) FROM track;"来看,Agent节点的大模型正确的把用户的问题转换为数据库的查询语句,运行结果如下图所示。

现在问一个稍微复杂一点的问题,"按歌曲的风格来统计歌曲数量并进行排序,列出排名前十位的歌曲风格及其歌曲数量", MCP服务打印出的SQL语句是SELECT genre.name, COUNT(track.track_id) as count FROM track JOIN genre ON track.genre_id = genre.genre_id GROUP BY genre.genre_id ORDER BY count DESC LIMIT 10;", 运行结果如下。

可见工作流可以准确的把用户的问题翻译为SQL语句,并在查询后给出结果。后续将进行功能的进一步丰富和优化。

相关推荐
胡萝卜3.02 小时前
现代C++特性深度探索:模板扩展、类增强、STL更新与Lambda表达式
服务器·开发语言·前端·c++·人工智能·lambda·移动构造和移动赋值
智算菩萨2 小时前
音乐生成模型综述:从符号作曲到音频域大模型、评测体系与产业化趋势
人工智能·深度学习·算法
AAD555888992 小时前
YOLOX-Nano彩色盒子目标检测:8x8批量训练300轮COCO数据集优化方案
人工智能·目标检测·目标跟踪
丝斯20112 小时前
AI学习笔记整理(30)—— 计算机视觉之动作识别相关算法
人工智能·笔记·学习
wei_shuo2 小时前
AI 代理框架:使用正确的工具构建更智能的系统
人工智能
独自归家的兔2 小时前
大模型通义千问3-VL-Plus - 视觉推理(图像列表)
人工智能·计算机视觉
Spring AI学习2 小时前
Spring AI深度解析(8/50):模型评估体系实战
人工智能·spring·microsoft
周名彥2 小时前
1Ω1[特殊字符]⊗雙朕周名彥|二十四芒星非硅基华夏原生AGI体系·授权绑定激活发布全维研究报告(S∅-Omega级·纯念主权终极版)
人工智能·去中心化·知识图谱·量子计算·agi