Дата публикации
ai_products

PII Shield от Microsoft: как не сливать персональные данные в каждый запрос к LLM

Что нового

Microsoft представила PII Shield — прослойку между вашим приложением и любым LLM, которая автоматически анонимизирует персональные данные в каждом запросе и восстанавливает их в ответе.

Ключевые новшества:

  • «Сэндвич»-паттерн для любого LLM-запроса
    Запрос проходит через /anonymize, все PII заменяются плейсхолдерами вида {{PERSON_1}}, LLM видит только их. После ответа приложение отправляет текст на /deanonymize, и PII Shield подставляет реальные значения обратно.

  • REST API и библиотека в одном пакете

    • REST-эндпоинты: /anonymize, /anonymize_unique, /deanonymize, /apps, /apps/{id}/config.
    • Режим библиотеки: pip install pii_shield и вызов движка напрямую из Python для батчевых задач.
  • Глубокая поддержка индийских идентификаторов плюс 100+ стандартных типов PII
    Помимо Presidio по умолчанию, есть кастомные детекторы для:

    • Aadhaar (с проверкой контрольной цифры по Verhoeff),
    • PAN,
    • водительских удостоверений всех 36 штатов Индии,
    • PIN-кода,
    • UPI ID,
    • индийских телефонов,
    • банковских счетов, IFSC, CKYC, PRAN, APAAR, геокоординат, естественных дат и др.
  • Выбор стратегии по каждому типу сущности
    Для каждого типа PII можно задать отдельное действие:

    • replace — плейсхолдеры {{PERSON_1}}, {{EMAIL_ADDRESS_2}} (полностью обратимо),
    • hash — SHA-256 (необратимо, подходит для аналитики),
    • encrypt — шифрование с ML-KEM-768 + AES-256-GCM (постквантовый KEM + симметричное шифрование),
    • fake — генерация реалистичных, но вымышленных значений через Faker (необратимо, удобно для демо и тестов).
  • Постквантовая криптография по умолчанию
    Для шифрования PII используется ML-KEM-768 (NIST-стандартизованный постквантовый KEM) + AES-256-GCM. Есть обратная совместимость с Fernet.

  • Мультиарендность на уровне конфигурации
    Приложения регистрируются через POST /apps, маршрутизация по заголовку X-App-Id. Для каждого приложения — свои стратегии по сущностям, свои ключи шифрования, свои allow-листы.

  • Наблюдаемость «из коробки»
    OpenTelemetry-трейсы, метрики и логи для каждого запроса. Поддержка OTLP-выгрузки сразу в два бэкенда: локальный стек Grafana LGTM и Azure Monitor. В комплекте — готовые Grafana-дэшборды: p95/p99 задержки, счётчики сущностей, ошибки по приложениям.

  • Готовые UI
    Две Streamlit-панели:

    • Playground — визуальное тестирование: вставили текст, выбрали NLP-бэкенд, сразу видите, что нашлось и как заанонимизировалось.
    • Admin UI — настройка приложений, стратегий по сущностям, allow-листов и просмотр живой статистики.
  • Гибкая NLP-подложка
    PII Shield использует Microsoft Presidio с подключаемыми NLP-бэкендами:

    • spaCy — самый быстрый вариант на CPU,
    • ONNX — ускоренные квантованные модели,
    • Stanza — повышенная полнота обнаружения,
    • Hugging Face Transformers — state-of-the-art модели, включая IndicNER для индийских данных.
  • Батч-обработка файлов
    В режиме библиотеки доступен BatchProcessor для CSV и DataFrame с потоковой и процессной параллелизацией — для офлайн-пайплайнов и разовых прогонов.

PII Shield можно развернуть локально или в любом облаке. В примере для Azure используются Container Apps, Azure Cache for Redis, Application Insights, Log Analytics и Azure Managed Grafana.

Как это работает

PII Shield строится вокруг трёх вещей: сущностей, распознающих модулей (recognizers) и «сэндвич»-паттерна.

Сущности и распознаватели

Сущность — это единый фрагмент PII в тексте: PERSON, EMAIL_ADDRESS, PHONE_NUMBER, CREDIT_CARD, IBAN_CODE, LOCATION, IN_AADHAAR, IN_PAN, IN_DRIVING_LICENSE, IN_UPI_ID и т.д.

Каждая сущность содержит:

  • тип (например, PERSON), от которого зависят формат плейсхолдера и стратегия анонимизации;
  • позицию в исходном тексте — смещения начала и конца, чтобы заменить ровно нужный фрагмент;
  • confidence-оценку 0.0–1.0, чтобы отсеивать шум и выбирать лучший из пересекающихся вариантов;
  • стабильный идентификатор внутри запроса: все вхождения одного и того же значения («Rahul Sharma») сводятся к одному плейсхолдеру {{PERSON_1}}, а не {{PERSON_1}} и {{PERSON_2}}. Это сохраняет кореференцию при проходе через LLM.

Распознаватель — компонент, который находит сущности в тексте. PII Shield использует три типа распознавателей, которые работают совместно:

  1. NLP-распознаватели
    Опираются на языковую модель Presidio Analyzer (spaCy / ONNX / Stanza / Transformers). Нужны для сущностей без фиксированного формата: PERSON, LOCATION, ORGANIZATION, NRP. Пример: строка «Rahul встретился с Priya в Bengaluru» не ловится регулярками, модель должна понять, что это два человека и место.

  2. Pattern-распознаватели
    Небольшие Python-классы, расширяющие PatternRecognizer, которые объединяют:

    • один или несколько regex-паттернов (формат 12-значного Aadhaar, структура PAN AAAAA9999A, номера прав с префиксом штата и т.п.);
    • список контекстных ключевых слов (aadhaar, uidai, licence, dl, pan, card, dob), которые повышают уверенность, когда встречаются рядом;
    • базовую confidence-оценку и опциональный валидатор для идентификаторов с контрольной суммой (Verhoeff для Aadhaar, mod-97 для IBAN и др.).

    Логика простая:

    • regex говорит «это может быть Aadhaar»,
    • контекст «рядом есть слово aadhaar — уверенность растёт»,
    • валидатор «контрольная сумма сошлась — принимаем».

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

  3. Гибридные / deny-list распознаватели
    Работают поверх остальных. Подходят для внутренних списков кодовых имён проектов, форматов внутренних клиентских ID и других бизнес-специфичных сущностей.

Analyzer Presidio запускает все распознаватели, каждый оценивает свои кандидаты. Пересекающиеся сущности объединяются: выигрывает наибольшая уверенность, более длинные спаны поглощают короткие. На выходе — список кортежей (entity_type, start, end, score), который получает анонимизатор.

Новые распознаватели добавляются через YAML-конфигурацию.

«Сэндвич»-паттерн

PII Shield оборачивает каждый вызов LLM двумя тонкими слоями:

  1. Верхний слой — анонимизация
    Приложение отправляет исходный текст в /anonymize или /anonymize_unique. PII Shield находит все PII и заменяет их на стабильные, непрозрачные плейсхолдеры ({{PERSON_1}}, {{EMAIL_ADDRESS_2}} и т.д.) ещё до выхода за границы доверенной инфраструктуры.

  2. Средний слой — LLM
    LLM видит только плейсхолдеры. Для него {{PERSON_1}} и {{IN_AADHAAR_1}} — просто имена собственные. Он рассуждает над ними, не зная исходных значений.

  3. Нижний слой — деанонимизация
    После ответа LLM приложение отправляет текст и session ID в /deanonymize. PII Shield подставляет реальные значения обратно.

Единственный компонент, который знает исходные PII, — это краткоживущая мапа «плейсхолдер → оригинал» в Redis. Кореференция сохраняется, потому что {{PERSON_1}} остаётся одним и тем же человеком во всех местах запроса и, как правило, ответа.

Зашифрованные сущности обрабатываются отдельно: по умолчанию используется ML-KEM-768 + AES-256-GCM.

Высокоуровневая архитектура

1. Пользователь / клиентское приложение
Пользователь пишет в чат-бот или агент. Он не знает о слое редактирования: на экране всегда полные, восстановленные данные.

2. AI-приложение (агент / RAG / чат)
Это ваш GenAI-сервис — бот, агентный сценарий, RAG-пайплайн. Логика принадлежит ему, но он никогда не шлёт сырой текст в LLM. Вместо этого он всегда идёт через PII Shield и пересылает дальше только анонимизированный текст.

3. PII Shield (FastAPI)
Центральный stateless-сервис, через который проходят все запросы. Это естественная точка для:

  • применения политики,
  • rate limiting,
  • аудита,
  • инструментирования.

Внутри несколько слоёв:

  • REST API

    • POST /anonymize_unique — детект + редакт за один вызов, возвращает session ID,
    • POST /deanonymize — восстановление по session ID,
    • /apps и /apps/{id}/config — регистрация приложений и настройка стратегий,
    • плюс health-check, метрики и OpenAPI-спека.
  • Presidio Engine
    Сердце детекта и редактирования. Работает в два этапа:

    • Analyze: запуск выбранного NLP-бэкенда (spaCy / ONNX / Stanza / Transformers) и кастомных распознавателей (IN_AADHAAR, IN_PAN, IN_IFSC, IN_UPI_ID, IN_BANK_ACCOUNT, IN_PHONE, IN_PIN_CODE, CKYC, PRAN, APAAR, GeoCoordinate, NaturalDate и др.). Каждый спан получает score и усиливается контекстными словами.
    • Anonymizer: применение операторов по сущностям: replace, hash, encrypt, fake.
  • State Stores (Redis)
    Два логических хранилища, оба на Redis, но с разной семантикой:

    • Session Mapping Store — краткоживущие записи UUID → entity-map для «сэндвича» (анонимизировать → LLM → деанонимизировать). TTL по умолчанию — секунды или минуты, чтобы plaintext PII не задерживались.
    • App Registry — долговременная конфигурация приложений: стратегии по сущностям, списки разрешённых сущностей, ссылки на ключи шифрования, allow-листы вымышленных брендов. Это обеспечивает мультиарендность.
  • Telemetry
    OpenTelemetry SDK оборачивает каждый этап пайплайна:

    • спан на запрос,
    • метрики по количеству сущностей, задержкам анонимизации, попаданиям в кэш,
    • структурированные логи с trace-id.

    Поток OTLP можно параллельно отправлять в Azure Monitor и в самодельный стек с Grafana.

4. LLM (Azure OpenAI / OSS)
Любая модель: Azure OpenAI (например, GPT-4o), self-hosted OSS, Foundry-развёртывание. Контракт PII Shield гарантирует, что модель видит только анонимизированный текст. Сырая PII не уходит в тенант поставщика LLM.

5. Наблюдаемость (Azure Monitor / OTLP → Grafana)
Сюда стекаются OpenTelemetry-данные. Операторы видят:

  • объём запросов по типам сущностей,
  • p95/p99 задержки по этапам,
  • использование по приложениям,
  • разбивку ошибок.

6. Playground и Admin UI (Streamlit)
Обе панели работают поверх того же REST API, что и прод-приложения. Всё, что делает UI, можно повторить из скрипта или CI-пайплайна.

Пример потока запроса

  1. Пользователь пишет в банковский чат-бот: номер счёта, Aadhaar, телефон.
  2. Приложение отправляет сырой текст в PII Shield на /anonymize_unique.
  3. PII Shield:
    • находит все PII,
    • заменяет их на плейсхолдеры,
    • сохраняет mapping в Redis с коротким TTL,
    • отдаёт приложению анонимизированный текст + session ID.
  4. Приложение вызывает LLM с этим текстом. Модель никогда не видит реальные Aadhaar, счёт или телефон.
  5. После ответа LLM приложение отправляет ответ + session ID на /deanonymize.
  6. PII Shield подставляет реальные значения и возвращает результат приложению.
  7. Пользователь видит естественный диалог с собственными данными. Mapping в Redis автоматически удаляется по истечении TTL.
  8. Параллельно все этапы шлют трейсы, метрики и логи в стек наблюдаемости.

Что это значит для вас

Для чего использовать

PII Shield полезен везде, где LLM неизбежно сталкиваются с персональными и чувствительными данными:

  • Банковские и финтех-приложения
    Чат-боты поддержки, ассистенты для операторов, RAG по CRM-документам, в которых встречаются номера счетов, карты, IBAN, Aadhaar, PAN и т.д.

  • Медицина и страхование
    Сценарии, подпадающие под HIPAA и аналогичные требования: истории обращений, результаты анализов, обращения пациентов.

  • Госуслуги и госкомпании
    Работа с Aadhaar, UPI, паспортами, водительскими правами и другими национальными идентификаторами.

  • Внутренние ассистенты в корпорациях
    Поиск по почте, CRM, тикетам поддержки, документам HR, где много имён, адресов, телефонов и внутренних ID.

  • Аналитика и дата-сайенс
    Когда нужно прогнать через LLM большой массив данных, но требования GDPR, DPDP или локальные нормы запрещают отдавать сырую PII стороннему провайдеру.

В чём практическая польза

  • Снижение регуляторных рисков по умолчанию
    EU AI Act, индийский DPDP Act, CCPA, HIPAA, PCI-DSS и отраслевые регуляции всё чаще отдельно оговаривают AI-пайплайны. PII Shield строит границу: сырая PII не выходит за пределы вашей инфраструктуры, а в tenancy провайдера LLM попадает только анонимизированный текст.

  • Один слой вместо десятков «заплаток»
    Вместо набора регулярных выражений в каждом сервисе вы получаете единый, хорошо протестированный слой, через который проходят все AI-запросы. Политику меняете один раз — она применяется ко всем приложениям.

  • Сохранение качества ответов LLM
    Плейсхолдеры стабильны и консистентны ({{PERSON_1}} везде означает одного и того же человека). Кореференция и логика в ответах не рушатся, LLM нормально рассуждает о сущностях, даже не зная их реальных значений.

  • Прозрачная интеграция
    Приложение продолжает использовать свои промпты и тот же API LLM. Меняется только маршрут: перед LLM — /anonymize, после — /deanonymize.

  • Управляемая обратимость
    Вы сами решаете, какие сущности должны быть полностью обратимыми (replace/encrypt), а какие нужно навсегда обезличить (hash/fake). Это удобно, когда, например, имена нужны для ответа пользователю, а номера карт нет.

  • Наблюдаемость и отладка
    Благодаря OpenTelemetry и Grafana вы видите, что именно детектируется, сколько времени занимают этапы, где узкие места и где распознаватель даёт лишние срабатывания.

Где не стоит применять

  • Приложения без PII
    Если вы строите ассистента по технической документации, открытым кодовым базам или публичным новостям, где персональных данных нет, дополнительный hops через PII Shield может быть лишним.

  • Сценарии, где LLM должен генерировать PII из внешних источников
    PII Shield защищает то, что уже есть в тексте запроса или документах RAG. Он не фильтрует, например, публичные базы, которые вы сами подключили к LLM как инструмент.

  • Жёсткие требования к сверхнизкой задержке
    PII Shield добавляет свой оверхед: запуск NLP, работу распознавателей, сохранение в Redis. Для большинства бизнесовых сценариев это приемлемо, но для realtime-инференса с миллисекундными SLA это может быть критично.

Доступность и инфраструктура

PII Shield — это Python-сервис на FastAPI плюс Redis и стэк наблюдаемости. Его можно развернуть:

  • локально (on-prem),
  • в Azure (пример архитектуры: Container Apps, Azure Cache for Redis, Application Insights, Log Analytics, Azure Managed Grafana),
  • в других облаках, если заменить компоненты на аналоги.

Для использования нужен доступ к соответствующей инфраструктуре и, если вы вызываете облачные LLM, — к их API. Если провайдер LLM заблокирован в России или требует VPN, PII Shield сам по себе это не решит: он не прокси для обхода ограничений, а слой приватности.

Место на рынке

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

В отличие от таких самописных решений PII Shield даёт:

  • централизованный REST-сервис,
  • поддержку нескольких NLP-бэкендов (spaCy, ONNX, Stanza, Transformers),
  • десятки готовых распознавателей Presidio плюс кастомные для индийских идентификаторов,
  • стратегии по сущностям (replace/hash/encrypt/fake),
  • мультиарендность с конфигурацией через /apps,
  • постквантовое шифрование ML-KEM-768 + AES-256-GCM,
  • встроенную наблюдаемость через OpenTelemetry и готовые дэшборды.

Другие игроки в этой нише — это:

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

Числовых сравнений по скорости, стоимости или качеству детекта с альтернативами Microsoft не приводит. Основной акцент — на архитектурном подходе: единый, наблюдаемый слой между всеми AI-приложениями и всеми LLM.

Установка

PII Shield можно использовать как отдельный сервис или как библиотеку внутри Python-приложения.

Режим библиотеки

Пример использования, приведённый авторами:

from pii_shield import PiiShieldEngine

engine = PiiShieldEngine()  # load NLP model once, reuse

result = engine.anonymize("Rahul's Aadhaar is 2345 6789 0123")
# "<PERSON_1>'s Aadhaar is <IN_AADHAAR_1>"

restored = engine.deanonymize(result.anonymized_text, result.entity_mapping)

Далее можно использовать BatchProcessor для CSV и DataFrame с потоковой/процессной параллелизацией, если нужно прогонять большие массивы данных офлайн.

Режим сервиса

Сервисная часть построена на FastAPI и предоставляет:

  • POST /anonymize и POST /anonymize_unique — анонимизация текста, выдача session ID и маппинга;
  • POST /deanonymize — восстановление исходных значений по session ID;
  • POST /apps и /apps/{id}/config — регистрация приложений и управление стратегиями;
  • health-check, метрики и OpenAPI-документацию.

Для прод-развёртывания потребуется:

  • Python-окружение,
  • Redis для session store и app registry,
  • система наблюдаемости с поддержкой OpenTelemetry (например, Grafana LGTM + OTLP или Azure Monitor),
  • опционально — Azure Container Apps и связанные сервисы, если вы повторяете референсную схему Microsoft.

Конкретные скрипты развёртывания и код сервиса Microsoft публикует в репозитории pii-shield (GitHub).

Как запустить: пример потока «анонимизировать → LLM → деанонимизировать»

Ниже — логика, которую вам нужно реализовать в своём приложении вокруг вызова LLM.

1. Анонимизация

Приложение отправляет запрос на /anonymize с текстом, например:

"Call Rahul Sharma at rahul@example.com about Aadhaar 2345 6789 0123."

PII Shield выполняет пять шагов:

  1. Разбор конфигурации
    Если есть заголовок X-App-Id, PII Shield загружает стратегии по сущностям для этого приложения из Redis (с коротким in-process кэшем). Если нет — применяются глобальные настройки.

  2. Детект PII
    Analyzer Presidio запускает выбранный NLP-бэкенд (spaCy / ONNX / Transformers) и все встроенные и кастомные распознаватели. На выходе — список спанов entity_type, start, end, score, text.

  3. Постобработка

    • соседние локации и PIN-коды объединяются в один ADDRESS,
    • пересекающиеся детекты дедуплицируются (выбирается самый длинный, при равенстве — по максимальному score),
    • контекстные ключевые слова повышают confidence,
    • сущности ниже порога отбрасываются.
  4. Назначение плейсхолдеров
    Для каждого уникального значения PII создаётся плейсхолдер: {{PERSON_1}}, {{PERSON_2}} и т.д. Нумерация — по типу сущности и в пределах запроса. Одно и то же имя в нескольких местах получает один плейсхолдер.

  5. Применение операторов
    В зависимости от стратегии приложения по типу сущности:

    • replace → плейсхолдер, маппинг сохраняется для обратной замены;
    • hash → строка вида {ENTITY}_<sha256-prefix>, маппинг не хранится (нечего восстанавливать);
    • encrypt → токен {{{ENTITY}_ENC_<base64-ciphertext>}}, шифрование ML-KEM-768 + AES-256-GCM, маппинг не нужен, всё есть в шифротексте;
    • fake → синтетическое значение от Faker, маппинг не хранится.

Реверсивный mapping {placeholder → original} сохраняется в session store (по умолчанию in-memory dict с UUID-ключом, в проде — Redis или БД). Ответ содержит id, anonymized_text и entity_mapping:

{
   "id": "a1b2c3d4-...",
   "anonymized_text": "Call {{PERSON_1}} at {{EMAIL_ADDRESS_1}} about Aadhaar {{IN_AADHAAR_1}}.",
   "entity_mapping": {
     "{{PERSON_1}}": "Rahul Sharma",
     "{{EMAIL_ADDRESS_1}}": "rahul@example.com",
     "{{IN_AADHAAR_1}}": "2345 6789 0123"
   }
}
``

### 2. Вызов LLM

Приложение отправляет `anonymized_text` в LLM так же, как раньше отправляло сырой текст. Модель работает с плейсхолдерами как с обычными токенами. 

Фраза вида:

> "Tell {{PERSON_1}} that their Aadhaar {{IN_AADHAAR_1}} has been verified"

для модели выглядит естественно, и логика не ломается.

Обычно LLM сохраняет плейсхолдеры как есть, хотя может переписать окружение. Главное — чтобы сами токены `{{PERSON_1}}` и т.п. остались в тексте.

### 3. Деанонимизация

После ответа LLM приложение вызывает `POST /deanonymize` с session `id` и текстом ответа. PII Shield делает три шага:

1. **Загрузка маппинга**  
   По `id` достаётся словарь плейсхолдеров из session store (одна операция чтения, очень быстро).

2. **Замена плейсхолдеров**  
   Все вхождения плейсхолдеров в тексте заменяются на исходные значения. Важно, что замена идёт по убыванию длины плейсхолдера, чтобы `{{PERSON_1}}` случайно не изменил часть `{{PERSON_10}}`.

3. **Расшифровка зашифрованных сущностей**  
   Токены вида `{{ENTITY_ENC_…}}` декодируются из base64 и расшифровываются выбранным бэкендом (по умолчанию постквантовый, для обратной совместимости возможен Fernet).

Текст, отправленный на `/deanonymize`, может сильно отличаться от исходного: LLM мог его перевести, сократить или переформулировать. Важно только, чтобы плейсхолдеры сохранились. Всё остальное проходит через PII Shield без изменений.

После истечения TTL запись в Redis удаляется, и plaintext PII перестаёт существовать в системе.


## Что дальше

PII Shield — это базовый слой. Его сила проявляется особенно заметно, когда вы встраиваете его во все точки входа к LLM, чтобы разработчики физически не могли обойти приватный контур.

Microsoft анонсирует ещё два направления интеграции:

- **PII Shield как middleware в Microsoft Agent Framework**  
  Агентные системы вызывают инструменты, создают подагентов, кэшируют контекст и обращаются к LLM из неожиданных мест. Middleware позволит автоматически анонимизировать каждый промпт и деанонимизировать каждый ответ, не заставляя авторов агентов думать о PII руками.

- **PII Shield + Azure API Management (APIM)**  
  Для организаций, которые используют APIM как единый шлюз к LLM-бэкендам. Встраивание PII Shield в политику APIM позволит перехватывать, анонимизировать и деанонимизировать все запросы ко всем LLM, независимо от того, какое приложение или команда их отправила.

Одна политика — приватность для всего AI-ландшафта.

---

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

- [Microsoft обновила гайд по управлению AI‑агентами в Microsoft 365: что нового в версии 3.2](/news/new-updates-administering-and-governing-agents-whitepaper-v32-26794)
- [Как Microsoft предлагает обезопасить 1,3 млрд AI-агентов: идентичность, управление и zero trust](/news/securing-ai-agents-at-scale-identity-governance-and-zero-trust-26808)
- [E2a: почта для AI-агентов с проверкой отправителя, WebSocket и HITL-контролем](/news/show-hn-e2a-open-source-email-gateway-for-ai-agents-26835)