На работе в моём ведении оказались сразу две связанные области: дата-инженерия и отчётность. Я отвечаю и за то, чтобы данные доехали до витрин, и за то, чтобы поверх них появились понятные дашборды. Для визуализации у нас два инструмента — Power BI и Superset. И если Superset живёт в мире кода и конфигов, то Power BI — это .pbix, бинарный файл, который исторически делается руками в Desktop.
Чем больше отчётов, тем больнее ручной процесс. Новый дашборд под запрос бизнеса, правка проверки перед публикацией, обновление схемы lineage на Confluence, аудит соответствия брендбуку перед показом руководству — всё это либо делалось вручную, либо висело на одном человеке. В рамках общей линии на автоматизацию и агентизацию я собрал для Power BI отдельный фреймворк.
Почему с Power BI всё сложнее, чем с Superset
.pbix — это обычный ZIP-контейнер, но внутри два принципиально разных слоя:
DataModel— бинарная VertiPaq-модель. Её нельзя корректно написать
байт за байтом на Python: формат закрыт, внутри XPress9-компрессия.
Report/Layout— текстовый JSON с описанием страниц и визуалов. Вот
его генерировать можно — при условии, что кодировка UTF-16LE без BOM, иначе Desktop просто не распарсит файл.
Отсюда главный приём: модель берётся от рабочего донора, а собранный нами layout вкладывается поверх неё. Визуалы ссылаются на объекты модели по имени, поэтому пока имена совпадают — отчёт открывается и показывает данные. Второй, канонический путь — дать Desktop RS-движку (msmdsrv.exe) самому сериализовать модель, но это требует Windows и установленного Desktop RS. Фреймворк прячет оба пути за один API.
Что умеет фреймворк
Всё построено вокруг пяти стадий жизненного цикла: develop → test → deploy → control → support.
- develop — из декларативного spec (YAML/JSON) или программного
Board собирается layout: KPI-карточки, графики, таблицы, фильтры, многостраничные борды с авторазметкой. Дальше layout свёртывается в бинарный .pbix через донора или собирается движком прямо из данных.
- test —
validate_pbixсверяет layout с моделью донора и падает, если
визуал ссылается на несуществующую таблицу, колонку или меру. Отдельно engine_verify делает обратный самотест: читает собранный .pbix обратно и подтверждает, что страницы, привязки и данные на месте. Ещё один слой — antipatterns: сканирование M-кода и DAX на хардкод путей, фикс-даты, SUMX/EARLIER, бизнес-логику в вычисляемых колонках и прочие грабли.
- deploy — публикация и обновление отчёта на Power BI Report Server
через REST /api/v2.0/CatalogItems с Windows SSO. Повторная публикация (409 Conflict) автоматически превращается в PUT.
- control — проверка, что отчёт действительно долетел: GET по пути и
сверка Id/Size/ModifiedDate, плюс диагностика каталога Report Server.
- support — единый каталог порогов, объяснение правил и triage.
Быстрый каркас, в котором остаётся только дизайн
Отдельная ценность — генератор скелета отчёта. По описанию таблицы, колонок и мер фреймворк собирает готовый PBIP-проект: KPI-карточка, график, таблица и фильтры на странице. Это не пустой шаблон, а отчёт, который уже открывается в Desktop и показывает данные по контракту колонок — с корректными привязками, layout в UTF-16LE без BOM и фильтрами через slicer, а не через ломающий drill IN.
То есть по правилам собирается рабочий каркас, и от него остаётся только реализация дизайна: цвета, шрифты, композиция, акценты. Аналитику больше не надо каждый раз вручную воспроизводить одну и ту же структуру страницы, а дизайнер получает не сырой холст, а осмысленный макет, который уже считает метрики.
Что находил аудит антипаттернов
Сканирование M-кода и DAX даёт не абстрактное «стиль кода не очень», а конкретный список вида «мера X, таблица Y, вот в чём проблема». В реальных бордах регулярно всплывает:
- хардкод путей и фиксированные даты вместо параметров — отчёт ломается при
первом переезде источника;
SELECT *и хрупкое разворачивание JSON в Power Query;- бизнес-логика, зашитая в вычисляемую колонку, вместо меры;
- по десятку разных шрифтов на одном листе: у части визуалов одна гарнитура,
у части — другая, и уже никто не помнит, почему так;
- 25 визуальных элементов, бережно спрятанных друг под другом: их
положили, потом перекрыли новыми, а старые не удалили. Глазами их не видно, но они живут в layout, тянут данные и раздувают файл.
Последние два примера — не про «плохой код», а про то, что дашборд визуально выглядит нормально, хотя внутри уже хаос. Ручной глаз такое не поймает.
Отдельно стоят инструменты, которые в работе оказались нужнее всего.
Lineage. Класс PbiLineage разбирает любой .pbix без установленного Power BI и вытаскивает полный след: происхождение → источник → Power Query → таблицы модели → семантику → страницы → визуалы. На выходе — JSON, Excel, Markdown и PlantUML-схема, которую скрипт сам публикует на Confluence. Причём перед публикацией схема валидируется, а публикация блокируется, если число листов вдруг упало — защита от «не того» файла. Плюс к каждому узлу считается refs — сколько раз он реально используется в визуалах. Это отвечает на вопрос «можно ли безболезненно удалить эту меру», на который обычно отвечают наугад.
Аудит брендбука. Дашборд, который не соответствует фирменному стилю, нельзя показывать. Проверка идёт по реально используемым в визуалах шрифтам и цветам, с допуском на искажения RGB, и локализует нарушение вплоть до конкретного визуала на конкретном листе. Для CI есть код возврата: есть листы-нарушения — выходной код 1.
Где здесь агенты
Агенты — не обязательный шаг конвейера, а опциональный умный слой. Конвейер прекрасно работает и без них. Каждый агент — декларативный манифест, привязанный к одной стадии: agent.builder (сборка), agent.tester (проверка), agent.deployer (публикация), agent.watchdog (контроль), agent.supporter (разбор инцидентов). Включаются, выключаются и переопределяются они прямо в spec. Это позволяет поручить агенту, например, весь путь «запрос → скелет → сборка → валидация → публикация → проверка», оставив за человеком только постановку задачи и приёмку.
Как агент отвечает на вопрос пользователя
Самое заметное на практике — не сборка отчётов, а скорость расследований. Вот несколько сценариев, которые раньше занимали полдня переписки, а теперь закрываются за один прогон.
«В первичке строк больше, чем в KPI на дашборде»
Пользователь приходит с расхождением: в таблице-источнике, скажем, 52 000 строк, а KPI на дашборде показывает 48 300. Классический вопрос «почему не сходится», который обычно уходит в аналитика на день.
Агент действует по фреймворку и не гадает:
- По
lineageнаходит, какой именно источник и какая мера стоят за KPI, и
вытаскивает её DAX-выражение.
- Видит, что KPI использует не
COUNTROWS, аDISTINCTCOUNTпо
идентификатору.
- Идёт в исходник и считает: сколько строк всего и сколько уникальных
идентификаторов. Если всего 52 000, а уникальных 48 300 — картина сходится, и дело не в дашборде.
- Ищет сами дубли и показывает их: вот строки с одинаковым идентификатором,
у которых различаются атрибуты A и B.
Ответ пользователю получается конкретным:
Расхождение не в дашборде: KPI считает уникальные идентификаторы, а в
источнике есть дубли. Например, идентификаторX-1042встречается три раза —
с разными значениямистатусидата_загрузки. Таких записей 3 700, что
ровно и даёт разницу 52 000 − 48 300. Причины дублей: перезагрузка источника
без дедупликации и два разных написания одного и того же атрибута.
Здесь срабатывает связка из статьи: lineage отвечает на «что за KPI и откуда он», а антипаттерны и разбор модели — на «почему цифра ведёт себя именно так».
Смысл не в том, что агент «умный». Смысл в том, что это закрывает заявку в поддержку за минуты вместо часов работы человека. Такой тикет раньше уходил в очередь к дата-инженеру, лежал до следующего окна, потом аналитик вручную открывал .pbix, искал меру, сверял со источником, писал ответ. Фреймворк превращает это в один прогон скриптов с готовым ответом и доказательством: вот мера, вот дубли, вот строки, вот причина. Человек остаётся там, где он действительно нужен — решить, что делать с дублями в источнике.
«Откуда взялась эта цифра»
К цифре в отчёте нужно объяснить путь: источник → Power Query → таблица модели → мера → визуал. Вместо ручного разбора .pbix агент строит lineage и отдаёт цепочку и саму формулу меры. Если мера используется ещё в десяти визуалах — это тоже видно по refs, так что сразу понятно, что менять её безопасно только проверив все места.
«Почему дашборд не проходит по брендбуку»
Агент запускает аудит и локализует нарушение до конкретного элемента: не «где-то не тот шрифт», а «лист 4, визуал „Выручка по месяцам“, шрифт X вместо фирменного, доля фирменных цветов 40%». Инженеру и дизайнеру не нужно просматривать весь отчёт глазами.
Чему я научился
Главный урок — инструмент для данных должен быть проверяемым. Красиво собрать отчёт мало; нужно, чтобы перед публикацией что-то независимо убедилось, что он не пустой и не сломанный. Отсюда validate_pbix перед публикацией и обратный самотест после сборки.
Второй урок — lineage окупается быстрее, чем кажется. Пока его нет, вопрос «а откуда взялась эта цифра» превращается в расследование. Когда схема строится автоматически из самого файла, ответ находится за минуты.
Третий — не надо бороться с закрытыми форматами. Бинарную модель VertiPaq лучше не реверсить, а аккуратно брать у Desktop. Это честнее и переживает обновления продукта.
Где посмотреть
Фреймворк лежит в открытом виде — с примерами, тестами и документацией по всем пяти стадиям: github.com/Bagilov/agentic_bi_framework. Там же разобраны конкретные приёмы: контейнер .pbix, кодировка layout, донорский перенос, движок-сборка, публикация и аудит брендбука.
Это не попытка заменить Power BI Desktop. Это попытка убрать из работы всё, что не является thinking-задачей: ручную сборку, ручную проверку, ручную публикацию и ручной поиск того, откуда взялась цифра.
Загрузка…