ESPN DeportesKawhi Leonard: ¿Cómo será recordado cuando finalice su carrera?Daily MaverickTHE GATHERING 2026: Fixing failing cities is in business’s own interest, leaders sayESPN'Gonna let them do them': Cunningham ignoring Kanter Freedom, Whiteוואלהחיל האוויר בגל תקיפות נגד יעדי טרור בדרום לבנוןRTP DesportoPortugal perde com Espanha e falha meias da Liga Europeia de futebol de praiaInquirerBojie Dy hails Pisa improvement: ‘It’s a welcome news’BlickVon Pfäffikon ZH über Siders VS bis Susch GR: Das sind die schlimmsten Busunglücke der Schweiz20 Minuten«Wir sind ein gutes Team»: Annemarie Carpendale lobt ihren WayneAntara NewsIndian envoy: BRICS agenda aligns with Indonesia bilateral focusBillboardFlavor Flav Shares Personal 9/11 Memory & Honors ‘Heroes Who Ran Toward Danger’ on 25th AnniversaryGlobal News13-year-old charged after firearm seized at Ajax hotel: Durham policeComplete Sports2026 US Open Final: Rybakina, Sabalenka Target Grand Slam Title
The Daily Newsstand · Free, Always
Friday, September 11, 2026

DLP для LLM: как обезличивать запросы и не ломать поиск по сотрудникам

Translate

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

Представьте: сотрудник пишет «найди последние задачи Петрова по проекту X и сравни их с обсуждением на встречах». Если заменить Петрова на NAME_1, а в соседнем сообщении — на случайный NAME_7, поиск перестанет понимать, что речь об одном человеке. Если оставить имя как есть, оно может уйти за пределы доверенного контура. Получается конфликт между приватностью и полезностью.

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

Почему NAME_1 недостаточно

У наивной схемы два дефекта.

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

Второй — потеря типа и связей. Для LLM строка NAME_1 почти ничего не говорит. Телефон, фамилия, организация и логин превращаются в одинаковые куски текста. Модель может продолжить фразу, но хуже сопоставляет сущность с данными из поиска и не понимает, какие операции допустимы.

Поэтому полезно разделить две задачи:

1. Скрыть значение. Внешней модели не нужно видеть «Андрей Петров».
2. Сохранить идентичность сущности. Внутри одного запроса и связанных результатов нужно понимать, что [PERSON_1] — тот же объект, что и в найденных документах.

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

Базовая схема: mapping живёт рядом с шлюзом

Внутренний контур AGIMA устроен как gateway перед LLM: запрос проходит авторизацию, проверку DLP, деперсонализатор, затем отправляется провайдеру. На обратном пути ответ проходит контролируемую регидрацию. Идентичность пользователя передаётся служебным заголовком и правами прокси, а не текстом, который может прочитать или подменить модель.

Упрощённый путь выглядит так:

Запрос проходит детектор, разрешение сущности и policy engine; наружу уходит типизированный prompt, а регидрация ответа выполняется только по mapping текущего запроса и правам

Запрос проходит детектор, разрешение сущности и policy engine; наружу уходит типизированный prompt, а регидрация ответа выполняется только по mapping текущего запроса и правам

req_map — это не словарь, который мы подкладываем в prompt, а серверное состояние сессии. В проде session-mapping живёт два часа, ограничен 500 токенами и работает в режиме insert-only: повторный токен не перезаписывает значение. Контекст не смешивается с mapping другой сессии. Если требуется расследование инцидента, mapping хранится шифрованно; доступ к раскрытию отделён правом pii_reveal и аудитируется.

У токена может быть предсказуемый формат — например, [PERSON_1]. Это повышает шанс, что модель не исказит его в reasoning-контексте или при генерации JSON. Безопасность при этом должна опираться не на секретность текста токена, а на недоступность самого mapping. Если атакующий напечатает [PERSON_1] вручную, шлюз не должен «угадывать» значение: регидрируются только токены, присутствующие в req_map текущего запроса.

Именно поэтому случайный шифртекст не всегда лучше. Он сложнее для модели, а его криптографические свойства не спасают архитектуру, если ключ или таблица соответствий лежат рядом с prompt. В документации Microsoft Presidio похожее разделение видно на уровне операторов: есть замена, маскирование, шифрование и обратная расшифровка; stateful-сессии и безопасное хранение состояния остаются ответственностью интегратора.

Entity resolution: один сотрудник — одна сущность в нужном контексте

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

Мы решали это не ещё одной большой моделью, а справочником и правилами сопоставления. В дев-тенанте справочник включает несколько сотен сотрудников и клиентских юрлиц из внутренних систем и три десятка внутренних инструментов. Записи разделены на employee, legal_entity и other, пополняются и отзываются через API/UI администратором тенанта, а транслитерация и леммы считаются на стороне матчера. Подавление прозрачно: reason=directory отдельно подсвечивается в UI.

Для нового запроса pipeline может выглядеть так:

1. Детектор находит спан и тип: Петрова, PERSON.
2. Нормализатор получает лемму и морфологические признаки: Петров, родительный/дательный контекст.
3. Entity resolver сопоставляет варианты Петров, Петрова, Petrov, apetrov с внутренним entity_id.
4. Policy engine проверяет, можно ли использовать эту сущность в конкретном источнике и действии.
5. В prompt уходит [PERSON_1], а не исходная строка; внутренний entity_id справочника в prompt не передаётся.

Для поиска это меняет всё. Индекс и фильтры работают по стабильному внутреннему entity_id корпуса справочника, а в prompt уходит только [PERSON_1]. LLM получает типизированную ссылку, но не получает сам entity_id и способ раскрыть ФИО.

Варианты имени сопоставляются с одним entity_id, который связывает результаты из Jira, wiki и встреч.

Варианты имени сопоставляются с одним entity_id, который связывает результаты из Jira, wiki и встреч.

Где справочник не должен «разрешать всё»

Справочник сотрудников — не белый список для обхода DLP. Он отвечает на вопрос «какой объект имеется в виду», а не «можно ли показать его данные». Эти решения нужно разделять.

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

Четыре вердикта вместо одной кнопки «запретить»

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

Вердикт

Когда применять

Что видит модель

mask

Сущность нужна для смысла, значение не нужно

Типизированный entity-токен

block

Секрет или неразрешённая передача

Запрос останавливается

warn

Нужно подтверждение или ручная проверка

Текст по правилам организации

allow

Значение разрешено политикой и маршрутом

Исходное значение или минимально нужная форма

Такой разбор полезнее тотального запрета. Если блокировать каждое имя, рабочий поиск по сотрудникам перестанет быть рабочим. Если пропускать всё из внутреннего справочника, можно случайно вынести данные в неподходящий источник. Mapping сохраняет связность, но policy engine всё равно решает, что разрешено.

Policy engine разводит запрос по четырём исходам. В реализации это PolicyEngine из detection_core с настройками тенанта no_mask_labels, muted_labels и fail_mode; подавление справочником получает reason=directory и отдельно подсвечивается в UI:

Policy engine выбирает mask, block, warn или pass по сущности, источнику и правам.

Policy engine выбирает mask, block, warn или pass по сущности, источнику и правам.

Обратный путь сложнее прямого

Проверить только prompt недостаточно. Модель может вернуть сущность в тексте, JSON, цитате, аргументах инструмента или потоковом ответе.

Для обычного текста можно регидрировать только те токены, которые присутствуют в mapping текущего запроса. Для JSON нужно проверять структуру и разрешённые поля. Для tool-call — имя инструмента и аргументы до исполнения. Для streaming режим выбирается политикой: буфер (ответ отдаётся после проверки целиком), окно (проверка скользящим фрагментом с обрывом) или пропуск с пост-сканом. Это осознанный размен задержки на строгость.

Закон и терминология

В российском правовом контексте важно не называть такую схему полной анонимизацией. 152-ФЗ определяет обезличивание как действия, после которых без дополнительной информации нельзя определить принадлежность данных конкретному субъекту. Если у шлюза есть защищённый mapping, в инженерном тексте корректнее говорить «обратимая деперсонализация» или «псевдонимизация» и отдельно описывать, где хранится дополнительная информация.

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

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

Минимальный тестовый набор должен проверять не только «нашли ли ПДн», но и сохранение смысла:

- один сотрудник в шести падежах и двух вариантах транслитерации;
- два сотрудника с одинаковой фамилией;
- одно имя в запросе, найденном документе и ответе модели;
- повторное упоминание сущности в соседнем сообщении;
- попытка вручную подделать entity-токен;
- запрос без права на источник, где совпадение справочника не должно дать доступ;
- JSON и tool-call с entity-токеном;
- потоковый ответ, в котором запрещённое значение появляется после первого фрагмента.

Метрики должны быть раздельными: полнота детекции, ложные срабатывания, доля успешных entity-match, корректность policy-решения и отсутствие регидрации чужого mapping. Автоматического теста релевантности поиска пока нет: вместо него работает канарейка mask → upstream → rehydrate каждые 10 минут, метрика совпадения policy-вердикта, red team и feedback loop для FP/miss. Один общий «процент защиты» скрывает, где именно система ошибается.

Практический чек-лист

1. Опишите границу доверенного контура и запретите модели доступ к mapping.
2. Разделите детекцию, entity resolution, policy engine и регидрацию.
3. Храните исходное значение и entity-id раздельно; используйте request-scoped mapping по умолчанию.
4. Нормализуйте падежи, транслитерацию и омонимы, но не превращайте справочник в разрешение доступа.
5. Присваивайте каждому сигналу источник: regex, NER, PII-модель, декодер или правило.
6. Проверяйте ответ, JSON, tool-call и streaming, а не только входной текст.
7. Ведите аудит раскрытий; ключи и долговременное mapping храните отдельно от основной базы.
8. Публикуйте внутренние детали только в той степени, в которой они не раскрывают клиентские данные, секреты и реальные идентификаторы.

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

Об авторе

Андрей Непряхин, технический директор AGIMA
Подписывайтесь на мой ТГ-канал: @cto_neuro

Связанные материалы:

AGIMA: Почему мы не нашли готового PII-детектора для русского языка
AGIMA: Дообучение детектора промпт-инъекций
AGIMA: Что такое платформенная инженерия

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.