之前有小伙伴咨询,Dify不支持直连数据库,如何做到通过自然语义给大模型然后返回对应的查询数据?收到这个留言的时候,脑海里就已经有了一个大致的方案,流程如下图:首先利用DeepSeek帮我准备数据库表结构和需要插入的数据相关的建表数据我贴在下面:
# 创建班级表CREATE TABLE classes ( class_id INT AUTO_INCREMENT PRIMARY KEY, class_name VARCHAR(50) NOT NULL);
# 创建用户表CREATE TABLE users ( user_id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL, email VARCHAR(100) NOT NULL, class_id INT, FOREIGN KEY (class_id) REFERENCES classes(class_id));
# 插入班级数据INSERT INTO classes (class_name) VALUES ('Class A'),('Class B'),('Class C'),('Class D'); # 插入用户数据INSERT INTO users (username, email, class_id) VALUES ('Alice', 'alice@example.com', 1),('Bob', 'bob@example.com', 2),('Charlie', 'charlie@example.com', 3),('David', 'david@example.com', 4),('Eve', 'eve@example.com', 1),('Frank', 'frank@example.com', 2),('Grace', 'grace@example.com', 3),('Hank', 'hank@example.com', 4),('Ivy', 'ivy@example.com', 1),('Jack', 'jack@example.com', 2);
然后通用利用DeepSeek帮我生成一个暴露接口用于查询数据库的服务,用python写整理后的python代码我贴在下面:
·
·
from flask import Flask, request, jsonifyimport pymysqlimport re
# 创建 Flask 应用app = Flask(__name__)
# 数据库连接配置DB_CONFIG = { 'host': 'localhost', 'user': 'test', # 替换为你的数据库用户名 'password': '123456', # 替换为你的数据库密码 'database': 'test', # 替换为你的数据库名称 'cursorclass': pymysql.cursors.DictCursor}
# 定义接口:执行 SQL 查询@app.route('/query', methods=['POST'])def execute_query(): # 获取客户端传递的 SQL 语句 data = request.json if not data or 'sql' not in data: return jsonify({'error': 'Missing SQL statement in request body'}), 400 sql = data['sql'] # 简单的 SQL 语句验证(防止恶意操作) if not re.match(r'^SELECTs', sql, re.IGNORECASE): return jsonify({'error': 'Only SELECT queries are allowed'}), 400 try: # 连接数据库 connection = pymysql.connect(**DB_CONFIG) with connection.cursor() as cursor: # 执行 SQL 查询 cursor.execute(sql) result = cursor.fetchall() return jsonify(result) except pymysql.MySQLError as e: return jsonify({'error': str(e)}), 500 finally: if connection: connection.close() # 启动服务if __name__ == '__main__': app.run(debug=True)
可以放在编辑器里面直接启动,也可以用命令行启动:
·
python .server.py
开始配置工作流创建一个单独的知识库,里面存放的就是我们的创建表结构的语句,可以是text格式也可以是markdown格式,这个都可以,我这边就很简单粗暴的直接扔建表语句进去,最好是带注释的,我演示用就简洁一点:创建一个空的工作流在【开始】节点添加“输入字段:content” 在【开始】节点后添加一个【知识检索】节点:在【知识检索】节点后添加【LLM】节点:【知识检索】节点的输出作为上下文传入,并在提示词内设置【开始】节点输入的"content"字段,以供LLM去做分析:我设置的提示词也贴在下面,“{}”花括号内的是你需要在节点中设置的参数,参考上图显示的最终结果:
·
·
·
·
·
·
·
·
·
·
·
·
·
你是一个数据分析师,根据用户输入的{content}需求以及检索到{上下文},生成对应的查询SQL,SQL必须经过严格的校验。## 你可以使用的其他方法用户输入类似于“求和”或“总和”时,则在sql语句中使用SUM()。用户输入类似于“平均数”或“平均”时,在在sql语句中使用AVG()。## 要求1.如果用户输入的内容无法生成为sql语句,请直接说“抱歉,该命令无法形成数据库查询操作”。2.当可以生成sql语句时,请确保输出的内容为完整正确的sql语句,不要输出此外的其他任何字符,确保你生成的内容用户可以直接执行查询操作。3.对于字符串内容的查询请使用LIKE操作而不是等于操作。4.请不要在回复中包括除sql语句之外的任何内容。5.禁止中间过程输出。6.输出的sql为一整行。
在【自然语言推导SQL语句LLM】节点后,添加【HTTP请求】节点,并在节点上添加API和查询参数(JSON格式),查询参数就是【自然语言推导SQL语句LLM】节点输出的SQL语句,参数名称"sql"可以根据上面的python代码中处理的字段名称来调整:需要注意的是,Dify是我本地Docker部署的,然后这个查询接口也是我本地启动的,所以这个接口地址不能用127.0.0.1,需要改成host.docker.internal。在【查询SQL结果请求】节点之后,就可以添加【结束】节点了,输出内容就是我们【查询SQL结果请求】的输出内容即可。因为输出的是JSON格式的数据,也可以让返回结果为表格等,但是需要额外的节点去做处理,在这儿就不在演示,感兴趣的小伙伴们可以在这个基础上再做优化调整。
感谢小伙伴们提供的留言问题,我这只是一种思路方案,还有一种方案就是,通过python代码连接Dify然后结合知识库解析自然语言并推导出对应的SQL语句提供给python去执行,这种方案和我提供的方案大同小异,都是可以实现效果。上述只是一个简单的demo,只是为了跑通这个逻辑,实际使用的话,要做很多层的限制,对SQL的推导也需要做更多的条件分支和二次分析等节点,以提高准确性和可用性。有需要不想动手重新操作的小伙伴也可以关注我公众号后,在公众号发送【1007】(发蓝色数字)获取DSL导出文件,你们直接导入Dify后,调整对应参数就能运行,然后再此基础上做优化,也希望你们有新的设计后也可以共享出来!
PM墨者
一个普通的PM分享着不一样的项目管理知识,期待和大家一起进步
深圳市福田区梅林街道梅林一村社区梅林路142号梅林一村1栋、2栋、3栋、4栋4栋5D