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

打印 上一主题 下一主题

主题 1876|帖子 1876|积分 5628

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


  • ollama,用于在本地运行、摆设和管理大型语言模子(LLMs)。
  • deepseek 模子,本文用的 deepseek-r1:14b。
  • langchain,大语言模子应用步伐的开发框架,主要 python 实现。
  • Mysql,这里建议单独摆设一个专门用来数据库问答,避免影响生产环境。
二、开发思路

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

  • 使用 deepseek 生成可实行的 sql 语句,langchain 自带了一些模块,比如:


  • create_sql_query_chain:基于用户自然语言标题构建SQL查询
  • SQLDatabaseChain:使用链举行查询、创建和实行来查询SQL数据库
  • create_sql_agent:使用署理举行健壮和灵活的与SQL数据库交互
发现还是不太抱负,决定还是让 deepseek 根据”表结构 + 提示词 + 使用示例“来生成 sql 语句。

  • 对生成的 sql 语句举行洗濯,比如推理思索过程、markdown标签、其他无关信息等,提取出可直接实行的纯 sql 。
  • 实行 sql 获取结果,在让 deepseek 根据”表结构 + 提示词 + 实行的SQL + 实行结果",来答复。
三、代码解读


  • 预备好用户、构造架构方面的表,注意以下几点:


  • 去掉用不着的字段,防止干扰 deepseek 思索
  • 去掉敏感字段,比如密码、身份证
  • 每个字段用自然语言添加注释
  • 有关联关系的字段,注释清晰
  • 每张表用自然语言添加注释
  • 由于表结构后续还会用到,建议单独放一个文件
新建一个文件 “table_schema”,写入表结构信息,这是我预备的表:
  1. - 用户信息表
  2. CREATE TABLE `uc_user` (
  3.   `ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '主键,用户ID',
  4.   `USER_NAME` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '名称',
  5.   `ACCOUNT` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '账号',
  6.   `GENDER` varchar(96) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '性别 男:F-男 女:F-女',
  7.   `EMAIL` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '邮箱',
  8.   `PHONE` varchar(48) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '手机号码',
  9.   `ADDRSS` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '地址',
  10.   `CREATE_DATE` datetime DEFAULT NULL COMMENT '创建时间',
  11.   `MODIFY_DATE` datetime DEFAULT NULL COMMENT '修改时间',
  12.   `STATUS` varchar(6) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '状态 1:正常 0:禁用',
  13.   `REMARK` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '备注',
  14.   `CREATE_ID` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建人id,用户表主键',
  15.   `into_date` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '入职日期',
  16.   PRIMARY KEY (`ID`) USING BTREE,
  17.   KEY `idx_user_name` (`USER_NAME`) USING BTREE,
  18.   KEY `idx_account` (`ACCOUNT`) USING BTREE
  19. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='用户信息表';
  20. - 公司/部门信息表
  21. CREATE TABLE `uc_organization` (
  22.   `ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '主键',
  23.   `ORG_CODE` varchar(60) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '部门编码',
  24.   `ORG_NAME` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '部门或公司名称',
  25.   `PARENT_ORG_ID` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '上级部门/公司ID,公司/部门信息表主键',
  26.   `ORG_PATH_NAME` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '组织架构全路径',
  27.   `SORT` int DEFAULT NULL COMMENT '排序号',
  28.   `ORG_TYPE` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '组织类型:0.根组 1.分公司 2.子公司 3.部门',
  29.   `CREATE_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建人ID,用户表的主键',
  30.   `CREATE_DATE` datetime DEFAULT NULL COMMENT '创建时间',
  31.   `MODIFY_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '修改人ID,用户表的主键',
  32.   `MODIFY_DATE` datetime DEFAULT NULL COMMENT '修改时间',
  33.   `STATE` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT '状态 1:正常 0:禁止',
  34.   `ADDR` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '详细地址',
  35.   PRIMARY KEY (`ID`) USING BTREE
  36. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='公司/部门信息表';
  37. - 用户和部门/公司关联表
  38. CREATE TABLE `uc_user_app_relation` (
  39.   `USER_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '用户ID,用户表的主键',
  40.   `STATUS` varchar(6) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '状态 1:正常 0:禁用',
  41.   `COMPANY_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '公司ID,组织和公司表的主键',
  42.   `ORG_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '部门ID,组织和公司表的主键',
  43.   `CREATE_DATE` datetime DEFAULT NULL COMMENT '创建时间',
  44.   `MODIFY_DATE` datetime DEFAULT NULL COMMENT '修改时间',
  45.   `CREATE_ID` varchar(192) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建人ID',
  46.   KEY `idx_user_id` (`USER_ID`) USING BTREE
  47. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='用户和部门/公司关联表';
复制代码
这里的表稍微有点复杂,主要在 uc_organization 表,即有公司又有部分,尚有上下级关系,所以接下来写系统提示词。

  • 假如不知道怎么写系统提示词的,可以去 deepseek 官网看示例,然后慢慢调整。
官网:https://api-docs.deepseek.com/zh-cn/prompt-library/

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


  • 每张表都有状态字段,都必要带上这个查询条件,类似的很多系统也有软删除 is_deleted 字段,要偏重夸大
  • 我们风俗性的会问公司简称,必要加上暗昧搜索
  • 有时间 deepseek 会捏造字段,也要特殊注意
到这里 deepseek 对于单表生成 sql 还可以,但是多表查询,特殊表结构又复杂,必要引导 deepseek 如何生成,这就表现了参考示例的作用,写几个稍微复杂的 sql 查询示例让 deepseek 理解,如下:


  • 查询某个用户信息
  1. SELECT
  2.     u.USER_NAME AS 姓名,
  3.     u.ACCOUNT AS 账号,
  4.     u.GENDER AS 性别,
  5.     u.EMAIL AS 邮箱,
  6.     u.PHONE AS 手机号码,
  7.     u.ADDRSS AS 地址,
  8.     u.into_date AS 入职日期,
  9.     o.ORG_NAME AS 公司名称,
  10.     d.ORG_NAME AS 部门名称
  11. FROM
  12.     uc_user u
  13. LEFT JOIN
  14.     uc_user_app_relation r ON u.ID = r.USER_ID AND r.STATUS = '1'
  15. LEFT JOIN
  16.     uc_organization o ON r.COMPANY_ID = o.ID
  17. LEFT JOIN
  18.     uc_organization d ON r.ORG_ID = d.ID
  19. WHERE
  20.     u.USER_NAME = '某某某';
  21. GROUP BY u.ID;
复制代码


  • 查询某个公司下面职员清单
  1. SELECT
  2.     u.USER_NAME AS 姓名,
  3.     u.ACCOUNT AS 账号,
  4.     u.GENDER AS 性别,
  5.     u.EMAIL AS 邮箱,
  6.     u.PHONE AS 手机号码,
  7.     u.ADDRSS AS 地址,
  8.     u.into_date AS 入职日期,
  9.     o.ORG_NAME AS 部门名称,
  10.     c.ORG_NAME AS 公司名称
  11. FROM
  12.     uc_user u
  13. LEFT JOIN
  14.     uc_user_app_relation r ON u.ID = r.USER_ID
  15. LEFT JOIN
  16.     uc_organization o ON r.ORG_ID = o.ID
  17. LEFT JOIN
  18.     uc_organization c ON r.COMPANY_ID = c.ID
  19. WHERE
  20.     u.STATUS = '1' AND r.STATUS = '1' AND o.STATE = '1' AND c.STATE = '1'  AND c.ORG_NAME LIKE '%某某公司%'
复制代码


  • 查询某个公司某个部分下面的职员清单
  1. SELECT
  2.     u.USER_NAME AS 姓名,
  3.     u.ACCOUNT AS 账号,
  4.     u.GENDER AS 性别,
  5.     u.EMAIL AS 邮箱,
  6.     u.PHONE AS 手机号码,
  7.     u.ADDRSS AS 地址,
  8.     u.into_date AS 入职日期,
  9.     o.ORG_NAME AS 部门名称,
  10.     c.ORG_NAME AS 公司名称
  11. FROM
  12.     uc_user u
  13. LEFT JOIN
  14.     uc_user_app_relation r ON u.ID = r.USER_ID
  15. LEFT JOIN
  16.     uc_organization o ON r.ORG_ID = o.ID
  17. LEFT JOIN
  18.     uc_organization c ON r.COMPANY_ID = c.ID
  19. WHERE
  20.     u.STATUS = '1' AND r.STATUS = '1' AND o.STATE = '1' AND c.STATE = '1'  AND c.ORG_NAME LIKE '%某某公司%'
  21. AND o.ORG_NAME LIKE '%某某部分%'
复制代码


  • 某某公司的子公司清单
  1. SELECT
  2.     c.ORG_NAME AS 公司名称,
  3.     p.ORG_NAME AS 上级公司名称,
  4.     c.ORG_PATH_NAME AS 组织架构全路径
  5. FROM
  6.     uc_organization c
  7. LEFT JOIN
  8.     uc_organization p ON c.PARENT_ORG_ID = p.ID
  9. WHERE
  10.     c.STATE = '1'
  11.     AND p.STATE = '1'
  12.     AND c.ORG_TYPE < 3
  13.     AND p.ORG_NAME LIKE '%某某公司%'
  14. ORDER BY
  15.     c.ORG_PATH_NAME;
复制代码


  • 某某公司的部分清单
  1. SELECT
  2.     c.ORG_NAME AS 部门名称,
  3.     p.ORG_NAME AS 上级部门名称,
  4.     c.ORG_PATH_NAME AS 组织架构全路径
  5. FROM
  6.     uc_organization c
  7. LEFT JOIN
  8.     uc_organization p ON c.PARENT_ORG_ID = p.ID
  9. WHERE
  10.     c.STATE = '1'
  11.     AND p.STATE = '1'
  12.     AND c.ORG_TYPE = 3
  13.     AND p.ORG_NAME LIKE '%某某公司%'
  14. ORDER BY
  15.     c.ORG_PATH_NAME;
复制代码
直接将参考示例放到提示词下面就好了(代码有 ```sql 标签贴特别式就乱了,大家本身搞一下)


  • deepseek 生成的内容带了推理过程和标签,直接用正则过滤一下。
代码:
  1. def extract_sql_blocks(text):
  2.     # 使用正则表达式匹配非贪婪模式,并包含换行符
  3.     pattern = r'```sql(.*?)```'
  4.     matches = re.findall(pattern, text, re.DOTALL)
  5.     # 去除每个匹配项两端的空白字符
  6.     return [match.strip() for match in matches]
  7. def remove_think_tags(text):
  8.     """移除文本中<think>标签及其内容"""
  9.     pattern = re.compile(r'<think>.*?</think>', re.DOTALL)  # 非贪婪匹配 + 跨行匹配
  10.     return pattern.sub('', text)
复制代码
过滤之前:

过滤之后:

4. 实行 sql 获取查询结果
  1. mysql_uri = "mysql+mysqlconnector://test:123456@127.0.0.1:3306/test"
  2. db = SQLDatabase.from_uri(mysql_uri)
  3. query_result = db.run(query_sql)
复制代码

  • 将表结构、提示词、实行sql、返回结果全都给 deepseek 答复,提示词模板如下:
  1. **指令**
  2. 你是一个数据库专家,根据表结构、查询sql、查询结果,回答用户问题,如果查询结果为空,直接回复”暂未找到您要的信息“。
  3. **数据库表结构**
  4. {query_tables}
  5. **查询sql**
  6. {query_sql}
  7. **查询结果**
  8. {query_result}
  9. ## 要求:
  10. 1. 用自然语言总结查询结果,回答用户的问题,不允许在回答中添加编造成分,回答请使用中文。
  11. 2. 字段请用中文描述,没有中文注释的不返回。
复制代码
代码:
  1. def start_chat_mysql(query, model):
  2.     # 根据自定义提示词写出SQL语句
  3.     response = create_query_sql(query)
  4.     # 过滤推理和无关信息,只保留可执行的SQL
  5.     sqls = extract_sql_blocks(remove_think_tags(response))
  6.     query_sql = sqls[0]
  7.     # print(query_sql)
  8.     # 初始化数据库连接
  9.     db = SQLDatabase.from_uri(mysql_uri)
  10.     # 执行查询
  11.     query_result = db.run(query_sql)
  12.     # 初始化LLM和链
  13.     llm = get_chat_llm(model)
  14.     prompt = get_answer_prompt()
  15.     chain = prompt | llm
  16.     with open("table_schema", "r", encoding="utf-8") as file:
  17.         table_schema = file.read()
  18.     response = chain.invoke({
  19.         "query_tables": table_schema,
  20.         "query_sql": query_sql,
  21.         "query_result": query_result,
  22.         "input": query
  23.     })
  24.     return response
复制代码
没有找到的时间,deepseek 答复:

找到的时间, deepseek 答复:

完备代码私信要吧~ 这里贴出来格式辩说不太好看

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表