手撸一个 deepseek 数据库对话,打造一个企业智能通讯录(ollama + deepseek + langchain)

前言
由于 deepseek 等大语言模型数据时效性问题,无法跟上现实世界信息的动态变化,企业内部信息更是无法理解,为了将 deepseek 应用到企业内部,之前有写过通过联网搜索、上传文件、搭建知识等检索增强生成(RAG)方式,现在继续探讨如何通过结合数据库来实现问答。

一、准备环境

  1. ollama,用于在本地运行、部署和管理大型语言模型(LLMs)。
  2. deepseek 模型,本文用的 deepseek-r1:14b。
  3. langchain,大语言模型应用程序的开发框架,主要 python 实现。
  4. Mysql,这里建议单独部署一个专门用来数据库问答,避免影响生产环境。

二、开发思路

本文打算通过三张表,用户基本信息表,公司/部门信息表,一个用户与公司/部门关联表,再结合 deepseek 根据用户问答使用自然语言流畅问答,打造一个企业智能通讯录。

  1. 使用 deepseek 生成可执行的 sql 语句,langchain 自带了一些模块,比如:
  • create_sql_query_chain:基于用户自然语言问题构建SQL查询
  • SQLDatabaseChain:使用链进行查询、创建和执行来查询SQL数据库
  • create_sql_agent:使用代理进行健壮和灵活的与SQL数据库交互

发现还是不太理想,决定还是让 deepseek 根据”表结构 + 提示词 + 使用示例“来生成 sql 语句。

  1. 对生成的 sql 语句进行清洗,比如推理思考过程、markdown标签、其他无关信息等,提取出可直接执行的纯 sql 。
  2. 执行 sql 获取结果,在让 deepseek 根据”表结构 + 提示词 + 执行的SQL + 执行结果",来回答。

三、代码解读

  1. 准备好用户、组织架构方面的表,注意以下几点:
  • 去掉用不着的字段,防止干扰 deepseek 思考
  • 去掉敏感字段,比如密码、身份证
  • 每个字段用自然语言添加注释
  • 有关联关系的字段,注释清楚
  • 每张表用自然语言添加注释
  • 由于表结构后续还会用到,建议单独放一个文件

新建一个文件 “table_schema”,写入表结构信息,这是我准备的表:

- 用户信息表
CREATE TABLE `uc_user` (`ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '主键,用户ID',`USER_NAME` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '名称',`ACCOUNT` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '账号',`GENDER` varchar(96) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '性别 男:F-男 女:F-女',`EMAIL` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '邮箱',`PHONE` varchar(48) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '手机号码',`ADDRSS` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '地址',`CREATE_DATE` datetime DEFAULT NULL COMMENT '创建时间',`MODIFY_DATE` datetime DEFAULT NULL COMMENT '修改时间',`STATUS` varchar(6) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '状态 1:正常 0:禁用',`REMARK` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '备注',`CREATE_ID` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建人id,用户表主键',`into_date` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '入职日期',PRIMARY KEY (`ID`) USING BTREE,KEY `idx_user_name` (`USER_NAME`) USING BTREE,KEY `idx_account` (`ACCOUNT`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='用户信息表';- 公司/部门信息表
CREATE TABLE `uc_organization` (`ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '主键',`ORG_CODE` varchar(60) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '部门编码',`ORG_NAME` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '部门或公司名称',`PARENT_ORG_ID` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '上级部门/公司ID,公司/部门信息表主键',`ORG_PATH_NAME` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '组织架构全路径',`SORT` int DEFAULT NULL COMMENT '排序号',`ORG_TYPE` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '组织类型:0.根组 1.分公司 2.子公司 3.部门',`CREATE_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建人ID,用户表的主键',`CREATE_DATE` datetime DEFAULT NULL COMMENT '创建时间',`MODIFY_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '修改人ID,用户表的主键',`MODIFY_DATE` datetime DEFAULT NULL COMMENT '修改时间',`STATE` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT '状态 1:正常 0:禁止',`ADDR` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '详细地址',PRIMARY KEY (`ID`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='公司/部门信息表';- 用户和部门/公司关联表
CREATE TABLE `uc_user_app_relation` (`USER_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '用户ID,用户表的主键',`STATUS` varchar(6) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '状态 1:正常 0:禁用',`COMPANY_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '公司ID,组织和公司表的主键',`ORG_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '部门ID,组织和公司表的主键',`CREATE_DATE` datetime DEFAULT NULL COMMENT '创建时间',`MODIFY_DATE` datetime DEFAULT NULL COMMENT '修改时间',`CREATE_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建人ID',KEY `idx_user_id` (`USER_ID`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='用户和部门/公司关联表';

这里的表稍微有点复杂,主要在 uc_organization 表,即有公司又有部门,还有上下级关系,所以接下来写系统提示词。

  1. 假如不知道怎么写系统提示词的,可以去 deepseek 官网看示例,然后慢慢调整。

官网:https://api-docs.deepseek.com/zh-cn/prompt-library/

在这里插入图片描述
提示词:

### 你是一个的 MYSQL 专家给定输入问题,根据提供的表结构信息,将自然语言查询需求转换为准确且可执行的SQL语句。**表结构信息**{table_schema}## 查询需求
1. 用清晰的自然语言描述查询需求,包括:
- 需要获取的数据字段
- 筛选条件
- 排序要求
- 聚合需求(如求和/计数/平均值等)
- 多表关联需求
2. 生成智能模糊查询,包括:
- 输入参数:`[用户输入的简称片段]` 
- 匹配字段:`[目标字段名]`
- 预期效果:智能匹配包含输入词素及其变体的全称
- 特殊要求:`[分词处理/同义词扩展/优先级排序]`## 约束条件
- 严格基于提供的表结构生成
- 优先使用标准SQL语法
- 不准捏造字段
- 不要列出系统字段,如主键、创建日期、修改日期等
- 每张表查询都要带上正常状态!!!不管单表还是多表查询,特别多表查询主表也要加上正常状态!!!
- 使用规范的SQL格式:关键字大写、适当缩进、使用表别名时保持一致性、避免使用*选择所有列
- 必须直接输出SQL语句,不要其他内容,不要分步骤列出
- 只能生成SELECT查询语句### 不准捏造表和字段!!!
### 主表一定要加上状态查询!!!

这里踩的坑有点多,比如:

  • 每张表都有状态字段,都需要带上这个查询条件,类似的很多系统也有软删除 is_deleted 字段,要着重强调
  • 我们习惯性的会问公司简称,需要加上模糊搜索
  • 有时候 deepseek 会捏造字段,也要特别注意

到这里 deepseek 对于单表生成 sql 还可以,但是多表查询,特别表结构又复杂,需要引导 deepseek 如何生成,这就体现了参考示例的作用,写几个稍微复杂的 sql 查询示例让 deepseek 理解,如下:

  • 查询某个用户信息
SELECT u.USER_NAME AS 姓名,u.ACCOUNT AS 账号,u.GENDER AS 性别,u.EMAIL AS 邮箱,u.PHONE AS 手机号码,u.ADDRSS AS 地址,u.into_date AS 入职日期,o.ORG_NAME AS 公司名称,d.ORG_NAME AS 部门名称
FROM uc_user u
LEFT JOIN uc_user_app_relation r ON u.ID = r.USER_ID AND r.STATUS = '1'
LEFT JOIN uc_organization o ON r.COMPANY_ID = o.ID
LEFT JOIN uc_organization d ON r.ORG_ID = d.ID
WHERE u.USER_NAME = '某某某';
GROUP BY u.ID;
  • 查询某个公司下面人员清单
SELECT u.USER_NAME AS 姓名,u.ACCOUNT AS 账号,u.GENDER AS 性别,u.EMAIL AS 邮箱,u.PHONE AS 手机号码,u.ADDRSS AS 地址,u.into_date AS 入职日期,o.ORG_NAME AS 部门名称,c.ORG_NAME AS 公司名称
FROM uc_user u
LEFT JOIN uc_user_app_relation r ON u.ID = r.USER_ID
LEFT JOIN uc_organization o ON r.ORG_ID = o.ID
LEFT JOIN uc_organization c ON r.COMPANY_ID = c.ID
WHERE u.STATUS = '1' AND r.STATUS = '1' AND o.STATE = '1' AND c.STATE = '1'  AND c.ORG_NAME LIKE '%某某公司%'
  • 查询某个公司某个部门下面的人员清单
SELECT u.USER_NAME AS 姓名,u.ACCOUNT AS 账号,u.GENDER AS 性别,u.EMAIL AS 邮箱,u.PHONE AS 手机号码,u.ADDRSS AS 地址,u.into_date AS 入职日期,o.ORG_NAME AS 部门名称,c.ORG_NAME AS 公司名称
FROM uc_user u
LEFT JOIN uc_user_app_relation r ON u.ID = r.USER_ID
LEFT JOIN uc_organization o ON r.ORG_ID = o.ID
LEFT JOIN uc_organization c ON r.COMPANY_ID = c.ID
WHERE u.STATUS = '1' AND r.STATUS = '1' AND o.STATE = '1' AND c.STATE = '1'  AND c.ORG_NAME LIKE '%某某公司%' AND o.ORG_NAME LIKE '%某某部门%'
  • 某某公司的子公司清单
SELECT c.ORG_NAME AS 公司名称,p.ORG_NAME AS 上级公司名称,c.ORG_PATH_NAME AS 组织架构全路径 
FROM uc_organization c
LEFT JOIN uc_organization p ON c.PARENT_ORG_ID = p.ID 
WHERE c.STATE = '1' AND p.STATE = '1' AND c.ORG_TYPE < 3 AND p.ORG_NAME LIKE '%某某公司%'
ORDER BY c.ORG_PATH_NAME;
  • 某某公司的部门清单
SELECT c.ORG_NAME AS 部门名称,p.ORG_NAME AS 上级部门名称,c.ORG_PATH_NAME AS 组织架构全路径 
FROM uc_organization c
LEFT JOIN uc_organization p ON c.PARENT_ORG_ID = p.ID 
WHERE c.STATE = '1' AND p.STATE = '1' AND c.ORG_TYPE = 3 AND p.ORG_NAME LIKE '%某某公司%'
ORDER BY c.ORG_PATH_NAME;

直接将参考示例放到提示词下面就好了(代码有 ```sql 标签贴出格式就乱了,大家自己搞一下)

在这里插入图片描述

  1. deepseek 生成的内容带了推理过程和标签,直接用正则过滤一下。

代码:

def extract_sql_blocks(text):# 使用正则表达式匹配非贪婪模式,并包含换行符pattern = r'```sql(.*?)```'matches = re.findall(pattern, text, re.DOTALL)# 去除每个匹配项两端的空白字符return [match.strip() for match in matches]def remove_think_tags(text):"""移除文本中<think>标签及其内容"""pattern = re.compile(r'<think>.*?</think>', re.DOTALL)  # 非贪婪匹配 + 跨行匹配return pattern.sub('', text)

过滤之前:

在这里插入图片描述
过滤之后:

在这里插入图片描述
4. 执行 sql 获取查询结果

mysql_uri = "mysql+mysqlconnector://test:123456@127.0.0.1:3306/test"
db = SQLDatabase.from_uri(mysql_uri)
query_result = db.run(query_sql)
  1. 将表结构、提示词、执行sql、返回结果全都给 deepseek 回答,提示词模板如下:
**指令**
你是一个数据库专家,根据表结构、查询sql、查询结果,回答用户问题,如果查询结果为空,直接回复”暂未找到您要的信息“。**数据库表结构**
{query_tables}**查询sql**
{query_sql}**查询结果**
{query_result}## 要求:
1. 用自然语言总结查询结果,回答用户的问题,不允许在回答中添加编造成分,回答请使用中文。
2. 字段请用中文描述,没有中文注释的不返回。

代码:

def start_chat_mysql(query, model):# 根据自定义提示词写出SQL语句response = create_query_sql(query)# 过滤推理和无关信息,只保留可执行的SQLsqls = extract_sql_blocks(remove_think_tags(response))query_sql = sqls[0]# print(query_sql)# 初始化数据库连接db = SQLDatabase.from_uri(mysql_uri)# 执行查询query_result = db.run(query_sql)# 初始化LLM和链llm = get_chat_llm(model)prompt = get_answer_prompt()chain = prompt | llmwith open("table_schema", "r", encoding="utf-8") as file:table_schema = file.read()response = chain.invoke({"query_tables": table_schema,"query_sql": query_sql,"query_result": query_result,"input": query})return response

没有找到的时候,deepseek 回答:

在这里插入图片描述

找到的时候, deepseek 回答:

在这里插入图片描述

完整代码私信要吧~ 这里贴出来格式冲突不太好看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/73530.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线段树SegmentTree

线段树当中的几个重要操作 1.PushUp 上推操作&#xff1a;由子节点算父节点的信息 p u s h u p push up pushup 操作的目的是为了维护父子节点之间的逻辑关系。当我们递归建树时&#xff0c;对于每一个节点我们都需要遍历一遍&#xff0c;并且电脑中的递归实际意义是先向底层…

SSH免密登录服务器方法

Window免密连接Linux系统 生成公匙 ssh-keygen -t rsa一路回车生成公钥 复制公匙&#xff0c;使用记事本打开复制全部内容 notepad C:\Users\DELL\.ssh\id_rsa.pub内容如"ssh-rsa AAAAB3NzaC1yc2EAAAA…" 远程登录服务器将内容写入~/.ssh/authorized_keys echo …

Go 1.24 新特性解析:泛型类型别名、弱指针与终结器改进

文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons&#xff1a;JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram&#xff0c;自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 &#xff1f; 5 IDEA必装的插件&…

MySQL 表 t1 建立联合索引 (a, b, c),在 where a < ? and b > ? and c < ? 中哪些索引生效

文章目录 联合索引 abc 均范围扫描时的索引生效情况无回表 表数据量非常少无回表 表数据量多有回表总结 联合索引 abc 均范围扫描时的索引生效情况 场景&#xff1a;表 t1 建立联合索引 (a, b, c)&#xff0c;在 where a < ? and b > ? and c < ? 中哪些索引生效…

海外营收占比近4成,泡泡玛特全球化战略迎收获期

3月26日&#xff0c;泡泡玛特国际集团发布2024全年财报。财报显示&#xff0c;2024年泡泡玛特实现营收130.4亿元&#xff08;人民币&#xff0c;下同&#xff09;&#xff0c;同比增长106.9%&#xff0c;经调整净利润34.0亿元&#xff0c;同比增长185.9%。中国内地营收79.7亿元…

ctf-web: 不统一的解析 + sql注入要求输入与输出相等 -- tpctf supersqli

# 从 django.shortcuts 模块导入 render 函数&#xff0c;用于渲染模板 from django.shortcuts import render # 从 django.db 模块导入 connection 对象&#xff0c;用于数据库连接 from django.db import connection# 此模块用于创建视图函数 # 从 django.http 模块导入 Http…

LLM推理加速框架有哪些

LLM推理加速框架有哪些 目录 LLM推理加速框架有哪些1. TensorRT简介简单使用示例2. Triton Inference Server简介简单使用示例3. SGLang简介简单使用示例4. vLLM简介简单使用示例1. TensorRT 简介 TensorRT 是 NVIDIA 推出的一个用于高性能深度学习推理的 SDK。它能够对训练好…

【深度学习与实战】2.1、线性回归模型与梯度下降法先导案例--最小二乘法(向量形式求解)

为了求解损失函数 对 的导数&#xff0c;并利用最小二乘法向量形式求解 的值&#xff0c;我们按照以下步骤进行&#xff1a; ‌1. 损失函数的含义‌ 这是‌线性回归‌的平方误差损失函数&#xff0c;目标是最小化预测值 与真实值 之间的差距。 ‌定义损失函数‌&#xf…

S7-1200对V90 PN进行位置控制的三种方法

S7-1200系列PLC通过PROFINET与V90 PN伺服驱动器搭配进行位置控制,实现的方法主要有以下三种: ? 方法一、在PLC中组态位置轴工艺对象,V90使用标准报文3,通过MC_Power、MC_MoveAbsolute等PLC Open标准程序块进行控制, 这种控制方式属于中央控制方式(位置控制在PLC中计算,驱…

爱普生FC-135晶振5G手机的极端温度性能守护者

在5G时代&#xff0c;智能手机不仅需要高速率与低延迟&#xff0c;更需在严寒、酷暑、振动等复杂环境中保持稳定运行。作为 5G 手机的核心时钟源&#xff0c;爱普生32.768kHz晶振FC-135凭借其宽温适应性、高精度稳定性与微型化设计&#xff0c;成为5G手机核心时钟源的理想选择&…

ROS--IMU数据包

IMU惯性测量单元 一&#xff1a;IMU二&#xff1a;ROS中三&#xff1a;IMU数据包三&#xff1a;总结 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一&#xff1a;IMU IMU&#xff08;Inertial Measurement Unit&#xff0c;惯性测量单元&#xff09…

数据文件误删除,OceanBase中如何重建受影响的节点

当不慎误删数据文件且当前没有现成的可替换节点时&#xff0c;在OceanBase中&#xff0c;不必急于采取极端措施&#xff0c;可以考虑运用 server_permanent_offline_time 参数&#xff0c;来重建受影响的节点。 原理&#xff1a; server_permanent_offline_time 是 OceanBase数…

Python:匹配多个字符,如何匹配开头

匹配字符0次或无数次(*)&#xff1a; import re resre.match([A-Z][a-z]*,Lihailu) print(res.group())#提取数据 输出结果可以全部输出 匹配字符至少一次()&#xff1a; import re resre.match([A-Za-z]python,apython) print(res.group())#提取数据(后边只写python会…

Unity-RectTransform设置UI width

不知道有没人需要这样的代码&#xff0c;就是.sizeDelta //不确定是不是英文翻译的原因&#xff0c;基本很难理解&#xff0c;sizeDeltaSize&#xff0c;//未必完全正确&#xff0c;但这么写好像总没错过 //image 在一个UnityEngine.UI.Image 的数组内foreach (var image in l…

java学习——函数式编程(1)

函数式编程 Java 的函数式编程是一种以函数为核心构建逻辑的编程范式,强调不可变性、声明式代码和无副作用的操作。它通过Lambda表达式、函数式接口(如Function、Predicate、Consumer等)和Stream API等特性实现,将计算过程抽象为函数的组合与转换,而非传统的命令式步骤。…

AP CSA FRQ Q2 Past Paper 五年真题汇总 2023-2019

Author(wechat): bigshuang2020 ap csa tutor, providing 1-on-1 tutoring. 国际教育计算机老师, 擅长答疑讲解&#xff0c;带学生实践学习。 热爱创作&#xff0c;作品&#xff1a;ap csa原创双语教案&#xff0c;真题梳理汇总&#xff0c; AP CSA FRQ专题冲刺, AP CSA MCQ小题…

线程池详解:在SpringBoot中的最佳实践

线程池详解&#xff1a;在SpringBoot中的最佳实践 引言 在Java并发编程中&#xff0c;线程池是一种非常重要的资源管理工具&#xff0c;它允许我们在应用程序中有效地管理和重用线程&#xff0c;从而提高性能并降低资源消耗。特别是在SpringBoot等企业级应用中&#xff0c;正…

2025年IT行业技术革命全景解析:从AI到量子计算的落地实践

简介 2025年&#xff0c;全球IT行业正经历一场由AI、量子计算、物联网等技术驱动的变革。从BOE的AI制造系统到德易科技的无人机光伏巡检&#xff0c;从鲲鹏处理器的国产化突破到量子计算的算力革命&#xff0c;技术创新正在重塑产业格局。本文结合最新行业动态与实战案例&…

JVM - 年轻代和老年代

通过一些问题来讨论 JVM 中年轻代和老年代的内容 为什么要区分年轻代和老年代&#xff1f;哪些对像会进入老年代&#xff1f;什么时候会进行年轻代GC&#xff1f;什么时候会进行老年代GC&#xff1f; 1. 为什么要区分年轻代和老年代&#xff1f; 年轻代中的对象大部分都是短期…

【react】在react中async/await一般用来实现什么功能

目录 基本概念 工作原理 优点 注意事项 底层原理 实际应用场景 1. 数据获取 (API 请求) 2. 表单提交 3. 异步状态管理 4. 异步路由切换 5. 异步数据预加载 6. 第三方 API 调用 7. 文件上传/下载 8. 路由导航拦截 关键注意事项 基本概念 async 函数&#xff1a;用…