
Годы идут, но что‑то остаётся неизменным: писать документацию никто не любит, но тем не менее все почему‑то ругают тех, кто её не пишет.
В Яндексе одних только таблиц с данными — десятки миллионов, общим объёмом в экзабайты данных. Даже когда мы оставляем из всего этого количества только самое востребованное, остаётся несколько десятков тысяч таблиц, которые кто‑то должен описать словами: что внутри, откуда взялось, можно ли этому доверять. Без таких описаний аналитик не находит данные через поиск, не понимает, что лежит в таблице, и заново собирает то, что уже собрал коллега. И страдает не только человек: ИИ‑агенты, которые всё чаще сами решают аналитические задачи, на неописанных данных также теряют в качестве — чем меньше известно про таблицу, тем хуже результат.
Год мы уговаривали людей описывать таблицы вручную — и собрали описания всего на 500 таблиц из 40 тысяч. Если описывать все данные с такой скоростью (при учёте, что постоянно появляются новые) — страшно представить, на сколько десятков лет мог бы растянуться этот процесс.
Меня зовут Роман Гриднев, я технический менеджер в Яндексе. Расскажу, как мы научились не писать документацию. «Не писать‑то все могут», — скажете вы. Но мы подключили к задаче LLM и дали людям вместо чистого листа черновик: пусть с ошибками, зато не пустую страницу, которая пугает. За полгода мы так описали 15 тысяч таблиц и сэкономили около пяти лет рабочего времени аналитиков. Со временем качество черновиков от LLM доросло до почти полного соответствия описаниям, сделанным людьми.
Как мы перестали просить людей писать документацию с нуля
Наши 40 тысяч уже отфильтрованных таблиц представляют собой совершенно разные данные. Там есть данные DWH, сырые логи, данные от аналитиков, разные ad‑hoc и всё, что лежит под дашбордами. Уровень подготовки этих данных и уровень команд, которые их делают, тоже нестабильный.
По уровню подготовки можно выделить три группы:
Данные DWH — в значительной степени задокументированы и имеют владельца.
Данные аналитиков — чаще всего имеют владельца, степень документированности зависит от команды, но чаще низкая. Аналитики понимают ценность документации, но перегружены производством новых отчётов и дашбордов.
Сырые данные — чаще всего никак не задокументированы и не имеют определённого владельца.
Закономерность простая: чем дальше данные от DWH, тем хуже они описаны и тем реже у них есть владелец, которого можно попросить. А приходишь с вопросом «Что это за таблица и можно ли ей доверять?» как раз чаще всего к верхнему слою данных — то есть туда, где спрашивать не у кого. Стратегия «найти ответственного и попросить описать» во многих таблицах упирается в то, что ответственного просто нет.
Поэтому мы и не стали чинить документацию по месту. Всё, что известно о таблицах, мы планировали собирать в одном месте — Датакаталоге, едином источнике знаний и внутреннем поисковике по данным. Там видно, как и кем формируются данные, какие считаются метрики и так далее.
Но когда я пришёл к коллегам с просьбой написать документацию, мне сказали: «Да, круто. Проблема важная, нужная. Но пусть кто‑то другой, как‑нибудь не сейчас, где‑нибудь в Q5».
Я пытался бегать за людьми и собирать обещания, но эффективность была низкой. За целый год такой ручной работы удалось собрать описания всего 500 таблиц, как мы помним, из 40 тысяч. Это было очень грустно.
Тогда пришлось проявить фантазию: как упростить задачу, чтобы сотрудникам было легче с ней справиться? И родилась главная гипотеза: будет ли быстрее и проще просить людей делать описания, если на странице уже будет лежать пусть не идеальная, но документация, пусть с ошибками, но не пустота, которая создаёт впечатление огромного объёма работы?
Чтобы побороть проблему чистого листа, которая вызывала у людей ступор, мы решили скормить табличку LLM. Она что‑нибудь опишет, а мы придём к коллегам и попросим просто поправить текст, а не сделать огромный пласт работы с нуля.
Эксперимент удался: когда задача превратилась не в «напиши с чистого листа», а «зайди, пожалуйста, посмотри, поправь, я за тебя уже написал», всё заработало быстрее. Стало проще с точки зрения человеческой психологии: по сути, человеку на тот момент переписывать надо было не меньше, чем с чистого листа, но то, что какими‑то буквами уже был забит фон, делало задачу психологически проще.
Я воодушевился и подумал: «Почему бы мне не попытаться раскачать эту тему?» И написал небольшого робота, который научился собирать описания за людей.
Сразу оговорюсь, что экономия времени аналитиков — это приятный побочный эффект, но не главная цель этой затеи. Главных было две:
LLM‑пригодность описаний: чтобы агенты, которые ходят в Датакаталог по API, находили нужные данные и понимали, про что таблица, а не гадали по названиям полей.
Подсвечивать ценные данные: аналитики часто строят отчёты на заброшенных и неточных табличках, толком не зная, что внутри. Хочется, чтобы перед работой человек видел проверенное описание и понимал, можно ли источнику доверять.
Как работает робот
Робот представляет собой скрипт на Python, который с помощью API Датакаталога, LLM‑моделей, баз данных YT и Memgraph собирает описания из разных источников.
Сбор описаний

Так как мы всё‑таки пытаемся создать максимально точную картину, полностью довериться фантазиям от LLM нельзя. Робот сначала собирает всё, что знает о данных, — объективно, точно и более‑менее уверенно:
Путь до таблицы. Собираем всё, что знаем о таблице: путь к данным, схему, образцы данных, если они есть.
Глоссарии, которые можно собрать во внутренней Вики. Это набор полей, которые внутри определённого контекста или команды всегда должны называться и описываться одинаково. Если для каких‑либо полей есть шаблонное описание — используем его.
Вики‑страницы с описанием. У нас есть огромные разделы на Вики со страницами разной степени давности — можно их попарсить и взять оттуда контекст про данные. Иногда там нет описания полей, но, например, написано, про что таблица, — и это хороший контекст для дальнейшей работы.
Соседи по графу. Если в предках или потомках сущности по графу поля описаны — используем это. Пришлось покопаться в логах и поднять базу данных Memgraph. Она быстро давала ответ на вопрос, из чего формируется таблица и что формируется из этой таблицы на много уровней вперёд и назад. Это помогло нам достроить данные: бывает, что таблицы не описаны в середине, а только по краям, или же, например, команда DWH не описала свою таблицу, а аналитик, который что‑то строил из этой таблицы, описал. Поэтому мы можем сходить по графу, посмотреть, где есть документация, и попытаться растянуть её по всей цепочке.
Соседи по папке. Если внутри какой‑то папки в DWH лежат данные и половина из них описана, можно с высокой вероятностью предположить, что эти данные внутри одного контекста. Скорее всего, у них одни и те же значения, если поля имеют одинаковые названия и тип.
Самое сложное во всей этой истории — даже не технически что‑то допилить, а получить доступы: права на максимум контекста, API ко всем источникам. В большой компании на каждый кусок есть инфобез и владельцы данных, и со всеми надо договориться. Кода в роботе в итоге оказалось меньше, чем переписки и согласований.
Поход в LLM

Робот берёт всё, что собрал на предыдущих этапах — путь, схему, образцы данных, контекст из Вики и соседей по графу, — и идёт с этим к LLM. Запрос примерно такой: «Мы собрали бизнесовый и технический смысл полей и то, откуда они берутся. Скажи, пожалуйста, условно в двух тысячах символов, как в целом назвать эту табличку и как её описать».
Пользуясь уже собранным контекстом, LLM делает это достаточно эффективно:
описывает поля, до которых не добрались предыдущие этапы;
если известен YQL (SQL‑подобный внутренний язык нашей базы данных) — добавляет, как формируется поле;
генерирует заголовок и описание таблицы целиком.
Ключевая деталь: LLM не сочиняет с нуля, а дописывает поверх того, что робот уже выяснил объективно — путей, схем, образцов, связей по графу. Поэтому в описании к каждому полю видно, откуда оно взялось. Это не фантазия нейросети, а черновик, который можно проверить, — он загружается в Датакаталог, и именно его мы отдаём человеку на правку.
Кстати, тут не обошлось без граблей. Выяснилось, что контекстному окну становится плохо, когда в таблице где‑то от 800 колонок. Отдельная история — когда колонок и строк немного, но в одной ячейке лежит гигантский JSON, который в одиночку забивает всё окно. Пришлось дописать простой механизм: чем больше в таблице колонок, тем меньше строк робот берёт в образец. Мелкий тюнинг, но без него на больших таблицах не собиралось вообще ничего.
Работа в Датакаталоге
Вот как всё это выглядит в Датакаталоге:


У каждого поля — не только описание, но и пометка, откуда оно взято. Где‑то стоит слово «граф» со ссылкой на таблицу, из которой мы протянули описание по связям. Где‑то — YQL со ссылкой на таблицу, из которой видно, что поле сформировано именно так. У самой таблицы — заголовок, общее описание. Датакаталог постоянно пополняется, и в любой момент можно там найти и скинуть ссылку на нужный документ коллегам.
За полгода сложились три основных сценария работы с автоописаниями:
Заготовка для доработки человеком. Самое простое: робот генерирует описание, а мы идём к автору данных и просим проверить текст. Для важных данных этот этап неизбежен — полностью доверять автоматике нельзя.
Описание второстепенных сущностей. Это то, что руками никто и никогда не стал бы описывать. Чаще всего описания после проверок остаются такими же, как их написала LLM, — оно всех устраивает.
Прямой перенос из Вики. Если у кого‑то в Вики уже есть нормальное описание, робот просто стягивает его — без всякой фантазии, перекладывает одно в другое. В каком формате оно там написано, неважно: LLM разберётся.
Общий знаменатель всех трёх сценариев: человек больше не пишет с нуля — он либо правит готовое, либо не делает вообще ничего. По нашим замерам, на описании каждой сущности это экономит в среднем около двух часов. Мы считали экономию исходя из того, сколько полей подтвердил человек после LLM и насколько сильно переписал, если редактировал.

Получилось, что в общем мы сэкономили около 5 лет рабочего времени аналитиков и улучшили доступность данных как для людей, так и, что особенно важно в современном мире, для моделей, решающих аналитические задачи на данных.
Как мы замеряли качество работы робота
Качество работы мы замеряли двумя способами:
Опрос коллег. Мы спрашивали, насколько описание, которое мы сгенерировали, соответствует тому, что они хотели бы видеть. Получили неплохие результаты, стали их растить. Но проблема была в том, что не все хотели качественно участвовать в опросе и заполнять анкеты.
Семантическая сверка. Оценка семантического совпадения между описанием, которое сделала LLM, и описанием, которое позже проверил или занёс заново человек. Сравнение показало 92% совпадений по смыслу. После валидации 71% полей был перенесён без изменений.
Важная деталь про саму оценку: описание генерирует одна модель, а семантическую близость проверяет другая. Одной и той же моделью и писать, и оценивать нельзя — она охотно выставляет себе хорошие отметки. Благо внутри у нас развёрнуто достаточно много моделей, было из чего выбрать и генератора, и независимого судью.
В результате за полгода мы описали 15 тысяч таблиц — это намного круче, чем 500 таблиц за год. Могли бы и больше, но увлеклись экспериментами с качеством и отладкой, и процесс шёл медленнее, чем мог бы.
Что дальше
В ближайших планах — сосредоточиться на трёх направлениях:
Подключиться к регулярным поставкам данных. Сейчас часть знаний робот достаёт из логов, а хочется получать их напрямую из регулярных поставок и знать сильно больше о том, как формируются данные.
Поколоночная проброска описаний. Сейчас робот знает, что табличка выросла из таблички. А хочется знать, что колонка выросла из колонки: знание куда более ценное — оно позволит точнее пробрасывать описания между таблицами. Бывает, название колонки меняется, а суть остаётся прежней, или поле получено несложным преобразованием — про это тоже можно будет сказать.
Кнопка прямо в Датакаталоге. Этот робот — сильно переросший MVP “вроде что‑то написано, а давайте попробуем, давайте сделаем”. Нужно сделать так, чтобы его мог запустить любой пользователь прямо в Датакаталоге по кнопке, а не по заявке. Сейчас мы как раз этим и занимаемся.
Главный вывод из нашей работы — не бояться чистого листа. По‑настоящему пустым лист не бывает почти никогда. Под ним всегда есть техническая мета, код формирования данных, соседи по графу и какая‑то часть уже описанных полей. Этого достаточно, чтобы робот собрал черновик, а человеку остаётся его проверить.
Дальше включается обратная связь. Как только люди начинают проверять автоописания, у нас появляются правки, а у людей — мотивация довести описание до ума. Проверенные описания робот берёт как контекст и протаскивает дальше по графу — документация растёт сама: так 500 описанных таблиц превратились в 15 тысяч.
И не стоит бояться, что настройка автоописаний — бесконечно долгий процесс. Нам хватило двух месяцев экспериментов, чтобы запустить первую версию.
А ещё, так как теперь все наши данные представлены в виде графа, мы можем легко даже визуально обнаружить сильно и слабо связанные области, что очень помогает при проектировании архитектуры хранения.

Если у вас есть подобный опыт, приходите и делитесь в комментариях!
А ещё приглашаю вас на нашу главную конференцию по аналитике Data Driven, которая пройдёт в Москве 26 сентября.