AI代码开发宝库系列:Vanna专业的Text-to-SQL
Vanna作为一款开源的Text-to-SQL框架,真正实现了让非技术人员也能轻松查询数据库的目标。其基于RAG技术的实现方式,有效解决了大语言模型在数据库查询中的准确性问题。通过简单的训练和配置,Vanna就能帮助企业和个人实现数据查询的智能化,大大降低了数据分析的门槛。无论是业务人员、客服还是运营,都能通过自然语言快速获取所需数据,真正实现了"数据民主化"。如果你也在为复杂的SQL查询而头疼,
Vanna:让数据库查询变得简单的开源RAG框架

在数据驱动的时代,数据库查询是每个业务人员和技术人员都需要掌握的技能。但传统的SQL查询对于非技术人员来说,往往是一道难以逾越的门槛。今天我要给大家介绍一个开源神器——Vanna,它能让你用自然语言就能轻松查询数据库,真正实现"一句话查数据"!
一、Vanna核心定位——专业的Text-to-SQL解决方案
Vanna是一款开源的检索增强生成(RAG)框架,专注于解决"自然语言转SQL(Text-to-SQL)"的需求。它支持与各类数据库交互,让非技术人员通过自然语言即可完成数据库查询,同时满足企业级场景下的定制化与本地化部署需求。
Vanna的核心价值在于:
-
降低技术门槛:让不懂SQL的业务人员也能轻松查询数据库
-
提升查询准确性:基于RAG技术,有效解决大语言模型的"幻觉"问题
-
灵活适配:支持多种大语言模型、向量数据库和关系型数据库
-
企业级安全:支持本地化部署,保障企业数据安全
二、Vanna核心特点
| 特点 | 详细说明 |
|---|---|
| 开源与可定制化 | 提供完整 Python 库,支持本地化部署;允许用户自主选择大语言模型(LLM)、向量数据库(VectorDB)和关系型数据库(如 MySQL、PostgreSQL),适配不同技术栈需求。 |
| RAG 增强准确性 | 基于检索增强生成技术,通过学习数据库元数据(DDL 语句、表注释)、示例 SQL、业务文档等信息,提升复杂 SQL 查询(如多表关联、聚合函数)的生成准确率,减少 LLM "幻觉"。 |
| 多场景适配 | 覆盖企业数据分析(如销售报表生成)、智能客服(如用户订单查询)、电商搜索(如商品库存统计)、金融报告(如交易流水核对)等场景,降低数据库使用门槛。 |
| 灵活的基础设施 | 支持主流 LLM(如 OpenAI、本地部署的 Ollama)、向量数据库(如 ChromaDB);可通过扩展接口适配非默认支持的数据库类型,兼容性强。 |
三、Vanna工作原理——RAG技术加持的智能查询
Vanna的核心在于其独特的RAG(检索增强生成)技术实现。传统的Text-to-SQL方案往往存在"幻觉"问题,即大语言模型生成的SQL语句可能不符合实际的数据库结构。Vanna通过以下方式解决了这个问题:
1. 智能训练机制
Vanna会学习数据库的元数据信息,包括:
-
数据库表结构(DDL语句)
-
字段含义说明
-
历史查询示例
-
业务规则文档
# 训练表结构 vn.train(ddl=""" CREATE TABLE heros ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL COMMENT '英雄名称', attack_max FLOAT COMMENT '最大攻击力', hp_max FLOAT COMMENT '最大生命值', role_main VARCHAR(255) COMMENT '主要定位' ); """) # 训练业务规则 vn.train(documentation=""" 英雄表查询规则: 1. attack_max字段表示英雄的最大攻击力 2. role_main字段表示英雄的主要定位,包括坦克、战士、法师、刺客、射手、辅助 3. 查询"前N名"时需要使用ORDER BY和LIMIT """) # 训练示例SQL vn.train(sql=""" -- 示例:查询role为"战士"的英雄中,生命值前3名的记录 SELECT name, hp_max FROM heros WHERE role_main = '战士' ORDER BY hp_max DESC LIMIT 3; """)
2. 两阶段查询流程
Vanna的查询过程分为两个阶段:
第一阶段:知识检索
-
将用户问题转换为向量
-
在向量数据库中检索相关知识(表结构、业务规则等)
第二阶段:智能生成
-
将检索到的知识与用户问题组合成Prompt
-
交给大语言模型生成准确的SQL语句
3. 核心函数解析
Vanna的查询流程依赖多个核心函数协同工作,其中ask是入口函数,会自动调用其他函数完成全流程:
-
ask函数(核心入口):
-
接收用户自然语言问题
-
串联"检索→SQL生成→执行→可视化"全流程
-
返回查询结果与图表
-
-
generate_sql函数(SQL生成):
-
调用get_similar_question_sql:检索相似的"问题-SQL"对
-
调用get_related_ddl:检索相关建表语句
-
调用get_related_documentation:检索相关业务文档
-
调用get_sql_prompt:组装Prompt
-
生成最终SQL语句
-
-
run_sql函数(SQL执行):
-
执行生成的SQL语句
-
与数据库交互并返回结果(Pandas DataFrame格式)
-
-
可视化函数:
-
generate_plotly_code:生成Plotly可视化代码
-
get_plotly_figure:生成图表对象
-
四、Vanna使用步骤(完整流程)
1. 安装Vanna
# 基础安装 pip install vanna # 完整安装(支持ChromaDB向量库、Ollama本地LLM、MySQL数据库) pip install vanna[chromadb,ollama,mysql] # 完整安装(支持ChromaDB、OpenAI、MySQL) pip install vanna[chromadb,openai,mysql]
2. 环境准备与初始化
from vanna.openai import OpenAI_Chat
from vanna.chromadb.chromadb_vector import ChromaDB_VectorStore
import mysql.connector
from openai import OpenAI
class MyVanna(ChromaDB_VectorStore, OpenAI_Chat):
def __init__(self, config=None):
chroma_config = config.copy() if config else {}
openai_config = config.copy() if config else {}
if config and 'client' in config:
self.client = config['client']
else:
self.client = None
if 'client' in chroma_config:
del chroma_config['client']
ChromaDB_VectorStore.__init__(self, config=chroma_config)
OpenAI_Chat.__init__(self, config=openai_config)
# 初始化Vanna
client = OpenAI(
api_key='your-api-key',
base_url='https://api.openai.com/v1'
)
vn = MyVanna(config={
'model': 'gpt-4',
'client': client
})
3. 数据库连接与训练
# 连接数据库
vn.connect_to_mysql(
host='your-host',
dbname='action',
user='your-username',
password='your-password',
port=3306
)
# 自动训练所有表的schema
connection = mysql.connector.connect(
host='your-host',
database='action',
user='your-username',
password='your-password',
port=3306
)
cursor = connection.cursor()
cursor.execute("""
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'action'
""")
tables = cursor.fetchall()
# 训练每个表的结构
for (table_name,) in tables:
try:
cursor.execute(f"SHOW CREATE TABLE {table_name}")
_, create_table = cursor.fetchone()
vn.train(ddl=create_table)
print(f"已训练表 {table_name}")
except Exception as e:
print(f"训练表 {table_name} 失败: {str(e)}")
4. 自然语言查询
现在我们可以用自然语言进行查询了:
# 查询攻击力最高的5个英雄
result = vn.ask("找出英雄攻击力最高的前5个英雄")
print(result["df"]) # 查看查询结果
# 带条件的查询
vn.ask("查询定位为法师的英雄,按最大生命值降序排列,显示前10条")
# 复杂查询
vn.ask("统计不同英雄定位的数量,显示定位名称和对应英雄数")
# 单独生成SQL(用于调试)
sql = vn.generate_sql("查询heros表中定位为刺客的英雄,攻击力前3名")
print("生成的SQL:", sql)
五、Vanna提升复杂SQL查询准确率的机制
Vanna通过以下机制显著提升复杂SQL查询的生成准确率:
1. 多维度知识学习
Vanna不仅仅依赖大语言模型的通用知识,而是通过训练让模型学习特定数据库的详细信息:
-
DDL语句训练:明确表结构、字段类型和约束关系
-
业务文档训练:理解字段含义和业务规则
-
示例SQL训练:学习常见的查询模式和逻辑
2. 检索增强生成(RAG)技术
在查询时,Vanna会:
-
将用户问题转换为向量表示
-
在向量数据库中检索最相关的知识(DDL、文档、示例SQL)
-
将检索到的知识与问题组合成结构化Prompt
-
交给大语言模型生成准确的SQL语句
这种方式有效避免了大语言模型因不了解具体数据库结构而产生的"幻觉"问题。
3. 多层次验证机制
Vanna提供了多种验证和调试手段:
-
可以单独调用generate_sql函数生成SQL而不执行,便于检查语法
-
提供get_related_ddl、get_related_documentation等函数查看检索到的相关知识
-
支持手动优化训练数据以提升准确率
六、Vanna在不同场景下的应用示例
1. 企业数据分析
业务人员可以直接问:"上个月销售额最高的产品是哪些?",Vanna会自动生成SQL并返回结果。
# 销售数据分析示例
vn.ask("查询上个月销售额最高的前10个产品,显示产品名称和销售额")
vn.ask("统计各部门的销售业绩,按销售额降序排列")
2. 智能客服系统
客户询问:"我的订单状态是什么?",系统自动查询数据库并返回结果。
# 订单查询示例
vn.ask("查询客户ID为12345的最新订单状态和预计送达时间")
3. 电商库存管理
运营人员问:"库存不足100的商品有哪些?",系统立即返回相关商品列表。
# 库存管理示例
vn.ask("查询库存数量少于100的商品,按库存数量升序排列")
vn.ask("统计各类别商品的库存总价值")
4. 金融报表生成
财务人员问:"本月交易金额超过10000的客户有哪些?",系统自动生成报表。
# 金融数据分析示例
vn.ask("查询本月交易金额超过10000的客户,显示客户姓名和交易总额")
vn.ask("统计不同风险等级的投资产品数量和平均收益率")
5. 游戏数据分析(基于heros表)
针对我们示例中的英雄数据表,可以进行以下查询:
# 英雄数据分析示例
vn.ask("查询所有定位为'坦克'的英雄,按最大生命值降序排列")
vn.ask("统计不同英雄定位的数量,显示定位名称和对应英雄数")
vn.ask("查询攻击力大于800的英雄,显示名称、攻击力和定位,按攻击力升序排列")
vn.ask("找出战士职业中生命值前5名的英雄")
vn.ask("统计各攻击范围类型的英雄数量")
七、实践打卡任务
结合前文内容,完成以下Text-to-SQL实践,熟练掌握Vanna的使用流程:
1. 任务目标
基于本地MySQL数据库中的heros表,使用Vanna实现自然语言查询,验证"从训练到查询"的全流程。
2. 任务步骤
-
环境准备:安装Vanna及扩展组件(
vanna[chromadb,openai,mysql]),确保MySQL服务正常运行。 -
数据准备:在MySQL中创建heros表,并插入测试数据。
-
Vanna训练:通过DDL语句、业务文档训练模型,明确heros表结构与查询规则。
-
自然语言查询:使用vn.ask完成至少3个查询需求。
-
结果验证:检查生成的SQL语法正确性,对比执行结果与预期是否一致。
八、总结
Vanna作为一款开源的Text-to-SQL框架,真正实现了让非技术人员也能轻松查询数据库的目标。其基于RAG技术的实现方式,有效解决了大语言模型在数据库查询中的准确性问题。
通过简单的训练和配置,Vanna就能帮助企业和个人实现数据查询的智能化,大大降低了数据分析的门槛。无论是业务人员、客服还是运营,都能通过自然语言快速获取所需数据,真正实现了"数据民主化"。
如果你也在为复杂的SQL查询而头疼,不妨试试Vanna这个开源神器,相信它会给你带来全新的数据查询体验!
完整代码
from vanna.openai import OpenAI_Chat
from vanna.chromadb.chromadb_vector import ChromaDB_VectorStore
import mysql.connector
import time
from openai import OpenAI
class MyVanna(ChromaDB_VectorStore, OpenAI_Chat):
def __init__(self, config=None):
# 分离配置,只将OpenAI客户端传递给OpenAI_Chat
chroma_config = config.copy() if config else {}
openai_config = config.copy() if config else {}
# 保存client到实例属性
if config and 'client' in config:
self.client = config['client']
else:
self.client = None
# 从chroma_config中移除client
if 'client' in chroma_config:
del chroma_config['client']
# 初始化两个基类
ChromaDB_VectorStore.__init__(self, config=chroma_config)
OpenAI_Chat.__init__(self, config=openai_config)
# 创建OpenAI客户端
client = OpenAI(
api_key='sk-mi9MCut4OAAfY4SUE8a4fCQBLfMZPZpV5an6Ove0PPUSVVBq',
base_url='https://chatapi.littlewheat.com/v1'
)
# 初始化Vanna实例
vn = MyVanna(config={
'model': 'gpt-4o-mini',
'client': client
})
vn.connect_to_mysql(host='rm-uf6z891lon6dxuqblqo.mysql.rds.aliyuncs.com',
dbname='action', user='student123', password='student321', port=3306)
# 连接到MySQL数据库
try:
connection = mysql.connector.connect(
host='rm-uf6z891lon6dxuqblqo.mysql.rds.aliyuncs.com',
database='action',
user='student123',
password='student321',
port=3306
)
print("成功连接到MySQL数据库")
# 获取所有表名
cursor = connection.cursor()
cursor.execute("""
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'action'
""")
tables = cursor.fetchall()
# 训练每个表的schema
for (table_name,) in tables:
try:
# 获取表的创建语句
cursor.execute(f"SHOW CREATE TABLE {table_name}")
_, create_table = cursor.fetchone()
print(f"正在训练表 {table_name} 的schema...")
vn.train(ddl=create_table)
except Exception as e:
print(f"训练表 {table_name} 失败: {str(e)}")
continue
print("Schema训练完成")
# 示例:使用Vanna进行自然语言查询
question = "找出英雄攻击力最高的前5个英雄"
#print(f"\n问题: {question}")
vn.ask(question)
#vn.ask("查询heros表中 英雄攻击力前5名的英雄")
# sql=vn.generate_sql("查询heros表中 英雄攻击力前5名的英雄")
# print('sql=', sql)
# df = vn.run_sql(sql)
# print('df=', df)
except mysql.connector.Error as err:
print(f"数据库连接错误: {err}")
finally:
if 'connection' in locals() and connection.is_connected():
cursor.close()
connection.close()
print("MySQL连接已关闭")
# In[ ]:
# #help(vn.ask)
# #vn.ask("查询heros表中 英雄攻击力前5名的英雄")
# sql=vn.generate_sql("查询heros表中 英雄攻击力前5名的英雄")
# print('sql=', sql)
# vn.run_sql(sql)
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)