Дата: 2026-05-10
Статус: v1 — superseded after CX/KM review (2026-05-10). Документ оставлен как исторический. Действующая baseline: 02_architecture_v2.md.
⚠️ Известные ошибки v1, исправлены в v2:
- BIRD Mini-Dev = 500 примеров (не 1500/11 БД, как ниже в разделе 5)
- codestral-2501 deprecated с ноября 2025 → переход на
codestral-latest(v25.08)- 11-узловой pipeline → 6 узлов
- 4 коллекции Chroma → 2
- стек: убраны Prometheus + OTel + Redis (избыточно для solo-demo)
- Vega-Lite от LLM → детерминированный chart picker + Plotly шаблоны
- Mistral-only → provider abstraction + 30-question bakeoff
- eval target: 50% EA → baseline 35-40%, stretch 50%, hard checkpoint неделя 3
«Максимально нагруженный» здесь = всё, что реально нужно для серьёзного демо-проекта уровня Senior Data Engineer, без фейкового overengineering'а. Каждый компонент обоснован задачей; ничего «на будущее».
┌──────────────────────────┐
│ Web UI (Next.js + React)│
│ ─ chat input │
│ ─ table / chart / SQL │
│ ─ history + bookmarks │
└────────────┬─────────────┘
│ HTTPS
▼
┌──────────────────────────────────────────┐
│ FastAPI gateway (auth, rate-limit, CORS)│
│ /ask, /databases, /history, /eval/run │
└────────────┬─────────────────────────────┘
│
┌────────────────────┼────────────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌────────────────┐ ┌────────────────────┐
│ LangGraph │ │ Eval harness │ │ Schema indexer │
│ NL→SQL graph │ │ (BIRD/Spider) │ │ (offline pipeline) │
└──────┬───────┘ └────────┬───────┘ └─────────┬──────────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────────────────┐
│ Shared services layer │
├──────────────┬──────────────┬─────────────┬──────────────────┤
│ Mistral API │ Chroma DB │ Postgres │ Redis │
│ codestral │ schema chunks│ target DBs │ result cache │
│ large-2 │ few-shot Q→S │ (multi-DB) │ rate-limit state │
│ mistral-embed│ │ + traces DB │ │
└──────────────┴──────────────┴─────────────┴──────────────────┘
│
▼
┌──────────────────────────┐
│ Observability │
│ Prometheus + OpenTelemetry│
│ Langfuse traces │
└──────────────────────────┘
Реиспользуем структуру из RAG_Support_Assistant
(classify → retrieve → rerank → generate → verify → evaluate),
но узлы заточены под NL→SQL:
┌────────────────┐
│ classify_intent│ intent = aggregation | ranking | filter |
└────────┬───────┘ time_series | comparison | lookup |
│ distribution
▼
┌────────────────┐
│ select_database│ если в системе несколько БД — выбрать целевую
└────────┬───────┘ по интенту + ключевым словам
│
▼
┌────────────────┐
│ retrieve_schema│ Chroma: relevant tables + columns + value samples
└────────┬───────┘
│
▼
┌────────────────┐
│ retrieve_examples│ Chroma: top-k похожих Q→SQL пар (few-shot)
└────────┬───────┘
│
▼
┌────────────────┐
│ generate_sql │ codestral-2501 + structured output (JSON-mode)
└────────┬───────┘ { "sql": "...", "rationale": "..." }
│
▼
┌────────────────┐
│ static_validate│ sqlglot parse → SELECT-only guard → schema check
└────────┬───────┘ (table/column existence vs catalog)
│ FAIL ──────────► retry_loop (max 2)
│ OK
▼
┌────────────────┐
│ explain_plan │ EXPLAIN на целевой БД, отказ если cost > threshold
└────────┬───────┘ (защита от full-scan на больших таблицах)
│
▼
┌────────────────┐
│ execute │ read-only коннект, statement_timeout, LIMIT-guard
└────────┬───────┘
│
▼
┌────────────────┐
│ verify_result │ проверки: непустой? типы соответствуют интенту?
└────────┬───────┘ аномалии? (нулей/null'ов слишком много)
│ FAIL ──────────► retry_loop
│ OK
▼
┌────────────────┐
│ choose_format │ intent + result shape →
└────────┬───────┘ scalar | sentence | table | chart
│
▼
┌────────────────┐
│ render_answer │ mistral-large-2: NL-объяснение + chart-spec (Vega-Lite)
└────────┬───────┘
│
▼
┌────────────────┐
│ persist_trace │ sqlite traces + Langfuse span + Prometheus counter
└────────────────┘
Retry loop: при фейле узлов static_validate, execute, verify_result
граф возвращается к generate_sql с приклеенным error-context'ом
(текст ошибки + предыдущий SQL + разъяснение что не так). Лимит — 2 попытки,
после чего отдаётся диагностический ответ.
Проблема: в BIRD есть БД с 50+ таблицами. Полная схема в промпт не лезет и зашумляет генерацию.
Решение: offline-пайплайн Schema indexer строит несколько коллекций в Chroma:
| Коллекция | Чанк | Эмбеддится |
|---|---|---|
schema_tables |
таблица | имя + описание + список колонок + 3 sample строки |
schema_columns |
колонка | имя + тип + описание + min/max/nunique + 5 sample значений |
fewshot_qsql |
Q→SQL пара | вопрос + аннотация интента (SQL не эмбеддится) |
relations |
FK-связь | from_table.col → to_table.col + семантика |
При вопросе retrieve_schema делает гибрид BM25 + dense на schema_tables,
дотягивает топ-N колонок из schema_columns для отобранных таблиц,
добавляет связи между ними. Получается компактный «срез схемы» под вопрос —
обычно 5-15 таблиц вместо 50+.
retrieve_examples достаёт из fewshot_qsql 3-5 наиболее похожих
вопросов с эталонными SQL — это мощно поднимает качество на сложных диалектах.
Read-only — это не «обещание промптом», а реальные гарды на четырёх уровнях:
- БД-роль: отдельный postgres-пользователь с GRANT SELECT ONLY, без CREATE/INSERT/UPDATE/DELETE/TRUNCATE/ALTER.
- Парсер:
sqlglotAST-валидация — отказ при не-SELECT, при множественных стейтментах, при наличии CTE с DML, приpg_*/information_schemaбез whitelist. - EXPLAIN-gate:
EXPLAIN (FORMAT JSON)передEXECUTE, отказ еслиTotal Cost > X(порог настраивается на БД). - Runtime:
SET statement_timeout = 30s, обязательныйLIMIT 10000если в запросе нет агрегации.
Отдельный модуль eval/, не часть онлайн-пайплайна:
eval/
├── datasets/
│ ├── bird_mini.jsonl # 1500 Q→SQL пар, 11 БД
│ └── stackexchange_gold.jsonl # 20 наших эталонных вопросов
├── runner.py # прогон через граф, сравнение
├── metrics/
│ ├── execution_accuracy.py # сравнение result-set'ов
│ ├── exact_match.py # SQL string match (слабая метрика)
│ └── component_match.py # сравнение по AST-компонентам
└── reports/
└── 2026-05-10-baseline.html # отчёт по прогонам
CI прогоняет smoke-eval на 50 примерах при каждом merge в main. Полный прогон — вручную или nightly.
Целевое число: Execution Accuracy ≥ 50% на BIRD-mini dev. Опубликованные результаты codestral-2501 на BIRD ~57%, так что 50% своими силами на узком сабсете — реалистично.
В config/databases.yml описаны подключения:
databases:
- id: stackexchange
dsn: postgresql://nlsql_ro@localhost/stackexchange
description: "StackOverflow public data — posts, users, votes"
schema_index: chroma://stackexchange
sample_questions: ["топ-10 тегов...", "распределение..."]
- id: bird_california_schools
dsn: sqlite:///data/bird/california_schools.sqlite
description: "California schools — performance, demographics"
schema_index: chroma://bird_california_schools
- id: chinook
dsn: sqlite:///data/chinook.sqlite
description: "Music store — invoices, tracks, customers"
schema_index: chroma://chinookUI даёт переключатель «target DB», граф читает её из state.
Минимально, но без обрезков:
- Chat-style вход с подсветкой SQL в ответе и copy-кнопкой.
- Multi-format ответ — компонент сам решает, что рендерить (scalar / sentence / DataGrid / Vega-Lite chart).
- «Show working»: разворачивающийся блок с retrieved schema, few-shot, rationale, EXPLAIN-планом, временем выполнения.
- History + bookmarks в localStorage + опционально на бэке.
- DB switcher + список sample-вопросов под каждую БД.
Отдельная страница /eval — таблица результатов eval-прогонов,
графики динамики Execution Accuracy по коммитам.
| Слой | Технология | Почему |
|---|---|---|
| LLM | Mistral API: codestral-2501, mistral-large-2, mistral-embed | Жёсткое требование задачи |
| Orchestration | LangGraph | Уже знакома по RAG_SA, retry-loop из коробки |
| API | FastAPI + Pydantic v2 | Стандарт, типобезопасность |
| Vector DB | ChromaDB | Уже знакома, локально без отдельного сервиса |
| SQL parser | sqlglot | Multi-dialect, AST-валидация, dialect translation |
| Target DB | Postgres 16 (StackExchange) + SQLite (BIRD, Chinook) | Реализм + простота |
| Cache | Redis 7 | Кэш результатов SQL, rate-limit |
| Charting | Vega-Lite (через спеку из LLM) + Plotly fallback | LLM хорошо генерит Vega-spec'и |
| Frontend | Next.js 15 + Tailwind + shadcn/ui | Быстрый красивый UI |
| Observability | Prometheus + OpenTelemetry + Langfuse | Стандартный стек, переиспользуется из RAG_SA |
| Tests | pytest + httpx + testcontainers (Postgres) | Реальная БД в CI |
| Lint/Type | ruff + mypy strict (api/, agent/) | Как в DE_project |
| CI | GitHub Actions | smoke-eval + pytest + ruff + mypy |
| Deploy | docker-compose (dev) + Dockerfile multi-stage (prod) | Достаточно для демо |
NL_SQL/
├── api/ # FastAPI app, routers, middleware
├── agent/ # LangGraph nodes, prompts, state
│ ├── graph.py
│ ├── nodes/
│ │ ├── classify.py
│ │ ├── retrieve_schema.py
│ │ ├── retrieve_examples.py
│ │ ├── generate_sql.py
│ │ ├── validate.py
│ │ ├── execute.py
│ │ ├── verify.py
│ │ ├── render.py
│ │ └── retry.py
│ └── prompts/
├── llm/ # Mistral provider, retry, cost guard
├── schema_index/ # offline indexer for Chroma
│ ├── extractor.py # introspect Postgres/SQLite catalog
│ ├── enricher.py # описания, sample values, stats
│ └── builder.py # build Chroma collections
├── execution/ # SQL guards, EXPLAIN gate, runner
├── eval/ # см. раздел 5
├── frontend/ # Next.js UI
├── config/ # databases.yml, prompts.yml
├── data/ # BIRD dump, Chinook, sample dumps (gitignore)
├── tests/
├── docker-compose.yml
├── Dockerfile
└── docs/
├── 00_task.md
├── 01_architecture.md ← вы здесь
├── 02_eval_methodology.md ← TODO
└── 03_demo_questions.md ← TODO
| # | Этап | DoD |
|---|---|---|
| 1 | Bootstrap | poetry/uv проект, FastAPI hello, Mistral provider, тесты на провайдер с моком |
| 2 | Target DBs ready | docker-compose поднимает Postgres со StackExchange dump + SQLite Chinook + BIRD dump в data/ |
| 3 | Schema indexer | offline скрипт строит Chroma-коллекции, smoke-тест на retrieval |
| 4 | Pipeline v1 | LangGraph граф работает на Chinook (простая БД), single-shot без retry |
| 5 | Guards & verify | sqlglot guard, EXPLAIN gate, retry-loop, тесты |
| 6 | Eval harness | runner + execution_accuracy метрика, baseline на BIRD-mini |
| 7 | Multi-format render | scalar/sentence/table/chart с автоопределением + Vega-Lite spec'и |
| 8 | UI v1 | chat + DB switcher + history, end-to-end на 3 БД |
| 9 | Polish & deploy | docker-compose prod-like, README, демо-видео, eval-страница |
Этапы 1-3 — фундамент (~неделя на каждом темпе). Этапы 4-6 — суть проекта (~2 недели). Этапы 7-9 — витрина (~неделя).
Итого: ~5-6 рабочих недель в спокойном темпе или 2-3 в плотном.
| Риск | Вероятность | Митигация |
|---|---|---|
| codestral-2501 даёт <40% на BIRD | средняя | улучшить few-shot retrieval, добавить chain-of-thought, schema-linking шаг |
| StackExchange dump слишком большой для локалки (≥100GB) | высокая | взять mini-dump (gaming.stackexchange.com, ~1GB) — реализм без боли |
| EXPLAIN-gate ломает легитимные тяжёлые запросы | средняя | tune порог на БД, дать override-флаг для админа |
| BIRD dataset лицензия | низкая | CC-BY-SA-4.0, для демо OK |
| Mistral API rate limits на eval-прогоне | средняя | local cache на (prompt → response), батчинг, exponential backoff |
Если сравнить с минимальным NL→SQL (один промпт + один вызов LLM + execute):
- + LangGraph pipeline на 10+ узлов с retry-loop и error-context.
- + Schema-RAG из 4 коллекций вместо «вся схема в промпт».
- + Few-shot retrieval из эталонных Q→SQL пар.
- + Static validate (sqlglot AST) + EXPLAIN-gate + 4-уровневая защита.
- + Multi-DB с переключателем и per-DB индексами.
- + Eval harness на публичном бенчмарке с измеримой метрикой.
- + Multi-format рендер (4 формата + auto-выбор графика).
- + Полноценный observability stack (Prom + OTel + Langfuse).
- + Web-UI с историей, eval-страницей, «show working».
Это потолок того, что осмысленно делать для демо-проекта без скатывания в production-overhead (мульти-тенант, RBAC, OIDC, freshness monitor и т.д. — всё то, что в RAG_SA уместно, а здесь было бы фейк-нагрузкой).