AI实战(Text_To_SQL)-数据库(mongodb) + MCP

发布时间:2025-04-13 19:54:00编辑:123阅读(61)

    Text-to-SQL应用概述

    什么是Text-to-SQL?Text-to-SQL也称为NL2SQL,是将自然语言查询转换为可在关系数据库上执行的SQL查询的技术。

    其核心目标是准确捕捉并反映用户意图,生成相应的SQL查询,确保执行后返回符合预期的结果。

    早在生成式人工智能LLM技术出现之前,已有很多专注于Text-to-SQL任务的机器学习项目。

    随着大模型技术的快速发展,凭借其强大的自然语言理解能力和推理能力,Text-to-SQL的性能得到了显著提升的同时,

    也大大降低了访问关系数据库和进行数据分析的门槛,并能够支持各种企业级应用。

    Text-to-SQL技术的实际应用所面临的挑战主要在于自然语言的不确定性、数据库的复杂性和数据质量差异、

    自然语言到SQL语言的转换3个方面。这不仅需要模型具备强大的语言理解能力,还必须深入了解SQL语法,

    并在面对多样化的数据库结构和环境时表现良好的泛化能力。

    大语言模型LLMs凭借其强大的语言理解和生成能力,为Text-to-SQL技术应用发展提供了新思路,

    LLMs能够通过理解自然语言问题的语义,建立问题与数据库模式之间的关联,并根据上下文生成正确的SQL查询。

    此外,LLMs还具备领域适应能力和错误修正能力,使其在Text-to-SQL任务中展现出显著优势。

    Text-to-SQL正在成为连接自然语言与结构化数据的重要桥梁,为企业数据分析和决策支持开辟了新的可能性。


    Text-to-SQL应用存在的不足

    当前,在Text-to-SQL的实际应用中,模型输出SQL的准确性尚未达到生产系统的精度要求,生成和执行效果仍存在优化空间。

    尽管借助大语言模型(LLMs)的能力,Text-to-SQL技术已取得了显著进展,但在实际应用中仍存在一些不足之处:

    查询意图理解偏差

    由LLMs直接生成的SQL有时无法准确反映用户的查询意图,导致生成的SQL逻辑不正确,从而无法得到所需的查询结果。

    尤其在涉及多表关联和复杂筛选查询需求时,这种偏差更为明显。

    捏造错误数据信息

    在生成SQL语句时,LLMs可能会产生一些看似合理但实际上并不存在的结构定义信息。

    这是由于大模型的幻觉问题所致,模型尚未充分学习数据库信息,并且对当前上下文的理解不足,从而导致误导性输出。

    多次生成答案不同

    LLMs生成的SQL信息存在不稳定性。对于同一问题的多次提问,生成的内容可能不完全一致。

    这就需要人为干预,通过择优筛选和修正优化,才能确保其达到正确且可用的状态。

    以上情况都在一定程度上影响了实际应用的用户体验


    利用提示工程、模型微调、RAG和Agent的优化思路

    为解决这些问题,可考虑采用提示工程(Prompt Engineering)、模型微调(Fine-tuning)、

    联合检索增强生成和智能代理(RAG & Agent)等方法,以优化模型及应用的Text-to-SQL任务设计。


    提示工程优化

    通过设计特定的提示词或语句,引导模型生成更贴合用户意图的输出内容。在处理SQL查询时,

    向模型注入特定领域的知识,如SQL规范、数据库架构以及数据字段注释等额外信息,

    能够显著提升模型对于SQL语句结构和逻辑的理解能力。

    提示工程的关键在于将自然语言问题与必要的数据库信息转化为适用于大语言模型(LLM)的自然语言序列输入,

    即问题表示。同时,当允许输入一些样例以利用LLM的上下文学习能力时,

    还需要考虑如何选择样例以及如何将这些样例有机地组织到输入序列中。


    提示工程的关键在于将自然语言问题与必要的数据库信息转化为适用于大语言模型(LLM)的自然语言序列输入,即问题表示。同时,当允许输入一些样例以利用LLM的上下文学习能力时,还需要考虑如何选择样例以及如何将这些样例有机地组织到输入序列中。


    通过构建包含基本提示、文本表示提示、OpenAI范式提示、代码表示提示、指令微调提示以及上下文学习等综合Prompt策略的方法,在Text-to-SQL的Prompt设计中融入说明、数据结构、示例、提示或约束、领域知识及用户问题等要素,能够取得较好的效果,具体如下:

    (1)说明:如,“你是一个SQL生成专家。请参考如下的数据表结构,输出SQL语句。”

    (2)数据结构:相当于语言翻译中的字典。即需要使用的数据库表结构,把数据结构组装进Prompt,包括表名、列名、列的类型、列的含义、主外键信息。

    (3)示例:作为可选项,也是提示工程的常见方式。即指导大模型生成SQL的参考范本。

    (4)提示或约束:其他必要的指示。    

    (5)领域知识:可选项,某些特定问题中,对常识描述的解释。

    (6)用户问题:用户提出的问题。

    融合上述元素,可以得到TEXT-TO-SQL通用Prompt模板框架如下:

    # 描述Text-to-SQL任务的说明
    ${示例}
    
    # 描述数据库表结构信息
    ${数据库表结构}
    
    # 相似用户问题及对应的SQL语句/[可选]
    ${示例}
    
    # 用户问题相关的领域知识/[可选]
    ${领域知识}
    
    # 提示或其他约束条件[可选]
    ${提示/约束}
    
    # 需要生成SQL的用户问题
    ${用户问题}


    模型微调优化

    针对预训练模型进行定制化调整,以更好地契合特定应用场景的需求。尤其在Text-to-SQL这类复杂任务中,

    通过利用包括SQL语句的专门数据集对模型进行微调,可以强化模型对SQL语言特性的理解和生成能力。

    这一过程不仅保留了大模型的语言理解广度,还提升了处理SQL转换的精确性和效率,有效避免生成SQL查询时的常见错误,

    从而提高了整体执行效果。能够支持微调的开源框架有很多,包括:

    DB-GPT-Hub

    DB-GPT-Hub是一个利用大型语言模型(LLMs)实现Text-to-SQL解析的实验项目,

    主要包含数据集收集、数据预处理、模型选择与构建以及微调权重等步骤。

    通过这一系列处理,可以在提高Text-to-SQL能力的同时降低模型训练成本,最终实现基于数据库的自动问答。

    DB-GPT-Hub采用了最新版本的预训练语言模型,如GPT-3或其开源变体,对大量的代码库进行训练,

    以学习编码模式和最佳实践。这种基于Transformer架构的模型具有以下特性:    

    上下文感知:模型能够理解代码块的整体结构,生成的代码与其上下文紧密相关。

    多样性:能够根据不同的编程风格生成多种可能的代码实现。

    可扩展性:通过持续训练和整合新的代码数据,可以不断提高代码生成的准确性和适用性。

    LLaMA-Factory

    LLaMA-Factory的目标是整合主流的高效训练微调技术,适配开源模型,形成一个功能丰富、适配性好的训练框架。它提供了多个高层抽象调用接口,包含多阶段训练、推理测试、benchmark评测以及API Server等。

    使用LLaMA-Factory进行模型微调是一个涵盖从选择模型、数据加载、参数配置到训练、评估优化直至部署应用的全面且高效的流程。


    RAG/Agent增强  

    RAG增强

    RAG作为一种融合了检索和生成任务的人工智能技术,正在引领数据库查询领域的革新。

    它通过增强语言模型的能力,使其能够更精确地理解查询意图并生成相应的SQL语句,从而实现对数据库的高效且直观的访问。

    Vanna是一个开源的、基于大模型和RAG框架的Text-to-SQL工具。它结合了RAG框架、大型语言模型、

    高质量的训练数据、持续优化、广泛的数据库支持以及开源定制特性,实现了在复杂数据集上的高精度表现。

    RAG技术结合了检索(Retrieval)和生成(Generation)两方面的能力。在数据库查询的背景下,

    它不仅能够检索数据库中的信息,还能够根据检索到的信息生成相应的SQL查询语句。其中,

    检索组件负责从数据库中提取与用户查询相关的数据,使用索引和搜索算法快速定位信息,

    确保查询的准确性和效率;生成组件则在检索到相关信息后,根据这些数据构建SQL语句。

    Vanna框架的工作原理可以概括为以下几个步骤:

    用户输入:用户以自然语言的形式提出查询请求。

    意图识别:通过自然语言处理(NLP)引擎分析用户的查询,识别其意图和关键信息。    

    信息检索:根据识别的意图,检索数据库中相关的数据。

    SQL生成:结合检索到的数据,生成相应的SQL语句。

    执行与反馈:生成的SQL语句在数据库上执行,并将结果反馈给用户。


    Agent增强

    AI Agent(智能体)是一种模拟人类或其他智能体行为和决策过程的系统。通过引入行动能力、

    长期记忆机制和工具整合能力,能够感知环境、处理信息、制定策略并执行行动来完成任务。

    AI Agent通过一个框架规划多个方法,这个框架具有一些具体模块,支持整个结构的运行。

    在Text-to-SQL任务中,这通常涉及多个步骤,Agent需要了解这些步骤并提前规划,具体的类型包括:

    目标和任务分解:Agent将大型任务分解为更小、更易管理的子目标,以便有效地处理复杂任务。

    反思与改进:Agent可以对过去的行为进行自我校准和自我反思,从错误中学习并改进未来步骤,从而提高最终结果的质量。

    外部工具与资源利用:Agent可以调用各种外部工具集,如搜索引擎、数据库接口等,以扩展其功能并增强解决问题的能力。

    对话管理与上下文保持:通过维护对话历史和关键信息,Agent能够在连续提问或修正查询时保持上下文的连贯性,提升用户体验。


    Cherry Studio+mongodb+MCP的Text-to-SQL应用实战

    设置cherry studio全局提示词,如下

    image.png

    把表结构复制到提示词的框里面,表结构如下:

    使用中文回复。
    
    当用户提问中涉及学生、教师、成绩、班级、课程等实体时,需要使用MongoDB MCP进行数据查询和操作,表结构说明如下:
    
    # 学生管理系统数据库表结构说明
    
    ## 1. 教师表 (teachers)
    
    | 字段名 | 类型 | 描述 | 约束 | 示例 |
    |--------|------|------|------|------|
    | id | String | 教师ID | 主键 | "T001" |
    | name | String | 教师姓名 | 必填 | "张建国" |
    | gender | String | 性别 | "男"或"女" | "男" |
    | subject | String | 教授科目 | 必填 | "数学" |
    | title | String | 职称 | 必填 | "教授" |
    | phone | String | 联系电话 | 必填 | "13812345678" |
    | office | String | 办公室位置 | 必填 | "博学楼301" |
    | wechat | String | 微信(可选) | 可选 | "lily_teacher" |
    | isHeadTeacher | Boolean | 是否为班主任 | 可选 | true |
    
    ## 2. 班级表 (classes)
    
    | 字段名 | 类型 | 描述 | 约束 | 示例 |
    |--------|------|------|------|------|
    | id | String | 班级ID | 主键 | "202301" |
    | className | String | 班级名称 | 必填 | "2023级计算机1班" |
    | grade | Number | 年级 | 必填 | 2023 |
    | headTeacherId | String | 教师ID | 外键(teachers.id) | "T003" |
    | classroom | String | 教室位置 | 必填 | "1号楼302" |
    | studentCount | Number | 学生人数 | 必填 | 35 |
    | remark | String | 备注信息 | 可选 | "市级优秀班集体" |
    
    ## 3. 课程表 (courses)
    
    | 字段名 | 类型 | 描述 | 约束 | 示例 |
    |--------|------|------|------|------|
    | id | String | 课程ID | 主键 | "C001" |
    | courseName | String | 课程名称 | 必填 | "高等数学" |
    | credit | Number | 学分 | 必填 | 4 |
    | teacherId | String | 授课教师ID | 外键(teachers.id) | "T001" |
    | semester | String | 学期 | 格式"YYYY-N" | "2023-1" |
    | type | String | 课程类型 | "必修"或"选修" | "必修" |
    | prerequisite | String | 先修课程ID | 可选,外键(courses._id) | "C003" |
    
    ## 4. 学生表 (students)
    
    | 字段名 | 类型 | 描述 | 约束 | 示例 |
    |--------|------|------|------|------|
    | id | String | 学号 | 主键 | "S20230101" |
    | name | String | 学生姓名 | 必填 | "王强" |
    | gender | String | 性别 | "男"或"女" | "男" |
    | birthDate | Date | 出生日期 | 必填 | new Date("2005-01-15") |
    | enrollmentDate | Date | 入学日期 | 必填 | new Date(2023, 8, 1) |
    | classId | String | 班级ID | 外键(classes.id) | "202301" |
    | phone | String | 联系电话 | 必填 | "13812345678" |
    | email | String | 电子邮箱 | 必填 | "20230101@school.edu.cn" |
    | emergencyContact | String | 紧急联系人电话 | 必填 | "13876543210" |
    | address | String | 家庭住址 | 必填 | "北京市海淀区中关村大街1栋101室" |
    | height | Number | 身高(cm) | 必填 | 175 |
    | weight | Number | 体重(kg) | 必填 | 65 |
    | healthStatus | String | 健康状况 | 必填 | "良好" |
    
    ## 5. 成绩表 (scores)
    
    | 字段名 | 类型 | 描述 | 约束 | 示例 |
    |--------|------|------|------|------|
    | id | String | 成绩记录ID | 主键 | "S20230101C001" |
    | studentId | String | 学生ID | 外键(students.id) | "S20230101" |
    | courseId | String | 课程ID | 外键(courses.id) | "C001" |
    | score | Number | 综合成绩 | 0-100 | 85 |
    | examDate | Date | 考试日期 | 必填 | new Date(2024, 5, 20) |
    | usualScore | Number | 平时成绩 | 70-100 | 90 |
    | finalScore | Number | 期末成绩 | 0-100 | 80 |
    
    ### 补考成绩记录说明
    补考记录在_id后添加"_M"后缀,如"S20230101C001_M"
    
    ## 表关系说明
    
    1. **一对多关系**:
       - 一个班级(classes)对应多个学生(students)
       - 一个教师(teachers)可以教授多门课程(courses)
       - 一个学生(students)有多条成绩记录(scores)
    
    2. **外键约束**:
       - students.classId → classes.id
       - courses.teacherId → teachers.id
       - scores.studentId → students.id
       - scores.courseId → courses.id
       - classes.headTeacherId → teachers.id

    把数据导入到mongodb中,如下图

    image.png

    数据访问地址:【有道云笔记】mongodb数据集  https://note.youdao.com/s/D1uAHuKR

    Cherry Studio+MCP配置可以查看:http://www.py3study.com/Article/details/id/20095.html

    mongodb数据导入脚本

    from pymongo import MongoClient
    
    
    def insert_mongodb(data, set_name):
        # 连接到 MongoDB
        client = MongoClient('mongodb://localhost:27017/')
        # 选择数据库
        db = client['studentManagement']
        # 选择集合
        collection = db[set_name]
        # 插入数据
        result = collection.insert_many(data)
        # 打印插入的文档 ID
        print("插入的文档 ID:", result.inserted_ids)
        # 关闭连接
        client.close()
    
    
    if __name__ == '__main__':
        # 表数据 list
        teachers_data = [
    {"id": "T001","name": "张建国","gender": "男","subject": "数学","title": "教授","phone": "13812345678",
    "office": "博学楼301","wechat": "lily_teacher","isHeadTeacher": "true",},
    { "id": "T002","name": "李明","gender": "男","subject": "英语","title": "副教授","phone": "13812345679",
    "office": "博学楼302","wechat": "tom_teacher","isHeadTeacher": "false",}, 
       ]
        # 表名
        set_name = "teachers" 
        insert_mongodb(teachers_data,set_name)

    最后测试效果:

    image.png

    对比查看下mongodb中数据是否正确

    image.png

    通过学生表中classid查看班级表中的老师信息。

    image.png

    通过关联班级id找到老师id,最后通过老师id到老师表中查询对应老师的信息。

    image.png

    最后把结果跟MCP返回对比一下,是正确的。

    Text_to_SQL的实现,通过大模型+数据库(mongodb)+MCP实现了无需写sql,就能查询对应表的内容。


关键字