Как построить RAG поиск для ИИ больших данных? Обсуждаем проблему.
RAG, который выдаёт 90% точности на 5 000 документов, на 500 000 разваливается до 50%. Та же модель эмбеддингов, тот же ретривер. Что произошло, и при чём тут геометрия embedding-пространства.
«У вас RAG, который на 5 000 корпоративных документов выдаёт 90% точности retrieval. Скейлите до 500 000, точность падает до 50%. Та же модель эмбеддингов, тот же ретривер. Объясните, почему».
Самый очевидный ответ: больше документов, больше конкуренции за топ-K слотов. Звучит правдоподобно. И в каком-то смысле верно. Только это никак не объясняет, почему точность падает так драматично. Объём корпуса вырос в 100 раз, а recall просел почти вдвое. Линейного объяснения не получается.
Настоящий ответ — про то, как корпоративные документы устроены в пространстве эмбеддингов.
Кластеры везде, а правды нигде
Любое продуктовое решение в современной компании оставляет за собой шлейф артефактов: транскрипт встречи, тред в Slack, страница в Confluence, тикет в Jira, цепочка email с клиентом. Все они описывают одно событие. И, что критично для нашей истории, все они оседают в одной и той же области пространства эмбеддингов.
Современные эмбеддеры обучаются методом contrastive learning. Их буквально натаскивают подтягивать семантически близкое поближе и отталкивать далёкое подальше. Когда десять разных артефактов обсуждают один и тот же фичефлаг, эмбеддер делает свою работу хорошо: он сжимает их в плотный комок. Для тематического поиска это фича. Для поиска факта это та ещё проблема.
А компания за полгода активной работы генерит таких комков сотни. По каждому проекту, по каждому клиенту, по каждой версии роадмапа, по каждому инциденту. К моменту, когда корпус доползает до 500 000 документов, его embedding-пространство выглядит не как ровное звёздное небо, а как скопление галактик: плотные горячие кластеры похожего, дублирующегося, перекликающегося контента.
Один вопрос, десять документов, один правильный
Дальше начинается вторая половина проблемы. Документы из одного кластера говорят про одно событие, но содержат разные факты:
- тред в Slack: что в итоге решили
- тикет в Jira: к какому числу выкатить
- страница в Confluence: техспек и архитектура
- email-цепочка: что изначально просил клиент
- транскрипт встречи: почему вообще это обсуждали
Когда пользователь задаёт вопрос «когда у нас дедлайн по проекту X», ответ лежит ровно в одном из этих документов. Остальные тематически релевантны, но фактически бесполезны.
На корпусе в 5 000 документов про этот проект пишут 3-5 артефактов. Нужный почти гарантированно попадает в топ-K, потому что вокруг него мало шума.
На корпусе в 500 000 — 40-60 артефактов. Тот самый, с дедлайном, легко выпихивается из топ-K соседями, которые говорят про тот же проект, но не отвечают на вопрос. Они не «менее релевантны» в геометрическом смысле. По косинусной близости они почти такие же, как нужный. Просто фактически бесполезные.
Что показали измерения
Команда Onyx выпустила EnterpriseRAG-Bench, открытый датасет на 500 000+ синтетических корпоративных документов: Slack, Gmail, Jira, GitHub, Confluence, Google Drive, HubSpot, Fireflies, Linear. Со всеми реалистичными артефактами вроде неправильно подшитых файлов, near-duplicates, конфликтующих версий и метаданных «отправлено в нерабочее время».
Они прогнали один и тот же ретривер на пяти размерах корпуса, от 5K до 500K. Результаты:
- Vector search: 90.7% точности на 5K → 50.6% на 500K. Падение на 40.1 п.п.
- BM25: 85.8% → 68.4%. Падение на 17.4 п.п. Легче, но тоже больно.
И главное наблюдение, которое они задокументировали: на каждом масштабе плотность окрестности в пространстве эмбеддингов монотонно коррелирует с recall. Чем больше похожих документов вокруг релевантного, тем хуже его достают. Без исключений.
[ИНФОГРАФИКА — embed infographic.html сюда]
Это свойство пространства, а не косяк датасета
Тут было бы соблазнительно списать всё на конкретный датасет. Мол, у Onyx синтетика, near-duplicates руками накидали, на реальных данных так не бывает. Бывает. И за этим эффектом стоит фундаментальная штука, известная двадцать лет.
Aggarwal et al. ещё в 2001 году показали: при росте размерности расстояния между точками концентрируются. Разница между ближайшим и дальним соседом схлопывается до неразличимой. В 768-мерном пространстве (стандарт для современных эмбеддеров вроде OpenAI text-embedding-3, BGE-M3, E5-Mistral) почти все векторы оказываются примерно на одинаковом расстоянии от запроса. «Похожее» перестаёт быть «сильно похожим». Оно становится «чуть-чуть похожим, как и всё остальное».
Свежий препринт Lakshman et al. (февраль 2026) сформулировал проблему через понятие stability: насколько устойчивы ближайшие соседи запроса к малым возмущениям. Они эмпирически показали, что популярные ANN-индексы вроде HNSW и IVF деградируют именно на нестабильных датасетах. Top-10 recall может проседать кратно по сравнению с brute-force kNN на тех же данных.
Salesforce AI Research в работе HERB (бенчмарк для deep search по корпоративным данным) пошли дальше. На пуле всего из 39 190 документов (это, на минуточку, в 13 раз меньше Onyx-овских 500K) даже лучшие агентные RAG-методы получили средний скор 32.96. Главным боттлнеком авторы прямо назвали retrieval. Системы не вытаскивают все нужные доказательства, а потом строят рассуждение на частичном контексте. И галлюцинируют, разумеется.
Отдельная группа исследователей в работе по HNSW нашла ещё более жёсткий артефакт: recall зависит даже от порядка вставки векторов в индекс. Сдвиг до 12 п.п. только за счёт insertion order. То есть один и тот же датасет, один и тот же индекс, разный порядок добавления — разные результаты. И никто из юзеров об этом не предупреждён.
Почему BM25 держится лучше
Это контр-интуитивный момент, но в больших корпусах старичок BM25 часто обгоняет дорогой dense retrieval. Не потому что он умнее. Потому что у него нет проблемы концентрации в принципе: BM25 считает лексические совпадения, а не геометрию.
Если в запросе есть редкое слово, типа артикула, имени клиента, номера тикета или кодового названия проекта, BM25 это слово увидит и достанет нужный документ, даже если в кластере вокруг него ещё 50 семантически близких. Vector search в той же ситуации сигнал задушит, потому что для эмбеддера «PROJ-7341» и «PROJ-7339» это почти один и тот же токен.
Поэтому почти все production-ready RAG-пайплайны последних двух лет — гибридные. По данным Pradeep et al., объединение BM25 и dense retrieval через Reciprocal Rank Fusion даёт прирост recall в 15-30% относительно любой одиночной стратегии. Cross-encoder reranking на втором этапе добавляет ещё до 28% nDCG@10. И это даже до того, как мы упомянули domain-specific эмбеддеры: модели, дотюненные на конкретной предметке (юр, мед, финтех), обходят универсальные на 15-25% на специализированных запросах.
Получается стек: BM25 + dense + RRF + cross-encoder. Каждый слой бьёт по своему классу ошибок. Без одного из них пайплайн на масштабе будет течь.
Что с этим делать
Главный практический вывод грустный, но честный.
90% точности на 5K документов не говорят ничего о том, как ваш ретривер будет работать в продакшене. Бенчмарк, на котором вы тестируете RAG, должен быть масштаба вашего реального корпуса. Не «мы взяли тысячу документов и получили красивые цифры», а «мы прогнали 500K и посмотрели, где у нас ломается кривая recall».
Что конкретно стоит сделать:
- Замерить плотность окрестностей в собственном embedding-пространстве. Если у вас в корпусе много кластеров с десятками семантически близких документов, у вас не плохой ретривер. У вас задача такая.
- Поставить гибридный поиск, если ещё нет. BM25 на масштабе деградирует мягче, и при коллапсе dense это спасает. Бесплатно, в смысле GPU. Платно в смысле инженерных часов на нормальный fusion.
- Добавить cross-encoder reranking. На stage 2 он переоценивает топ-K и часто вытаскивает правильный документ из 5-10 близких соседей. Дорого по латенси, дёшево по точности.
- Прогнать свой пайплайн против EnterpriseRAG-Bench в обоих режимах: 5K и 500K. Посмотреть, где сломается ваша собственная кривая. Не «сломается ли», а где именно.
Весь EnterpriseRAG-Bench (датасет, вопросы, evaluation harness) лежит в опенсорсе. Можно брать и проверять.
И последнее. Если ваш RAG показывает 90% на тестовом наборе из тысячи документов, это не значит, что у вас отличный RAG. Это значит, что у вас отличный тестовый набор.
Ссылка на набор данных для тестов системы, чтобы не обнаруживать на проде, что все перестало работать.
У меня нет пока готового решения, на проекте, который мы ведем и где постепенно накапливаются десятки тысяч документов на юзера и близки сотни тысяч это уже начинает становиться проблемой и мы пока работаем с 2 или 3 слойным поиском по векторам. Но это тема отдельной статьи.