Персданные не должны уходить в модель: как мы это сделали и что намеряли
Имена, телефоны и ИНН подменяются по дороге к модели и возвращаются настоящими в ответе. Паспорта и ключи не отправляются вовсе. Базовый уровень стоит 34 МБ и 0,8 мс, полный — гигабайт и 12 мс.
Агент получает от человека ровно то, что человек пишет: «позвони Петру Васильеву, вот его телефон», «проверь счёт по этому ИНН», «вот выписка из базы». Дальше всё это уходит в облачную модель целиком — потому что иначе модель не поймёт задачу. Мы сделали так, чтобы уходило не всё.
Что происходит с текстом
текст
человек написал — Клиент Иванов, ИНН 7707083893, тел +7 916 123-45-67, IBAN DE89 3704 0044 0532 0130 00
ушло в модель — Клиент Иванов, ИНН 8804646751, тел +7 817 544-16-30, IBAN DE72 8585 2694 0508 5200 42
человек увидел — Клиент Иванов, ИНН 7707083893, тел +7 916 123-45-67, IBAN DE89 3704 0044 0532 0130 00
Это не пример из документации: средняя строка — то, что записал приёмник, поставленный вместо провайдера на нашем собственном поде. Модель отвечает про подставные значения, а человек снова видит настоящие. Для агента не меняется ничего.
Подстановка правдоподобная, а не заглушка вида «PERSON» и не звёздочки, и это принципиально. Текст с заглушками модель читает как шаблон и отвечает шаблоном; текст с обычным именем и обычным телефоном она читает как обычный текст.
Что не подменяется, а отклоняется
Паспорт, СНИЛС, номер карты, API-ключ, JWT, строка подключения к базе — такие запросы не уходят никуда. Агент получает отказ с кодом 400 и списком того, что нашлось.
Причина простая. Подмена работает настолько, насколько сработал детектор, а для этих типов промах недопустим. Отказать надёжнее, чем надеяться.
Два уровня и их цена
базовый — полный
Подменяет — ИНН, ОГРН, телефоны любых стран, почты, IBAN, BIC, номера счетов — всё это плюс имена, организации и города
Отклоняет запрос — СНИЛС, паспорт, карты, ключи, токены, строки подключения — то же самое
Память — 34 МБ при старте, 44 МБ под нагрузкой — 1046 МБ с одним языком
Задержка на запрос — 0,8 мс (медиана 30 запросов, максимум 1,4) — 12 мс (медиана, 95-й перцентиль 18)
Старт — мгновенно — около 40 секунд
Тариф — любой, включая самый маленький — от medium
Статус — работает — работает, с тарифа medium
Базовый уровень честно называется базовым. Имена, названия компаний и города он не распознаёт — для них нужна языковая модель, а она и есть тот самый гигабайт. В примере выше базовый уровень подменил бы телефон, почту и IBAN, а имя и компанию пропустил бы как есть, и в ответе об этом сказано отдельным полем. Зато он стоит ничего: на самом маленьком тарифе это пять процентов памяти пода.
Что было сломано в полном уровне и как это чинилось
Сначала он в продажу не пошёл. Модель склоняет подставное имя — «Федотовым Аркадием Терентьевичем» вместо «Федотов Аркадий Терентьевич», — а обратная подстановка искала дословное совпадение и такую форму не узнавала. В ответе оставался выдуманный человек: это хуже пропуска, потому что пропуск виден, а правдоподобная неправда — нет. Вторая беда была грубее: загрузка второго языкового пайплайна выбивала контейнер по памяти, и агент оставался вообще без модели.
Обе починены в самом модуле и проверены на живом поде. Склонённые формы возвращаются настоящими — «Передал Васильеву документы», «Звонил Петру вчера» — а нехватка памяти теперь честный отказ с объяснением, а не смерть контейнера.
Рассказываем это не из любви к подробностям. Если вы берёте такой щит себе, знайте, где он ломается: восстановление по словоформам — место, которое стоит проверить на своём языке и своих данных.
Как это выглядит не по-русски
Полный уровень на немецком, тот же приёмник вместо провайдера:
текст
человек написал — Überweisung an Anna Schmidt, IBAN DE89 3704 0044 0532 0130 00, BIC COBADEFFXXX, Frankfurt am Main
ушло в модель — Überweisung an Ingolf Schüler, IBAN DE09 0762 8428 2880 9322 25, BIC EMNDDEUGUYG, München
человек увидел — Überweisung an Anna Schmidt, IBAN DE89 3704 0044 0532 0130 00, BIC COBADEFFXXX, Frankfurt am Main
Имя заменилось немецким, город — немецким, IBAN остался немецким и сохранил разбивку по четыре, BIC остался немецким. Это не косметика: IBAN другой страны увёл бы платёж не туда, а не спрятал отправителя.
Как включить
Галочка «Защита персданных» в карточке агента, затем «Пересобрать». Щит встаёт отдельным контейнером внутри того же пода и слушает только петлю: наружу пода он недоступен никому, включая соседние поды. Это важнее, чем кажется — служба, которая держит в памяти сырые персданные, не должна быть доступна по сети вообще.
Ограничения сегодняшнего дня. Работает на движке Hermes со своим ключом. Щит понимает две формы запроса — OpenAI (/v1/chat/completions) и Anthropic (/v1/messages), — поэтому годятся OpenAI, Anthropic, DeepSeek, OpenRouter, Groq, Mistral и xAI; у Google форма третья, и с ним пока нельзя. Карточка агента сама скажет, что именно мешает включить.
На живом поде замкнутый круг с настоящей моделью занял 2256 мс: DeepSeek ответил, подставные значения вернулись настоящими.
Честно о точности
Открытое распознавание персданных — нерешённая задача. На кросс-доменном тесте 2026 года лучший средний F1 среди пяти распространённых подходов — 0,542, у Presidio, на котором мы стоим, — 0,481. То, что проверяется контрольной суммой или имеет жёсткую форму, находится почти безошибочно. Имена в свободном тексте — нет.
Восстановленное имя вдобавок встаёт в именительном падеже: ответ читается как «встречу с Пётр Николаевич Васильев». Данные верные, грамматика — нет. Подстановка к тому же не всегда держит регистр: британский Manchester в наших прогонах стал выдуманным North Carolburgh, а название счёта — человеческим именем. На защиту это не влияет, но текст, который читает модель, выглядит чуть более странно, чем исходный.
Поэтому правильная формулировка такая: это снижение риска, а не гарантия соответствия. Если вам нужна гарантия, персданные не должны попадать в облачную модель вообще — и тогда разговор не про щит, а про локальную модель.
Чего мы не знаем
Как это ведёт себя на очень длинных диалогах, где подставные имена живут десятками ходов, мы пока не мерили: все замеры сделаны на коротких обменах. Качество распознавания на языках кроме русского, английского и немецкого мы своими глазами не проверяли. И мы не знаем, как часто модель спотыкается о подставное имя и переспрашивает: на наших примерах не спотыкалась ни разу, но примеров было мало.
Модуль открытый, MIT, лежит на github.com/radianceteam/pii-shield. Его можно поставить себе и без нас — тогда цифры выше вы проверите сами.