| --- |
| title: Ru2SQL |
| emoji: 🗄️ |
| colorFrom: blue |
| colorTo: purple |
| sdk: docker |
| pinned: false |
| --- |
| |
| # ru2sql |
|
|
| Генеративная модель для преобразования вопросов на русском языке в SQL-запросы. |
| Практическая часть ВКР, направление «Программная инженерия», 4 курс. |
|
|
| **Стек:** Python 3.10+, PyTorch, transformers, PEFT (LoRA), FastAPI, Streamlit, sqlglot. |
| **Основная модель:** Qwen2.5-Coder-3B-Instruct, дообученная методом QLoRA на датасете PAUQ. |
| **Сравнение:** ruT5-base baseline + GigaChat API. |
|
|
| См. `plan_VKR_text2sql_ru.md` для полного плана работ. |
|
|
| --- |
|
|
| ## Архитектура |
|
|
| ``` |
| ┌─────────────────────┐ HTTP ┌──────────────────────┐ |
| │ Streamlit-клиент │ ─────────► │ FastAPI REST API │ |
| │ (порт 8501) │ │ (порт 8000) │ |
| └─────────────────────┘ └──────────┬───────────┘ |
| │ |
| ┌──────────────────┼──────────────────┐ |
| ▼ ▼ ▼ |
| ┌──────────────────┐ ┌──────────────┐ ┌────────────────┐ |
| │ InferenceEngine │ │ SchemaProvi- │ │ BusinessVocab- │ |
| │ Qwen + LoRA │ │ der + Sql- │ │ ulary (YAML) │ |
| │ │ │ Executor │ │ │ |
| └──────────────────┘ └──────────────┘ └────────────────┘ |
| ``` |
|
|
| Streamlit-интерфейс не вызывает модель напрямую — он обращается к REST API |
| через `httpx`. Это позволяет запускать UI и инференс на разных машинах, |
| а также подключать к API любых сторонних клиентов. |
|
|
| --- |
|
|
| ## Быстрый старт |
|
|
| ### 1. Установка |
|
|
| ```bash |
| pip install uv |
| git clone <твой-репо> ru2sql |
| cd ru2sql |
| uv venv |
| .venv\Scripts\activate # Windows |
| # source .venv/bin/activate # Linux/Mac |
| uv pip install -e ".[dev]" |
| ``` |
|
|
| ### 2. Конфигурация |
|
|
| ```bash |
| copy .env.example .env # Windows |
| # cp .env.example .env # Linux/Mac |
| ``` |
|
|
| Заполни в `.env`: |
| - `BASE_MODEL_NAME` (по умолчанию Qwen/Qwen2.5-Coder-3B-Instruct), |
| - `LORA_ADAPTER_PATH` (локальная папка или HF-repo), |
| - опционально — API-ключ GigaChat для baseline-сравнения. |
|
|
| Если HuggingFace недоступен из вашей сети, добавь: |
| ``` |
| HF_ENDPOINT=https://hf-mirror.com |
| ``` |
|
|
| ### 3. Тесты |
|
|
| ```bash |
| pytest -v |
| ``` |
|
|
| Ожидаемо: 80+ зелёных тестов. |
|
|
| ### 4. Smoke-проверка |
|
|
| Быстрая (5 сек, без модели): |
| ```bash |
| python scripts/smoke_local.py |
| ``` |
|
|
| Полная (с загрузкой Qwen, ~5 минут на CPU): |
| ```bash |
| python scripts/smoke_local.py --with-model |
| ``` |
|
|
| ### 5. Запуск приложения |
|
|
| Нужны **два процесса** — API и UI: |
|
|
| **Окно 1** — REST API: |
| ```bash |
| uvicorn src.api.main:app --reload |
| # Swagger UI: http://127.0.0.1:8000/docs |
| ``` |
|
|
| **Окно 2** — Streamlit-интерфейс: |
| ```bash |
| streamlit run streamlit_app.py |
| # UI: http://127.0.0.1:8501 |
| ``` |
|
|
| При первом запуске модель Qwen2.5-Coder-3B (~6 GB) скачивается из HuggingFace |
| Hub. На CPU инференс одного запроса занимает 15–30 секунд — это ожидаемо. |
|
|
| Адрес API можно переопределить переменной окружения: |
| ```bash |
| set RU2SQL_API_URL=http://192.168.1.10:8000 # Windows |
| # export RU2SQL_API_URL=http://192.168.1.10:8000 # Linux/Mac |
| ``` |
|
|
| --- |
|
|
| ## REST API |
|
|
| ### Базовые эндпоинты |
|
|
| | Метод | Путь | Назначение | |
| |---|---|---| |
| | GET | `/health` | статус сервиса и загруженной модели | |
| | GET | `/databases` | список БД из data/databases (PAUQ-структура) | |
| | POST | `/generate-sql` | генерация SQL по db_id из PAUQ | |
| | POST | `/schema` | схема произвольной БД по connection string | |
| | POST | `/query` | полный pipeline для произвольной БД | |
| |
| ### Пример: запрос к произвольной БД |
| |
| ```bash |
| curl -X POST http://127.0.0.1:8000/query \ |
| -H "Content-Type: application/json" \ |
| -d '{ |
| "question": "Какая выручка за 2026 год?", |
| "connection_string": "sqlite:///data/demo/sales.sqlite", |
| "execute": true, |
| "vocabulary": { |
| "company": "Демо-магазин", |
| "terms": {"выручка": "SUM(orders.amount) WHERE status='paid'"} |
| } |
| }' |
| ``` |
| |
| Ответ содержит `sql`, `raw_output`, `is_valid_sql`, `gen_time_seconds` и |
| опционально `execution` с результатами выполнения. Перед исполнением |
| SQL проходит AST-уровневую проверку (см. `is_select_only` в |
| `src/models/postprocess.py`) — DDL и DML на БД через API невозможны. |
|
|
| ### Пример: PAUQ-режим (старый эндпоинт) |
|
|
| ```bash |
| curl -X POST http://127.0.0.1:8000/generate-sql \ |
| -H "Content-Type: application/json" \ |
| -d '{"question": "Сколько студентов на факультете ПИ?", "db_id": "university"}' |
| ``` |
|
|
| --- |
|
|
| ## Обучение модели |
|
|
| Тренировка идёт **в Kaggle Notebook** (бесплатный T4 GPU). Локально на CPU/AMD GPU |
| обучить 3B-модель не получится. |
|
|
| Шаги: |
| 1. Открой `notebooks/kaggle_train_qwen_qlora.ipynb` на kaggle.com. |
| 2. В Settings выбери Accelerator: GPU T4 x1. |
| 3. Add-ons → Secrets → добавь `HF_TOKEN` и `WANDB_API_KEY`. |
| 4. Запусти все ячейки. Тренировка ~4–6 часов. |
| 5. По завершении адаптер пушится на твой приватный HF-репо. |
| 6. Скачай его на десктоп: |
| ```bash |
| huggingface-cli download your-username/qwen-coder-pauq-lora \ |
| --local-dir checkpoints/qwen-coder-pauq-lora |
| ``` |
|
|
| После этого `LORA_ADAPTER_PATH` в `.env` укажет на скачанный адаптер, |
| и API будет использовать дообученную модель. |
|
|
| --- |
|
|
| ## Структура проекта |
|
|
| ``` |
| ru2sql/ |
| ├── pyproject.toml # зависимости |
| ├── .env.example # шаблон конфигурации |
| ├── plan_VKR_text2sql_ru.md # план работ |
| ├── notebooks/ |
| │ └── kaggle_train_qwen_qlora.ipynb |
| ├── scripts/ |
| │ └── smoke_local.py # локальная проверка работоспособности |
| ├── configs/ |
| │ ├── example_vocabulary.yaml |
| │ └── sales_vocabulary.yaml |
| ├── src/ |
| │ ├── config.py # настройки через pydantic-settings |
| │ ├── data/ |
| │ │ ├── loader.py # чтение PAUQ JSON |
| │ │ ├── schema_provider.py # SchemaProvider — единый интерфейс |
| │ │ ├── schema.py # SchemaRetriever (фасад для PAUQ) |
| │ │ └── prompt.py # PromptBuilder + chat-template |
| │ ├── db/ |
| │ │ ├── connector.py # DbConnector — чтение схем |
| │ │ └── executor.py # SqlExecutor с read-only |
| │ ├── business/ |
| │ │ └── vocabulary.py # BusinessVocabulary (YAML-конфиг) |
| │ ├── models/ |
| │ │ ├── inference.py # InferenceEngine (модель + LoRA) |
| │ │ └── postprocess.py # очистка SQL + guardrail |
| │ ├── evaluation/ |
| │ │ ├── metrics.py # EM + Execution Accuracy |
| │ │ └── evaluate.py # CLI для прогона на split |
| │ └── api/ |
| │ ├── main.py # FastAPI app (5 эндпоинтов) |
| │ ├── schemas.py # Pydantic-модели |
| │ └── dependencies.py # lifespan + DI |
| ├── streamlit_app.py # UI (HTTPX-клиент к API) |
| └── tests/ # 80+ тестов |
| ├── test_prompt.py |
| ├── test_postprocess.py |
| ├── test_metrics.py |
| ├── test_schema.py |
| ├── test_schema_provider.py |
| ├── test_vocabulary.py |
| └── test_db.py |
| ``` |
|
|
| --- |
|
|
| ## Прогон оценки |
|
|
| ```bash |
| # Полный прогон на dev split |
| python -m src.evaluation.evaluate --split dev |
| |
| # Быстрая проверка на 50 примерах |
| python -m src.evaluation.evaluate --split dev --limit 50 |
| ``` |
|
|
| Результат сохраняется в `results/predictions.jsonl`, метрики печатаются в stdout. |
|
|
| --- |
|
|
| ## Метрики |
|
|
| | Модель | EM | Execution Accuracy | |
| |---|---|---| |
| | ruT5-base (baseline) | 25–35 % | 30–40 % | |
| | **Qwen2.5-Coder-3B + QLoRA** | **40,0 %** | **71,9 %** | |
| | BRIDGE / RAT-SQL (PAUQ, mono) | 51 / 52 % | 48 / 49 % | |
|
|
| --- |
|
|
| ## Что НЕ входит в MVP |
|
|
| Сознательно оставлено в раздел «направления дальнейшей работы»: |
| - Few-shot retrieval похожих примеров. |
| - Schema linking (автоматический отбор релевантных таблиц). |
| - Self-correction по ошибкам исполнения SQL. |
| - Constrained decoding (грамматика SQL). |
| - Дообучение на синтетических данных. |
|
|
| --- |
|
|
| ## Лицензия и атрибуция |
|
|
| Учебный проект. Использует: |
| - PAUQ — Apache 2.0, https://github.com/ai-forever/pauq |
| - Qwen2.5-Coder — Apache 2.0, https://huggingface.co/Qwen/Qwen2.5-Coder-3B-Instruct |
| - ruT5 — MIT, https://huggingface.co/ai-forever/ruT5-base |
|
|