
Giga4DQM — открытый проект, реализующий концепцию ИИ-агентов для автоматизированного расследования инцидентов с данными и построения целостной картины зависимостей в существующей БД. Система понимает вопросы на естественном языке, самостоятельно анализирует структуру базы, строит граф зависимостей и формирует диагностические запросы. Архитектура не привязана к одной СУБД: в качестве примера взята PostgreSQL, но подход может быть адаптирован к любой системе с развитым каталогом метаданных. В основе — мультиагентная архитектура на основе GigaChat и LangGraph. Код открыт, доступен для тестирования и внедрения.
Введение
В современных компаниях корпоративные хранилища данных играют критически важную роль, обеспечивая централизованное хранение и обработку больших объёмов информации. Данные поступают из разнообразных источников: операционных систем, CRM, ERP, IoT-устройств, отражая все аспекты деятельности организации. На их основе формируется отчётность, отслеживаются KPI, оптимизируются бизнес-процессы и принимаются стратегические решения.
Ценность данных напрямую зависит от их качества. Некорректные, неполные или несвоевременные данные ведут к ошибочным выводам, финансовым потерям и репутационным рискам. Анализ и разбор инцидентов качества данных — будь то пропажа записей, аномальные значения или нарушения целостности — становятся неотъемлемой частью работы дата-команд. Скорость обнаружения и диагностики таких инцидентов напрямую влияет на операционную устойчивость бизнеса.
Инженеры и аналитики данных проектируют структуры, очищают и объединяют информацию. Однако с ростом объёмов данных и требований к скорости их обработки даже опытные команды сталкиваются с трудностями.
Рутинные операции — поиск таблиц, проверка качества, выяснение взаимосвязей — требуют не только технических навыков, но и глубокого понимания архитектуры хранилища. Значительное время тратится на навигацию по каталогу, выяснение происхождения данных (data lineage) и однотипные диагностические запросы.
В крупных организациях с большим количеством взаимосвязанных объектов и распределёнными командами эта проблема усиливается. Традиционные подходы, документация в Confluence, ручные runbook’и плохо масштабируются и быстро устаревают.
Поэтому для решения подобных проблем применяются большие языковые модели (LLM) — GigaChat, GPT, BERT, DeepSeek. Обученные на текстах и журналах запросов, они способны автоматизировать подбор таблиц, JOIN-условий и шаблонов SQL.
Мы покажем на примере PostgreSQL, как мультиагентная система на базе LLM ускоряет расследование инцидентов. Архитектура не привязана к конкретной СУБД: она использует абстрактный адаптер метаданных, который в данной статье реализован для pg_catalog PostgreSQL, но может быть заменён на аналогичный слой для ClickHouse, Greenplum, Vertica и других.
Основная гипотеза заключается в следующем: система специализированных агентов, получающих актуальный контекст схемы данных и координируемых оркестратором, способна автоматизировать не только генерацию запросов, но и построение графа зависимостей, проверку гипотез и формирование диагностического отчёта.
Модель данных для тестирования
Для проверки гипотезы спроектирована синтетическая схема loans кредитного домена, не содержащая реальной персональной информации. Схема включает пять взаимосвязанных таблиц: клиенты, счета, кредитные договоры, платежи и факты просрочек. Все таблицы снабжены COMMENT’ами на русском и английском языках, чтобы агенты могли интерпретировать назначение объектов.
Основные сущности:
-
customers— мастер-данные клиентов (ФИО, дата рождения, страна, доход, кредитный рейтинг 300–850); -
accounts— банковские счета (тип, баланс, статус); -
loans— кредитные договоры (сумма, ставка, срок, статус); -
payments— платежи (основной долг, проценты); -
delinquencies— события просрочки (дни задержки).
Внешние ключи: customers → accounts, customers → loans, loans → payments, loans → delinquencies. Такая структура порождает цепочки зависимостей, характерные для реальных хранилищ. Например, представление customer_credit_risk агрегирует данные из всех пяти таблиц. Именно на этой схеме проводились эксперименты.
Подход к решению
LLM предварительно обучены на текстовых данных и генерируют связные последовательности, но не имеют доступа к актуальной структуре конкретной базы данных. Для решения этой проблемы создана мультиагентная архитектура, в которой каждый агент получает целевой контекст через адаптер метаданных и решает ограниченный класс задач.
Ансамбль специализированных агентов разделяет ответственность. Это даёт контролируемость (узкая зона ответственности снижает риск галлюцинаций), расширяемость (можно добавлять новых агентов) и прозрачность (видно, какой агент задействован).
|
Агент |
Роль |
Пример задачи |
|---|---|---|
|
Catalog Agent |
Инвентаризация схемы: таблицы, колонки, типы, комментарии |
«Какие объекты в схеме |
|
Data Agent |
Выполнение безопасных read-only запросов, интерпретация результатов |
«Сколько заявок со статусом “просрочка” появилось за последний час?» |
|
Lineage Agent |
Восстановление происхождения данных, построение графа зависимостей |
«От каких исходных таблиц зависит колонка |
|
Audit Agent |
Lineage + проверки качества (NULL, дубликаты, ограничения) |
«Проверь, нет ли в источнике клиентов с пустым scoring.» |
|
Investigation Agent |
Управление расследованием: гипотезы, координация агентов, отчёт |
«Почему показатель одобрения кредитов упал на 15% за вчера?» |
Чтобы пользователь мог задавать вопросы на естественном языке, не задумываясь о выборе агента, реализован модуль intent_route.py — «диспетчер» системы. Он определяет, какому агенту передать вопрос, и делает это быстро, устойчиво и прозрачно. Принятие решения производится в два этапа:
-
Быстрые эвристики (без вызова модели).
Сначала вопрос проверяется набором правил, анализирующих ключевые слова и паттерны.-
Если в тексте присутствует SQL (
SELECT ... FROM) и слова-маркеры подозрения на ошибку (возможная ошибка, проверь и т.п.) запрос классифицируется какinvestigateи направляется в Investigation Agent. -
При явных терминах lineage (
upstream, «откуда берётся») и квалифицированном идентификаторе таблицы или колонки (например,loans.customer_id) назначаетсяlineage(Lineage Agent). -
Когда вопрос содержит слова «проверь», «NULL», «нет ли ошибок» без явного SQL, выбирается комбинированный режим both (Catalog + Data).
Если эвристики дали однозначный ответ, маршрутизация завершается мгновенно, экономя токены и время.
-
-
Вызов LLM с JSON-схемой (когда эвристик недостаточно).
В неоднозначных случаях отправляется короткий промпт в GigaChat. Модель получает системную инструкцию с чёткими определениями каждого режима и Pydantic-схемой ожидаемого ответа:
class RouterAnswer(BaseModel):
route: str # catalog | data | lineage | audit | both | investigate
Ответ парсится с трёхуровневой защитой: сначала Pydantic, затем обычный json.loads, и, наконец, fallback на безопасный режим catalog. Это гарантирует, что даже при неидеальном ответе модели система не «упадёт», а просто покажет метаданные.
Все решения маршрутизатора логируются через Langfuse после его настройки. В трассу попадают исходный вопрос, промпт, ответ модели и итоговый маршрут. Это позволяет анализировать качество классификации, отлаживать «странные» маршрутизации и при необходимости дорабатывать эвристики или промпт.
Такой гибридный подход обеспечивает быстроту и предсказуемость для типовых запросов, а LLM подстраховывает в сложных случаях, делая интерфейс вопросов на естественном языке действительно удобным.
Для наглядного представления архитектуры приведены три диаграммы, отражающие ключевые аспекты работы системы. Все они относятся к реализации на примере PostgreSQL.
На рисунке 1 показано, как пользователь взаимодействует с веб-интерфейсом на базе Streamlit, который передаёт запрос в модуль маршрутизации intent_route.py.
Через интерфейс активируются один или несколько агентов. Агенты Catalog и Lineage не обращаются напрямую к данным — они получают информацию только из адаптера метаданных (postgres_metadata.py), который, в свою очередь, выполняет запросы к системным таблицам PostgreSQL (pg_catalog, information_schema). Агенты Data и Audit при необходимости работают напрямую с базой данных, но только через read-only подключение.
На рисунке 2 показана реализация маршрутизации запросов intent_route.py. Вопросы о структуре схемы передаются Catalog Agent, вопросы с агрегациями и выборками — Data Agent, запросы о происхождении полей — Lineage Agent, проверки качества — Audit Agent (при этом иногда запускается комбинированный режим, координирующий Audit и Lineage), а сообщения о подозрительных значениях или явные ошибки активируют полноценное расследование с участием Investigation Agent.
Такой подход позволяет избежать запуска ресурсоёмкого расследования для простых вопросов и, напротив, не отвечать поверхностно на сложные проблемы.
На рисунке 3 показана обработка запроса. Пользователь в Streamlit выбирает рабочую схему, режим работы (Auto, Catalog, Data и пр.) и лимиты (бюджеты токенов). При вводе вопроса в автоматическом режиме Streamlit вызывает Intent Router, который анализирует текст и сообщает, какой агент должен быть запущен. Далее Streamlit запускает соответствующий агент как отдельный процесс, передавая ему все необходимые параметры (контекст схемы, лимиты, текст вопроса). Агент выполняет свою работу (возможно, обращаясь к другим агентам или к метаданным) и возвращает структурированный JSON-ответ на стандартный вывод. Streamlit обрабатывает этот JSON и отображает пользователю форматированный результат вместе с возможностью просмотреть «сырой» ответ.
Такой подход обеспечивает прозрачность и упрощает отладку.
Уточним:
-
Разрешены только
SELECTиWITH ... SELECT; любые DML/DCL блокируются валидатором. -
Режим Investigate не выполняет запросы автоматически — аналитик сам решает, запускать ли предложенный SQL.
-
Подключение к PostgreSQL выполняется под отдельной учётной записью с минимальными привилегиями.
-
Сгенерированный SQL проходит
EXPLAIN(без исполнения) перед показом пользователю.
Практические сценарии применения: детальный разбор
Ниже по шагам описана внутренняя работа системы для каждого из четырёх сценариев. Во всех случаях используется одна и та же схема loans и синтетические данные.
Сценарий 1: Исследование схемы (Catalog Agent)
Вопрос пользователя:
«Какие таблицы и представления есть в схеме loans и какие колонки у таблицы customers?»
Шаг 1. Классификация запроса.
Intent Router анализирует текст вопроса. Присутствуют ключевые слова «таблицы», «представления», «колонки», «схема», нет указаний на агрегации, ошибки или происхождение данных. Запрос уверенно классифицируется как catalog.
Шаг 2. Инициализация Catalog Agent.
Оркестратор (Streamlit) запускает процесс Catalog Agent с параметрами: целевая схема loans, режим catalog, оригинальный вопрос. Агенту также передаются лимиты контекста, заданные пользователем (например, максимальная длина DDL-описания).
Шаг 3. Сбор метаданных.
Catalog Agent через адаптер postgres_metadata.py выполняет несколько запросов к системным таблицам PostgreSQL:
-- Получить список таблиц и представлений в схеме loans
SELECT table_name, table_type
FROM information_schema.tables
WHERE table_schema = 'loans';
-- Получить подробную информацию о колонках таблицы customers
SELECT column_name, data_type, is_nullable,
pg_catalog.col_description('loans.customers'::regclass, ordinal_position) AS comment
FROM information_schema.columns
WHERE table_schema = 'loans' AND table_name = 'customers'
ORDER BY ordinal_position;
Адаптер агрегирует результаты в структурированный объект, содержащий имена таблиц/представлений и детали колонок customers с комментариями из COMMENT ON.
Шаг 4. Формирование промпта для GigaChat.
Агент составляет промпт, включающий:
-
Системную инструкцию: «Ты агент каталога данных. Отвечай на вопрос, используя только предоставленные метаданные. Обязательно цитируй имена таблиц и представлений».
-
Контекст: загруженный список объектов схемы и описание колонок
customers. -
Вопрос пользователя.
Промпт помещается в шаблон, ограничивающий ответ форматом JSON с полями answer (текст на русском) и structured (список цитируемых объектов).
Шаг 5. Генерация ответа моделью.
GigaChat получает промпт и генерирует ответ, опираясь строго на предоставленные данные. Модель не выдумывает несуществующие таблицы, поскольку видит только реальный список.
Шаг 6. Валидация и возврат.
Ответ парсится на наличие обязательных полей. Из answer извлекаются цитируемые названия (перекрёстная проверка с исходными метаданными). Итоговый JSON-ответ возвращается в Streamlit, где рендерится в читаемом виде.
Пример результирующего JSON:
{
"schema": "loans",
"summary": { "tables_count": 5, "views_count": 1 },
"answer": "В схеме loans обнаружено 5 базовых таблиц и 1 представление. Таблица customers содержит следующие колонки:
- customer_id (integer, NOT NULL) — суррогатный первичный ключ
- full_name (text, NOT NULL) — полное юридическое имя
- birth_date (date, NOT NULL) — дата рождения
- country (text, NOT NULL) — страна проживания
- income (numeric(12,2), NOT NULL) — годовой доход
- credit_score (smallint, NOT NULL) — кредитный рейтинг (300–850)
- created_at (timestamptz, NOT NULL, DEFAULT NOW()) — дата регистрации клиента",
"structured": {
"cited_table_names": ["customers"],
"cited_routine_names": []
}
}
Благодаря использованию метаданных и шаблонизации, ответ точен и готов к немедленному использованию аналитиком.
Сценарий 2: Аналитический запрос (Data Agent)
Вопрос:
«Покажи топ-5 клиентов по сумме выданных кредитов»
Шаг 1. Классификация.
Вопрос содержит запрос на агрегацию и сортировку («сумма кредитов», «топ-5»), нет слов «ошибка» или «происхождение». Intent Router распознаёт намерение data.
Шаг 2. Инициализация Data Agent.
Запускается процесс Data Agent с параметрами: схема loans, режим data, вопрос. Агенту разрешено выполнять read-only запросы к базе.
Шаг 3. Получение контекста таблиц.
Data Agent обращается к тому же адаптеру метаданных и запрашивает контекст, необходимый для генерации SQL. В частности, он вызывает SQLDatabase.get_context(), который возвращает:
-
Список таблиц схемы с именами колонок, типами и референсными ключами.
-
Примеры нескольких строк (опционально, для понимания данных).
Для вопроса о кредитах и клиентах агент фокусируется на таблицах customers и loans, извлекая информацию о колонках customer_id, full_name, loan_amount.
Шаг 4. Генерация SQL моделью GigaChat.
Агент формирует промпт, содержащий:
-
Системную инструкцию: «Ты — Data Analyst. Напиши SQL-запрос ТОЛЬКО
SELECT, используя предоставленные таблицы и колонки». -
Контекст таблиц (сокращённый до релевантных).
-
Вопрос пользователя.
GigaChat генерирует SQL:
SELECT c.full_name, SUM(l.loan_amount) AS total_loan
FROM loans.loans l
JOIN loans.customers c ON l.customer_id = c.customer_id
GROUP BY c.customer_id, c.full_name
ORDER BY total_loan DESC
LIMIT 5;
Шаг 5. Валидация SQL.
Сгенерированный запрос проходит парсер: проверяется, что он начинается с SELECT или WITH … SELECT и не содержит INSERT, UPDATE, DELETE, DROP. Затем выполняется EXPLAIN (без реального исполнения), чтобы убедиться в синтаксической корректности. Если валидация не пройдена, агент возвращает ошибку с предложением переформулировать вопрос.
Шаг 6. Выполнение и интерпретация.
Запрос выполняется под ограниченной учётной записью с правами только на чтение. Результат выборки возвращается агенту. Data Agent отправляет новый промпт модели: «Вот результат запроса: <таблица>. Переведи его в понятный ответ на вопрос пользователя». Модель генерирует: *«Топ-5 клиентов по сумме выданных кредитов:
-
Иван Петров — 2 450 000 ₽
-
Ольга Смирнова — 1 980 000 ₽
-
Алексей Иванов — 1 750 000 ₽ …»*
Шаг 7. Финальный JSON.
Агент упаковывает ответ, использованный SQL и цитируемые таблицы в стандартную JSON-структуру.
Аналитик получает готовый ответ без ручного написания JOIN и агрегации, а также видит сгенерированный SQL для аудита.
Сценарий 3: Lineage на основе DDL (Lineage Agent)
Вопрос:
«Откуда берётся поле risk_category в представлении customer_credit_risk?»
Шаг 1. Классификация.
Ключевые слова «откуда берётся поле», «представление» явно указывают на запрос происхождения данных. Intent Router назначает lineage.
Шаг 2. Инициализация Lineage Agent.
Агент запускается с режимом lineage. Его задача — восстановить цепочку зависимостей колонки, не выполняя выборку данных.
Шаг 3. Извлечение DDL представления.
Lineage Agent через адаптер postgres_metadata.py выполняет:
SELECT pg_get_viewdef('loans.customer_credit_risk', true);
Возвращается полный текст определения представления. Дополнительно агент может запросить имена исходных таблиц, фигурирующих в запросе, из information_schema.tables.
Шаг 4. Анализ DDL моделью.
Агент формирует промпт, содержащий:
-
Системную инструкцию: «Ты — эксперт по происхождению данных. Проанализируй определение представления и определи, от каких таблиц и колонок зависит указанная колонка. Укажи трансформации (CASE, функции, JOIN-условия)».
-
Определение представления.
-
Целевая колонка
risk_category.
GigaChat, изучив определение, находит, что risk_category вычисляется как:
CASE
WHEN c.credit_score < 580 THEN 'HIGH'
WHEN c.credit_score < 670 THEN 'MEDIUM'
ELSE 'LOW'
END
и что оно ссылается на customers.credit_score. Также модель определяет, что представление содержит JOIN с loans и фильтрацию по loan_status, что может влиять на контекст использования, но не на само значение risk_category. Дополнительно выявляется зависимость от payments.payment_date для расчёта просрочек, хотя это не прямое влияние.
Шаг 5. Формирование ответа.
Агент структурирует ответ:
-
Источник:
customers.credit_score. -
Логика преобразования: CASE с порогами.
-
Дополнительные зависимости:
loans.loan_status,payments.payment_date(косвенные).
Никакие запросы к пользовательским данным не выполняются — только анализ DDL.
Пример вывода:
Поле risk_category в представлении customer_credit_risk формируется так:
-
Прямой источник:
customers.credit_score(smallint,NOT NULL). -
Логика:
CASE WHEN credit_score < 580 THEN 'HIGH' WHEN credit_score < 670 THEN 'MEDIUM' ELSE 'LOW'
-
Косвенные зависимости:
loans.loan_status(фильтр активных кредитов) иpayments.payment_date(расчёт просрочки) — не влияют на значение.
Инженер получает мгновенное объяснение происхождения поля без ручного разбора многострочного представления.
Сценарий 4: Расследование аномалии (Investigation Agent)
Вопрос:
«Возможная ошибка в значении risk_category. Запрос: SELECT risk_category FROM customer_credit_risk WHERE customer_id = 1; Помоги проверить.»
Шаг 1. Классификация.
Наличие конкретного SQL и слов «ошибка», «проверить» активирует эвристику investigate. Intent Router направляет запрос в Investigation Agent.
Шаг 2. Инициализация Investigation Agent.
В отличие от остальных, Investigation Agent координирует работу подчинённых агентов (Lineage, Audit) и формирует сводный отчёт.
Шаг 3. Параллельный сбор информации.
Investigation Agent запускает два параллельных процесса:
-
Lineage Agent (как в сценарии 3) для выяснения происхождения
risk_category. Получает информацию, что поле строится изcustomers.credit_scoreчерезCASEбез обработкиNULL. -
Audit Agent с заданием: «Проверь таблицу
customersи представлениеcustomer_credit_riskна наличиеNULLвcredit_score, дубликатов и иных аномалий, связанных сrisk_category».
Audit Agent, в свою очередь:
-
Через адаптер метаданных получает список колонок и ограничений.
-
Генерирует и выполняет (с валидацией) несколько проверочных запросов:
SELECT COUNT(*) FROM customers WHERE credit_score IS NULL; SELECT customer_id, credit_score FROM customers WHERE credit_score IS NULL LIMIT 5; SELECT risk_category, COUNT(*) FROM customer_credit_risk GROUP BY risk_category;
-
Выясняет, что в таблице customers есть записи с
credit_score IS NULL(например, 23 клиента), и в представлении появляются записи сrisk_categoryравнымNULLили строке'UNKNOWN'(если позднее приводит тип).
Шаг 4. Синтез отчёта Investigation Agent.
Агент получает результаты от Lineage и Audit, объединяет их и формирует промпт для финального ответа:
«На основе полученных данных объясни причину аномалии, предложи гипотезы и набор проверочных запросов, которые НЕ должны выполняться автоматически.»
GigaChat генерирует связный отчёт, включающий:
-
Резюме: «Пропуск обработки
NULLвCASEприводит к появлениюUNKNOWNилиNULLвrisk_category». -
Гипотезы: (1) недостаток исходных данных — клиенты без кредитного рейтинга; (2) ошибка ETL, допускающая NULL; (3) изменение логики без поддержки NULL.
-
Диагностический пакет (SQL, который пользователь может скопировать и выполнить вручную):
-- 1. Проверить исходный credit_score для подозрительного клиента
SELECT credit_score FROM customers WHERE customer_id = 1;
-- 2. Количество клиентов с NULL credit_score
SELECT COUNT(*) FROM customers WHERE credit_score IS NULL;
-- 3. Все уникальные значения risk_category в представлении
SELECT risk_category, COUNT(*) FROM customer_credit_risk GROUP BY risk_category;
-- 4. Полное определение представления для аудита
SELECT pg_get_viewdef('customer_credit_risk', true);
Шаг 5. Возврат ответа.
Важно: ни один из сгенерированных в шаге 4 запросов не выполняется автоматически. В режиме Investigate все диагностические SQL только предлагаются. Пользователь получает отчёт, может скопировать запросы и выполнить их в безопасной среде.
Инженер получает не общие рекомендации, а структурированный план действий с конкретными проверками, сэкономив часы ручного анализа.
Ограничения, рекомендации, развитие
Что система не обеспечивает:
-
Не гарантирует семантическую корректность результатов (зависит от DDL, формулировки, модели).
-
Не синхронизирует документацию с БД — все миграции должны быть применены до запросов.
-
Не выполняет запросы автоматически в режиме Investigate.
Рекомендации:
-
Формулируйте вопросы максимально чётко, указывая нужные таблицы и колонки.
-
Используйте очистку диалога Clear conversation при смене контекста.
-
Начинайте с Catalog или Lineage, если структура данных незнакома.
-
Проверяйте сгенерированный SQL через
EXPLAINперед запуском в эксплуатации. -
Настраивайте лимиты контекста в соответствии с размером схемы.
Направления развития:
-
Кеширование метаданных и визуализация lineage с использованием графовых баз, например, Neo4j.
-
Включение в процесс обучения с подкреплением от человеческой обратной связи RLHF для повышения качества ответов модели.
-
Расширение возможностей сервиса для автоматической валидации качества данных на основе «истории разбора инцидента».
-
Снижение стоимости сервиса за счет использования fine-tuned SLM (Small language models).
Заключение
Мультиагентная архитектура на базе LLM и LangGraph демонстрирует значительный потенциал для автоматизации расследования инцидентов качества данных, а также обеспечения глубокого понимания зависимостей внутри БД. Детально проработанный подход с разделением ролей, структурированными промптами и адаптером метаданных позволяет ускорить диагностику и снизить нагрузку на аналитиков и инженеров. Решение адаптируется на любую реляционную СУБД.
Исследование ограничено синтетическими данными; для промышленного внедрения необходимы эксперименты на реальных инцидентах и разработка метрик семантической точности.
Как попробовать
git clone https://github.com/Xpehutta/giga4dqm.git
cd giga4dqm
cp .env.example .env
# заполните .env (PGHOST, PGDATABASE, PGUSER, PGPASSWORD, GIGACHAT_API_KEY)
uv sync
uv run streamlit run streamlit_app.py
Откройте http://localhost:8501, выберите схему loans после развёртывания демо-схемы согласно setup_loan_db.md.
Литература
-
Auffarth, B. Generative AI with LangChain. Packt, 2023.
-
Raieli S., Luculano G., Building AI Agents with LLMs, RAG, and Knowledge Graph. Packt, 2025.
-
Lanham M., AI Agents in action. Manning Publications. 2024.
-
ResearchGate. The Role of AI Agents in Data Quality Assurance. 2025.
-
arXiv. Automated Database Exploration and Instruction Synthesis. 2025.
-
Dr. Ali Arsanjani, Juan Pablo Bustos, Agentic Architectural Patterns for Building Multi-Agent Systems: Proven design patterns and practices for GenAI, agents, RAG, LLMOps, and enterprise-scale AI systems. Packt, 2026.
Автор: Sber


