Vanna 및 Milvus로 SQL 작성
Vanna는 SQL 생성 및 관련 기능을 위한 오픈 소스 Python RAG(검색 증강 생성) 프레임워크입니다. Milvus는 세계에서 가장 진보된 오픈 소스 벡터 데이터베이스로, 임베딩 유사도 검색 및 AI 애플리케이션을 강화하기 위해 구축되었습니다.
Vanna는 데이터에 대해 RAG '모델'을 학습시킨 다음, 데이터베이스에서 실행되도록 설정할 수 있는 SQL 쿼리를 반환하는 질문을 하는 두 가지 간단한 단계로 작동합니다. 이 가이드에서는 Vanna를 사용해 데이터베이스에 저장된 데이터를 기반으로 SQL 쿼리를 생성하고 실행하는 방법을 설명합니다.
전제 조건
이 노트북을 실행하기 전에 다음 종속성이 설치되어 있는지 확인하세요:
$ pip install "vanna[milvus,openai]"
Google Colab을 사용하는 경우, 방금 설치한 종속성을 사용하려면 런타임을 다시 시작해야 할 수 있습니다(화면 상단의 "런타임" 메뉴를 클릭하고 드롭다운 메뉴에서 "세션 다시 시작"을 선택하세요).
그리고 환경 변수에 OPENAI_API_KEY
을 설정해야 합니다. OpenAI에서 API 키를 받을 수 있습니다.
import os
os.environ["OPENAI_API_KEY"] = "sk-***********"
데이터 준비
먼저 Vanna의 Milvus_VectorStore
및 OpenAI_Chat
클래스를 상속하고 두 클래스의 기능을 결합한 새 클래스 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
인스턴스를 사용하여 임베딩을 저장하고, milvus_model에서 초기화된 model.DefaultEmbeddingFunction()
을 사용하여 embeddings.C를 생성합니다.
의 인수는 MilvusClient
입니다:
uri
를 로컬 파일(예:./milvus.db
)로 설정하는 것이 가장 편리한 방법인데, Milvus Lite를 자동으로 활용하여 모든 데이터를 이 파일에 저장하기 때문입니다.- 데이터 규모가 큰 경우, 도커나 쿠버네티스에 더 고성능의 Milvus 서버를 설정할 수 있습니다. 이 설정에서는 서버 URL(예:
http://localhost:19530
)을uri
으로 사용하세요. - 밀버스의 완전 관리형 클라우드 서비스인 질리즈 클라우드를 사용하려면, 질리즈 클라우드의 퍼블릭 엔드포인트와 API 키에 해당하는
uri
와token
을 조정하세요.
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로 설정하여 가장 유사한 상위 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)
데이터로 훈련하기
SQLite 데이터베이스의 DDL 데이터로 모델을 훈련할 수 있습니다. 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 | question | content |
---|---|---|---|
0 | 595b185c-e6ad-47b0-98fd-0e93ef9b6a0a-sql | Joh...라는 고객의 세부 정보는 무엇입니까? | SELECT * FROM Customer WHERE Name = 'John Doe' |
0 | 25f4956c-e370-4097-994f-996f22d145fa-ddl | None | CREATE TABLE Company (\n ID INTEGER PRIMARY ... |
1 | b95ecc66-f65b-49dc-a9f1-c1842ad230ff-ddl | None | CREATE TABLE Customer (\n ID INTEGER PRIMAR... |
2 | fcc73d15-30a5-4421-9d73-b8c3b0ed5305-ddl | None | CREATE TABLE sqlite_sequence(name,seq) |
3 | feae618c-5910-4f6f-8b4b-6cc3e03aec06-ddl | None | CREATE TABLE User (\n ID INTEGER PRIMARY KE... |
0 | 79a48db1-ba1f-4fd5-be99-74f2ca2eaeeb-doc | None | 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'
# | Phone |
---|---|
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 | Name | 회사 | 도시 | 전화 |
---|---|---|---|---|---|
0 | 2 | 제인 스미스 | XYZ Inc | Los Angeles | 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)