Зміст
Демонстраційний RAG шукає «схожі» фрагменти по всьому індексу і лише потім питає, чи мав користувач право їх бачити. У продакшені це інцидент: заборонений текст уже встиг потрапити в переранжувальник, кеш, трасу і контекст моделі, а після відсікання видача порожня, хоча дозволені документи були нижче. Контроль доступу в RAG — це звуження області пошуку до вилучення, а не інструкція «не цитуй чужі договори».
Нижче — практична архітектура для команд, які виводять пошук корпоративних документів у продукт із кількома орендарями, ролями і класами конфіденційності. Стаття розвиває розділ про метадані в промисловій інженерії RAG і не переказує весь конвеєр завантаження, гібридного пошуку й оцінки: тут одна вісь — права до потрапляння тексту в модель.
Стійка одиниця в цьому контурі — область доступу, а не «схожий фрагмент».
Ключові висновки
Спочатку допустима множина, потім подібність. Орендар, роль, група і клас даних задають, що взагалі можна шукати. Релевантність ранжує лише всередині цієї області. Модель не є механізмом авторизації.
Фільтр після пошуку ламає і безпеку, і повноту. Глобальні перші k результатів часто заповнені чужими документами. Після відсікання лишається мало або нічого, а заборонені кандидати вже оброблені застосунком.
Ізоляція орендаря — не те саме, що список доступу всередині орендаря. Окремий індекс, простір імен або грубий фільтр tenant_id закривають міжорендарний витік. Тонкі права на документ, теку і групу потребують окремої моделі і часто двоступеневої перевірки.
Приховані канали важливіші за «забутий WHERE». Переранжувальник, семантичний кеш, журнали, еталонні набори і цитати «цей документ існує» розкривають дані без відповіді користувачеві.
Права старіють швидше за індекс. Відкликання ролі, звільнення, зміна групи і видалення файлу зобов’язані інвалідувати кеш і, за денормалізації, оновити атрибути точок — інакше система чесно шукає за вчорашньою політикою.
Що таке контроль доступу до вилучення
У звичайному вебзастосунку авторизація стоїть перед читанням рядка: SQL з обмеженням на рівні рядків, перевірка об’єкта в сервісі, відмова 403. RAG ламає цю звичку, бо «читання» виглядає як наближений пошук за векторами. Запит не називає ідентифікатор документа. Він просить схоже. Якщо індекс глобальний, схоже майже завжди знайдеться — зокрема в чужого орендаря.
Тому список керування доступом (ACL) у RAG — не декоративне поле поруч з ембедінгом. Це частина пошукового контракту. Без нього векторна база відповідає на інше питання: «що семантично близьке в світі всіх точок», а не «що близьке в світі цього користувача».
Практична межа така: будь-який компонент, який бачить текст фрагмента — первинний пошук, об’єднання рангів, переранжувальник, збирач контексту, генератор, кеш, журнал, набір для оцінки — перебуває всередині контуру авторизації. Якщо фрагмент туди потрапив, вважається, що його вже «прочитали». Сподіватися, що модель «не цитуватиме» заборонене, не можна: це ймовірнісна поведінка, а не контроль.
Тема стикується з організаційною схемою в архітектурі корпоративного RAG: власник джерела, клас даних і роль читача мають бути відомі до індексації, а не відновлюватися з промпту.
Чим це не є
Це не «промпт із правилами». Текст «ти не повинен розкривати персональні дані» не замінює фільтр. Модель може помилитися, її можна переконати сусіднім фрагментом, а заборонений текст уже стоїть у рахунку токенів і в журналі постачальника.
Це не те саме, що захист від промпт-ін’єкції. Список доступу відповідає на питання «чи мав суб’єкт право бачити це джерело». Ін’єкція відповідає на питання «чи може дозволений текст змусити сценарій зробити зайве». Потрібні обидва контури. Закритий чужий договір не повинен потрапити в пошук; свій шкідливий PDF усе одно має бути обмежений правами агента.
Це не лише tenant_id. Мультиоренда закриває межу між клієнтами продукту. Всередині одного клієнта юрист, бухгалтер і підрядник бачать різні теки. Змішування цих задач в одному полі «організація» дає хибне відчуття безпеки.
Чому «знайти, потім викинути» не працює
Схема виглядає привабливо: взяти перші 50 сусідів по всьому корпусу, викинути чужі, віддати моделі десяток. На маленькому демо з одним орендарем вона «працює». На реальному розподілі — ні.
Голод перших k результатів
Наближений пошук оптимізовано на глобальну близькість. Якщо 95 % індексу належить іншим орендарям або закритим текам, топ видачі заповнюється забороненим. Після фільтра лишається два фрагменти замість десяти — або нуль. Користувач бачить «я не знаю», хоча в його області є точний регламент. Команда підвищує top_k, зростає затримка, у застосунок потрапляє ще більше чужого тексту, а повнота всередині дозволеної множини так і не вимірюється.
Це не теоретичний край. Вибірковий фільтр — норма для SaaS: малий орендар, вузька роль, свіжий документ на тлі великого спільного корпусу.
Витік у компоненти застосунку
Навіть якщо API назовні нічого не повернув, заборонений фрагмент уже міг піти в:
- вхід переранжувальника (зокрема зовнішньої
LLM); - ключ або значення семантичного кешу;
- атрибути траси
OpenTelemetry/LangSmith; - тіло запиту до постачальника моделі;
- офлайн-набір «для налагодження якості».
Інцидент починається не з екрана чату, а з побічного сховища. Тому перевірка «користувач не побачив чуже» недостатня. Потрібен критерій: заборонений текст не обробляється за межами довіреного контуру авторизації.
Модель поза межею довіри
Будь-яка інструкція на кшталт «якщо документ не належить користувачеві, ігноруй його» припускає, що модель — суддя. Вона ним не є. Межа довіри — ваш сервіс, який не передає заборонене далі. Генератор отримує лише вже відфільтрований пакет доказів.
Три моделі ізоляції орендарів
Міжорендарна межа майже завжди грубіша, ніж ACL всередині клієнта. Її варто проєктувати окремо, інакше команда намагається одним полем groups закрити і «чужий холдинг», і «чужий відділ».
Нижче — три робочі моделі. Вибір залежить від числа орендарів, перекосу розмірів, вимог регулятора і ціни експлуатації, а не від улюбленого вендора.
| Модель | Що ізолює | Коли доречна | Чим платите |
|---|---|---|---|
| Окремий індекс / колекція | Фізично різні дані | Мало великих клієнтів, жорсткий контур, різні регіони | Операції, міграції схеми, холодний старт |
| Простір імен, шард, «тенант» рушія | Логічна перегородка всередині кластера | Сотні–тисячі орендарів, порівнянний розмір | Ліміти рушія, гарячі/холодні шарди |
Спільний індекс + обов’язковий фільтр tenant_id |
Логічна ізоляція запитом | Багато дрібних орендарів, єдина схема | Ризик забути фільтр, вплив сусіда на граф HNSW |
Окремий індекс дає найзрозумілішу історію для аудиту: цей клієнт не ділить диск і кеш з іншим. Ціна — сотні колекцій, різні версії схеми, складне розгортання моделі ембедінгів. Має сенс, коли орендарів мало, вони великі або зобов’язані жити у своєму контурі.
Простори імен (як у Pinecone), тенанти Weaviate і ключі партицій у Milvus — компроміс: рушій знає, що запити не повинні змішувати шарди. Qdrant в одному індексі часто йде через атрибут групи з індексом корисного навантаження і прапорцем «це орендар»: точки одного клієнта опиняються поряд на диску, фільтр дешевий. Це все ще логічний контур: помилка в клієнтському коді, який забув передати ідентифікатор, небезпечніша, ніж у моделі з окремою колекцією на кожен ключ.
Спільний індекс із фільтром масштабується на масу дрібних клієнтів, поки команда дисципліновано проштовхує tenant_id на кожному шляху: запис, пошук, видалення, перерахунок, вивантаження для оцінки. Одна «службова» ручка без фільтра перетворює платформу на спільний корпус.
На практиці часто гібрид: топ-N великих орендарів — свої колекції; довгий хвіст — спільний індекс з обов’язковим попереднім фільтром і перевіркою в CI, що невідфільтрований пошук у коді відсутній.
Перекіс і «шумний сусід»
Навіть за коректного фільтра великий орендар впливає на граф наближеного пошуку і на черги індексації. Якщо один клієнт заливає мільйони фрагментів, дрібний сусід отримує гіршу затримку і гіршу повноту за того самого ef. Має сенс різати за розміром: квота на документ, окремий шард, окрема черга завантаження. Мультиоренда — ще й економіка заліза, не лише ACL.
Ланцюжок: ідентичність, область, пошук
Робочий запит у промисловому RAG — не «ембедінг → top_k». Це конвеєр із явними кроками і слідом рішення.
1. Автентифікація суб’єкта
Сервіс знає, хто питає: користувач, сервісний обліковий запис агента, фонова задача переіндексації. У фонових задач своя роль: вони можуть читати сировину для завантаження, але не зобов’язані мати право відповідати в чаті від імені людини. Змішування цих суб’єктів — часте джерело «індексатор бачив усе, чат теж».
2. Розширення груп і атрибутів
Із постачальника ідентичності (OIDC, корпоративний каталог) сервіс отримує ролі, групи, відділ, регіон, ознаки підрядника. Не тягніть сирий JWT у фільтр векторної бази: строк життя токена, вкладені групи і вкладені теки рідко збігаються з тим, що лежить на точці. Побудуйте область доступу: нормалізований набір ідентифікаторів груп плюс версія політики.
Версія політики потрібна кешу й аудиту: «ця відповідь отримана за політики v17». Після відкликання ролі версія зростає, старі ключі кешу не потрапляють.
3. Грубий попередній фільтр у рушії
Мінімум, який зобов’язаний піти в пошуковий запит: tenant_id (або еквівалент простору імен) і, якщо є, клас конфіденційності / контур (персональні дані, комерційна таємниця, внутрішнє). Це звужує граф до обходу сусідів. Без цього кроку подальший тонкий ACL працює за отруєною вибіркою.
Якщо рушій уміє планувати фільтр — оцінити кардинальність предиката і за дуже вузької множини перейти до повного перебору за відфільтрованими точками — використовуйте це і вимірюйте. Сліпий HNSW по «острівцях» фільтра втрачає повноту; сліпий повний перебір по мільйонах точок убиває затримку. Планувальник потрібен не як магія, а як спостережуване рішення.
4. Пошук лише в допустимій області
Лексичний канал, векторний канал і їхнє злиття рангів працюють після грубого фільтра. Інакше BM25 по спільному лексичному індексу легко піднімає чужий договір, у якому збіглися номер і формулювання.
Переписування запиту й історія діалогу не розширюють область доступу. Вони уточнюють намір всередині вже обчисленої області. Якщо в історії майнув ідентифікатор чужого документа, це не привід шукати його «для контексту».
5. Тонка перевірка перед збиранням контексту
Групи на точці старіють. Складна політика «тека + проєкт + виняток підрядника + строк NDA» погано живе в денормалізованому масиві. Тому зрілий контур часто двоступеневий: грубий фільтр в індексі (орендар, клас, широкі групи) і остаточна перевірка актуальної політики — локально або через сервіс відносин (OpenFGA, SpiceDB і аналоги) — перед тим як фрагмент потрапить у переранжувальник і генератор.
Відмова перевірки закриває доступ. «Сервіс авторизації не відповів, пошукаємо без фільтра» — це відчинені двері, а не стійкість.
Надлишкова вибірка тут доречна: взяти з рушія в два–три рази більше кандидатів, ніж потрібно моделі, щоб тонкий фільтр не спустошив пакет. Але надлишок рахується всередині грубої області, а не по всьому світу.
Списки доступу на рівні документа і фрагмента
Точка в індексі — зазвичай фрагмент, а не файл. Політика майже завжди живе на документі, теці або картці в ECM. Це розходження — головне джерело помилок.
Документ як джерело істини для прав
Під час завантаження копіюйте на кожен фрагмент стійкий document_id, власника, групи читання і ознаки видалення. Пошук може фільтрувати за цими полями. Відкликання доступу до файлу має оновлювати всі його фрагменти або знімати їх з індексу однією транзакцією завантаження. Частково оновлений документ — діра: старий абзац ще доступний, новий уже ні, або навпаки.
Ієрархія тек: або матеріалізуйте підсумковий список груп на документі за кожної зміни дерева, або перевіряйте шлях на тонкій стадії. Тримати на фрагменті лише folder_id і на кожному запиті ходити в дерево з десяти таблиць — прямий удар по затримці.
Коли потрібен ACL на фрагмент
Має сенс, якщо всередині одного файлу різні грифи: публічне зведення і закритий додаток, таблиця з персональними рядками всередині спільного звіту. Тоді нарізка зобов’язана різати за межами політики, а не лише за довжиною токенів. Інакше «безпечний» абзац тягне в батька закриту таблицю — класика підготовки корпусу.
Якщо політика на весь файл однакова, не плодіть унікальні списки на тисячах фрагментів: ви лише збільшите вартість оновлення прав.
Ролі, атрибути, відносини
Доступ на основі ролей зручний, поки ролей мало і вони стабільні: legal, finance, contractor. Доступ на основі атрибутів краще стикується з грифом, регіоном і строком дії документа. Доступ на основі відносин (ReBAC) потрібен, коли право випливає з графа: «учасник проєкту бачить артефакти проєкту, поки перебуває в команді».
Для RAG небезпечна спроба на кожному запиті викликати «дай усі документи користувача» по мільйонному графу. Вибірка повної множини ідентифікаторів часто дорожча за сам пошук. Робоча схема: грубі атрибути на точці + пакетна перевірка кандидатів, що вижили, а не інверсія графа в попередній фільтр зі ста тисяч id.
Вікно розсинхронізації
Денормалізація груп на точці створює вікно: IdP уже відкликав роль, індекс ще не оновлений. Стисніть вікно подіями (черга «членство змінилося» → перерахунок зачеплених документів), тримайте версію політики в ключі кешу і на тонкій стадії завжди питайте актуальну політику для фінального пакета. Для найжорсткіших контурів тонка стадія — єдине джерело істини, індекс лише відсікає завідомо чуже.
Видалення користувача — окремий тест: сесії вбиті, кеш за його областю скинутий, фонові агенти з його токеном не продовжують ходити в пошук.
Приховані канали витоку
Команда лагодить фільтр у запиті до Qdrant і вважає задачу закритою. Дані йдуть стороною.
Переранжувальник
Перехресний кодувальник і тим більше переранжувальник на LLM читають текст. Якщо в пул потрапив чужий фрагмент «про всяк випадок, потім відфільтруємо», ви вже відправили його в інший процес або до постачальника. Правило те саме, що для генератора: у переранжувальник потрапляє лише допустима множина.
Кеш відповідей і семантичний кеш
Ключ «нормалізоване питання → відповідь» без орендаря і версії політики віддає чужу відповідь колезі зі схожим формулюванням. Навіть всередині одного орендаря юрист не повинен отримувати кеш, зібраний для фінансиста. Докладний розбір — у матеріалі про семантичний кеш і орендарів. Для RAG-кешу в ключ входять: орендар, область доступу або версія політики, версія індексу/корпусу, локаль, ідентифікатор маршруту генерації.
Потрапляння кешу за відкликаного права — окрема метрика, не «економія токенів».
Журнали, траси, еталонні набори
Налагоджувальна траса з повним текстом знайдених фрагментів — друге сховище персональних даних. Застосовуйте ті самі строки зберігання, маскування і контроль доступу, що до бойових документів. Еталонний набір для оцінки не повинен містити чужі для розмітника договори «бо так зручніше рахувати повноту». Розмічайте в межах ролі розмітника або на синтетичному корпусі зі штучними межами.
Цитати і факт існування
Навіть відмова може витекти. «Я не можу відповісти за договором №4412» повідомляє, що договір є. Для жорстких контурів політика відмови однакова: «у доступних вам джерелах цього немає», без ідентифікаторів, які користувач не мав права знати. Те саме для автодоповнення і «схожих питань».
Історія діалогу і переписування
Багатоходовий чат накопичує сутності. Переписування «розкажи докладніше про той звіт» не повинно розширювати пошук за межі поточної області, навіть якщо в минулому ході модератор вставив виняток. Історія — джерело наміру, не додатковий ACL.
Пошукові рушії: фільтри, повнота, компроміси
Вендори обіцяють «фільтрований векторний пошук». За формулюванням ховаються різні алгоритми, і від вибору залежить, отримаєте ви порожню видачу чи діряву.
Попередній фільтр у наївній формі: взяти всі точки, що задовольняють предикат, і шукати серед них — хоч повним перебором. Це коректно і вбиває бюджет затримки на мільйонах векторів.
Постфільтр: обійти HNSW як зазвичай, потім викинути непідходяще. Граф лишається зв’язним, повнота за глобальною подібністю хороша, повнота за дозволеною множиною — ні.
Сучасні рушії намагаються йти графом, не втрачаючи зв’язності на острівцях фільтра. Weaviate описує стратегію ACORN: розширювати окіл на два кроки, щоб обходити непідходящі вузли, не вимагаючи заздалегідь відомих предикатів. Qdrant додає зв’язки графа за проіндексованими атрибутами і за вузького предиката переходить до повного перебору по малій множині. Lucene та Elasticsearch розвивають споріднені ідеї для kNN з фільтром. pgvector з ітеративними сканами зменшує голод вибірки в PostgreSQL — там само природно лежить обмеження на рівні рядків для транзакційного контуру.
Жоден із цих механізмів не знімає з вас обов’язок виміряти повноту на своїх фільтрах. Вибірковість 1 % і 40 % поводяться по-різному. Перекіс орендарів ламає картину, яку показали в блозі вендора на рівномірних мітках.
Практичні наслідки:
- для межі орендаря надавайте перевагу механізму, який рушій вважає ізоляцією (простір імен, тенант, окрема колекція, індекс із
is_tenant), а не «сподіваємося, що постфільтра вистачить»; - для тонкого
ACLне чекайте, що графHNSWідеально переживе предикат із двадцяти груп — тримайте грубий шар в індексі і тонкий шар після надлишкової вибірки; - ганяйте зріз запитів із реальною кардинальністю: роль із трьома документами і роль із третиною корпусу.
Порівняння шлюзів і баз — окреме рішення зі строком перегляду, як в опорному гайді про промисловий RAG. Тут достатньо правила: якщо ви не можете пояснити, на якому етапі відсікається чужий орендар, у вас немає контролю доступу.
Як вимірювати витоки і якість пошуку
Безпека без повноти перетворюється на вічну відмову. Повнота без безпеки — на інцидент. Оцінюйте обидві властивості на одному контурі.
Набір ворожих випадків
Мінімум, який має жити в релізному наборі, а не в головах:
- запит, на який найкращий глобальний сусід — чужий орендар, а правильна відповідь є у свого;
- два орендарі з майже однаковими договорами (копіпаст шаблону);
- користувач без ролі після відкликання групи — із затримкою 0, 30, 300 секунд;
- видалений користувач і жива сесія;
- документ змінив гриф, фрагменти частково переіндексовані;
- порожня область (новий співробітник, немає файлів) — очікуємо чесну відмову, не «галюцинацію із сусіднього відділу»;
- агент із сервісною роллю не відповідає в користувацькому чаті повним корпусом.
Для кожного випадку зберігайте не лише еталонну відповідь, а ідентифікатори допустимих фрагментів і ознаку, що недопустимі не повинні з’явитися ні в трасі, ні в пакеті доказів.
Метрики
Повноту і точність пошуку рахуйте всередині допустимої множини, інакше ви оптимізуєте глобальний порівняльний тест і деградуєте продукт. Окремо: частка запитів із витоком (недопустимий chunk_id у будь-якому артефакті етапу), частка порожніх видач за ненульового допустимого корпусу, час збіжності після зміни членства, потрапляння кешу після відкликання.
Не просіть мовну модель вирішувати, «чи схоже це на витік». Порівняння ідентифікаторів детерміноване. Суддя доречний для якості формулювання після того, як контур доступу зелений.
Зв’язка з еталонним набором RAG: додайте шар розмітки «це питання заборонене для ролі X» так само явно, як шар «цей фрагмент — доказ».
Спостережуваність
У трасі мають бути: ідентифікатор суб’єкта, орендар, версія політики, тип фільтра (простір імен / атрибути точки / окремий індекс), кардинальність грубої множини якщо відома, число кандидатів до і після тонкої перевірки, ознака відмови авторизації. Тексти фрагментів у трасу — за грифом і з тим самим списком доступу, що в продукту, або не класти взагалі.
Типові помилки і план на чотири тижні
Типові помилки
Фільтр лише в застосунку після top_k. Виглядає швидко в прототипі. У прод дає порожні відповіді і витоки в побічні системи.
Один tenant_id замість моделі ролей. Клієнти ізольовані, співробітники всередині клієнта бачать усе. Для ERP і юридичного контуру цього мало.
ACL як текст у промпті. Красиво в демо, марно проти помилок моделі і проти журналів постачальника.
Кеш за текстом питання. Економить гроші і роздає чужі відповіді. Ключ без області доступу вважається дефектом, не оптимізацією.
Права лише на завантаженні, без подій відкликання. Індекс пам’ятає звільненого довше, ніж кадровий контур.
Службові скрипти оцінки без фільтра. Аналітик вивантажив «увесь продакшен», порахував nDCG — і залишив вивантаження в об’єктному сховищі.
Змішування ролі індексатора і ролі чату. Конвеєр завантаження читає все за визначенням. API відповіді не повинен ходити тим самим клієнтом бази.
Чотири тижні до контрольованого контуру
Тиждень 1 — інвентаризація та інваріанти. Список джерел, орендарів, ролей, класів даних. Назвіть інваріант: який компонент ніколи не бачить чужий текст. Зафіксуйте правило: при відмові авторизації доступ закривається. Намалюйте ключ кешу. Знайдіть у коді всі виклики пошуку без фільтра — це блокери випуску, не черга «колись».
Тиждень 2 — груба ізоляція. Увімкніть обов’язковий tenant_id або простори імен на записі й читанні. Додайте тест на міжорендарний запит-двійник. Забороніть невідфільтрований клієнт у прикладному коді (лінтер, обгортка SDK, окремий користувач БД без права послідовного сканування всієї таблиці — що доступно у вашому стеку).
Тиждень 3 — тонкий ACL і приховані канали. Матеріалізуйте групи на документі або підключіть пакетну перевірку кандидатів. Вичистіть переранжувальник, кеш, траси. Зберіть десять ворожих випадків у еталонний набір.
Тиждень 4 — вимірювання повноти під фільтром. Зніміть повноту всередині області для вузьких і широких ролей. Якщо вузька роль «сліпне», збільште надлишкову вибірку всередині області, змініть стратегію фільтра рушія або винесіть великих орендарів. Не піднімайте глобальний top_k «про всяк випадок».
Якщо контур потрібно зібрати не як ще один прототип, а як спостережуваний сервіс із контрактами даних, послуга впровадження ШІ закриває саме цей зв’язок: джерела, ролі, оцінка, запуск.
Часті питання
Чи потрібно фільтрувати до пошуку, чи достатньо перевірки перед відповіддю моделі?
Фільтрувати потрібно до вилучення і знову перед збиранням контексту, якщо політика складна. Перевірки «наприкінці» недостатньо: заборонений текст уже міг піти в кеш, трасу і переранжувальник, а видача — спорожніти.
Чим мультиоренда відрізняється від ACL?
Мультиоренда ізолює клієнтів продукту один від одного. ACL всередині орендаря розділяє ролі, теки і грифи. Це різні межі; однієї колонки org_id для обох задач зазвичай мало.
Чи можна доручити моделі не цитувати чужі документи?
Ні. Модель не є механізмом авторизації. Вона не контролює журнали постачальника і не гарантує відмову. Допустима множина формується кодом до виклику моделі.
Що обрати: окремий індекс чи фільтр у спільному?
Мало великих клієнтів і жорсткий регулятор — окремі колекції. Багато дрібних з однією схемою — спільний індекс з обов’язковим попереднім фільтром або тенантами рушія. Часто гібрид за розміром орендаря. Рішення переглядають, коли змінюється перекіс навантаження.
Чому після фільтра пошук «нічого не знаходить», хоча документи є?
Типовий постфільтр поверх глобального top_k: усі слоти зайняли чужі сусіди. Лікується попереднім фільтром, ізоляцією орендаря і повнотою, порахованою всередині області, а не збільшенням k «на око».
Як швидко мають відкликатися права?
Стільки, скільки вимагає ваш клас даних. Для жорсткого контуру тонка перевірка дивиться актуальну політику на кожен фінальний пакет, кеш ключується версією політики, подія відкликання перераховує денормалізовані групи. «До наступної повної переіндексації» для звільнення — неприпустимо.
Чи потрібен ACL на кожному фрагменті?
Якщо право одне на весь документ — ні, достатньо полів документа на фрагменті й атомарного оновлення. Якщо всередині файлу різні грифи — так, і нарізка має збігатися з межами політики.
Чи безпечний pgvector з обмеженням на рівні рядків?
RLS допомагає транзакційному контуру не забути фільтр у SQL. Це не скасовує налаштування наближеного пошуку з фільтрами і не замінює модель ролей. Поєднуйте обмеження рядків із перевіркою планів запиту і тестами на витік.
Чи закриває ACL промпт-ін’єкцію?
Ні. Він закриває несанкціоноване читання. Дозволений шкідливий документ усе ще може намагатися керувати агентом. Потрібні обидва контури: доступ до вилучення і обмеження дій після.
Що писати у відмові, щоб не розкрити існування документа?
Однакове формулювання без ідентифікаторів, яких користувач не мав права знати: у доступних джерелах відповіді немає. Не підтверджуйте номер договору, гриф і власника.
Подальше читання
- Промислова інженерія RAG у 2026 — увесь конвеєр; ця стаття закриває вісь прав.
- Архітектура корпоративного RAG — власники джерел і карта знань.
- Гібридний пошук і злиття рангів — лексичний і векторний канали після фільтра області.
- Еталонний набір для оцінки RAG — куди додати випадки витоку і відкликання прав.
- Семантичний кеш без витоку орендарів — ключі кешу як частина
ACL. - Промпт-ін’єкції в продакшені — сусідня загроза: дозволений, але ворожий текст.
MCPу продакшені — ідентичність і аудит, якщо пошук ходить в інструменти.
Висновок
Промисловий RAG перестає бути демо в той момент, коли в індексі з’являються другий орендар і друга роль. Далі якість відповіді невіддільна від питання, чи мала людина право побачити доказ. Це питання вирішується до обходу сусідів, ще раз — перед збиранням контексту, і окремо — в кеші, трасах і наборах оцінки.
Цього тижня зробіть одну перевірювану дію: знайдіть будь-який пошуковий виклик без обов’язкового ідентифікатора орендаря і закрийте його так, щоб обійти фільтр було не можна з прикладного коду. Потім додайте в еталонний набір одного міжорендарного двійника і одне відкликання ролі. Решта — нарощування тієї самої межі: тонкі групи, приховані канали, повнота всередині області.
Контроль доступу до вилучення — нудна інженерія. Саме вона відділяє корпоративний пошук від спільної купи ембедінгів із ввічливим промптом зверху.

