DLP для LLM: как обезличивать запросы и сохранять поиск по сотрудникам
Корпоративные LLM-системы должны одновременно решать две противоположные задачи: защищать персональные данные и сохранять практическую ценность запросов. Особенно сложно это становится в сценариях, где модель должна искать документы, задачи, переписку или встречи конкретного сотрудника.
Представим запрос: "Найди последние задачи Петрова по проекту X и сравни их с обсуждением на встречах". Если перед отправкой во внешнюю модель заменить фамилию на `NAME_1`, а в следующем сообщении того же диалога использовать уже `NAME_7`, поиск может потерять связь между запросами. Если же передать фамилию без изменений, персональные данные покинут доверенный контур.
Решение заключается не в полном удалении сущностей, а в контролируемой псевдонимизации. Исходное значение заменяется типизированным токеном, а соответствие между токеном и реальным объектом хранится внутри защищённого шлюза. Например, модель получает `[PERSON_1]`, но не видит, что за этим обозначением скрывается конкретный сотрудник.
Важно различать анонимизацию и псевдонимизацию. При анонимизации восстановление исходных данных невозможно или практически нереализуемо. При псевдонимизации существует дополнительная таблица соответствий, позволяющая вернуть исходное значение. Поэтому mapping - отображение между токенами и реальными данными - является чувствительной информацией и должен защищаться так же строго, как исходные персональные данные.
Почему простого `NAME_1` недостаточно
Наивная схема обычно строится по принципу: система находит имя и заменяет его на первый доступный номер. У такого подхода есть несколько серьёзных проблем.
Во-первых, нумерация часто действует только в рамках одного сообщения. Один и тот же человек в разных запросах получает разные обозначения. Для короткой переписки это уже неудобно, а в многошаговом агентном сценарии приводит к ошибкам: модель перестаёт понимать, что речь идёт об одном сотруднике.
Во-вторых, маркер не содержит информации о типе сущности. Для языковой модели `[NAME_1]`, номер телефона, логин и название компании могут выглядеть как одинаковые фрагменты текста. В результате ухудшается классификация намерения, поиск по индексам и выбор допустимых действий.
В-третьих, исчезают связи между объектами. Например, система может не понять, что сотрудник, его корпоративный логин и автор задачи - одна и та же сущность. Поэтому обезличивание должно скрывать исходное значение, но не разрушать идентичность объекта внутри разрешённого контекста.
Такой механизм можно сравнить с внешним ключом в базе данных. Он не раскрывает содержимое записи, но позволяет соединить несколько таблиц. Отличие в том, что токен нельзя использовать для восстановления данных вне контролируемой серверной логики.
Архитектура защищённого шлюза
Практическая схема может выглядеть следующим образом:
1. Пользователь отправляет запрос во внутренний gateway.
2. Система проверяет права доступа и запускает DLP-анализ.
3. Детектор находит персональные данные и определяет типы сущностей.
4. Для каждой сущности создаётся или выбирается стабильный псевдоним.
5. Внешней LLM передаётся очищенный запрос.
6. Поисковый слой использует внутреннее соответствие токена и реального объекта.
7. Ответ модели проходит проверку перед обратной регидрацией.
8. Пользователь получает результат с исходными значениями только в пределах своих прав.
Mapping не следует помещать в prompt или передавать модели отдельным сообщением. Это серверное состояние сессии, а не часть диалога. Внутренний контур должен хранить его отдельно от истории запросов и ограничивать доступ к нему.
Например, срок жизни соответствий может составлять два часа, а максимальный размер - 500 токенов. Полезен режим `insert-only`: после создания соответствие нельзя незаметно перезаписать. Это предотвращает ситуации, когда один и тот же маркер начинает обозначать разных людей в разных этапах обработки.
Для расследования инцидентов mapping можно хранить в зашифрованном виде. Право на раскрытие персональных данных следует отделять от обычного доступа к системе. Операция восстановления исходного значения должна требовать специального разрешения вроде `pii_reveal`, фиксироваться в журнале аудита и выполняться только по необходимости.
Типизированные токены вместо случайных замен
Оптимальный токен должен быть понятен модели по структуре, но не раскрывать исходные данные. Примеры:
- `[PERSON_1]` - сотрудник;
- `[EMAIL_1]` - электронный адрес;
- `[PHONE_1]` - телефон;
- `[PROJECT_2]` - проект;
- `[ORG_1]` - организация;
- `[DATE_3]` - дата.
Предсказуемый формат помогает модели не искажать маркеры при генерации ответа, структурированного JSON или промежуточных рассуждений. При этом безопасность не должна зависеть от того, насколько трудно угадать строку. Если пользователь вручную напечатает `[PERSON_1]`, шлюз не должен автоматически подставлять настоящее имя. Регидрации подлежат только токены, созданные и зарегистрированные в mapping текущего запроса или сессии.
Случайный шифртекст не всегда является лучшим решением. Длинные криптографические строки сложнее обрабатывать языковой модели, повышают вероятность опечаток и могут нарушить формат ответа. Криптографическая стойкость самого токена не спасает архитектуру, если ключ или таблица соответствий доступны рядом с prompt.
Где справочник не должен "разрешать всё"
Корпоративный справочник - важный компонент, но его нельзя превращать в универсальный механизм раскрытия данных. Наличие сотрудника в каталоге ещё не означает, что любая модель, агент или пользователь вправе получить его имя, телефон, должность или историю активности.
Нужно разделять несколько уровней:
- право найти сущность;
- право использовать её в поисковом запросе;
- право получить связанные документы;
- право увидеть персональные атрибуты;
- право раскрыть исходное значение в финальном ответе.
Например, сотруднику может быть разрешено найти задачи коллеги в рамках проекта, но запрещено получить личный номер телефона. Модель должна получать не больше информации, чем необходимо для выполнения конкретной операции.
Четыре вердикта вместо одной блокировки
DLP не обязательно должен работать по схеме "разрешить или запретить". Для более точного управления полезно использовать минимум четыре результата проверки:
1. Разрешить - запрос безопасен и может выполняться без изменений.
2. Обезличить - персональные данные заменяются токенами, после чего запрос продолжается.
3. Ограничить - операция разрешена частично, например только поиск по проекту без раскрытия контактов.
4. Заблокировать - риск слишком высок либо отсутствуют необходимые права.
Такая модель уменьшает количество ложных срабатываний. Фамилия в запросе "найди задачи Петрова" не обязательно должна приводить к блокировке: её можно заменить на идентификатор сотрудника и выполнить поиск в разрешённом индексе. А вот запрос на выгрузку телефонов всех сотрудников должен обрабатываться гораздо строже.
Обратный путь сложнее прямого
Заменить имя на токен проще, чем безопасно вернуть имя в ответ. Модель может изменить маркер, добавить к нему знаки препинания, склонить его или сгенерировать новый токен, которого не было в исходном mapping.
Поэтому перед регидрацией нужно:
- проверять, существует ли токен в текущей сессии;
- учитывать точные границы сущности;
- отклонять неизвестные или изменённые маркеры;
- контролировать, имеет ли пользователь право видеть исходное значение;
- не восстанавливать данные в свободном тексте без дополнительной проверки;
- отдельно проверять поля JSON и результаты инструментов.
Если модель вернула `[PERSON_1]`, которого нет в текущем mapping, система должна оставить его как обычный текст или удалить, но не пытаться угадать, кто за ним скрывается. Это одно из ключевых правил, защищающих от подмены и утечек.
Entity resolution: одна сущность в нужном контексте
Обезличивание должно учитывать не только текстовую форму, но и смысловую идентичность. У одного человека может быть фамилия, имя, логин, адрес электронной почты и внутренний идентификатор. Если каждый вариант обрабатывается отдельно, поиск будет неполным.
Слой entity resolution должен сопоставлять такие значения с единой внутренней сущностью, если это разрешено политиками доступа. При этом совпадение по одной фамилии не всегда достаточно: в компании могут работать несколько Петровых. Для разрешения неоднозначности используются подразделение, проект, должность, логин или контекст запроса.
Если уверенность низкая, система должна запросить уточнение или вернуть несколько допустимых вариантов без раскрытия лишних данных. Автоматически выбирать первого найденного сотрудника опасно: ошибка может привести к неправильному поиску и раскрытию чужой информации.
Как не сломать поиск
Для проверки качества нужны не только тесты на обнаружение PII, но и сценарии на сохранение смысла. В тестовый набор стоит включить:
- повторное упоминание одного человека в одном диалоге;
- использование фамилии, имени и логина;
- несколько сотрудников с одинаковой фамилией;
- поиск по задачам, встречам и документам;
- запросы с изменённым порядком слов;
- склонение и сокращённые формы;
- несколько языков;
- параллельные сессии разных пользователей;
- истёкшие mapping;
- неизвестные токены в ответе модели.
Оценивать нужно сразу несколько показателей: полноту обнаружения персональных данных, число ложных срабатываний, точность сопоставления сущностей, долю успешных поисковых запросов и количество некорректных регидраций.
Полезно проводить сравнительное тестирование: сначала выполнять поиск по исходным данным внутри доверенного контура, затем - по псевдонимизированному запросу. Если результаты заметно расходятся, проблема может быть в типизации токенов, разрешении сущностей, индексации или недостаточном контексте для поискового сервиса.
Практический чек-лист
Перед запуском DLP-шлюза для LLM стоит проверить:
- mapping не передаётся в prompt;
- соответствия изолированы по сессиям и пользователям;
- повторная сущность получает стабильный токен;
- каждому токену назначен тип;
- неизвестные маркеры не регидрируются;
- доступ к раскрытию PII отделён от обычных прав;
- все операции восстановления журналируются;
- срок жизни mapping ограничен;
- превышение лимита токенов обрабатывается явно;
- поисковый индекс работает с внутренними идентификаторами;
- агент не может самостоятельно запросить полный справочник;
- ответы и tool-вызовы проходят повторную DLP-проверку;
- предусмотрен аварийный режим с запретом раскрытия;
- есть набор тестов на неоднозначные имена и одинаковые фамилии.
Главный принцип такой архитектуры прост: внешней модели не нужно знать реальные имена, но системе необходимо сохранить устойчивые связи между сущностями. Для этого псевдоним должен быть стабильным, типизированным и действовать только в ограниченном контексте, а таблица соответствий - находиться под контролем защищённого шлюза.
Так удаётся совместить приватность и полезность: LLM работает с понятными объектами, корпоративный поиск сохраняет точность, а персональные данные не покидают доверенную зону без явного разрешения.
