免费POC, 零成本试错
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


RAG进阶神技:让AI自动将“人话”翻译成SQL和Cypher查询!

发布日期:2025-08-28 08:32:19 浏览次数: 1522
作者:小曾AI纪

微信搜一搜,关注“小曾AI纪”

推荐语

让AI听懂你的"人话",自动生成精准SQL和Cypher查询,大幅提升数据检索效率!

核心内容:
1. 传统RAG在处理结构化数据时的局限性
2. 查询构建技术:自然语言转SQL/Cypher的两种关键步骤
3. 实际应用案例与代码实现示例

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家

在我们之前的文章中我们已经了解了两种预检索的优化策略。比如怎么“翻译”用户那七零八落的问题,还有怎么做一个聪明的“导航员”,把问题带到正确的数据源。

那么,现在问题来了,我们知道去哪里找数据了,那我们如何查不同类型的数据呢?

这就是我们今天想聊的另一种预检索优化策略:查询构建(Query Construction)

在本文中,我们将聚焦于如何将用户的自然语言问题,翻译成数据源能理解的那套"行话"。比如SQL语言,或者Cypher查询语句。

什么是查询构建?

传统那套RAG,把问题变成一串向量数字,再去另一堆向量数字里找最相似的。这招在处理非结构化的文字,比如博客、文章时,确实管用。我得承认,这很巧妙。

但世界不是只有文字啊。

要是我们面对的是一张冷冰冰的Excel表,或是一座结构严密、壁垒分明的关系型数据库呢?我第一次遇到这个问题时,真的有点懵。你总不能跟一张员工薪资表谈“语义相似”吧?它有它的脾气,有行有列,有不容置疑的数据类型。跟它打交道,你得说它的“方言”——那些结构化的查询语言。

这感觉,就像从一个诗人,突然要转变成一个会计。

查询构建技术流派

1. Text-to-SQL -- 从自然语言到SQL转换

企业里最常见的就是这种“会计式”的数据了。MySQL、PostgreSQL... 它们就像一个个巨大的账本,记录着一切。

一个真正好用的RAG系统,我觉得它不应该偏科,不能只会读诗(非结构化文档),也得会算账(结构化数据)。

如果能让系统自己学会把我们的日常白话,转换成SQL,那该多好。用户只管提问,系统默默地把查询、整合、生成答案这些脏活累活全干了。这听起来才够智能,不是吗?

要做到这一点,其实没那么玄乎。关键就两步:

  1. 1. 数据库描述: 你得先让大模型看明白数据库长什么样,有哪些表,表里有哪些字段。
  2. 2. 少量示例: 在提示词里给它几个标准提问的例子,它就能有样学样。

用一个简单的实现流程代码来理解:

  1. 1. 创建一个 SQLite 数据库,并创建一个包含一些示例数据的 sales_database 表。
    import sqlite3

    def__init__(self, db_path="sales_database.db"):
        """
        初始化转换器
        Args:
            db_path (str): SQLite数据库文件路径
        """

        self.db_path = db_path
        self.conn = None
        self.cursor = None

    defconnect_database(self):
        """连接数据库"""
        try:
            self.conn = sqlite3.connect(self.db_path)
            self.cursor = self.conn.cursor()
            print(f"✅ 成功连接数据库: {self.db_path}")
        except Exception as e:
            print(f"❌ 数据库连接失败: {e}")
            raise

    defcreate_sample_database(self):
        """创建示例数据库和数据"""
        try:
            # 创建销售数据表
            self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS sales_data (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                product_name TEXT NOT NULL,
                quantity INTEGER NOT NULL,
                sale_date TEXT NOT NULL,
                revenue REAL NOT NULL,
                region TEXT NOT NULL,
                customer_type TEXT NOT NULL
            )
            '''
    )

            # 清空现有数据
            self.cursor.execute('DELETE FROM sales_data')

            # 插入示例数据
            sample_data = [
                ('iPhone 15'10'2023-07-15'15000.0'北京''个人'),
                ('iPhone 15'5'2023-08-10'7500.0'上海''个人'),
                ('MacBook Pro'20'2023-07-20'40000.0'广州''企业'),
                ('iPhone 15'15'2023-09-01'22500.0'深圳''个人'),
                ('iPad Air'7'2023-09-15'3500.0'北京''个人'),
                ('MacBook Air'12'2023-08-25'12000.0'上海''企业'),
                ('iPhone 14'8'2023-07-30'8000.0'成都''个人'),
                ('iPad Pro'6'2023-09-10'7200.0'杭州''企业'),
                ('MacBook Pro'3'2023-08-05'6000.0'武汉''个人'),
                ('iPhone 15 Pro'25'2023-09-20'37500.0'北京''企业'),
            ]

            self.cursor.executemany('''
            INSERT INTO sales_data (product_name, quantity, sale_date, revenue, region, customer_type)
            VALUES (?, ?, ?, ?, ?, ?)
            '''
    , sample_data)

            self.conn.commit()
            print("✅ 示例数据库和数据创建成功")

            # 显示数据统计
            self.cursor.execute('SELECT COUNT(*) FROM sales_data')
            count = self.cursor.fetchone()[0]
            print(f"📊 数据库中共有 {count} 条销售记录")

        except Exception as e:
            print(f"❌ 数据库创建失败: {e}")
            raise
  2. 2. 使用LLM生成查询
    import os
    from dotenv import load_dotenv
    from langchain_DeepSeek import ChatDeepSeek
    from langchain_core.prompts import ChatPromptTemplate

    defgenerate_sql(self, natural_query):
        """
        使用DeepSeek模型生成SQL查询
        将所有SQL生成相关的初始化和配置集中在此函数中,便于理解整个生成流程
        Args:
            natural_query (str): 自然语言查询
        Returns:
            str: 生成的SQL语句
        """

        try:
            print("🔧 步骤1: 初始化DeepSeek模型...")
            # 初始化DeepSeek模型
            llm = ChatDeepSeek(
                model="deepseek-chat",
                temperature=0.1,  # 设置较低温度确保SQL生成的准确性
                max_tokens=1024,
                api_key=os.getenv("DEEPSEEK_API_KEY"),
            )

            print("📋 步骤2: 准备数据库Schema信息...")
            # 数据库schema信息
            schema_info = """
                数据库Schema信息:

                表名: sales_data
                字段说明:
                - id: INTEGER PRIMARY KEY (主键,自增)
                - product_name: TEXT (产品名称)
                - quantity: INTEGER (销售数量)
                - sale_date: TEXT (销售日期,格式:YYYY-MM-DD)
                - revenue: REAL (销售收入)
                - region: TEXT (销售区域)
                - customer_type: TEXT (客户类型:个人/企业)
            """


            print("📝 步骤3: 创建SQL生成提示模板...")
            # 创建SQL生成提示模板
            sql_prompt = ChatPromptTemplate.from_template(
                """
                你是一个专业的SQL查询生成专家。基于以下数据库schema,将用户的自然语言查询转换为准确的SQL语句。
                {schema}
                规则要求:
                1. 只生成SQL语句,不要包含任何解释文字
                2. 确保SQL语法正确且符合SQLite标准
                3. 使用适当的聚合函数、WHERE条件、GROUP BY、ORDER BY等
                4. 日期比较请使用字符串比较(如:sale_date >= '2023-07-01')
                5. 产品名称匹配请使用LIKE操作符支持模糊查询
                6. 如果查询涉及时间范围,请合理解释季度、月份等时间概念
                用户查询: {query}
                SQL语句:"""

            )

            print("⚙️ 步骤4: 格式化提示词...")
            # 格式化提示词
            formatted_prompt = sql_prompt.format(
                schema=schema_info, query=natural_query
            )

            print("🤖 步骤5: 调用DeepSeek模型生成SQL...")
            # 调用DeepSeek模型生成SQL
            response = llm.invoke(formatted_prompt)
            sql_query = response.content.strip()

            print("✨ 步骤6: 清理和格式化SQL语句...")
            # 清理SQL语句(移除可能的markdown格式)
            if sql_query.startswith("```sql"):
                sql_query = sql_query.replace("```sql""").replace("```""").strip()
            elif sql_query.startswith("```"):
                sql_query = sql_query.replace("```""").strip()

            print("✅ SQL生成完成!")
            return sql_query

        except Exception as e:
            print(f"❌ SQL生成失败: {e}")
            return None
  3. 3. 执行生成的 SQL 查询
    def execute_sql(self, sql_query):
        """
        执行SQL查询

        Args:
            sql_query (str): SQL查询语句

        Returns:
            list: 查询结果
        """

        try:
            self.cursor.execute(sql_query)
            results = self.cursor.fetchall()

            # 获取列名
            column_names = [description[0for description inself.cursor.description]

            return results, column_names

        except Exception as e:
            print(f"❌ SQL执行失败: {e}")
            returnNoneNone
  4. 4. 示例输出
    📝 用户查询: 2023年第三季度iPhone 15的总销售收入是多少?
    --------------------------------------------------------------------------------
    🔄 正在生成SQL查询...
    🔧 步骤1: 初始化DeepSeek模型...
    📋 步骤2: 准备数据库Schema信息...
    📝 步骤3: 创建SQL生成提示模板...
    ⚙️ 步骤4: 格式化提示词...
    🤖 步骤5: 调用DeepSeek模型生成SQL...
    ✨ 步骤6: 清理和格式化SQL语句...
    ✅ SQL生成完成!
    🔍 生成的SQL: SELECT SUM(revenue) AS total_revenue 
    FROM sales_data 
    WHERE product_name LIKE '%iPhone 15%' 
    AND sale_date >= '2023-07-01' 
    AND sale_date <= '2023-09-30';
    --------------------------------------------------------------------------------
    ⚡ 正在执行查询...
    📊 查询结果:
    total_revenue  
    ---------------
    82500.0     

2. Text-to-Cypher -- 从自然语言到图数据库查询

图数据库是一种基于图结构进行数据存储的形式。这东西跟关系型数据库给人的感觉完全不一样。如果说SQL是精准、严谨的法律条文,那Cypher(图数据库的查询语言)就像是在描绘一张复杂的人际关系网。

它不关心一行行的数据,它关心的是实体(节点)和它们之间千丝万缕的联系(关系)。

  • • 一个“糖尿病”是个节点。
  • • 一个“头痛”症状也是个节点。
  • • “糖尿病”会有“头痛”这个症状,这个“会有”就是一条关系。

这种结构,简直是为了回答那些“打破砂锅问到底”的复杂问题而生的。

比如,你问:“什么药能治那些既会引起头痛、又会引起发烧的病?”

传统的RAG可能会被问傻,因为它很难找到一篇文章正好把这几样东西都凑在一起说。但对图数据库来说,这太自然了。它会沿着“关系”的藤蔓,一步步帮你把答案“摸”出来。

用它的语言Cypher写出来,大概是这个感觉:

// 寻找同时拥有'头痛'和'发烧'两种症状的疾病
MATCH (s1:Symptom {name: '头痛'}), (s2:Symptom {name: '发烧'})
MATCH (disease:Disease)-[:HAS_SYMPTOM]->(s1)
MATCH (disease)-[:HAS_SYMPTOM]->(s2)

// 寻找能够治疗这些疾病的药物
MATCH (drug:Drug)-[:TREATS]->(disease)

// 返回药物和对应治疗的疾病名称
RETURN drug.name, disease.name

你看,它思考的方式,是不是更像人脑的联想?把自然语言翻译成Cypher的过程,和翻译成SQL大同小异,都是让大模型去理解、匹配、然后生成。

Text-to-Cypher的实现主要流程是:

  • • 自然语言理解:你先得让它听懂你的“人话”,明白你到底想干嘛。
  • • Schema匹配:你给它一张家族图谱(数据库的schema),让它把你话里提到的人和事在图谱上对号入座。
  • • Cypher生成:等它都搞清楚了,它就会学着用图谱的“官方语言”,写出一句像模像样的查询。
  • • 查询验证与执行:它还会自己检查一下语法,确认无误后才把问题真正递出去。

由于篇幅原因,详细的可运行示例代码,请访问我的GitHub仓库,仓库链接见文章底部。

3. Self-Query Retriever -- 通过自然语言生成元数据过滤器

在向量数据库这边,我们虽然可以直接用自然语言去查,但也不是没有优化的空间。在该环节中也有一些预检索优化技巧,Self-Query Retriever就是其中一种。

它的想法是:为什么不让用户的提问“自己告诉自己”该怎么查?

它会自动从你的问题里,抠出一些关键词作为“元数据”过滤条件。比如你问“给我找找2023年关于AI的论文”,它会先用“2023”和“AI”这两个硬性条件,把海量的文档筛掉一大批,再在剩下的小范围里去做向量相似度计算。

这不就是我们人脑处理信息的方式吗?先分类,再细看。简单,但极其有效。

同样,这个的完整代码我也放在GitHub上了,有兴趣可以去看看,仓库链接见文章底部。

总结

从SQL的严谨,到Cypher的关联,再到Self-Query的小巧思,我们其实一直在做一件事:努力让机器放下身段,来迁就我们的思考方式。

这不只是个“翻译”工作,我觉得这更像是在驯兽,或者说,是在和一个异类寻找沟通的桥梁。我们希望它能突破那些冷冰冰的数据结构,真正理解我们字里行间那些模糊、跳跃、甚至充满情感的意图。

这个过程还在继续,远没到画上句号的时候。或许,下一代智能应用,真的能像个老朋友一样,听懂我们所有的言外之意吧。谁知道呢。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询