Зачем языковой модели синтаксическое дерево
Как структура SQL помогает ИИ понимать данные — и почему текста недостаточно
Языковые модели умеют читать текст. SQL — это тоже текст. Почему бы просто не дать модели текст запроса и не попросить объяснить, что он делает?
Это работает. Для одного запроса. Для объяснения. Для небольших задач.
Но когда задача — проанализировать десятки тысяч запросов, извлечь из них структуру, построить граф зависимостей и научить другую модель работать с конкретным хранилищем — простой текст оказывается недостаточным.
Что видит модель в тексте запроса
Возьмём запрос:
WITH dept_stats AS (
SELECT d.DEPT_CODE, COUNT(DISTINCT s.STUDENT_ID) as cnt
FROM SIS_DEPARTMENT d
JOIN SIS_ENROLLMENT e ON d.DEPT_CODE = e.DEPT_CODE
JOIN SIS_STUDENT s ON e.STUDENT_ID = s.STUDENT_ID
GROUP BY d.DEPT_CODE
)
SELECT * FROM dept_stats WHERE cnt > 100
Для языковой модели это последовательность токенов: WITH, dept_stats, AS, (, SELECT, d, ., DEPT_CODE, ...
Модель достаточно умна, чтобы понять смысл. Но «понять» здесь — значит каждый раз заново восстанавливать структуру из последовательности символов. Это дорого. И каждая следующая модель, которая работает с этим текстом, делает то же самое заново.
Что такое AST и что он даёт
AST (Abstract Syntax Tree, абстрактное синтаксическое дерево) — это структурированное представление кода, где иерархия элементов явно выражена в виде дерева.
Для того же запроса AST явно говорит:
- Это запрос типа SELECT с CTE
- CTE называется
dept_statsи является подзапросом - Реальные таблицы:
SIS_DEPARTMENT,SIS_ENROLLMENT,SIS_STUDENT - JOIN-условия:
d.DEPT_CODE = e.DEPT_CODE,e.STUDENT_ID = s.STUDENT_ID - Агрегация: COUNT DISTINCT по
STUDENT_ID - Внешний SELECT фильтрует по результату CTE — не по реальной таблице
Эта информация не требует интерпретации — она явна в структуре дерева. Любой алгоритм, который обходит дерево, получает её мгновенно и детерминированно.
Три преимущества структуры над текстом
Первое: нормализация.
Один и тот же запрос можно написать по-разному:
-- Вариант А
SELECT s.STUDENT_ID FROM SIS_STUDENT s WHERE s.DEPT = 'Math'
-- Вариант Б
SELECT STUDENT_ID FROM SIS_STUDENT WHERE DEPT = 'Math'
-- Вариант В
select student_id from sis_student where dept = 'Math'
Текстово — три разных строки. В AST-представлении — одна и та же структура (с поправкой на регистр после нормализации). Алгоритм, работающий с AST, видит их как идентичные. Алгоритм, работающий с текстом, видит три разных запроса.
Это критично при поиске дублирующихся паттернов и при оценке покрытия схемы историческими запросами.
Второе: точное извлечение.
Из AST можно точно извлечь любой элемент: все таблицы (исключая CTE-псевдонимы), все JOIN-условия, все агрегации, все колонки в SELECT. Без риска спутать псевдоним с реальным именем, без неоднозначностей.
Из текста то же самое извлекается с ошибками. Регулярные выражения не справляются с вложенностью. Языковая модель иногда галлюцинирует или упускает детали в сложных запросах.
Третье: сравнение структур.
Два запроса могут быть похожи по смыслу, но различаться в деталях: один использует INNER JOIN, другой — подзапрос в WHERE. Семантически эквивалентно, синтаксически — нет.
С AST можно формально сравнивать структуры: считать структурное расстояние, находить общие поддеревья, группировать запросы по шаблонам. Это невозможно с текстом без предварительного его разбора.
Как AST помогает языковой модели
Исследования показывают: когда языковая модель получает на вход не текст запроса, а его структурированное представление, качество ответов улучшается на задачах, требующих понимания схемы.
Причина интуитивно понятна. Модель не тратит «внимание» на разбор синтаксиса — эта работа уже сделана. Вместо последовательности токенов она получает структуру с явными отношениями между элементами.
Для задачи поиска нужных таблиц это означает: модель видит не «WHERE d.DEPT_CODE = e.DEPT_CODE» как строку, а явное отношение «таблица SIS_DEPARTMENT соединяется с SIS_ENROLLMENT через поле DEPT_CODE». Это утверждение о структуре данных, а не синтаксическая конструкция.
Чанкинг по AST
Отдельная задача — как нарезать длинный SQL-запрос для передачи в языковую модель.
Наивный подход: разбить по числу токенов. 500 токенов на чанк — и передавать последовательно. Проблема: границы чанков режут запрос посередине подзапроса, теряется контекст JOIN, непонятно к какой таблице относится условие.
AST-чанкинг нарезает по структурным границам: каждый CTE — отдельный чанк, каждая ветка UNION — отдельный чанк, каждый подзапрос — отдельный чанк. Каждый фрагмент сохраняет контекст: какие таблицы в нём участвуют, откуда пришли данные, к чему относится условие фильтрации.
Это меняет качество векторного поиска по истории запросов: система ищет не «похожие куски текста», а «похожие структурные паттерны». Два чанка, оба про агрегацию финансовых данных по кварталам — близки в векторном пространстве, даже если написаны совершенно разными аналитиками в разное время.
AST как мост между текстом и графом
Синтаксическое дерево — промежуточный уровень между сырым текстом SQL и графом зависимостей схемы.
Текст → AST: разбор, который делает парсер. Детерминированно, без потери информации.
AST → граф: извлечение рёбер (таблица A соединяется с таблицей B через поле C). Каждый запрос добавляет рёбра в граф зависимостей. Тысячи запросов строят насыщенный граф реальных зависимостей.
Граф → ответ: поиск нужных таблиц, импакт-анализ, рекомендации по JOIN — всё это работает по графу.
Без AST как промежуточного слоя этот конвейер не работает или работает с потерями. AST — это то, что превращает «кучу текстовых запросов» в «структурированное знание о схеме».
Где AST не помогает
Честности ради: AST решает не все проблемы.
Семантика за пределами синтаксиса. AST знает, что поле называется BUDGET_AMOUNT. Он не знает, что в одной таблице это утверждённый бюджет, а в другой — запрошенная сумма. Для этого нужны данные, документация или контекст использования — не структура запроса.
Динамический SQL. Многие системы генерируют запросы на лету: строки конкатенируются в коде, WHERE-условия добавляются по логике приложения. Такой SQL никогда не попадает в историю запросов в полном виде — только фрагменты. AST можно построить только по тому, что есть.
Хранимые процедуры и макросы. Часть логики живёт не в SQL-запросах, а в хранимых процедурах, триггерах, функциях. Их разбор требует дополнительных парсеров и дополнительной работы по извлечению зависимостей.
AST — это не волшебство. Это инструмент, который превращает неструктурированный текст запросов в структурированное знание о том, как устроены данные. Без этого шага системы понимания данных работают вслепую — умно, но вслепую.