Содержание
  1. Что делает AnonymizerEngine и как устроена карта операторов
  2. Ручной эталон и фактический выход модели
  3. Проверка положительного и отрицательного случаев
  4. Продуктовый путь, API и условия доступа
  5. Границы применимости и что не гарантируется
  6. Согласование scope, схемы данных и критериев приёмки
  7. Частые вопросы
Гайды

Обезличивание текста в Presidio: карта операторов

7 ноября 2026 · 10 минут чтения

Обезличивание текста в Presidio: карта операторов строится вокруг AnonymizerEngine, который принимает текст, список RecognizerResult и словарь OperatorConfig. Детерминированный маршрут начинается с ручной разметки спана: вы сами указываете границы сущности, а движок применяет выбранный оператор. Вероятностное обнаружение AnalyzerEngine подключается отдельным шагом.

Что делает AnonymizerEngine и как устроена карта операторов

Документация проекта на presidio.dataprivacystack.org описывает AnonymizerEngine как главный класс модуля presidio-anonymizer: он получает текст, результаты анализа и операторы, после чего возвращает EngineResult с полем text и списком OperatorResult. Каждый OperatorResult хранит start, end, entity_type, text и имя применённого оператора. Такая схема даёт проверяемый след: по items видно, какой спан обработан и чем именно.

Карта операторов — это словарь, где ключом идёт тип сущности, а значением OperatorConfig с именем оператора и параметрами. Если словарь пуст или в нём нет ключа DEFAULT, документация называет поведение по умолчанию: применяется replace, а подстановкой служит имя типа сущности в угловых скобках, например . Ключ DEFAULT задаёт оператор для всех типов, не перечисленных отдельно.

Модуль поддерживает два направления. Anonymizers заменяют текст сущности по оператору, Deanonymizers возвращают исходное значение там, где операция обратима. Документация перечисляет встроенные операторы: replace, redact, hash, mask, encrypt, custom, surrogate_ahds, keep. Для обратного прохода доступен decrypt. Набор расширяется: класс Operator с методом operate можно добавить в движок через add_anonymizer.

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

Оператор Что делает Ключевые параметры
replace Заменяет сущность заданным значением new_value
redact Удаляет сущность из текста нет
hash Хеширует текст сущности с солью hash_type, salt
mask Заменяет часть символов chars_to_mask, masking_char, from_end
encrypt Шифрует сущность ключом key
custom Подставляет результат функции lambda
keep Оставляет сущность без изменений нет

Ручной эталон и фактический выход модели

Учебный вход в этом разборе — строка «Email me at alex@example.test. Order A-17 costs 40 EUR.». Ручная разметка задаёт email-спан [12:29]: правая граница исключается, поэтому срез text[12:29] равен «alex@example.test». Проверка среза выполняется до обезличивания и отсекает неверные границы.

Ручной эталон результата: «Email me at . Order A-17 costs 40 EUR.». Здесь score 1.0 — часть учебной разметки, заданная вручную. Это значение не является уверенностью детектора и не описывает работу AnalyzerEngine.

Фактический выход модели — отдельная величина. AnalyzerEngine строит спаны вероятностным способом, и его результат зависит от модели, языка и набора сущностей. В документации проекта на presidio.dataprivacystack.org прямо сказано, что автоматические механизмы обнаружения не дают гарантии нахождения всей чувствительной информации, поэтому применяются дополнительные системы и защиты. Полнота детектора в учебном контракте не измеряется.

Разделение важно для приёмки. Ручной эталон проверяет преобразование: правильно ли движок заменил заданный спан и не тронул лишнее. Выход модели проверяет обнаружение: попал ли реальный email в список RecognizerResult. Смешивание двух проверок в одну маскирует ошибку: неверный спан при верном операторе даст корректный на вид результат замены и оставит часть адреса в тексте.

Для второго шага документация проекта на presidio.dataprivacystack.org приводит установку: pip install presidio-analyzer, pip install presidio-anonymizer и загрузку модели spaCy командой python -m spacy download en_core_web_lg. Анализ выполняется вызовом analyzer.analyze с текстом, списком entities и языком, после чего results передаются в anonymizer.anonymize. Спаны из ответа стоит сверить с исходным текстом до преобразования.

Проверка положительного и отрицательного случаев

Положительный случай — корректный спан [12:29]. Срез совпадает с адресом, оператор replace подставляет , результат совпадает с ручным эталоном. Номер заказа A-17 занимает [37:41], сумма с валютой 40 EUR — [48:54]. Эти фрагменты не передаются как подлежащие замене сущности и остаются в тексте по условиям учебного контракта.

Отрицательный случай — спан [12:28]. Он теряет последний символ адреса, срез не совпадает с ожидаемым значением, и проверка границ отклоняет разметку до обезличивания. Если такую разметку пропустить, в тексте останется хвост адреса, а заменённая часть будет короче исходной сущности.

Второй отрицательный случай — потеря A-17 или 40 EUR. Оба фрагмента входят в учебный контракт как сохраняемые, поэтому их исчезновение считается ошибкой этого контракта. Проверка сравнивает результат с эталоном целиком.

Третий случай связан с детектором. Если AnalyzerEngine не вернул email в результатах, пустой список не означает защиту текста: адрес останется в исходном виде. Документация проекта на presidio.dataprivacystack.org относит такие ситуации к ложным пропускам и отсылает к разделу с вопросами по обработке необнаруженных сущностей.

PYTHON14 строк
from presidio_anonymizer import AnonymizerEngine
from presidio_anonymizer.entities import RecognizerResult, OperatorConfig

text = 'Email me at alex@example.test. Order A-17 costs 40 EUR.'
assert text[12:29] == 'alex@example.test'

result = AnonymizerEngine().anonymize(
    text=text,
    analyzer_results=[
        RecognizerResult(entity_type='EMAIL_ADDRESS', start=12, end=29, score=1.0)
    ],
    operators={'EMAIL_ADDRESS': OperatorConfig('replace', {'new_value': '<EMAIL>'})},
)
print(result.text)

Этот пример воспроизводит принятый учебный артефакт: ручная разметка, проверка среза, один оператор replace. Строку с assert можно заменить на сравнение с ожидаемым значением и выбросом исключения при расхождении.

Продуктовый путь, API и условия доступа

Документация проекта на presidio.dataprivacystack.org перечисляет варианты запуска: Python или PySpark, Docker, Kubernetes. Для HTTP-доступа используется серверный маршрут anonymizer. Запрос отправляется методом POST на /anonymize с телом JSON, где перечислены text, anonymizers и analyzer_results.

Для полного маршрута в Docker документация приводит два контейнера: ghcr.io/data-privacy-stack/presidio-analyzer на порту 5002 и ghcr.io/data-privacy-stack/presidio-anonymizer на порту 5001. Анализ вызывается POST на /analyze, обезличивание — POST на /anonymize. Тело запроса на обезличивание содержит текст, словарь anonymizers по типам сущностей и массив analyzer_results со start, end, score и entity_type.

Условия доступа к моделям описаны в документации проекта на presidio.dataprivacystack.org: движок по умолчанию построен на spaCy, доступен вариант с transformers, для ускорения на Linux с NVIDIA GPU ставят cupy-cuda12x, а на macOS с Apple Silicon поддержка MPS не заявлена, и анализатор использует CPU. Модель transformers и модель spaCy скачиваются при первом вызове AnalyzerEngine, если их нет локально.

Интеграцию с NeMo Guardrails описывает документация NVIDIA: Presidio подключается для обнаружения чувствительных данных на входе, выходе и в извлечённых фрагментах базы знаний. Установка требует presidio-analyzer, presidio-anonymizer, spacy и модели en_core_web_lg либо extras sdd. Порог score_threshold по умолчанию равен 0.2 и настраивается отдельно для каждого источника. Потоки маскирования переписывают проверяемый текст, а поток detect заставляет бота отказаться от ответа. Для retrieval-потоков документация указывает поддержку только в LLMRails, поскольку у IORails нет конвейера извлечения.

Источник Поток Поддержка
Вход detect, mask LLMRails, IORails
Выход detect, mask LLMRails, IORails
Извлечение detect, mask LLMRails

Границы применимости и что не гарантируется

Документация проекта на presidio.dataprivacystack.org называет Presidio инструментом управления и сопровождения чувствительных данных и одновременно предупреждает: автоматическое обнаружение не гарантирует нахождение всей чувствительной информации. Замена email на метку не превращает документ в анонимный по любому режиму обработки: номер заказа и сумма остаются в тексте по условиям учебного контракта.

Обратимые операторы требуют отдельного внимания. encrypt и decrypt работают с ключом, hash по умолчанию использует случайную соль для каждой сущности. Документация проекта на presidio.dataprivacystack.org отмечает изменение в операторе hash начиная с версии 2.2.361: одинаковые значения получают разные хеши, если соль не задана явно. Для сквозной согласованности записей соль передают параметром, хранят в защищённом месте и не включают в выходной текст.

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

Отдельная граница — перекрытия спанов. Документация проекта на presidio.dataprivacystack.org описывает четыре сценария: без пересечения применяется оператор к каждой сущности; при полном перекрытии берётся сущность с более высоким score, а при равных score выбор произволен; когда одна сущность содержится в другой, используется более длинный фрагмент даже при меньшем score; при частичном пересечении каждая сущность обезличивается отдельно, и результат склеивается. Для текста «I’m George Washington Square Park.» с сущностями George Washington и Washington State Park результат принимает вид «I’m .».

Согласование scope, схемы данных и критериев приёмки

Scope фиксирует, какие сущности входят в контракт и какие фрагменты сохраняются. В учебном примере под замену идёт только EMAIL_ADDRESS, а A-17 и 40 EUR объявлены сохраняемыми. Любое расширение списка сущностей меняет эталон и требует нового прогона проверок.

Схема данных описывает вход и выход. Вход: строка текста, список RecognizerResult с полями entity_type, start, end, score, словарь операторов. Выход: EngineResult содержит преобразованную строку text и список OperatorResult с полями start, end, entity_type, text и operator. Исходную строку и ручные спаны сохраняйте отдельно для сверки. Эта схема совпадает с описанием классов в документации проекта на presidio.dataprivacystack.org.

Критерии приёмки формулируются проверяемо. Первый: срез text[start:end] совпадает с ожидаемой сущностью. Второй: результат равен ручному эталону посимвольно. Третий: сохраняемые фрагменты присутствуют в выходном тексте. Четвёртый: список items содержит запись для каждого заменённого спана. Пятый: при пустом результате анализа текст помечается как непроверенный.

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

Частые вопросы

Как выбрать оператор для email в Presidio?

Для замены на метку подходит replace с параметром new_value. Оператор redact удалит адрес полностью, mask закроет часть символов, hash вернёт необратимый отпечаток. Выбор зависит от того, нужна ли читателю связь между записями и требуется ли восстановление исходного значения.

Почему hash даёт разные значения для одинакового текста?

Документация проекта на presidio.dataprivacystack.org указывает, что начиная с версии 2.2.361 оператор hash использует случайную соль по умолчанию. Одинаковые значения получают разные хеши в разных вызовах. Для согласованности соль передают параметром и хранят в защищённом месте.

Что происходит при перекрытии спанов?

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

Можно ли запустить Presidio как HTTP-сервис?

Да, документация проекта на presidio.dataprivacystack.org приводит запуск через Docker на порту 5001 и через python app.py. Запрос на обезличивание отправляется методом POST на /anonymize с телом JSON, содержащим текст, словарь anonymizers и массив analyzer_results.

Достаточно ли замены email для анонимности документа?

Замена email закрывает один тип сущности. Номер заказа и сумма остаются в тексте по условиям учебного контракта. Документация проекта на presidio.dataprivacystack.org предупреждает, что автоматическое обнаружение не гарантирует нахождение всей чувствительной информации, поэтому применяются дополнительные системы и защиты.

Читайте также

3 материала