从自然语言输入生成查询缓慢且效率低下,是决策制定的瓶颈。这迫使分析师和业务用户严重依赖数据团队,从而延迟洞察并限制敏捷性。
Text-to-SQL 正在改变我们与数据交互的方式,使用户能够以自然语言查询结构化数据库。在为专业行业部署特定领域的模型时,这尤其有用。然而,大规模使用这些模型进行分析工作负载推理会带来延迟和性能挑战。
在本教程中,我们将展示如何使用 NVIDIA NIM 优化 Vanna 的文本转 SQL 解决方案。Vanna 的开源文本转 SQL 解决方案因其灵活性、安全性和适应性而在组织中备受关注。
您会学习:
- 将预处理数据插入数据库并连接 Vanna。
- 对 Vanna 进行业务术语或定义培训。
- 利用 NVIDIA NeMo Retriever 嵌入模型检索上下文以生成 SQL。
- 使用适用于 LLM 的 NVIDIA NIM 端点加速推理。
在演示中,我们使用了 Kaggle 中的两个开源 Steam 游戏数据集,这是一个丰富的游戏元数据集,非常适合分析查询。
预备知识
- 已安装 Python 3.10 或更高版本
- 适用于 NVIDIA NeMo Retriever 嵌入模型的 NVIDIA 支持 LangChain 软件包
- 访问 NVIDIA NIM 端点
- 熟悉已安装的 SQLiteVanna 库
- Steam 数据集 数据集 1 数据集 2
程序
1. 下载并预处理 Steam 数据集
为此,请克隆位于/ NVIDIA/ GenerativeAIExamples 的存储库,并在社区部分打开 Vanna_with_NVIDIA notebook。
关键预处理步骤包括:
- 过滤所需列
- 将具有范围的列解压缩为单独的列
- 为每款游戏添加游戏长度
预处理步骤结束时,我们会得到三个 CSV:
tableau_games.csv
tableau_categories.csv
tableau_tags.csv
2. 使用 NVIDIA NIM 和 NeMo Retriever 初始化 Vanna
Vanna 实例需要连接到向量数据库、嵌入器和 LLM 端点。我们使用 Milvus 向量数据库,因为它具有 GPU 加速功能、NVIDIA 检索器嵌入模型 (llama-3.2-nv-embedqa-1b-v2) 和 Llama 3.1 70B NIM 微服务。
借助 NIM 微服务,您的推理模型可在 NVIDIA 加速基础设施上运行,从而为生产部署提供更快的响应时间和成本效益。NVIDIA NIM 包含在 NVIDIA AI Enterprise 软件许可证中,可在任何地方运行,让您拥有自定义设置的所有权,并完全控制您的知识产权 (IP) 和 AI 应用。
有关 NIM 端点的设置说明,请参阅 NVIDIA NIM 文档。

在以下文本中,我们将介绍如何使用 NVIDIA 加速组件初始化 Vanna 实例。
- 将 Vanna 类定义如下。
from pymilvus import MilvusClient, model
from vanna.milvus import Milvus_VectorStore
from vanna.openai import OpenAI_Chat
from openai import OpenAI
# Set the nvidia api key
nvidia_api_key = '...'
# Define Vanna Class
class VannaMilvus(Milvus_VectorStore, OpenAI_Chat):
def __init__(self, llm_client, config=None):
Milvus_VectorStore.__init__(self, config=config)
OpenAI_Chat.__init__(self, client=llm_client, config=config)
- 接下来,使用 NVIDIA API 密钥创建基于 OpenAI Wrapper 的 NIM 客户端。
def get_openai_client():
client = OpenAI(
base_url = "https://integrate.api.nvidia.com/v1",
api_key = nvidia_api_key
)
return client
llm_client = get_openai_client()
- 通过 Milvus DB 为 NeMo Retriever 嵌入模型使用包装器。您可以使用相同的
nvidia_api_key
。
class EmbeddingWrapper:
def __init__(self, embedder):
self.embedder = embedder
def encode_documents(self, texts):
result = self.embedder.embed_documents(texts)
return [np.array(r) for r in result]
def encode_queries(self, texts):
embeddings = []
for text in texts:
embeddings.append(self.embedder.embed_query(text))
return embeddings
vanna_embedder = EmbeddingWrapper(nvidia_embedder)
- 接下来,使用 NVIDIA API 密钥创建基于 OpenAI Wrapper 的 NIM 客户端。
def get_openai_client():
client = OpenAI(
base_url = "https://integrate.api.nvidia.com/v1",
api_key = nvidia_api_key
)
return client
llm_client = get_openai_client()
- 使用本地 Milvus DB 实例。
milvus_uri = "./milvus_nvidia.db"
milvus_client_nvidia = MilvusClient(uri=milvus_uri)
- 使用之前定义的组件指定 Vanna 实例的配置。
# Specify the LLM used for SQL generation
model_name = "nvidia/llama-3.1-70b-instruct"
# Define the configuration for Vanna instance
config_nvidia = {
"model": model_name,
"milvus_client": milvus_client_nvidia,
"embedding_function": vanna_embedder,
"n_results": 2, # The number of results to return from Milvus semantic search.
}
vn_nvidia = VannaMilvus(llm_client, config=config_nvidia)
3. 创建并填充 SQLite 数据库
- 在此演示中使用 SQLite 提供了一个轻量级、无服务器的数据库,用于测试文本转 SQL。您可以使用 Vanna 支持的任何数据库。将预处理步骤中的三个 CSV 插入数据库。
import sqlite3
import pandas as pd
# Specify the path to the SQLite database
sqlite_path = 'steam_data.db'
# Connect to the SQLite database
sql_connect = sqlite3.connect(sqlite_path)
c = sql_connect.cursor()
# Create tables
init_sqls = """
CREATE TABLE IF NOT EXISTS games (
app_id INTEGER PRIMARY KEY,
name TEXT,
release_date TEXT,
price REAL,
short_description TEXT,
positive INTEGER,
negative INTEGER,
min_owners INTEGER,
max_owners INTEGER,
hltb_single REAL
);
CREATE TABLE IF NOT EXISTS categories (
app_id INTEGER,
categories TEXT,
FOREIGN KEY (app_id) REFERENCES games(app_id)
);
CREATE TABLE IF NOT EXISTS tags (
app_id INTEGER,
tags TEXT,
tag_frequencies TEXT,
FOREIGN KEY (app_id) REFERENCES games(app_id)
);
"""
for sql in init_sqls.split(";"):
c.execute(sql)
# Read the CSV files
games_df = pd.read_csv('processed_dataset/games.csv')
categories_df = pd.read_csv('processed_dataset/categories.csv')
tags_df = pd.read_csv('processed_dataset/tags.csv')
# Insert data into tables
games_df.to_sql('games', sql_connect, if_exists='append', index=False)
categories_df.to_sql('categories', sql_connect, if_exists='append', index=False)
tags_df.to_sql('tags', sql_connect, if_exists='append', index=False)
sql_connect.commit()
- 现在,将 SQL DB 连接到 Vanna。
# Connect to the SQLite database
vn_nvidia.connect_to_sqlite(sqlite_path)
4. 训练数据
Vanna 在处理查询数据和业务特定术语的上下文时表现最佳。
- 删除现有训练数据以避免重复数据,并使用数据库数据定义语言 (DDL) 训练 Vanna。
# Remove existing training data
existing_training_data = vn_nvidia.get_training_data()
if len(existing_training_data) > 0:
for _, training_data in existing_training_data.iterrows():
vn_nvidia.remove_training_data(training_data["id"])
# Get the DDL of the SQLite database
df_ddl = vn_nvidia.run_sql("SELECT type, sql FROM sqlite_master WHERE sql is not null")
# Train the model on the DDL data
for ddl in df_ddl["sql"].to_list():
vn_nvidia.train(ddl=ddl)
- 接下来,添加有关数据库模式
games
、tg_ 15 和 tg_ 16 中三个表的文档。
# Add documentation about your business terminology or definitions.
vn_nvidia.train(
documentation="""
This dataset is used to answer questions about the game trends.
"""
)
# Add documentation about the tables
vn_nvidia.train(
documentation="""
The games table contains information about the games.
The app_id is the unique identifier for the game.This is a primary key.
The name is the name of the game.
The release_date is the date the game was released.
The price is the price of the game. Price in USD, 0.0 if its free.
The short_description is a brief description of the game.
The positive is the number of positive reviews or votes.
The negative is the number of negative reviews or votes.
The min_owners is the minimum number of owners. Used together with max_owners to get an estimate of the player base.
The max_owners is the maximum number of owners. Used together with min_owners to get an estimate of the player base.
The hltb_single is the average playtime of the game. This is an estimate.
"""
)
vn_nvidia.train(
documentation="""
The categories table contains information about the categories of the games.
The app_id is the unique identifier for the game.
The categories is the categories of the game.
The app_id is a foreign key to the games table.
"""
)
vn_nvidia.train(
documentation="""
The tags table contains information about the tags of the games.
The app_id is the unique identifier for the game.
The tags is the tags of the game. These are user defined.
The tag_frequencies is the frequencies of the tags.
The app_id is a foreign key to the games table.
"""
)
- 然后,使用简单的命令查看训练数据。
training_data = vn_nvidia.get_training_data()
training_data
5. 生成 SQL
您已准备好开始使用由 NIM 提供支持的 Vanna 查询数据库。
- 从简单查询开始。生成的 SQL 也可以在执行之前打印出来。
sql = vn_nvidia.generate_sql("Which 5 games have the most positive reviews and how many?")
vn_nvidia.run_sql(sql)
- Run a harder query now.
sql = vn_nvidia.generate_sql("Which indie game has the biggest player base?")
vn_nvidia.run_sql(sql)
总结
在本教程中,您学习了如何使用 NVIDIA NIM 加速 Vanna 上的文本转 SQL 推理。凭借清晰的数据库架构、真实数据集和优化的推理端点,该系统能够为用户生成的查询提供响应速度更快的分析。
进一步探索:
- 以此 Notebook 为起点,在您自己的数据集上试用 Vanna。
- 部署 NVIDIA NIM 端点进行生产级推理。
尝试添加不同的训练信息,以更好地生成 SQL。