Векторний пошук на pgvector: де ламається RAG
На демонстраційному стенді RAG по внутрішній базі знань відповідає за частки секунди: поки корпус — це кілька тисяч фрагментів, pgvector порівнює вектор запиту з кожним і вкладається в прийнятний час відповіді. Межа з'являється непомітно.
Точний перебір векторів лінійний за розміром корпусу, і на сотнях тисяч фрагментів пошук починає конкурувати за процесор з іншими операціями бази — спочатку зростає хвіст затримок, потім загальний фон.
Другий симптом — витрати пам'яті на проміжні обчислення. Щоб віддати верхні збіги, база тримає в сортуванні всі відстані, а не лише потрібну верхівку; за паралельних запитів це витісняє кеш сторінок, і час відповіді перестає бути передбачуваним.
Варто додати фільтр за атрибутами — права доступу, дата документа, джерело — і план може піти в обхід індексу, навіть якщо той побудований.
Деградація пошуку при зростанні корпусу рідко проявляється як явна помилка. Частіше це тихе розходження: сьогодні в контекст моделі потрапили одні фрагменти, завтра — інші, і відповіді плавають від запиту до запиту.
Індексація векторів знімає обчислювальну стелю, але приносить свої налаштування — скільки зв'язків тримати в графі, скільки кандидатів переглядати на запит, — і за неправильних значень повнота видачі тихо зрізається на рідкісних, але важливих формулюваннях.
Окрема пастка — змішування двох режимів в одному індексі: частина корпусу оновлюється частіше, ніж перебудовується граф, і свіжі документи випадають з пошуку, хоча лежать у таблиці.
Тому якість тут вимірюють не на одному гарному питанні, а на наборі з відомими правильними відповідями — до і після кожної зміни параметрів. Як це закривається на практиці і в якому порядку, розбираємо далі.
Що дає RAG-пошук: терміни, точність, відмови
Чотири ефекти ми фіксуємо на прийманні, і кожен перевіряється на вашому корпусі: час відповіді пошуку, частка релевантних видач, зниклий клас відмов і обсяг ручного розбору результатів. Нижче — як це виходить і що саме замірюється, а не декларується.
Швидкість відповіді при зростанні корпусу
Без векторного індексу час відповіді зростає разом із корпусом: кожен запит порівнюється з усіма фрагментами, тому за десятикратного зростання документів пошук сповільнюється в ті самі рази.
Індекс HNSW у pgvector будує граф зв'язків між векторами, і обхід іде по ньому, а не по всій таблиці — час відповіді залишається майже сталим, поки обсяг корпусу зростає в рази.
Точність регулюється параметром обходу: чим він ширший, тим ближча видача до повного перебору, і це усвідомлений вибір, а не прихована деградація.
Частка релевантних видач і ручна перевірка
Другий замір — частка запитів, де потрібний фрагмент потрапив у перші рядки видачі.
Вона залежить від того, як документи нарізані: великі фрагменти розмивають сенс, дрібні втрачають контекст, тому розмір і перекриття ми підбираємо за вашим корпусом і додаємо фільтри за метаданими — датою, типом документа, підрозділом.
Клас відмов «знайшлося не те» зникає передбачувано: поряд із векторним пошуком ставимо повнотекстовий і переранжування, щоб збіги за ключовими словами й за сенсом не конкурували.
Разом із цим падає обсяг ручного розбору: аналітик перестає перевіряти кожну видачу й дивиться лише ті, де спрацював поріг низької впевненості.
Порівняння підходів до векторного пошуку на pgvector
Механізм пошуку визначає, як швидко зростає база знань і коли знадобиться переїзд на інший стек. Нижче — чотири схеми, між якими реально обирають під час розробки пошуку на pgvector усередині PostgreSQL.
| Варіант | Коли підходить | Обмеження |
|---|---|---|
| Точний перебір | До сотень тисяч векторів, потрібна еталонна повнота видачі | Час відповіді зростає лінійно: читається вся таблиця |
| Наближений індекс у базі | Мільйони векторів, втрата частки відсотків повноти допустима | Потрібне налаштування параметрів і періодичне перезбирання індексу |
| Зовнішнє векторне сховище | Десятки мільйонів векторів, окремий контур навантаження | Друге джерело даних, розсинхронізація, власний контур відмовостійкості |
| Гібридна схема з текстовим пошуком | Запити зі словами, артикулами, іменами | Складніше ранжування: дві видачі зводяться в один список |
Наближений індекс проти точного перебору
Точний перебір гарантує правильний топ видачі, але на великих обсягах читає всю таблицю, і час відповіді зростає лінійно. Наближений пошук за індексом відповідає кратно швидше, зате може пропустити частину близьких векторів.
Повноту регулюють параметром пошуку: її піднімають до рівня, на якому видача збігається з еталоном на тестовому наборі питань.
Коли зовнішнє векторне сховище надмірне
Окреме сховище виправдане, коли обсяг і навантаження не вміщаються в один контур бази. Якщо документи й вектори лежать поруч і оновлюються разом, винесення додає мережевий обмін, другу схему доступів і розсинхронізацію під час переіндексації.
Поки йдеться про мільйони рядків, достатньо індексу всередині бази, а гібридний пошук збирається звичайним повнотекстовим запитом поруч із векторним.
Етапи впровадження RAG-пошуку в продукт
Впровадження пошуку за документами рідко впирається у вибір бази — впирається в якість даних і передбачуваність оновлень. Маршрут іде від розбору корпусу й запитів до проєктування зберігання, і лише потім — до налаштування видачі.
- Розбір корпусу й запитів. Формати, обсяг, дублі, частота змін і те, як співробітники формулюють питання насправді.
- Схема зберігання векторів. У pgvector проєктуємо таблиці фрагментів і метадані для фільтрації за правами доступу та версіями документів.
- Стратегія пошуку й розбиття. Розмір і перекриття фрагментів, зважування, гібридний режим із повнотекстовим пошуком.
- Оновлення індексу. Переіндексація при зміні документів, видалення застарілих версій, контроль зростання сховища.
- Перевірка якості. Прогін набору контрольних запитів зі звіркою з еталонними фрагментами.
- Передача в експлуатацію. Регламенти, моніторинг, інструкції для команди підтримки.
Розбиття документів і підготовка векторів
Розмір фрагмента підбираємо під структуру тексту: регламенти й таблиці потребують одного підходу, суцільний текст — іншого. Перекриття зберігає сенс на межах, а метадані — документ, розділ, версія, права — відсікають зайве до самого пошуку.
Перевірка на наборі контрольних запитів
Збираємо реальні питання з еталонними фрагментами й дивимося, чи потрапляє потрібне джерело в перші рядки видачі. Розходження розбираємо й правимо розбиттям, вагами або стратегією пошуку.
Що передаємо на руки: конфігурація й регламенти
Пакет передачі — не тека з кодом, а комплект, за яким команда супроводу відтворює пошук без нас. Нижче — що саме фіксуємо в документації та конфігурації.
Схема зберігання й параметри індексу
- Схема таблиць: розбиття на фрагменти, типи полів, зв'язки з джерелом, політика видалення при відкликанні документа.
- Конфігурація векторного індексу в pgvector: тип, розмірність векторів, параметри побудови й пошуку, зафіксовані у файлі міграції.
- Опис розбиття тексту: розмір фрагмента, перекриття, правила обробки таблиць, заголовків і коду.
- Набір запитів-еталонів з очікуваною видачею — за ними перевіряють, що після перебудування індексу якість пошуку не знизилася.
Регламенти оновлення й доступу
- Регламент оновлення корпусу: періодичність і тригери переіндексації, порядок завантаження нових документів, обробка змінених і видалених.
- Політики доступу до документів і фрагментів: фільтри на рівні рядків і прив'язка прав до розділів — пошук не повертає те, що співробітнику не належить.
- Порядок перебудування індексу: прогін на копії, звірка з еталонними запитами, точка відкату.
- Інструкція для чергової зміни: типові збої, як відрізнити проблему завантаження від деградації пошуку, кому передавати далі.
Окремо — документація з пошуку: як формулювати запити, як читати метрики релевантності та які правки в корпусі потребують погодження з власником даних.
Кейс: пошук за базою знань на pgvector
Задача надійшла від команди підтримки: база знань на кілька тисяч документів — регламенти, інструкції, розбори інцидентів — зростала швидше, ніж її встигали описувати, а пошук за ключовими словами знаходив сторінку лише за точного збігу формулювання.
Як було до впровадження
Фахівці шукали відповідь очима за змістом: відкрити розділ, переглянути суміжні документи, повернутися назад.
На реальних зверненнях одне питання займало від двох до трьох хвилин, а потрібний розділ знаходився приблизно в чотирьох випадках із десяти — решту закривали питанням колезі в чаті.
Ручний пошук був основним способом роботи, і нові співробітники виходили на нормативну швидкість лише через кілька тижнів.
Що змінилося після налаштування індексу
Пошук перенесли в PostgreSQL: pgvector зберігає векторні представлення поруч із текстом документа, тому фільтри за відділом, типом і датою застосовуються в тому самому запиті, що й порівняння за близькістю.
Індекс налаштовували у два проходи — спочатку завантажили корпус і заміряли базову повноту видачі, потім підібрали параметри списків і кількість сегментів під розмір бази, щоб точність не падала при її зростанні.
Відповідь на питання тепер надходить за 2-4 секунди замість хвилин, влучання в потрібний розділ зросло з 40 до 85 % на тому самому наборі запитів, а звернень до ручного пошуку стало вчетверо менше.
Корпус оновлюється нічною переіндексацією: новий регламент потрапляє у видачу наступного дня без ручних правок.
Чим pgvector відрізняється від окремої векторної бази
pgvector — розширення PostgreSQL, за якого вектори лежать у тій самій таблиці, що й звичайні дані.
Пошук найближчих сусідів іде одним запитом разом із фільтром за метаданими — орендар, права доступу, свіжість документа; вектор і запис первинного документа потрапляють в одну транзакцію, а резервна копія залишається одна.
Окреме векторне сховище беруть під іншу задачу: коли пошуковий індекс не вміщається в пам'ять разом із робочими даними й потрібен пошук за розподіленим індексом.
Воно дає передбачувану затримку на дуже великих колекціях, але переносить складність в інтеграцію — з'являється друге джерело правди.
Основна ціна — синхронізація даних і векторів. Рядок і його вектор пов'язують фоновою задачею або потоком змін, і між записом та індексацією виникає вікно, коли документ уже оновлено, а пошук віддає старий фрагмент.
Окремо вирішуються видалення — інакше накопичуються осиротілі чанки — і повна переіндексація при зміні моделі ембедингів.
Далі — точки відмови: до бази додаються сервіс, його доступи, його бекап і його схема. Відмова бази й так зупинила б застосунок, а тепер ламатися можуть два незалежні контури.
Тому вибір роблять за порогом обсягу: поки корпус та індекс вкладаються в пам'ять вузла й пошук не конкурує з робочими запитами, одна база простіша — один бекап, одна транзакція, жодної синхронізації.
Розділяти варто там, де індекс перестає вміщатися або пошук починає заважати основній роботі з даними.
Технічні сумніви: обмеження й деградація
Поки корпус — десятки тисяч фрагментів, пошук у pgvector відповідає швидко й передбачувано. На сотнях тисяч ті самі запити йдуть помітно довше, а видача на перефразованих питаннях розходиться: один і той самий сенс, заданий іншими словами, приводить до різних документів.
Це наслідок того, що індекс будувався на іншому обсязі та структурі даних, ніж лежить у таблиці зараз, — і окремо стоїть питання роботи поверх уже розгорнутої системи.
Як зрозуміти, що індекс пора перебудовувати?
Ознаки: час відгуку зростає за незмінної кількості рядків, частка релевантних відповідей у верхівці видачі падає, після масових завантажень і видалень з'являється сміттєва периферія.
Індекс, побудований на неповному корпусі, втрачає точність у міру довантаження, тому перезбираємо його, коли основна маса документів на місці, — в окремій гілці, з перевіркою на контрольних питаннях і подальшим перемиканням.
Як ізолювати дані різних замовників в одній базі?
Розділяємо на рівні схеми та рядків: окремий розділ на замовника плюс обов'язковий фільтр за його ідентифікатором, застосовуваний до етапу ранжування. Додаємо політики доступу на рівні рядків у PostgreSQL і контроль на боці сервісу, який формує запит.
Перевірка — негативним тестом: запит від імені одного замовника не знаходить жодного чужого фрагмента.
Чому видача нестабільна на схожих формулюваннях?
Векторний пошук погано розрізняє близькі за сенсом запити, коли в корпусі багато однотипних документів. Допомагає поєднання з повнотекстовим пошуком, уточнювальний етап ранжування, поріг відсікання за близькістю й нормалізація запиту. Збережені результати частих формулювань знімають частину навантаження на базу.
Чи не просяде база під час роботи поверх готової системи?
Пошук читає дані окремо від основного навантаження: запити йдуть на репліку, важке перебудування — у вікно обслуговування. Схему з векторами додаємо поруч, наповнення йде фоном, пошук вмикаємо поступово. Відкат — вимкнення шару пошуку: решта системи продовжує працювати як раніше.
Обговоримо задачу: що підготувати до розмови
Щоб оцінка була предметною, а не «за векторний пошук загалом», до розмови достатньо кількох вступних. Частину уточнимо в листуванні, решту розберемо на зустрічі.
- Постановка задачі пошуку: які рішення людина ухвалює за видачею — знаходить конкретний пункт регламенту, порівнює умови чи просить синтез за кількома документами одразу. Від цього залежить, чи потрібен лише пошук за pgvector або шар генерації поверх нього.
- Приклади користувацьких запитів — 10–20 реальних формулювань, включно з короткими, з одруками й двома мовами. За ними налаштовуємо розбиття на фрагменти й розуміємо, де додатково потрібен пошук за ключовими словами.
- Обсяг і типи документів: скільки файлів, які формати, як швидко зростає корпус. Це визначає вибір індексу в pgvector і порядок переіндексації без зупинки сервісу.
- Вимоги до свіжості даних: допустиме відставання між публікацією документа та його появою у видачі. Якщо рахунок іде на хвилини, закладаємо потокове завантаження й чергу оновлення векторів.
- Схема доступу до інформації: хто які документи бачить. Права розмежовуємо фільтрами на рівні рядків у PostgreSQL, щоб вони застосовувалися до відбору найближчих векторів, а не після.
- Поточне навантаження й поведінка при збої: скільки запитів за секунду в піку, який час відповіді прийнятний і що сервіс робить при недоступності бази — віддає кеш чи чесно повідомляє про помилку.
Опишіть задачу у вільній формі — повернемося з оцінкою та планом робіт за етапами.







