Hugging Face рассказала, как построила гибридный поиск для Papers with Code

Hugging Face рассказала, как построила гибридный поиск для Papers with Code

Hugging Face опубликовала техническое описание поисковой системы Papers with Code, сервиса поиска научных статей. Задача была не просто найти точное совпадение по заголовку или идентификатору arXiv, а понимать запросы вроде «маленькие языковые модели для генерации кода», распознавать навигационные запросы («оригинальная статья про BERT»), терпеть опечатки и неполные заголовки и при этом быстро отвечать, даже если модель временно недоступна.

Решением стал гибридный поиск: полнотекстовый (лексический) поиск средствами PostgreSQL совмещён с векторным поиском на pgvector, а результаты двух веток объединяются алгоритмом взвешенного reciprocal rank fusion (RRF) с равными весами веток и константой k=60. Каждая ветка отдаёт до 50 кандидатов на запрос. Лексический поиск точно находит точные термины, идентификаторы и редкие имена, векторный, улавливает смысловую близость запроса и текста, а RRF комбинирует не сами оценки (у них разные шкалы), а ранги результатов.

Для эмбеддингов используется модель Qwen/Qwen3-Embedding-0.6B с зафиксированной ревизией; каждый документ кодируется как связка нормализованного заголовка и нормализованной аннотации. Благодаря технологии Matryoshka Representation Learning (MRL) вектор из полноразмерного представления обрезается до 256 измерений и нормализуется, это осознанный компромисс между качеством и скоростью/объёмом хранения. На сегодня система поддерживает эмбеддинги более чем для 110 000 статей, собранных из arXiv и Daily Papers.

Архитектурно расчёт эмбеддингов разделён на офлайн-пакет и онлайн-сервис. Полный пересчёт корпуса запускается как батч-задача Hugging Face Jobs: экспортёр читает снимок базы PostgreSQL построчно (не загружая весь каталог в память), пишет шардированные JSONL-файлы с манифестом и контрольными суммами SHA-256, а сама задача выполняется на аппаратном профиле l4x1, это один GPU NVIDIA L4 с 24 ГБ видеопамяти, с таймаутом задачи 6 часов в примере команды. Каждый обработанный шард отмечается отдельным маркером, поэтому перезапущенная задача не пересчитывает то, что уже готово. На пилотном корпусе из 5000 статей задача на Qwen обрабатывала около 75 статей в секунду при 1024 измерениях на одном GPU L4.

Связующим звеном между базой данных, экспериментами и задачами служат Hugging Face Storage Buckets, изменяемое, похожее на S3 объектное хранилище, которое монтируется в задачи напрямую по пути hf://buckets/.... Артефакты организованы в неизменяемые префиксы runs/ с входными и выходными манифестами; неизменность, правило на уровне приложения: идентификатор запуска никогда не перезаписывается, и каждый файл сверяется по контрольной сумме. Импортёр повторно проверяет схемы, контрольные суммы, размерность, нормализацию и уникальность идентификаторов статей перед загрузкой векторов в PostgreSQL; затем строится отдельный HNSW-индекс для нового поколения векторов, и оно атомарно помечается активным только тогда, когда покрыты все актуальные статьи. Это даёт воспроизводимость, безопасные повторные попытки, дешёвые эксперименты с разными моделями и измерениями и простой откат на предыдущее поколение при необходимости.

Эмбеддинг самого запроса пользователя считается на лету через аутентифицированный Inference Endpoint на базе Text Embeddings Inference (TEI), который отдаёт нормализованный 256-мерный вектор с использованием query-промпта модели. Поиск по активному поколению векторов в pgvector идёт по косинусному расстоянию с ограничением в 50 кандидатов. HNSW-индекс держит эту выборку быстрой: на пилоте из 5000 статей 256-мерный индекс на базе Qwen показал Recall@20 = 0,9955 относительно точного поиска, задержку поиска 1,31 мс на медиане (p50) и 2,21 мс на 95-м перцентиле (p95), а его таблица и индекс заняли около 27% места по сравнению с 1024-мерной версией при практически той же точности приближённого поиска.

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

Поверх слияния рангов сохранена детерминированная логика: точные заголовки и идентификаторы arXiv всегда оказываются на первом месте, таксономия методов распознаёт навигационные запросы вроде «оригинальная статья про BERT», неполные заголовки и умеренные опечатки обрабатываются консервативными триграммными кандидатами, а неоднозначные нечёткие совпадения система предпочитает не форсировать, а воздержаться от результата. Авторы (ранее работавшие, по их словам, в консалтинговой компании ML6, где строили RAG-системы для клиентов) отмечают отдельно: гибридный поиск, не универсальный первый шаг, начинать рекомендуется с дешёвого и быстрого ключевого (лексического) поиска, а семантику и гибридную схему добавлять уже поверх него по мере необходимости.

Ключевые факты

  • Поиск Papers with Code, гибридный: полнотекстовый поиск PostgreSQL и векторный поиск pgvector объединяются через взвешенный reciprocal rank fusion (RRF, k=60, равные веса веток, до 50 кандидатов от каждой ветки).
  • Эмбеддинги считает модель Qwen/Qwen3-Embedding-0.6B с зафиксированной ревизией; вектор урезан до 256 измерений технологией Matryoshka Representation Learning (MRL) ради баланса скорости и объёма хранения. Сейчас система поддерживает эмбеддинги для более чем 110 000 статей из arXiv и Daily Papers.
  • Офлайн-пересчёт корпуса идёт как батч-задача Hugging Face Jobs на профиле l4x1 (один GPU NVIDIA L4, 24 ГБ VRAM); результаты и манифесты с контрольными суммами хранятся в Storage Buckets в неизменяемых префиксах runs/.
  • Онлайн-эмбеддинг запроса считает Inference Endpoint на Text Embeddings Inference: максимум одна реплика, масштабирование до нуля при простое, тайм-аут в 1 секунду и автоматический откат на обычный лексический поиск при сбое или холодном старте.
  • На пилоте из 5000 статей 256-мерный HNSW-индекс дал Recall@20 = 0,9955 при задержке 1,31 мс (p50) / 2,21 мс (p95) и занял около 27% места по сравнению с 1024-мерной версией; throughput расчёта эмбеддингов на том же пилоте, около 75 статей в секунду при 1024 измерениях на одном GPU L4.

Почему это важно

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

Кому это важно

Инженерам, которые строят поиск или RAG-системы поверх больших текстовых корпусов, командам, уже использующим инфраструктуру Hugging Face (Jobs, Storage Buckets, Inference Endpoints), и разработчикам, выбирающим между чисто лексическим, чисто векторным и гибридным поиском для собственных продуктов.

Как это применить

Из поста можно забрать готовый архитектурный паттерн: разделять офлайн-расчёт эмбеддингов (батч-задача с проверкой контрольных сумм и манифестами) и легковесный онлайн-эмбеддинг запроса за отдельным сервисом; использовать Matryoshka-модели, чтобы обрезать размерность вектора без заметной потери точности и сократить расходы на хранение; объединять ранги двух источников поиска через RRF вместо попытки сравнивать разнородные оценки; и обязательно проектировать деградацию до простого лексического поиска на случай недоступности или холодного старта семантического сервиса.

Можно ли доверять

Это техническая публикация от первого лица, инженеров Hugging Face, описывающих собственную продакшен-систему с конкретными числами конфигурации (модель, размерность, тайм-ауты, аппаратный профиль). Источник надёжен как первоисточник, но нужно учитывать: часть приведённых метрик (Recall@20, задержка HNSW-поиска, экономия места, throughput расчёта эмбеддингов) измерена на пилотном корпусе из 5000 статей, а не на полном продакшен-корпусе из более чем 110 000 статей, в тексте это прямо не оговаривается как гарантия для полного масштаба.

Риски и подводные камни

Ключевые метрики (Recall@20 = 0,9955, задержки 1,31/2,21 мс, экономия ~27% места, throughput 75 статей/сек) получены на пилоте из 5000 статей и при этом throughput измерен для 1024-мерных векторов, а не для 256-мерных, которые используются в продакшене, переносить эти цифры на полный корпус из 110 000+ статей без дополнительной проверки не стоит. В посте также не раскрыты стоимость эксплуатации, размер команды и сроки внедрения системы, а сохранённый текст источника обрывается на середине предложения в последнем абзаце, поэтому финальная рекомендация авторов о выборе между лексическим, семантическим и гибридным поиском передана не полностью.