之前有小伙伴咨询,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, jsonify
import pymysql
import 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'^SELECT\s', 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后,调整对应参数就能运行,然后再此基础上做优化,也希望你们有新的设计后也可以共享出来!

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐