Классифайды давно столкнулись с одной и той же проблемой: пользователь ищет «кресло виды Лондона», а продавец написал в объявлении только «кресло-мешок». Фотография с Биг Беном на заднем плане никак не помогала — традиционный полнотекстовый поиск требует, чтобы каждое слово из запроса присутствовало в тексте объявления. Авито решило закрыть этот разрыв, добавив к каждому объявлению автоматически сгенерированное текстовое описание на основе изображений.
Основой стала опенсорсная мультимодальная модель Qwen2.5-VL-7B-Instruct — она умеет анализировать изображения и генерировать текст одновременно. Инженеры Авито дообучили её на собственных данных и назвали результат A-Vision. Модель оценивалась по трём benchmark-метрикам: Bert Score измеряет семантическую близость сгенерированного текста к эталону, MMMU-RU проверяет понимание научных тем на русском языке, RealWorldQA — пространственное понимание реальных объектов, что особенно важно для товарных объявлений.
Отдельной проблемой оказался токенизатор. Стандартные токенизаторы, обученные преимущественно на английском тексте, дробят одно русское слово на 4–6 токенов — это напрямую увеличивает число шагов декодирования и замедляет генерацию. После переобучения токенизатора под кириллицу время генерации описаний сократилось вдвое при сохранении качества.
LoRA-адаптеры позволяют адаптировать модель под категорию товаров, добавляя лишь 0,1–1% новых параметров.

Для адаптации модели под конкретные категории товаров — мебель, одежда и другие — команда выбрала метод LoRA (Low-Rank Adaptation). Суть подхода в том, что исходная модель полностью замораживается, а к ней добавляются небольшие матрицы с обучаемыми параметрами. Их объём составляет всего 0,1–1% от числа параметров базовой модели, что в 100–1000 раз меньше, чем при полном дообучении. Дата-сайентисты Авито обучают отдельные LoRA-адаптеры на объявлениях из каждой категории, не затрагивая веса A-Vision.
Для ускорения инференса выбран фреймворк vLLM. Его ключевая особенность — механизм Paged Attention: KV-кэш делится на небольшие блоки, которые размещаются в памяти GPU не последовательно, а через таблицу соответствия. Это снижает фрагментацию памяти и позволяет эффективнее обрабатывать батчи запросов на нескольких GPU параллельно.
Инфраструктурно система устроена следующим образом. Когда объявление создаётся или обновляется, событие попадает в шину данных. Воркеры фильтруют сообщения — проверяют, изменились ли заголовок или фотографии и относится ли объявление к категории, для которой включена генерация описаний. Прошедшие фильтр объявления попадают в изолированную очередь QaaS, которая буферизует нагрузку и позволяет масштабировать число GPU-воркеров независимо от основного поиска. LLM-воркер забирает пачку объявлений, генерирует описания, сохраняет их в Redis с TTL и уведомляет поисковый сервис. Тот забирает описания через API и добавляет их в поисковый индекс на базе Sphinx.
Чтобы не терять объявления, которые по каким-то причинам остались без описания, раз в сутки запускается cron-задача: она запрашивает у Sphinx все объявления без LLM-описания и отправляет их в ту же очередь. За полтора часа пробел закрывается. Такой подход проще, чем детальная диагностика причин пропусков, и при этом достаточно надёжен для продакшена с десятками миллионов объявлений.


