Пишите SQL с помощью Vanna и Milvus
Vanna - это фреймворк Python RAG (Retrieval-Augmented Generation) с открытым исходным кодом для генерации SQL и связанных с ним функций. Milvus - самая продвинутая в мире векторная база данных с открытым исходным кодом, созданная для работы с приложениями для поиска сходства при встраивании и искусственного интеллекта.
Vanna работает в два простых шага - обучает "модель" RAG на ваших данных, а затем задает вопросы, которые возвращают SQL-запросы, которые могут быть настроены для выполнения в вашей базе данных. В этом руководстве показано, как использовать Vanna для генерации и выполнения SQL-запросов на основе данных, хранящихся в базе данных.
Предварительные условия
Перед запуском этого блокнота убедитесь, что у вас установлены следующие зависимости:
$ pip install "vanna[milvus,openai]"
Если вы используете Google Colab, для включения только что установленных зависимостей может потребоваться перезапуск среды выполнения (щелкните на меню "Runtime" в верхней части экрана и выберите "Restart session" из выпадающего меню).
Также вам нужно установить OPENAI_API_KEY
в переменных окружения. Ключ API можно получить в OpenAI.
import os
os.environ["OPENAI_API_KEY"] = "sk-***********"
Подготовка данных
Сначала нам нужно наследоваться от классов Milvus_VectorStore
и OpenAI_Chat
из Vanna и определить новый класс VannaMilvus
, который объединяет возможности обоих классов.
from pymilvus import MilvusClient, model
from vanna.milvus import Milvus_VectorStore
from vanna.openai import OpenAI_Chat
class VannaMilvus(Milvus_VectorStore, OpenAI_Chat):
def __init__(self, config=None):
Milvus_VectorStore.__init__(self, config=config)
OpenAI_Chat.__init__(self, config=config)
Мы инициализируем класс VannaMilvus
с необходимыми параметрами конфигурации. Мы используем экземпляр milvus_client
для хранения вкраплений и model.DefaultEmbeddingFunction()
, инициализированный из milvus_model, для генерации вкраплений.C
Что касается аргумента MilvusClient
:
- Установка
uri
в качестве локального файла, например,./milvus.db
, является наиболее удобным методом, так как он автоматически использует Milvus Lite для хранения всех данных в этом файле. - Если у вас большой объем данных, вы можете настроить более производительный сервер Milvus на docker или kubernetes. В этом случае используйте ури сервера, например
http://localhost:19530
, в качествеuri
. - Если вы хотите использовать Zilliz Cloud, полностью управляемый облачный сервис для Milvus, измените
uri
иtoken
, которые соответствуют публичной конечной точке и ключу Api в Zilliz Cloud.
milvus_uri = "./milvus_vanna.db"
milvus_client = MilvusClient(uri=milvus_uri)
vn_milvus = VannaMilvus(
config={
"api_key": os.getenv("OPENAI_API_KEY"),
"model": "gpt-3.5-turbo",
"milvus_client": milvus_client,
"embedding_function": model.DefaultEmbeddingFunction(),
"n_results": 2, # The number of results to return from Milvus semantic search.
}
)
Это простой пример с несколькими выборками данных, поэтому мы установили значение n_results
равным 2, чтобы обеспечить поиск двух наиболее похожих результатов. На практике при работе с большим набором обучающих данных следует установить значение n_results
на более высокое значение.
Мы будем использовать пример базы данных SQLite с несколькими таблицами, содержащими некоторые примеры данных.
import sqlite3
sqlite_path = "./my-database.sqlite"
sql_connect = sqlite3.connect(sqlite_path)
c = sql_connect.cursor()
init_sqls = """
CREATE TABLE IF NOT EXISTS Customer (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Company TEXT NOT NULL,
City TEXT NOT NULL,
Phone TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS Company (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Industry TEXT NOT NULL,
Location TEXT NOT NULL,
EmployeeCount INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS User (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Username TEXT NOT NULL UNIQUE,
Email TEXT NOT NULL UNIQUE
);
INSERT INTO Customer (Name, Company, City, Phone)
VALUES ('John Doe', 'ABC Corp', 'New York', '123-456-7890');
INSERT INTO Customer (Name, Company, City, Phone)
VALUES ('Jane Smith', 'XYZ Inc', 'Los Angeles', '098-765-4321');
INSERT INTO Company (Name, Industry, Location, EmployeeCount)
VALUES ('ABC Corp', 'cutting-edge technology', 'New York', 100);
INSERT INTO User (Username, Email)
VALUES ('johndoe123', 'johndoe123@example.com');
"""
for sql in init_sqls.split(";"):
c.execute(sql)
sql_connect.commit()
# Connect to the SQLite database
vn_milvus.connect_to_sqlite(sqlite_path)
Обучение на данных
Мы можем обучить модель на DDL-данных базы данных SQLite. Мы получаем данные DDL и передаем их в функцию train
.
# If there exists training data, we should remove it before training.
existing_training_data = vn_milvus.get_training_data()
if len(existing_training_data) > 0:
for _, training_data in existing_training_data.iterrows():
vn_milvus.remove_training_data(training_data["id"])
# Get the DDL of the SQLite database
df_ddl = vn_milvus.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_milvus.train(ddl=ddl)
Adding ddl: CREATE TABLE Customer (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Company TEXT NOT NULL,
City TEXT NOT NULL,
Phone TEXT NOT NULL
)
Adding ddl: CREATE TABLE sqlite_sequence(name,seq)
Adding ddl: CREATE TABLE Company (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Industry TEXT NOT NULL,
Location TEXT NOT NULL,
EmployeeCount INTEGER NOT NULL
)
Adding ddl: CREATE TABLE User (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Username TEXT NOT NULL UNIQUE,
Email TEXT NOT NULL UNIQUE
)
Кроме обучения на DDL-данных, мы также можем обучаться на документации и SQL-запросах базы данных.
# Add documentation about your business terminology or definitions.
vn_milvus.train(
documentation="ABC Corp specializes in cutting-edge technology solutions and innovation."
)
vn_milvus.train(
documentation="XYZ Inc is a global leader in manufacturing and supply chain management."
)
# You can also add SQL queries to your training data.
vn_milvus.train(sql="SELECT * FROM Customer WHERE Name = 'John Doe'")
Adding documentation....
Adding documentation....
Using model gpt-3.5-turbo for 65.0 tokens (approx)
Question generated with sql: What are the details of the customer named John Doe?
Adding SQL...
'595b185c-e6ad-47b0-98fd-0e93ef9b6a0a-sql'
Давайте посмотрим на обучающие данные.
training_data = vn_milvus.get_training_data()
training_data
# | id | вопрос | содержание |
---|---|---|---|
0 | 595b185c-e6ad-47b0-98fd-0e93ef9b6a0a-sql | Каковы данные о клиенте по имени Джо... | SELECT * FROM Customer WHERE Name = 'John Doe' |
0 | 25f4956c-e370-4097-994f-996f22d145fa-ddl | Нет | CREATE TABLE Company (\n ID INTEGER PRIMARY... |
1 | b95ecc66-f65b-49dc-a9f1-c1842ad230ff-ddl | Нет | CREATE TABLE Customer (\n ID INTEGER PRIMAR... |
2 | fcc73d15-30a5-4421-9d73-b8c3b0ed5305-ddl | Нет | CREATE TABLE sqlite_sequence(name,seq) |
3 | feae618c-5910-4f6f-8b4b-6cc3e03aec06-ddl | Нет | CREATE TABLE User (\n ID INTEGER PRIMARY KE... |
0 | 79a48db1-ba1f-4fd5-be99-74f2ca2eaeeb-doc | Нет | Компания XYZ Inc является мировым лидером в производстве... |
1 | 9f9df1b8-ae62-4823-ad28-d7e0f2d1f4c0-doc | Нет | ABC Corp специализируется на передовых технологиях... |
Генерация SQL и их выполнение
Поскольку мы тренировались с данными DDL, структура таблицы теперь доступна для генерации SQL-запросов.
Давайте попробуем выполнить простой вопрос.
sql = vn_milvus.generate_sql("what is the phone number of John Doe?")
vn_milvus.run_sql(sql)
SQL Prompt: [{'role': 'system', 'content': "You are a SQLite expert. Please help to generate a SQL query to answer the question. Your response should ONLY be based on the given context and follow the response guidelines and format instructions. \n===Tables \nCREATE TABLE Customer (\n ID INTEGER PRIMARY KEY AUTOINCREMENT,\n Name TEXT NOT NULL,\n Company TEXT NOT NULL,\n City TEXT NOT NULL,\n Phone TEXT NOT NULL\n)\n\nCREATE TABLE User (\n ID INTEGER PRIMARY KEY AUTOINCREMENT,\n Username TEXT NOT NULL UNIQUE,\n Email TEXT NOT NULL UNIQUE\n)\n\n\n===Additional Context \n\nABC Corp specializes in cutting-edge technology solutions and innovation.\n\nXYZ Inc is a global leader in manufacturing and supply chain management.\n\n===Response Guidelines \n1. If the provided context is sufficient, please generate a valid SQL query without any explanations for the question. \n2. If the provided context is almost sufficient but requires knowledge of a specific string in a particular column, please generate an intermediate SQL query to find the distinct strings in that column. Prepend the query with a comment saying intermediate_sql \n3. If the provided context is insufficient, please explain why it can't be generated. \n4. Please use the most relevant table(s). \n5. If the question has been asked and answered before, please repeat the answer exactly as it was given before. \n"}, {'role': 'user', 'content': 'What are the details of the customer named John Doe?'}, {'role': 'assistant', 'content': "SELECT * FROM Customer WHERE Name = 'John Doe'"}, {'role': 'user', 'content': 'what is the phone number of John Doe?'}]
Using model gpt-3.5-turbo for 367.25 tokens (approx)
LLM Response: SELECT Phone FROM Customer WHERE Name = 'John Doe'
# | Телефон |
---|---|
0 | 123-456-7890 |
А вот более сложный вопрос. Информация о названии производственной корпорации находится в данных документа, который является справочной информацией. Сформированный SQL-запрос извлекает информацию о клиенте на основе конкретного названия производственной корпорации.
sql = vn_milvus.generate_sql("which customer works for a manufacturing corporation?")
vn_milvus.run_sql(sql)
SQL Prompt: [{'role': 'system', 'content': "You are a SQLite expert. Please help to generate a SQL query to answer the question. Your response should ONLY be based on the given context and follow the response guidelines and format instructions. \n===Tables \nCREATE TABLE Company (\n ID INTEGER PRIMARY KEY AUTOINCREMENT,\n Name TEXT NOT NULL,\n Industry TEXT NOT NULL,\n Location TEXT NOT NULL,\n EmployeeCount INTEGER NOT NULL\n)\n\nCREATE TABLE Customer (\n ID INTEGER PRIMARY KEY AUTOINCREMENT,\n Name TEXT NOT NULL,\n Company TEXT NOT NULL,\n City TEXT NOT NULL,\n Phone TEXT NOT NULL\n)\n\n\n===Additional Context \n\nXYZ Inc is a global leader in manufacturing and supply chain management.\n\nABC Corp specializes in cutting-edge technology solutions and innovation.\n\n===Response Guidelines \n1. If the provided context is sufficient, please generate a valid SQL query without any explanations for the question. \n2. If the provided context is almost sufficient but requires knowledge of a specific string in a particular column, please generate an intermediate SQL query to find the distinct strings in that column. Prepend the query with a comment saying intermediate_sql \n3. If the provided context is insufficient, please explain why it can't be generated. \n4. Please use the most relevant table(s). \n5. If the question has been asked and answered before, please repeat the answer exactly as it was given before. \n"}, {'role': 'user', 'content': 'What are the details of the customer named John Doe?'}, {'role': 'assistant', 'content': "SELECT * FROM Customer WHERE Name = 'John Doe'"}, {'role': 'user', 'content': 'which customer works for a manufacturing corporation?'}]
Using model gpt-3.5-turbo for 384.25 tokens (approx)
LLM Response: SELECT *
FROM Customer
WHERE Company = 'XYZ Inc'
# | ID | Имя | Компания | Город | Телефон |
---|---|---|---|---|---|
0 | 2 | Джейн Смит | XYZ Inc | Лос-Анджелес | 098-765-4321 |
Отключитесь от SQLite и Milvus и удалите их, чтобы освободить ресурсы.
sql_connect.close()
milvus_client.close()
os.remove(sqlite_path)
if os.path.exists(milvus_uri):
os.remove(milvus_uri)