Как создавали нейропоиск Discovery AI — технология для крупнейшей контентной базы в РФ

от автора

Привет! Меня зовут Евгений Астафуров, я ведущий разработчик в Отделе экспериментальных технологий AI VK. Мы разрабатываем Discovery AI — набор ИИ‑технологий для интеллектуального поиска, рекомендаций и взаимодействия с контентом. В него вошли нейропоиск, анализ контекста, персонализация, генеративные модели и рекомендательные алгоритмы, чтобы помогать пользователям находить нужную информацию, получать релевантные ответы и новый контент.

В этой статье подробно разберу архитектуру технологии нейропоиска в Discovery AI, которая объединяет большую языковую модель (LLM), поиск, инференс и данные многомиллиардной контентной базы VK. Технология становится важным компонентом развития рекомендательных и поисковых систем в наших продуктах и будет поэтапно внедряться в сервисы для пользователей, авторов и бизнеса (Дзен, VK, Медиапроекты Mail, VK Видео и другие). 

Технология нейропоиска в Discovery AI оперирует петабайтами гетерогенных данных и генерирует точные ответы на запросы пользователей в режиме реального времени. Чтобы реализовать этот проект, мы оптимизировали поиск и инференс так, что задержка от момента отправки поискового запроса до первого токена ответа составляет менее 500 мс, собрали датасеты из миллиардов качественных синтетических разметок, обучили семейство BERT-like трансформеров и создали агентский сценарий Deep Research для многошагового поиска и анализа контента.

Поиск

Точкой входа для пользовательского запроса является общий маршрутизатор. Его задача — распределить запрос по изолированным вертикалям кандидатогенерации. Каждая вертикаль обслуживает свой тип контента, имеет собственную логику индексации и поиска. 

В поиске мы используем два вида кандидатогенераторов: текстовый BM25 и семантический векторный нейросетевой поиск.

Для семантического поиска используем метод Approximate Nearest Neighbors (ANN): на основании расстояния между точкой запроса и точками кандидатов в многомерном метрическом пространстве строится ранжирование по убыванию косинусной схожести. В свою очередь, BM25 позволяет находить документы по словоформам, но часто проигрывает семантическому поиску для широких смысловых запросов. В основе любой поисковой системы всегда лежит симбиоз этих двух компонентов, они друг друга дополняют: BM25 ловит точные совпадения и редкие термины, семантический поиск разбирается в синонимии и смысловой близости. Вместе они дают полноценное покрытие спектра пользовательских запросов: от конкретных до размытых и концептуальных. 

После получения сырых кандидатов из разных независимых вертикалей данные отправляются в «блендер», работающий по следующему алгоритму:

  1. Назначение приоритетов. Каждому источнику контента присваивают динамический вес (приоритет) в зависимости от продуктового контекста запроса.

  2. Дедупликация. Исключают пересекающиеся или идентичные документы, которые могут транслироваться разными вертикалями (например, перезаливы одной и той же публикации, ботофермы и так далее).

  3. Смешивание через Round-Robin. Кандидатов объединяют в пул с использованием модифицированного алгоритма round-robin. Это гарантирует, что в топ с большей вероятностью попадут лучшие представители от каждой вертикали, а не только документы из одного доминирующего источника.

Но даже после блендера сырые документы можно только грубо охарактеризовать как релевантные. На этом этапе нужно некоторое подобие бутылочного горлышка, через которое пройдут только по-настоящему релевантные и полезные для ответа документы.

Модели

Мы реализовали бутылочное горлышко через хитрую нейросетевую модель ранжирования, которая решает сразу две задачи:

  1. Выделение релевантных кусочков каждого документа.

  2. Обеспечении фиксированного размера контекста для LLM.

Для этого каждый документ режут на чанки текста так, чтобы сумма токенов запроса и чанка не превышала 320 токенов, к этому прибавляют перекрытие в 160 токенов между чанками. Мы используем свою кастомную BERT-like модель для оценки релевантности каждого чанка текста к запросу пользователя.

Если говорить про производительность, то стоит заметить, что в условиях промышленной эксплуатации GPU инференс нейросетей — это всегда компромисс между пропускной способностью (throughput) и задержкой (latency). В подобных случаях в технических отчётах чаще приводят пиковую пропускную способность, и в нашем случае модель способна обрабатывать до 5 тысяч документов (или около 30 тысяч чанков) в секунду на одном GPU среднего консьюмерского уровня.

В 2026 году никого не удивить использованием BERT-like трансформеров для решения NLP задач, это давно стало стандартом для всей индустрии. Но, к сожалению, большинство часто обходят стороной финальную производительность, хотя на больших масштабах неоптимальный инференс просто зря жжёт электричество и бюджет компании.

Для достижения производительности в 30 тысяч чанков в секунду мы использовали ряд эвристик и оптимизаций:

Токенизация и архитектура. Токенизация представляет собой разбиение текста на последовательность токенов. Для трансформерных нейросетевых моделей с классическим Multihead-Self-Attention алгоритмическая сложность инференса квадратично зависима от длины последовательности. Следовательно, если мы хотим увеличить скорость вычислений, нам следует научиться кодировать тексты как можно меньшим количеством токенов. Мы обучили токенизатор Byte-Pair Encoding (BPE) специально на контенте из соцсетей и новостях, и добились фертильности 1,2(то есть в среднем 12 токенов на 10 слов текста) при размере словаря в 128 тысяч. Это самая низкая фертильность среди всех open source-моделей для русскоязычного контента из соцсетей, и одна лишь эта оптимизация дала нам чистый прирост к скорости инференса ~50%. После обучения токенизатора мы выполнили претрейн моделей разных размеров. Использовали весь свой опыт в высокопроизводительном инференсе для выбора оптимальных гиперпараметров модели: все размерности, операторы и порядок исполнения настроили так, чтобы снизить вероятность появления эффекта квантования волн (GPU Wave Quantization), корректной топологии SM и памяти в тех моделях GPU, которые мы используем для инференса.

Teacher-Student Knowledge Distillation. При обучении под целевую задачу ранжирования сначала обучили большую модель (teacher), а затем маленькую модель сигналу задачи и сигналу логитов большой модели. Это известный приём, позволяющий уменьшить размер модели с минимальными потерями в качестве.

QAT & Structured Sparsity & TensorRT. При обучении применяли симуляцию INT8-квантования (Quantize Aware Training), а также симуляцию паттерна структурной разреженности Structured Sparsity 2:4. Эти две оптимизации при сборке инференс-движка TensorRT позволили кратно увеличить скорость инференса практически без снижения качества.

Датасеты

Теперь расскажу про датасеты, использованные для обучения семантического поиска и ранжирования релевантности чанков.

Семантический поиск проектировали с расчётом на то, чтобы система могла корректно обрабатывать произвольные, длинные и сложносоставные вопросы (интенты) пользователей. К сожалению, с этим требованием, мы не могли переиспользовать существующие общие поисковые системы и собрать датасет по их журналам, так как особенностью классического поиска являются короткие запросы, жесткие паттерны и так далее.

У нас было два пути: внедрить промежуточный шаг с перефразированием (когда большая модель дробит сложный запрос на множество мелких подзапросов из домена классического поиска) или научить поисковый движок понимать комплексный синтаксис и длинные интенты напрямую. Первый вариант значительно увеличивал общую задержку системы из-за дополнительной стадии с вызовом LLM (либо любого другого текстового генератора), поэтому мы выбрали второй путь. 

Для реализации этой идеи потребовался колоссальный объём обучающих данных. Мы решили эту проблему без привлечения ручной разметки или асессоров, создав конвейер LLM-as-a-judge.

Пошаговый конвейер генерирования датасета выглядит так.

Обратное генерирование интентов. Мы сгенерировали огромную часть всего массива публикаций нашей экосистемы. Для каждого документа с помощью крупной LLM-модели создали список разнообразных гипотетических вопросов, ответы на которые явно содержатся в тексте. На этом этапе мы столкнулись с двумя большими проблемами:

  1. LLM склонна галлюцинировать, выдумывая вопросы, на которые нет ответа в документе.

  2. У LLM всегда присутствует байес, его нельзя исправить только промптом.

Первую проблему позже элегантно разрешим на этапе фильтрации, а вторую — на этапе с аугментацией. Сейчас же мы постарались сделать интенты максимально разнообразными невзирая на галлюцинации и заставили LLM писать их по категориям (например, Fact Checking, Information Retrieval, Arbitrary Interest, и так далее). Таким образом, на каждый документ мы получили от 15 до 30 различных «грязных» синтетических интентов.

Аугментация запросов. Каждый базовый вопрос подвергли семантической аугментации. Мы меняли лексику, стиль, усложняли синтаксические конструкции, имитируя живую речь реальных пользователей. Искусственно удлиняли или укорачивали, добавляли или удаляли детали. В итоге для каждого документа получилось около 100-200 вариаций интентов.

Нарезка на чанки и оценка релевантности. В параграфе про модель я упомянул, что для оценки релевантности документа запросу мы использовали нарезку на чанки. Фиксируя конкретный интент и документ, последний разбивали на чанки так, чтобы суммарное количество токенов в интенте и чанке не превосходило 320, и при этом соседние чанки пересекались с перекрытием в 160 токенов. Перекрытие нужно для исключения потери контекста и более точной резметки. Каждую пару (интент-чанк) оценивали на релевантность через отдельно обученный LLM-jujge: «NOREL» (не релевантно), «REL‑» (слегка релевантно), «REL» (релевантно), «REL+» (высокорелевантно). Формат ответа — структурированный JSON словарь с ключами {reasoning, label}.

Фильтрация. После всех этапов мы использовали эвристику которую можно описать так: если для интента X среди всех чанков документа Y есть хотя бы один«REL+», то документ Y можно считать релевантным для интента X. Таким образом из пяти миллиардов интентов мы получили сразу две разметки:

  1. 200 миллионов пар (интент, документ) для обучения эмбеддеров семантического векторного поиска;

  2. миллиард троек (интент, чанк, label) для обучения модели ранжирования релевантности.

Генеративный слой

В среде исполнения после блендера, нарезки документов на чанки и скоринга мы получаем ранжирование документов. Далее, чтобы собрать контекст для LLM, для каждого документа из топ-7 мы конкатенируем наиболее релевантные чанки в хронологическом порядке без пересечения так, чтобы финальное количество токенов с каждого документа не превышало 1000.

Полученный контекст передаём в LLM с набором политик, и получаем связный текст — ответ на вопрос пользователя. Мы применяем легковесную языковую модель (8B) на основе архитектуры LLaMA. 

Поскольку нейропоиск работает в строгих рамках фактологии, критически важно было минимизировать галлюцинации: модель жёстко ограничена переданным ей контекстом так, чтобы не извлекать знания и факты из собственных весов, если их нет в переданном контексте.

Deep Research

Одной из мастер-фич нейропоиска, про которую хочу рассказать, стал сценарий Deep Research. Это автономный агентский цикл поиска с уточнениями, и чтобы понять мотивированность его использования, стоит вспомнить о главном ограничении одношагового поиска: чтобы собрать достаточный объём информации по некоторой теме, часто недостаточно одного шага. При углублении в тему открываются новые вопросы и подтемы, которые нужно покрыть отдельно, сопоставляя факты из разрозненных источников.

Наш Deep Research работает итеративно: на каждом шаге агент оценивает достаточность собранной информации, балансируя между сужением скоупа (поиском специфических деталей) и его расширением (запросом смежного контекста).

Визуально можно изобразить схематически:

Как это работает на практике: пример агентского сценария

Чтобы протестировать систему в реальных условиях, предположим, что пользователь вводит в поисковую строку сложный, комплексный запрос:

Изменения в законе о маркировке рекламы за последний квартал: новые штрафы для самозанятых авторов и пошаговый алгоритм действий

Одношаговый поисковый движок нашёл бы пару свежих новостных заметок и статей по ключевым словам. Генеративная модель выдала бы ответ про изменения в законе, размеры штрафов, нормативные акты, но не про алгоритм действий. Пользователю пришлось бы искать его отдельно, вручную сшивая информацию из новостей с практическими руководствами, и самостоятельно проверять, не устарели ли эти руководства после последних правок закона.

Deep Research решает эту задачу иначе. Запрос изначально гетерогенный: в нём смешаны фактологическая часть (что изменилось в законе), узкоспецифичная (штрафы именно для самозанятых) и процедурная (что конкретно делать). Ни один документ не покрывает все три аспекта сразу, поэтому агент разбирает запрос на под-интенты и идёт по ним итеративно.

Шаг 1. Широкий заход. Агент начинает с общего интента «изменения в законе о маркировке рекламы за квартал» и собирает свежие новостные заметки и разборы. Оценка достаточности: фактура по самим поправкам есть, но два других аспекта запроса не покрыты. Фиксируется пробел.

Шаг 2. Сужение скоупа. Агент целенаправленно идёт за специфической подробностью: штрафами для самозанятых. Здесь важно, что это не повтор первого поиска, а сужение: общий запрос про штрафы вернул бы суммы для юрлиц и агентств, а нам нужна именно вертикаль «физлицо/самозанятый». Агент достаёт конкретные санкции и сопоставляет их с поправками из Шага 1.

Шаг 3. Расширение в смежный контекст. Самая интересная часть. Пошаговый алгоритм — это не документ, а конструкт, которого в исходном виде может не существовать. Агент это распознаёт и расширяет скоуп на процедурный домен: ищет, как автору зарегистрироваться в ОРД, как получить токен и промаркировать креатив, как отчитываться. Эти фрагменты живут в авторских руководствах и обучающем контенте.

Шаг 4. Сверка и проверка фактов. Агент замечает конфликт: процедурные руководства старше, чем поправки из Шага 1, и часть шагов могла измениться (сроки, новые требования к отчётности). Он переоценивает собранное, сводит противоречия и приоритизирует самые свежие источники: ровно та логика «сопоставления фактов из разрозненных источников», ради которой Deep Research и существует.

Шаг 5. Достаточность достигнута. Теперь у агента на руках три согласованных блока: суть правовых изменений, санкции конкретно для самозанятых и собранный из разных источников и проверенный по последней редакции закона алгоритм действий. Контекст уходит в LLM и пользователь получает единый ответ, которого не вернул бы ни один отдельный документ.

В сухом остатке 

Можно с уверенностью сказать, что подобная технология будет актуальной по меньшей мере ближайшее десятилетие: независимо от технических возможностей, размера контекста и capacity в современных и будущих языковых моделей, сценарий обобщения поиска гораздо дешевле и эффективнее решать через комбинацию легковесной LLM и аккуратного механизма сбора документов в контекстное окно.

Несмотря на волну LLM-хайпа, оптимизация дискриминаторов BERT-like не потеряла своей актуальности, а грамотная оптимизация инференса позволяет кратно снизить затраты, что критично в условиях дороговизны и вечной нехватки GPU.

ссылка на оригинал статьи https://habr.com/ru/articles/1054358/