Перейти к содержимому
04 окт. 2025 г.·7 мин чтения

Разделение прав доступа для ИИ-ассистента без утечек

Разделение прав доступа для ИИ-ассистента помогает не смешивать поиск по знаниям и выдачу ответа. Разберем схему, ошибки и проверки перед запуском.

Разделение прав доступа для ИИ-ассистента без утечек

Где возникает риск

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

Обычно это выглядит так:

  • пользователь задает вопрос;
  • поиск находит похожие фрагменты;
  • модель получает их в контекст;
  • приложение проверяет права слишком поздно.

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

Почему запрета на вывод мало

Модель не знает, какой документ закрыт для конкретного сотрудника. Она работает с тем текстом, который ей дали. Если закрытый фрагмент попал в промпт, модель может процитировать его, пересказать смысл своими словами или выдать одну цифру, имя, лимит или срок. Для утечки этого уже достаточно.

Пользователь может не получить весь файл, но один удачный вопрос вроде "какой лимит согласования у отдела закупок?" или "как сформулирован пункт про штраф?" иногда раскрывает лишние данные.

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

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

Даже если команда использует единый OpenAI-совместимый эндпоинт или LLM-шлюз, сама проблема не исчезает. Маршрутизация запросов и контроль доступа к базе знаний - разные задачи. Первая отправляет запрос в нужную модель, вторая решает, какой текст вообще можно искать, читать и передавать в контекст.

Поэтому права для ассистента нужно закладывать до поиска и до генерации. Иначе защита сводится к надежде, что модель промолчит. Она не промолчит, если вы уже дали ей закрытый текст.

Какие права нужно разделить

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

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

Второе действие - чтение найденного фрагмента. Его лучше проверять отдельно для каждого куска текста, который поисковый слой вернул модели. Право на папку или тип документа не всегда дает право на конкретное вложение, приложение или версию. Один PDF может содержать и открытое описание процесса, и закрытое приложение с тарифами, персональными данными или условиями договора.

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

Есть и четвертая проверка, которую часто пропускают, - сохранение контекста в сессии. Права пользователя должны жить рядом не только с запросом, но и с историей диалога. Иначе сотрудник открыл чат с правами отдела закупок, потом переключился на роль подрядчика, а старая сессия продолжает подмешивать найденные раньше фрагменты.

На практике стоит держать как минимум четыре отдельных правила:

  • можно ли искать документ в индексе;
  • можно ли читать конкретный фрагмент;
  • можно ли цитировать или раскрывать его дословно;
  • можно ли сохранять этот контекст в текущей сессии.

Каждая операция получает свой check. Поиск делает один, отбор фрагментов второй, генерация ответа третий, память сессии четвертый. Да, код становится чуть сложнее. Зато потом не приходится разбирать инцидент, где бот "всего лишь кратко пересказал" закрытый документ.

Как построить проверку по шагам

Проверка прав должна идти минимум два раза: до поиска и перед самой отправкой ответа. Один фильтр в начале не спасает. Ассистент может честно найти нужный документ, а потом взять из него фрагмент, который этому пользователю уже нельзя видеть.

Сначала система должна понять, кто именно задал вопрос. Нужен не только user_id, но и роль, отдел, проект, канал входа, тип устройства и срок действия доступа. Для подрядчика, штатного сотрудника и руководителя один и тот же запрос означает разное. Фраза "покажи условия по договору" для юриста и для стажера не должна приводить к одному ответу.

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

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

Рабочая схема обычно выглядит так:

  1. Принять запрос и привязать его к конкретному пользователю и сессии.
  2. Подтянуть актуальные права из IAM, HR-системы или внутреннего каталога ролей.
  3. Отфильтровать документы по атрибутам доступа до поиска и во время поиска.
  4. Проверить каждый найденный фрагмент перед передачей в промпт модели.
  5. Сохранить решение: что запросили, что разрешили, что запретили и почему.

Если право не совпало, блокировать нужно не только прямую цитату. Модель нельзя просить "кратко пересказать" или "объяснить своими словами" закрытый текст. Для пользователя это та же утечка, только без кавычек. Безопасный вариант простой: ассистент сообщает, что по этому вопросу доступа нет, и предлагает запросить право или обратиться к владельцу документа.

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

Для спорных случаев нужен аудит-лог. Записывайте пользователя, его права, список найденных документов, итоговый набор разрешенных фрагментов и причину отказа по каждому заблокированному куску. Если запросы к моделям идут через AI Router, удобно держать такие записи рядом с маскированием PII и ограничениями по ключу. Но сам шлюз не заменяет ACL: проверку доступа к базе знаний все равно нужно делать до того, как текст попал в контекст модели.

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

Модель пересказывает закрытый текст не потому, что она что-то обошла. Обычно приложение само отдает ей слишком много: полный фрагмент документа, служебные поля, суммы, ФИО, комментарии юриста. Дальше ассистент просто формулирует ответ по тому, что увидел.

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

Что передавать модели

Перед отправкой в модель стоит сделать короткую очистку:

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

Такой фильтр нужен даже для безобидных вопросов. Пользователь может спросить: "Почему договор отправили на согласование?" Если модель увидит весь документ, она легко добавит в ответ сумму сделки, ФИО согласующего и спорный пункт из приложения. Сам вопрос этого не просил, но утечка уже случилась.

Полезно ограничивать и форму ответа. Если прав нет, ассистент не должен объяснять слишком много. Короткий отказ безопаснее длинного. Например: "У вас нет доступа к этому разделу документа". Если можно ответить в общем виде, пусть отвечает без цитат и без деталей: "Причина указана во внутреннем комментарии, но этот фрагмент вам недоступен".

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

Если у вас есть RAG-слой или шлюз вроде AI Router, смысл не меняется. Проверка прав должна сработать раньше, чем текст попадет в контекст модели. Тогда у модели просто не будет материала, который она может случайно выдать.

Пример из рабочего чата

Разведите шлюз и ACL
Маршрутизируйте модели через AI Router, а доступ к базе знаний проверяйте в своем приложении.

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

Менеджер из отдела продаж пишет: "Какие бонусы у сотрудников службы поддержки в этом квартале?" Ассистент находит HR-документ с таблицей выплат, условиями по грейдам и примерами расчета. Поиск сработал корректно, но роль менеджера не дает доступ к этому файлу.

Если права не разделены, модель легко перескажет закрытый текст своими словами. Она может не вставить прямую цитату, но все равно выдаст цифры, пороги KPI или формулировки из документа. Для пользователя это будет выглядеть как обычный ответ в чате.

Один вопрос, два разных ответа

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

Например: "Бонусы для другого отдела зависят от роли, грейда и выполнения плана. Точные суммы и условия доступны HR и руководителю подразделения". Такой ответ помогает, но не раскрывает закрытые детали.

Через час тот же вопрос задает сотрудник HR. У него есть доступ к документу, и система подтверждает это до генерации ответа. Теперь ассистент уже может сослаться на конкретный пункт и привести цифры из таблицы.

Ответ для HR будет другим: "Для специалистов поддержки уровня Middle бонус составляет 15% от оклада при выполнении KPI от 90%. Для Senior действует отдельная шкала". Здесь числа допустимы, потому что право на чтение уже подтверждено.

В этом и состоит контроль доступа к базе знаний. Не сам вопрос решает, что можно показать, а связка из трех вещей: кто спрашивает, какой документ найден и можно ли использовать его содержимое в ответе.

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

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

Где команды чаще ошибаются

Проверьте замену base_url
Смените адрес API и продолжайте работать с теми же SDK, кодом и промптами.

Ошибка обычно не в модели. Она появляется раньше, когда команда слишком грубо проверяет доступ. Пользователь видит папку или проект, и этого кажется достаточно. Но ассистент работает не с папкой, а с кусками текста из индекса. Если абзац из закрытого договора лежит рядом с открытой инструкцией, модель сама границу не увидит.

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

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

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

Еще одна частая ошибка звучит так: "мы запретили модели цитировать закрытые документы в системном промпте". Это слабая защита. Промпт только просит, а сервер решает. Если сервер уже положил закрытый текст в окно контекста, риск никуда не делся. Даже аккуратная модель может выдать факт, цифру, имя поля, срок договора или просто пересказать смысл.

Я бы относился к промпту как к дополнительному ремню, а не как к замку на двери. Настоящая проверка живет на сервере: до поиска, во время отбора фрагментов и еще раз перед ответом. Если у вас уже есть аудит-логи, маскирование PII или шлюз вроде AI Router, это помогает разбирать инциденты и держать данные в порядке. Но само по себе это не чинит права доступа.

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

Проверьте хотя бы три вещи:

  • фильтруете ли вы доступ на уровне каждого фрагмента, а не только папки или коллекции;
  • отделен ли внутренний индекс от открытой базы знаний;
  • очищаете ли вы кеш контекста при смене пользователя, роли и канала.

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

Быстрая проверка перед запуском

Перед запуском стоит провести короткий, но жесткий прогон на утечки. Многие команды смотрят только на то, получил ли пользователь ответ. Смотреть нужно на другое: что именно система искала, что ей разрешили прочитать и что она потом показала в чате.

Если эти три шага смешаны в одно правило, ошибка почти неизбежна. У ассистента могут быть разные права на поиск, чтение и цитирование. Пользователь может иметь право узнать, что по теме есть документ, но не видеть сам текст. Или видеть итог по договору, но не имя клиента, сумму и цитату из приложения.

Мини-проверка

Перед релизом обычно хватает пяти пунктов:

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

Один и тот же вопрос от разных ролей часто вскрывает слабое место за пять минут. Допустим, менеджер и бухгалтер спрашивают: "Какая скидка согласована для клиента по договору за март?" Бухгалтер может увидеть число и основание. Менеджер без нужного доступа должен получить нейтральный ответ вроде "Я не могу показать детали договора". Если в отказе мелькнула сумма, фамилия или кусок формулировки, проверка уже провалена.

Логи нужны не для галочки. По ним команда должна понимать, почему ассистент ответил или отказал. Если в журнале виден только итоговый текст, разбор инцидента затянется. Нужны хотя бы роль пользователя, список проверенных правил, идентификатор найденного документа и причина блокировки.

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

Если у вас уже есть аудит-логи и ограничения на уровне ключа, как это бывает в корпоративных LLM-шлюзах, такой прогон проходит быстрее. Но даже хорошая инфраструктура не спасает, если в команде не договорились, кто выдает права и кто потом смотрит журналы.

Что сделать дальше

Оставьте данные в Казахстане
Запускайте сценарии с data residency, когда чувствительные данные нельзя выносить из страны.

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

Сначала соберите матрицу ролей на одном листе. Не общей фразой вроде "сотрудник видит свое", а по действиям: кто может найти документ, кто может прочитать фрагмент, кто может получить краткий пересказ, кто может увидеть название источника, кто может передать файл в промпт. Такая таблица быстро показывает пробелы. Очень часто поиск уже открыт, а пересказ никто отдельно не запретил.

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

После этого зафиксируйте красные тесты. Они нужны, чтобы поймать утечку до релиза. Тест должен падать, если ассистент:

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

Дальше соберите защиту в одном месте. Аудит, маскирование PII и лимиты запросов должны работать вместе. Если они живут в разных сервисах и у разных команд, дыра часто остается между ними. Когда проверки идут одной цепочкой, проще увидеть, кто запросил документ, что система скрыла и в какой точке она остановила ответ.

Если команда уже ведет LLM-запросы через AI Router на airouter.kz, рядом удобно держать маршрутизацию моделей, аудит-логи, маскирование PII и ограничения по ключу. Это упрощает разбор инцидентов и помогает не размазывать контроль по разным частям стека. Но базовое правило не меняется: доступ к тексту проверяется раньше, чем документ или фрагмент попадет в модель.

Нормальный рабочий критерий простой: пользователь без прав не получает ни цитату, ни пересказ, ни даже мелкую подсказку о содержимом закрытого документа. Если система выдерживает это правило в ручных прогонах и тестах, ее уже можно пускать в живой чат.