Разработка RAG с pgvector: векторный поиск в PostgreSQL

База знаний растёт, а поиск по ней отвечает всё медленнее и неточнее — знакомая картина. Мы разрабатываем RAG-поиск на pgvector под ключ: собираем конвейер обработки документов, настраиваем векторный индекс и выдачу ответов со ссылками на источник. Сокращаем время поиска нужного фрагмента в разы и убираем выдуманные ответы.
Часто задаваемые вопросы

Векторный поиск на pgvector: где ломается RAG

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

Второй симптом — расход памяти на промежуточные вычисления. Чтобы отдать верхние совпадения, база держит в сортировке все расстояния, а не только нужную верхушку; при параллельных запросах это вытесняет кэш страниц, и время ответа перестаёт быть предсказуемым. Стоит добавить фильтр по атрибутам — права доступа, дата документа, источник — и план может пойти в обход индекса, даже если тот построен.

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

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

Что даёт RAG-поиск: сроки, точность, отказы

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

Скорость ответа при росте корпуса

Без векторного индекса время ответа растёт вместе с корпусом: каждый запрос сравнивается со всеми фрагментами, поэтому при десятикратном росте документов поиск замедляется в те же разы. Индекс HNSW в pgvector строит граф связей между векторами, и обход идёт по нему, а не по всей таблице — время ответа остаётся почти постоянным, пока объём корпуса растёт в разы. Точность регулируется параметром обхода: чем он шире, тем ближе выдача к полному перебору, и это осознанный выбор, а не скрытая деградация.

Доля релевантных выдач и ручная проверка

Второй замер — доля запросов, где нужный фрагмент попал в первые строки выдачи. Она зависит от того, как документы нарезаны: крупные фрагменты размывают смысл, мелкие теряют контекст, поэтому размер и перекрытие мы подбираем по вашему корпусу и добавляем фильтры по метаданным — дате, типу документа, подразделению. Класс отказов «нашлось не то» уходит предсказуемо: рядом с векторным поиском ставим полнотекстовый и переранжирование, чтобы совпадения по ключевым словам и по смыслу не конкурировали.

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

Сравнение подходов к векторному поиску на pgvector

Механизм поиска определяет, как быстро растёт база знаний и когда потребуется переезд на другой стек. Ниже — четыре схемы, между которыми реально выбирают при разработке поиска на pgvector внутри PostgreSQL.

Вариант Когда подходит Ограничения
Точный перебор До сотен тысяч векторов, нужна эталонная полнота выдачи Время ответа растёт линейно: читается вся таблица
Приближённый индекс в базе Миллионы векторов, потеря доли процентов полноты допустима Нужна настройка параметров и периодическая пересборка индекса
Внешнее векторное хранилище Десятки миллионов векторов, отдельный контур нагрузки Второй источник данных, рассинхронизация, свой контур отказоустойчивости
Гибридная схема с текстовым поиском Запросы со словами, артикулами, именами Сложнее ранжирование: две выдачи сводятся в один список

Приближённый индекс против точного перебора

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

Когда внешнее векторное хранилище избыточно

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

Этапы внедрения RAG-поиска в продукт

Внедрение поиска по документам редко упирается в выбор базы — упирается в качество данных и предсказуемость обновлений. Маршрут идёт от разбора корпуса и запросов к проектированию хранения, и только потом — к настройке выдачи.

  1. Разбор корпуса и запросов. Форматы, объём, дубли, частота изменений и то, как сотрудники формулируют вопросы на самом деле.
  2. Схема хранения векторов. В pgvector проектируем таблицы фрагментов и метаданные для фильтрации по правам доступа и версиям документов.
  3. Стратегия поиска и разбиения. Размер и перекрытие фрагментов, взвешивание, гибридный режим с полнотекстовым поиском.
  4. Обновление индекса. Переиндексация при изменении документов, удаление устаревших версий, контроль роста хранилища.
  5. Проверка качества. Прогон набора контрольных запросов со сверкой с эталонными фрагментами.
  6. Передача в эксплуатацию. Регламенты, мониторинг, инструкции для команды поддержки.

Разбиение документов и подготовка векторов

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

Проверка на наборе контрольных запросов

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

Что передаём на руки: конфигурация и регламенты

Пакет передачи — не папка с кодом, а комплект, по которому команда сопровождения воспроизводит поиск без нас. Ниже — что именно фиксируем в документации и конфигурации.

Схема хранения и параметры индекса

  • Схема таблиц: разбиение на фрагменты, типы полей, связи с источником, политика удаления при отзыве документа.
  • Конфигурация векторного индекса в pgvector: тип, размерность векторов, параметры построения и поиска, зафиксированные в файле миграции.
  • Описание разбиения текста: размер фрагмента, перекрытие, правила обработки таблиц, заголовков и кода.
  • Набор запросов-эталонов с ожидаемой выдачей — по ним проверяют, что после перестроения индекса качество поиска не просело.

Регламенты обновления и доступа

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

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

Кейс: поиск по базе знаний на pgvector

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

Как было до внедрения

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

Что изменилось после настройки индекса

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

Ответ на вопрос теперь приходит за 2-4 секунды вместо минут, попадание в нужный раздел выросло с 40 до 85 % на том же наборе запросов, а обращений к ручному поиску стало вчетверо меньше. Корпус обновляется ночной переиндексацией: новый регламент попадает в выдачу на следующий день без ручных правок.

Чем pgvector отличается от отдельной векторной базы

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

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

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

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

Технические сомнения: ограничения и деградация

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

Как понять, что индекс пора перестраивать?

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

Как изолировать данные разных заказчиков в одной базе?

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

Почему выдача нестабильна на похожих формулировках?

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

Не просядет ли база при работе поверх готовой системы?

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

Обсудим задачу: что подготовить к разговору

Чтобы оценка была предметной, а не «за векторный поиск в целом», к разговору достаточно нескольких вводных. Часть уточним в переписке, остальное разберём на встрече.

  • Постановка задачи поиска: какие решения человек принимает по выдаче — находит конкретный пункт регламента, сравнивает условия или просит синтез по нескольким документам сразу. От этого зависит, нужен ли только поиск по pgvector или слой генерации поверх него.
  • Примеры пользовательских запросов — 10–20 реальных формулировок, включая короткие, с опечатками и на двух языках. По ним настраиваем разбиение на фрагменты и понимаем, где дополнительно нужен поиск по ключевым словам.
  • Объём и типы документов: сколько файлов, какие форматы, как быстро растёт корпус. Это определяет выбор индекса в pgvector и порядок переиндексации без остановки сервиса.
  • Требования к свежести данных: допустимое отставание между публикацией документа и появлением его в выдаче. Если счёт идёт на минуты, закладываем потоковую загрузку и очередь обновления векторов.
  • Схема доступа к информации: кто какие документы видит. Права разграничиваем фильтрами на уровне строк в PostgreSQL, чтобы они применялись до отбора ближайших векторов, а не после.
  • Текущая нагрузка и поведение при сбое: сколько запросов в секунду в пике, какое время ответа приемлемо и что сервис делает при недоступности базы — отдаёт кэш или честно сообщает об ошибке.

Опишите задачу в свободной форме — вернёмся с оценкой и планом работ по этапам.

Подход Основа Когда уместен Что даёт Ограничения Сроки внедрения
Полный перебор по векторам Векторы лежат в обычных таблицах, приближённый поиск не используется База знаний до нескольких десятков тысяч фрагментов, важна эталонная точность Ни один фрагмент не теряется, выдача предсказуема Время ответа растёт вместе с объёмом базы; на больших массивах скорость падает 1–2 недели
Приближённый векторный индекс в PostgreSQL Векторный индекс внутри pgvector, данные в одной базе с основным продуктом Основной сценарий: поиск по документам и базе знаний там, где база уже работает Точность близка к эталонной при кратном ускорении ответа; один контур данных, права и резервные копии как у обычных таблиц Нужна настройка параметров индекса и повторная сборка при массовой загрузке 2–4 недели
Гибрид: полнотекстовый поиск + векторный Совместный поиск по словам и по смыслу, результаты объединяются Смешанные запросы: точные термины, артикулы, названия и вопросы «своими словами» Точные совпадения не теряются, смысловые находятся; меньше пустых ответов Требуется настройка весов и порядка объединения результатов 3–5 недель
Переранжирование найденного Модель переранжирования поверх первичной выдачи Нужна высокая точность верхних позиций ответа Доля релевантных фрагментов в начале выдачи заметно выше Дополнительный шаг обработки удлиняет ответ 2–4 недели
Отдельное хранилище векторов Специализированная векторная база рядом с основной Объёмы в десятки миллионов фрагментов, под сервис выделена отдельная команда Высокая скорость на больших объёмах, готовое масштабирование Второй контур данных: синхронизация, резервные копии, доступы, отдельная эксплуатация 6–10 недель
Готовый внешний сервис поиска Внешняя платформа, данные уходят за пределы контура Быстрый запуск, если нет требований к хранению данных внутри Минимум своей эксплуатации, запуск в короткий срок Зависимость от чужого контура, ограничения по чувствительным данным, сложнее менять логику поиска 1–3 недели
  • Считают, что задачу решает сама загрузка документов: если файлы не разбиты на смысловые фрагменты, поиск возвращает обрывки в середине мысли и ответ получается бессвязным.
  • Проверяют качество на двух-трёх вопросах, которые сами же и придумали. Нужен набор контрольных запросов с заранее известными верными ответами — иначе после любой правки непонятно, стало лучше или хуже.
  • Сваливают в одно хранилище документы разного возраста и назначения: действующие регламенты, черновики, переписку, отменённые приказы. Выдача засоряется устаревшим, и пользователь перестаёт доверять системе.
  • Не разделяют доступ: в общий набор попадают материалы разных отделов и заказчиков, и поиск начинает показывать чужие данные тому, кому они не предназначены.
  • Меняют способ построения векторов, но не пересчитывают уже загруженные записи. Старые и новые документы оказываются в разных системах координат, и поиск по ним перестаёт работать.
  • Ждут, что система сама поймёт короткий разговорный вопрос. Без обработки запроса пользователя — уточнения формулировки, расширения сокращений, отсечения лишних слов — выдача приходит пустой или не по теме.
  • Оставляют только поиск и убирают проверку найденного. Без повторной сортировки и порога по теме в ответ попадают материалы с формальным совпадением слов, но противоположным смыслом.
  • Загружают весь архив «на всякий случай» и ничего не удаляют. Объём растёт, а ответы начинают противоречить друг другу, потому что в выдачу попадают взаимоисключающие версии одного документа.

Направления AI-разработки

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    815
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139