Як я створив генератор SQL запитів на основі ШІ за допомогою FastAPI та Groq
Вступ
В еру розробки з підтримкою ШІ, поєднання природної мови та технічних систем відкриває нові можливості. У цій статті ми розглянемо HyperQuery, систему, яка перетворює прості питання англійською мовою на SQL запити за допомогою великих мовних моделей (LLM), виконує їх проти бази даних і виводить результати через веб-інтерфейс.
Архітектура системи
Основні компоненти системи та потік даних
Основні компоненти:
- Обробка природної мови: Модель Llama3-70B від Groq
- Backend: FastAPI + SQLite + Pydantic
- Frontend: Vanilla HTML/CSS/JS
- Конвеєр запитів: AI → SQL → Виконання → HTML
Ключові технічні компоненти
1. Генерація SQL за допомогою ШІ
services/query_service.py
class QueryService:
def generate_sql(self, user_query: str) -> SQLResponse:
response = self.client.chat.completions.create(
model="llama3-70b-8192",
messages=[
{"role": "system", "content": self.base_prompt},
{"role": "user", "content": f"Query: {user_query}\nSQL:"}
],
response_model=SQLResponse,
temperature=0.1
)
return self._validate_sql(response.sql)
Файл query_service.py
є "мозком" HyperQuery. Він використовує модель Llama3-70B від Groq для перетворення запитів на природній мові в SQL. Метод generate_sql
відправляє запит користувача до LLM, який генерує SQL на основі схеми бази даних. Метод _validate_sql
перевіряє, чи є згенерований SQL безпечним і правильним, розширюючи SELECT *
на конкретні назви стовпців і забезпечуючи синтаксис, специфічний для SQLite. Цей компонент також забезпечує генерацію запитів з урахуванням схеми, гарантуючи, що SQL відповідає структурі бази даних.
2. Керування підключеннями до бази даних
database/connector.py
class DatabaseConnector:
@contextmanager
def get_connection(self):
conn = sqlite3.connect(
settings.DATABASE_PATH,
detect_types=sqlite3.PARSE_DECLTYPES,
check_same_thread=False
)
sqlite3.register_converter('timestamp', convert_timestamp)
conn.row_factory = sqlite3.Row
yield conn
conn.close()
def execute_safe_query(self, query: str):
# Only allows SELECT/PRAGMA queries
if not query.upper().startswith(tuple(settings.ALLOWED_OPERATIONS)):
raise ValueError("Unauthorized query type")
Файл connector.py
керує всіма взаємодіями з базою даних. Він використовує модуль Python sqlite3
для створення та управління підключеннями, забезпечуючи безпеку потоків через check_same_thread=False
. Метод get_connection
надає контекстний менеджер для підключень до бази даних, а метод execute_safe_query
забезпечує виконання лише запитів для читання (SELECT
і PRAGMA
). Цей файл також обробляє конвертацію часових міток, підтримуючи кілька форматів дати та часу, щоб уникнути помилок під час розбору.
3. Динамічне управління схемою
database/schema_manager.py
class SchemaManager:
def get_schema_prompt(self):
tables = self.db.execute_safe_query(
"SELECT name FROM sqlite_master WHERE type='table'"
)
schema = {}
for table in tables:
columns = self.db.execute_safe_query(
f"PRAGMA table_info({table['name']})"
)
schema[table['name']] = [col['name'] for col in columns]
return schema
Файл schema_manager.py
динамічно отримує схему бази даних, включаючи таблиці та стовпці, за допомогою команди PRAGMA table_info
в SQLite. Ця схема потім форматуються в запит для LLM, що дає можливість генерувати точні SQL запити. Динамічне отримання схеми гарантує, що HyperQuery завжди працює з останньою структурою бази даних, навіть якщо таблиці чи стовпці додаються чи змінюються.
4.
Рендеринг результатів
services/html_generator.py
class HTMLGenerator:
@staticmethod
def generate_table(data: List[Dict], columns: List[str]):
return f"""
{"".join(f"" for col in columns)}{"".join( f"{''.join(f'' for col in columns)}" for row in data )}
{col} {row[col]}
"""
Файл html_generator.py
перетворює результати запитів на HTML таблиці. Він динамічно генерує заголовки таблиць на основі стовпців, що повертаються запитом, і заповнює рядки даними. Цей компонент також обробляє крайні випадки, такі як порожні результати або відсутні стовпці, забезпечуючи постійну взаємодію з користувачем. Сформований HTML є адаптивним і оформлений сучасним CSS для елегантного вигляду.
5. Backend API
backend/main.py
@app.post("/api/query")
async def handle_query(payload: Dict):
try:
user_query = payload.get("query", "")
sql_response = query_service.generate_sql(user_query)
results, columns = db.execute_safe_query(sql_response.sql)
return {
"sql": sql_response.sql,
"html": html_gen.generate_table(results, columns),
"columns": columns,
"row_count": len(results)
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
Пояснення:
Файл main.py
є точкою входу для backend FastAPI. Він надає кінцеву точку /api/query
, яка приймає запити на природній мові, генерує SQL, виконує його та повертає результати у вигляді HTML. Цей файл організовує взаємодію між сервісом запитів, підключенням до бази даних і генератором HTML. Він також обробляє помилки коректно, надаючи користувачеві змістовний зворотний зв'язок.
Висновок
HyperQuery демонструє, як сучасні можливості ШІ можуть спростити взаємодію з базами даних, одночасно зберігаючи безпеку та продуктивність. Поєднуючи LLM з традиційними базами даних, ми створюємо мости між природною мовою та структурованими даними — важливий крок до більш доступної аналітики даних.
GitHub Репозиторій: https://github.com/iamAliAsgharKhan/HyperQuery
Про автора
Ali Asghar — розробник повного стеку та консультант з ШІ, захоплений створенням мостів між природною мовою та технічними системами. Підключайтеся в LinkedIn і Twitter для отримання більше статей про розробку з підтримкою ШІ.
Перекладено з: Building HyperQuery: A Natural Language Interface for SQL Databases