- BrainTools - https://www.braintools.ru -
Всем привет, меня зовут Сергей Прощаев, я Tech Lead и руководитель направления Java | Kotlin разработки в FinTech & E‑commerce и преподаю на курсах разработки и архитектуры в ОТУС.
В этой статье расскажу, почему AI‑агент [1], который блестяще отвечает на вопросы по демо‑базе, начинает путаться на настоящем хранилище данных, и что с этим может сделать аналитик ещё до выбора модели.
Знакомая картина.
На демо вендор открывает чат, пишет «покажи выручку за сентябрь по регионам», и через пять секунд на экране таблица и красивый график. Пилот согласован. Через месяц агента подключают к рабочему хранилищу, финансовый директор задаёт тот же вопрос и получает число, которое не совпадает ни с отчётом бухгалтерии, ни с дашбордом продаж. Переформулирует вопрос — получает третье.
Модель здесь обычно не главная проблема. Она хорошо пишет SQL там, где задача уже формализована.
В корпоративном хранилище часть этой формализации живёт вне схемы: в определениях метрик, в кардинальности связей, в терминах компании и в том, по какой дате принято резать период.
Если этот контекст не дан машине явно, модель восстанавливает его наугад.
Задача, о которой пойдёт речь, называется enterprise text‑to‑SQL — генерация SQL по вопросу на естественном языке поверх корпоративного хранилища.
Я посмотрел на неё через три работы разных команд. Сразу оговорюсь: в одну шкалу эти цифры не складываются, у исследований разные данные, модели и протоколы.
Но тенденция одна: переход от открытых учебных данных к закрытым корпоративным резко усложняет задачу.
Первая — бенчмарк Spider 2.0. В версии, опубликованной на ICLR 2025, авторы собрали 632 задачи из реальных корпоративных сценариев: базы на BigQuery и Snowflake, нередко больше тысячи колонок, несколько диалектов SQL. Их агент на модели o1-preview решил 21,3% задач, тогда как на учебном Spider 1.0 — 91,2%, на BIRD — 73,0%. На 69,9 процентного пункта ниже, примерно в 4,3 раза.
Честности ради: исходный вариант бенчмарка с тех пор убрали, а на новом Spider 2.0-Snow (547 задач на Snowflake) лучшие агентные системы уже выше 90%. Так что 21,3% — не потолок, а снимок конца 2024 года.
Вторая — бенчмарк BEAVER. Его авторы взяли запросы не у студентов, а из логов закрытых корпоративных хранилищ: 9 128 пар «вопрос — SQL», 812 таблиц, 19 предметных областей. В среднем запрос затрагивает 4 таблицы и содержит 5,7 соединения, а заодно CTE, вложенные запросы и аналитические функции. Базовый агентный фреймворк ReFoRCE на GPT-5.2 показывает здесь 10,8%, на Claude 4.5 Sonnet — 11,4%.
Самое интересное в BEAVER — опыт [2] с подсказками. Авторы делят задачу на пять подзадач: найти нужные таблицы, определить ключи соединения, сопоставить колонки, извлечь знание предметной области и разложить вопрос на шаги.
В среднем по моделям точность без подсказок — 9,5%. Подсказки по трём подзадачам схемы (таблицы, ключи, колонки) поднимают её до 18,9%, все пять — до 25,9%.
Цифра 30,1% из аннотации авторов получена в другом разрезе, в одну цепочку с этими её ставить не стоит.
И даже с полным набором подсказок ошибки [3] остаются: 46,8% из них структурные (группировки, сортировки, сложные функции), 35,2% — снова выбор элементов схемы, 18,0% — фильтры.
Третья — статья Майкла Стоунбрейкера и Питера Чена в Communications of the ACM от 23 сентября 2026 года. Стоунбрейкер руководил проектом POSTGRES и получил премию Тьюринга, так что в нелюбви к базам данных его не заподозришь.
По их наблюдению, «чистая» LLM на BEAVER набрала ноль, RAG, промпт‑инжиниринг и агенты подняли результат примерно до 10%, а передача модели нужных таблиц и условий соединения — примерно до 30%. По словам авторов, это разница между «у технологии есть потенциал» и «технология не работает».
Меня в этих цифрах зацепила пропорция.
Подсказки о схеме и связях дают заметный прирост, хотя и не закрывают задачу целиком. Значит, один из главных дефицитов здесь — не столько умение писать SQL, сколько умение связать вопрос с конкретными данными, бизнес‑правилами и структурой запроса.
А это и есть работа аналитика.
В той же статье есть история, которую я бы показывал на каждом пилоте AI‑аналитики.
Команда Стоунбрейкера два года пробовала text‑to‑SQL на настоящих хранилищах. Начали с административного хранилища MIT: Oracle, больше 1 400 таблиц, к которому ходят многие подразделения университета.
Исследователи взяли реальные запросы из лога Oracle и вместе с пользователями восстановили, какой вопрос стоял за каждым.
Авторы называют четыре проблемы, которых почти нет в учебных бенчмарках:
Учебные данные лежат в открытом доступе, и модели могли их видеть при обучении [4]. Корпоративные хранилища закрыты.
Схема «гниёт». Бизнес меняется, компания покупает и продаёт подразделения, приходят требования регулятора. Стоунбрейкер приводит пример: в разных таблицах оказывается шесть колонок «salary», и одна означает сумму на руки, а другая — до вычетов.
У каждого хранилища свой словарь. В данных MIT встречается J‑Term — месячный учебный период в январе, а здания там не названы, а пронумерованы. Из схемы этого не вывести.
Реальные запросы сложнее учебных: по наблюдению авторов, им обычно нужны два‑три соединения, а в BEAVER в среднем уже 5,7.
Помню, как на одном из проектов у меня была похожая ситуация, только без всякого AI. Три отчёта о выручке за один месяц расходились, и каждый автор был уверен в своей цифре.
Ушло несколько дней, чтобы выяснить: один считал по дате заказа, второй — по дате оплаты, третий забыл про возвраты.
Ни одна из команд не ошибалась в SQL. Они по‑разному понимали слово «выручка».
Чтобы не рассуждать вокруг темы, я собрал учебную схему интернет‑магазина в SQLite 3 и сгенерировал данные с фиксированным seed: 1 000 заказов с конца августа по конец сентября.
Типы намеренно упрощены: суммы — целые рубли, даты — строки вида ГГГГ‑ММ‑ДД. Часть заказов отменена, часть ждёт оплаты, 165 заказов оплачены двумя платежами, по 42 есть возвраты.
Всё, что ниже, можно повторить у себя: схема, данные, запросы и разбор ошибок лежат в репозитории text‑to‑sql‑dwh‑demo на GitHub, ссылка в конце статьи.
Команда ./run.sh собирает базу с нуля, печатает результаты и сверяет их с эталоном, а CI на каждый push проверяет, что данные воспроизводятся байт в байт. Нужен только sqlite3.
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER,
created_at TEXT, -- дата создания заказа
status TEXT, -- completed / pending / cancelled
amount INTEGER -- сумма заказа, рубли
);
CREATE TABLE payments (
payment_id INTEGER PRIMARY KEY,
order_id INTEGER, -- связь с заказом не объявлена внешним ключом
paid_at TEXT,
amount INTEGER
);
CREATE TABLE refunds (
refund_id INTEGER PRIMARY KEY,
order_id INTEGER,
refunded_at TEXT,
amount INTEGER
);
Вопрос бизнеса: «Какая выручка за сентябрь?». Ниже три запроса. Каждый из них я видел в живых отчётах, и каждый правдоподобно мог бы сгенерировать агент, глядя только на схему.
Запрос A — «самый очевидный»: сумма заказов, созданных в сентябре. Зерно — заказ.
SELECT SUM(amount)
FROM orders
WHERE created_at >= '2026-09-01'
AND created_at < '2026-10-01';
Запрос B — «аккуратный». Агент решает: раз показатель связан с оплатой, нужно присоединить payments, а отменённые заказы отбросить.
SELECT SUM(o.amount)
FROM orders o
JOIN payments p ON p.order_id = o.order_id
WHERE o.status = 'completed'
AND o.created_at >= '2026-09-01'
AND o.created_at < '2026-10-01';
Запрос C — другая бизнес‑договорённость: чистые поступления денег. Деньги, пришедшие в сентябре, минус деньги, возвращённые в сентябре.
Я специально не называю это универсальной «выручкой»: в другой компании под выручкой может пониматься сумма отгрузок без НДС — в зависимости от принятой методологии учёта.
SELECT
COALESCE((SELECT SUM(amount) FROM payments
WHERE paid_at >= '2026-09-01' AND paid_at < '2026-10-01'), 0)
-
COALESCE((SELECT SUM(amount) FROM refunds
WHERE refunded_at >= '2026-09-01' AND refunded_at < '2026-10-01'), 0)
AS net_cash_collected;
Результаты на одних и тех же данных:
|
Запрос |
Что считает |
Результат |
Отклонение от C |
|---|---|---|---|
|
A |
все заказы сентября по дате создания |
4 465 500 |
+23,6% |
|
B |
завершённые заказы, соединённые с платежами |
4 623 500 |
+28,0% |
|
C |
чистые поступления по дате движения денег |
3 613 500 |
— |
Самое показательное — запрос B.
Он выглядит строже A: отменённые заказы отфильтрованы, а результат получился больше. Проблем у него две, и обе независимы.
Первая — соединение. У payments другое зерно: одна строка — один платёж. Само размножение строк ещё не ошибка, ошибка в том, что после него суммируется o.amount — мера уровня заказа. Заказ на 20 000, оплаченный двумя платежами по 10 000, после join становится двумя строками, и SUM(o.amount) даёт 40 000. В моих данных так задвоились 138 сентябрьских заказов.
Вторая — время. Запрос задуман «про оплаты», а фильтр стоит по дате заказа: 44 заказа, созданные в сентябре, оплачены уже в октябре и всё равно попали в сумму.
Оба счётчика считает diagnostics.sql в репозитории.
Все три запроса синтаксически корректны и выполняются без ошибок. Различаются они не SQL, а семантикой: какое событие считается основанием для показателя, какое зерно допустимо и какие операции входят в расчёт. Ничего этого в схеме нет.
Первое: модель промахивается не в синтаксисе, а в смысле. Проверкой «запрос отработал» такую ошибку не поймать, её видно только при сверке с эталоном.
Второе: самые дорогие ошибки сидят в соединениях. Неявная связь один‑ко‑многим тихо размножает строки. Внешних ключей в хранилищах часто нет, и модели приходится угадывать связь по совпадению названий колонок.
Третье: словарь компании не выводится из схемы. «Сентябрь» может быть календарным или фискальным, «Москва» — городом доставки, складом или юрлицом. Модель может узнать это из документации, каталога или логов запросов, если этот источник доступен системе и попадает в её контекст.
Четвёртое: учебные бенчмарки завышают ожидания. Данные из них могли попасть в обучение, и даже современные публичные бенчмарки не воспроизводят целиком сочетание закрытых данных, корпоративного словаря и сложности рабочих запросов. Цифра из презентации вендора ничего не говорит о точности на вашем хранилище.
Пятое: контекст о данных даёт заметный прирост, но не всё. В BEAVER подсказки по схеме почти удваивают точность. Ещё в 2023 году Секеда и коллеги из data.world получили похожую картину: GPT-4 отвечала на вопросы к корпоративной SQL‑базе с точностью 16%, а через граф знаний с онтологией и маппингами — 54%. При этом структурные ошибки остаются и с подсказками.
Из пятого наблюдения следует подход, который сейчас обсуждают почти все, кто строит AI‑аналитику, — семантический слой.
Это описание данных на уровне бизнеса: сущности, связи и их кардинальность, зерно таблиц, определение каждой метрики.
В такой архитектуре агент выбирает из описанных метрик и измерений, а SQL строит движок слоя по записанным правилам.
Документация dbt прямо говорит, что MetricFlow знает типы ключей сущностей и поэтому избегает fan‑out и chasm join — ровно той ошибки, на которой споткнулся запрос B.
Отдельный рыночный сигнал дают опросы.
В исследовании Futurum Research среди более чем 800 руководителей по данным 44,5% планируют увеличить расходы на семантический слой в ближайшие 24 месяца, ещё 14,4% собираются его внедрить впервые.
Вот как выглядит метрика из запроса C в актуальной спецификации dbt Semantic Layer:
models:
- name: fct_payments
description: "Одна строка — один платёж. На один заказ бывает несколько платежей."
semantic_model:
enabled: true
agg_time_dimension: paid_at
columns:
- name: payment_id
entity: {type: primary, name: payment}
- name: order_id
entity: {type: foreign, name: order}
- name: paid_at
granularity: day
dimension: {type: time}
metrics:
- name: paid
label: Поступило денег
type: simple
agg: sum
expr: amount
- name: fct_refunds
description: "Одна строка — один возврат."
semantic_model:
enabled: true
agg_time_dimension: refunded_at
columns:
- name: refund_id
entity: {type: primary, name: refund}
- name: order_id
entity: {type: foreign, name: order}
- name: refunded_at
granularity: day
dimension: {type: time}
metrics:
- name: refunded
label: Возвращено денег
type: simple
agg: sum
expr: amount
metrics:
- name: net_cash_collected
label: Чистые поступления
description: >
Деньги, поступившие за период, минус возвраты за тот же период.
Дата — дата движения денег, а не дата заказа.
type: derived
expr: paid - refunded
input_metrics:
- name: paid
- name: refunded
Обратите внимание [5] на время. У каждой простой метрики своя дата агрегации: paid считается по paid_at, refunded — по refunded_at.
При запросе за сентябрь слой режет каждую по её собственной дате, и именно это решение в запросе B никто не принимал.
В description задокументированы зерно таблицы и определение показателя, для человека и для агента, а машинная часть кардинальности задаётся через entities.
Для простоты показан расчёт общей метрики по времени: чтобы группировать её по клиенту или региону, нужные сущности и пути соединения тоже придётся описать.
Не менее важно, что должен делать агент, если термина в слое нет. Если термин не определён или допускает несколько толкований, правильное поведение [6] агента — не угадывать, а уточнить: «Считать по поступлению денег или по отгрузке?».
Для финансовой аналитики это важнее любой точности.
На рисунке 2 показаны пути вопроса к хранилищу: напрямую через схему и через описанный слой.
Главная мысль схемы: семантический слой не делает модель умнее. Он переносит знание о кардинальности, допустимых соединениях и определениях метрик из догадки модели в описание, которое можно проверить. А там, где описания нет, честнее спросить, чем выдать число.
Семантический слой — не серебряная пуля.
Во‑первых, он не заменяет моделирование данных. dbt строит его поверх подготовленных моделей: если исходный слой запутан, сначала придётся собрать аналитические витрины, а уже на них фиксировать смысл. И кто‑то должен поддерживать описания: без этого слой гниёт так же, как хранилище, только незаметнее.
Во‑вторых, слой закрывает повторяющиеся вопросы про описанные метрики. Если нужной метрики в слое нет, системе нужен другой источник контекста: каталог, документация, примеры запросов. Без него агент снова восстанавливает смысл наугад.
И наконец, мой эксперимент демонстрирует механику ошибки, а не оценивает её вероятность в продакшене.
Плюс 23,6% и 28,0% — свойство моих синтетических данных, а не типичная погрешность. YAML выше — иллюстрация подхода: он лежит в репозитории рядом с запросами, но компиляция через dbt там не проверяется.
Если вы планируете пилот AI‑аналитики или уже его ведёте, я бы начал не с выбора модели, а с такой проверки:
Выпишите 10–15 вопросов, которые бизнес задаёт чаще всего, и для каждого — эталонный SQL, согласованный с владельцем метрики.
Прогоните вопросы через агента и сравните результат, затем SQL и объяснение: какие метрики, таблицы, фильтры и даты он взял. Совпадение числа — необходимый сигнал, но не доказательство: две разные ошибки могут случайно дать одно число.
Для каждой таблицы, которая участвует в ответах, запишите зерно: одна строка — это заказ, платёж или позиция заказа.
Составьте словарь терминов компании: что такое выручка, активный клиент, регион, месяц.
Опишите пять самых спрашиваемых метрик в семантическом слое и повторите шаг 2.
Задайте агенту вопрос с термином, которого нет в словаре, и посмотрите: он переспросит или уверенно ответит.
Для разминки подойдёт и мой репозиторий: три таблицы и три вопроса, на которых видно, ошибётся ли ваш агент на соединении и на дате.
Мой вариант, который я обычно советую: шаги 1 и 2 сделать до разговора с вендором. Тогда на демо вы проверяете не красивый график, а свои пятнадцать вопросов.
AI‑агенты сделали SQL дешёвым. Дорогим осталось другое — договориться о том, что значат данные, и записать это так, чтобы прочитала машина. Enterprise text‑to‑SQL — не один шаг генерации SQL, а цепочка разрешения контекста: какие данные нужны, как они связаны, что значат термины, по какой дате считать и какую структуру запроса построить. Часть этого контекста традиционно живёт в голове аналитика.
Поэтому, как мне кажется, роль аналитика с приходом агентов не уменьшается, а смещается: от написания каждого запроса к формализации смысла, на котором эти запросы строятся.
А как у вас: пробовали подключать AI‑агента к рабочему хранилищу? На чём он ошибался чаще всего — на соединениях, на терминах или на датах? Буду рад обсудить в комментариях.
Ссылка на мой репозиторий с экспериментом [7].

Как интегрировать ИИ‑агентов с корпоративными системами и оценивать качество их работы?
Эти вопросы разберём на бесплатных демо-уроках OTUS:
20 октября, 20:00. «Tool Calling и MCP: интеграция ИИ‑агентов с корпоративными системами» [16]. Записаться.
27 октября, 18:00. «Langfuse в AgentOps: наблюдаемость и оценка LLM‑агентов» [17]. Записаться.
Больше тем об искусственном интеллекте [18], разработке и работе с данными — в октябьском дайджесте. [19]
Автор: sproshchaev
Источник [20]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/37048
URLs in this post:
[1] AI‑агент: https://otus.pw/GcLJ/
[2] опыт: http://www.braintools.ru/article/6952
[3] ошибки: http://www.braintools.ru/article/4192
[4] обучении: http://www.braintools.ru/article/5125
[5] внимание: http://www.braintools.ru/article/7595
[6] поведение: http://www.braintools.ru/article/9372
[7] Ссылка на мой репозиторий с экспериментом: https://github.com/sproshchaev/text-to-sql-dwh-demo
[8] Lei et al., Spider 2.0: Evaluating Language Models on Real‑World Enterprise Text‑to‑SQL Workflows (ICLR 2025): https://arxiv.org/abs/2411.07763
[9] BEAVER: An Enterprise Benchmark for Text‑to‑SQL: https://arxiv.org/abs/2409.02038
[10] Michael Stonebraker, Peter Baile Chen, If You Think You Can Do Real‑World Text‑to‑SQL, Communications of the ACM, 23.09.2026: https://cacm.acm.org/research/if%E2%80%91you%E2%80%91think%E2%80%91you%E2%80%91can%E2%80%91do%E2%80%91real%E2%80%91world%E2%80%91text%E2%80%91to%E2%80%91sql/
[11] Sequeda et al., A Benchmark to Understand the Role of Knowledge Graphs on Large Language Model’s Accuracy for Question Answering on Enterprise SQL Databases: https://arxiv.org/abs/2311.07509
[12] DBTA, Semantic Layers Are Rising to the Top of the Data Agenda, Survey Shows (Futurum Research): https://www.dbta.com/Editorial/Trends%E2%80%91and%E2%80%91Applications/RESEARCH%E2%80%91at%E2%80%91DBTA%E2%80%91Semantic%E2%80%91Layers%E2%80%91Are%E2%80%91Rising%E2%80%91to%E2%80%91the%E2%80%91Top%E2%80%91of%E2%80%91the%E2%80%91Data%E2%80%91Agenda%E2%80%91Survey%E2%80%91Shows-175441.aspx
[13] dbt Docs, About MetricFlow: https://docs.getdbt.com/docs/build/about-metricflow
[14] dbt Docs, Semantic models: https://docs.getdbt.com/docs/build/semantic-models
[15] dbt Docs, Derived metrics: https://docs.getdbt.com/docs/build/derived
[16] «Tool Calling и MCP: интеграция ИИ‑агентов с корпоративными системами»: https://otus.pw/Ragz/
[17] «Langfuse в AgentOps: наблюдаемость и оценка LLM‑агентов»: https://otus.pw/a1XK/
[18] интеллекте: http://www.braintools.ru/article/7605
[19] октябьском дайджесте.: https://otus.pw/xFNM/
[20] Источник: https://habr.com/ru/companies/otus/articles/1088874/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1088874
Нажмите здесь для печати.