微信扫码
添加专属顾问
我要投稿
让AI听懂你的"人话",自动生成精准SQL和Cypher查询,大幅提升数据检索效率! 核心内容: 1. 传统RAG在处理结构化数据时的局限性 2. 查询构建技术:自然语言转SQL/Cypher的两种关键步骤 3. 实际应用案例与代码实现示例
在我们之前的文章中我们已经了解了两种预检索的优化策略。比如怎么“翻译”用户那七零八落的问题,还有怎么做一个聪明的“导航员”,把问题带到正确的数据源。
那么,现在问题来了,我们知道去哪里找数据了,那我们如何查不同类型的数据呢?
这就是我们今天想聊的另一种预检索优化策略:查询构建(Query Construction)。
在本文中,我们将聚焦于如何将用户的自然语言问题,翻译成数据源能理解的那套"行话"。比如SQL语言,或者Cypher查询语句。
传统那套RAG,把问题变成一串向量数字,再去另一堆向量数字里找最相似的。这招在处理非结构化的文字,比如博客、文章时,确实管用。我得承认,这很巧妙。
但世界不是只有文字啊。
要是我们面对的是一张冷冰冰的Excel表,或是一座结构严密、壁垒分明的关系型数据库呢?我第一次遇到这个问题时,真的有点懵。你总不能跟一张员工薪资表谈“语义相似”吧?它有它的脾气,有行有列,有不容置疑的数据类型。跟它打交道,你得说它的“方言”——那些结构化的查询语言。
这感觉,就像从一个诗人,突然要转变成一个会计。
企业里最常见的就是这种“会计式”的数据了。MySQL、PostgreSQL... 它们就像一个个巨大的账本,记录着一切。
一个真正好用的RAG系统,我觉得它不应该偏科,不能只会读诗(非结构化文档),也得会算账(结构化数据)。
如果能让系统自己学会把我们的日常白话,转换成SQL,那该多好。用户只管提问,系统默默地把查询、整合、生成答案这些脏活累活全干了。这听起来才够智能,不是吗?
要做到这一点,其实没那么玄乎。关键就两步:
用一个简单的实现流程代码来理解:
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
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
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[0] for description inself.cursor.description]
return results, column_names
except Exception as e:
print(f"❌ SQL执行失败: {e}")
returnNone, None
📝 用户查询: 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
图数据库是一种基于图结构进行数据存储的形式。这东西跟关系型数据库给人的感觉完全不一样。如果说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
的实现主要流程是:
由于篇幅原因,详细的可运行示例代码,请访问我的GitHub仓库,仓库链接见文章底部。
在向量数据库这边,我们虽然可以直接用自然语言去查,但也不是没有优化的空间。在该环节中也有一些预检索优化技巧,Self-Query Retriever就是其中一种。
它的想法是:为什么不让用户的提问“自己告诉自己”该怎么查?
它会自动从你的问题里,抠出一些关键词作为“元数据”过滤条件。比如你问“给我找找2023年关于AI的论文”,它会先用“2023”和“AI”这两个硬性条件,把海量的文档筛掉一大批,再在剩下的小范围里去做向量相似度计算。
这不就是我们人脑处理信息的方式吗?先分类,再细看。简单,但极其有效。
同样,这个的完整代码我也放在GitHub上了,有兴趣可以去看看,仓库链接见文章底部。
从SQL的严谨,到Cypher的关联,再到Self-Query的小巧思,我们其实一直在做一件事:努力让机器放下身段,来迁就我们的思考方式。
这不只是个“翻译”工作,我觉得这更像是在驯兽,或者说,是在和一个异类寻找沟通的桥梁。我们希望它能突破那些冷冰冰的数据结构,真正理解我们字里行间那些模糊、跳跃、甚至充满情感的意图。
这个过程还在继续,远没到画上句号的时候。或许,下一代智能应用,真的能像个老朋友一样,听懂我们所有的言外之意吧。谁知道呢。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2025-08-28
自适应RAG:用本地 LLM 构建更聪明的检索增强生成系统
2025-08-28
使用RAG构建高质量知识库(四)- 数据检索
2025-08-28
RAG检索后如何应用更有效?
2025-08-28
RAG 不止能检索!它还能在 LangGraph 中当“工具调用大脑”
2025-08-28
如何将 RAG 检索召回率从 50% 提高到 95% 以上
2025-08-28
告别“搜不到、搜不准”:用这套查询优化,让你的RAG检索召回率飙升
2025-08-28
比RAG提升27.4%,阿里等ComRAG利用“质心式”记忆机制实现实时社区问答
2025-08-27
如何评估RAG系统:给你的AI助手做个"体检"
2025-06-05
2025-06-06
2025-06-05
2025-06-05
2025-06-20
2025-06-20
2025-06-24
2025-07-15
2025-06-24
2025-06-05