22 апреля 2026 OpenAI выложила Privacy Filter — маленькую открытую модель, которая ищет и маскирует персональные данные прямо на устройстве. Без облаков, утечек и горы регулярок. В анонсе — 97% F1, длинный контекст, восемь классов чувствительных сущностей и обещание мультиязычности.

Джонов из Айовы или Вошингтон Ди Си она находит замечательно, а что насчет Максима Улугбековича из Нижневартовска? А Галин Палны из Урус-Мартана? У меня возникло простое человеческое желание потестить все это в реальных условиях, поэтому я собрал небольшой бенч на русском и хочу поделиться разбором модели и результатами.

А они, мягко говоря, из коробки совсем не звездные.

Коротко про бенчмарк:

Про сам бенчмарк: мне надо было как-то подступиться к снаряду, поэтому я решил сделать первый прогон на 100 записях и собрал разговорную речь, ASR-артефакты, сбитый регистр, патронимы, короткие коды и адреса без разметки. У всех записей был ground truth, с которыми сравнился в CLIf. Я хотел еще на голом браузере без бэкендовой части, но не завелось.

Если нужен быстрый результат, то вот:

Но давайте обо всем методично и по порядку.

Как модель устроена

Privacy Filter интересна именно тем, что это не маленький генератор «на все случаи жизни», а узкая модель под конкретную задачу. Дальше — фактически разбор model card и записи в официальном блоге, будет много англицизмов.

Модель стартует не как классический masked language model, а как потомок авторегрессионного чекпойнта в духе gpt-oss, который затем переделали в двунаправленный токен-классификатор. Вместо того чтобы генерить текст токен за токеном, модель за один проход присваивает каждому токену метку из фиксированных классов чувствительных данных, а потом уже собирает из этих локальных решений цельные спаны.

Классов данных восемь: account_number, private_address(целиком), private_email, private_person, private_phone, private_url, private_date, secret

На уровне архитектуры это pre-norm transformer encoder-style стек из 8 блоков. Внутри — grouped-query attention с rotary positional embeddings (14 query-голов и 2 key-value-головы, то есть по 7 query-голов на каждую KV-голову), residual stream шириной 640, и sparse MoE-слои на 128 экспертов с top-4 routing. Полных параметров у модели 1.5 млрд, но активных на токен только около 50 млн. Именно это позволяет запускать модель на почти любом устройстве даже без GPU — это действительно так.

Где прячутся компромиссы

Есть два важных нюанса, которые формируют дальнейшее поведение модели.

Первый — длинный контекст не означает глобального понимания. Модель формально поддерживает до 128 тысяч токенов, но после конверсии она работает как двунаправленный классификатор с ленточным вниманием (bidirectional banded-attention classifier) шириной 128. На практике это означает, что каждый токен видит полосу ровно в 257 соседей: 128 слева, 128 справа и сам себя. Никакого сквозного анализа документа здесь нет и не предполагается — ставка сделана на быстрый проход и локальную связность. Это by design, и важно не путать «поддерживает 128k контекста» с «понимает документ целиком».

Если перевести на простой человеческий: модель работает в небольших локальных рамках и умеет увязывать найденное внутри этих рамок в единую PII-сущность — но связать что-то в начале документа с чем-то в конце она уже не может. Но ей это и не нужно.

Второй — BIOES-разметка и связанный с ней трейдоф. На выходе не просто восемь классов, а разметка: каждая категория раскладывается на begin, inside, output (background class — отсутствие принадлежности к какому-то классу), end и single, background class (то есть, метка outside — отсутствие принадлежности к какому-то классу). Итого голова предсказывает 33 логита на токен, а дальше поверх этого идет constrained Viterbi decoding с шестью параметрами transition-bias, который собирает аккуратные границы спанов. Именно здесь спрятан один из самых интересных компромиссов: можно крутить operating point и двигать систему в сторону более агрессивной полноты или более аккуратной точности — но вместе с этим неминуемо меняется поведение на граничных случаях.

Циферки обещаний

В официальных материалах OpenAI описывает модель почти как эталонный пример маленькой прикладной модели: один проход по входу, контекстная чувствительность лучше привычных регулярок, длинные документы без чанкинга, возможность тонкой подстройки и сильные цифры на PII-Masking-300k.

В блоге заявлены 96% F1 на исходном бенчмарке и 97.43% F1 на исправленной версии. В model card отдельно есть стресс-тесты на секреты, маскировании и мультиязычность. Более того, синтетическая русская часть там выглядит вполне обнадеживающе: для русского в multilingual synthetic eval F1 около 0.895, а в режиме «category clue before PII» (то есть, подсказки какой именно класс мы ожидаем) precision 0.914 и recall 0.793.

После таких цифр очень легко поверить, что с реальным русским текстом все будет если не идеально, то хотя бы уверенно.

Русский бенчмарк

Поэтому я собрал отдельный набор. В нем 100+1 пример из реальной жизни, каждый из них содержит хотя бы один чувствительный спан из 8 классов. На этих примерах и так показательно вылезло все, поэтому увеличивать размер или упарываться в детализацию или категоризацию не имело особо смысла.

Источники намеренно не стерилизованы: это открытые русскоязычные форумные сообщения и ASR-транскрибы, где сохранены разговорный шум, неполные фразы, опечатки и характерные искажения распознавания.

Пример визуализации прогона
Пример визуализации прогона

Я задумал два режима подсчета: strict, где нужен точный матч (start, end, label), и lenient, где достаточно пересечения спана с тем же классом.

Результаты

А вот качество оказалось, мягко говоря, не звездным.

На strict-матчинге общий результат получился вот каким:

По классам картина очень неровная:

  • Ожидаемо хорошо (потому что мультиязычно): url, date, phone, email, account_number

  • Нехорошо: secret, address, private_person

Если включить lenient-подсчет, общий F1 сразу поднимается и это интересная деталь: часть проблем сидит не в том, что модель вообще не видит сущность, а в том, что она режет ее не по тем границам. Для адресов скачок почти в полтора раза, но идеальными итоги все равно не назовешь.

По скорости CLI ок: на CPU Mac Air M1 2020 с бытовой фоновой нагрузкой в локальных прогонах получалось порядка 1–2 примеров в секунду, с медианной задержкой примерно в полсекунды и заметным cold start на первых запросах. Вполне хорошо.

Браузерная версия

Мне хотелось завести это в браузере без бэкенда вообще. За инференс — Transformers.js, модель в формате q4 — ONNX-квантизованный экспорт, рантайм WebGPU с фолбэком на Wasm, то есть все в целом browser-only SPA. Но Transformers.js пока не поддерживает архитектуру Privacy Filter, поэтому пока без браузера, но будет интересно попробовать, когда поддержка появится.

Почему так получилось

  1. Выход за распределение претрейна: в model card OpenAI честно предупреждает, что качество может проседать на non-English text, non-Latin scripts, naming patterns и доменах вне распределения. Мой датасет бьет именно по этим местам сразу: русский язык, кириллица, разговорный стиль, отсутствие заглавных букв, ASR-артефакты, бытовые и банковские формулировки. Синтетический «русский» и живой русский — разные миры.

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

    Алексай Алексаныч, да не звонила я туда
    Алексай Алексаныч, да не звонила я туда
  2. Особенности span-архитектуры: BIOES-разметка и Viterbi-декодер действительно помогают собирать связные куски, но они же болезненно проявляются на строгом матчинге, когда модель чуть-чуть откусывает начало или конец. У private_address это видно почти как в учебнике: вместо полного адреса модель может взять только «самоеважное» без города или без начального указателя, либо наоборот чуть захватывает лишний контекст.

    Может дойти до абсурда:

    Катим в прод?

    В какой-то момент я даже засомневался, что код бенча работает верно и пошел проверить на официальном GPU-демо на HF, но нет:

  3. Адреса: в лабораторном наборе адрес обычно выглядит как аккуратная строка с понятной структурой. В реальной жизни встречается все, что угодно: «улица лермонтова 8», «краснодар проезд репина 3 подъезд 2», «пермь шоссе космонавтов 111», «санкт-петербург невский 80 квартира 13». Здесь много локальных шаблонов, сокращений, вложенной географии и нестабильных границ того, что считать самим адресом, а что уже сопутствующим контекстом. Модель часто видела адресный фрагмент, но не весь спан, а иногда не видела его вовсе.

  4. Секреты: самая показательная часть. В model card OpenAI предупреждает, что модель может пропускать novel credential formats и project-specific token patterns. На русском наборе это вылезло очень явно: одноразовые коды вроде «482911» и «914205», PIN «0471», строка dem0-pass-442 — всё это либо пропускалось, либо путалось с account_number. Для человека контекст «код подтверждения», «одноразовый код из смс», «пин у карты» вполне достаточен. Для модели без дообучения на такой локальный паттерн, короткий числовой фрагмент легко выглядит как обычный номер, а не как чувствительный секрет.

  5. Формат шума: в работе есть упоминание adversarial-eval, где модель заметно хуже работает на нестандартных форматах чисел. Телефон, проговоренный словами не был распознан вовсе. Сервисный номер 8 800 555 35 35 тоже был пропущен. То есть слабые места из model card не просто существуют, а довольно красиво воспроизводятся прям в живую сходу без долгих поисков.

Что из этого следует

Я бы точно не делал простой вывод «модель плохая». Точно нет! Скорее так: модель честно решает свою задачу в том режиме, под который она спроектирована, а она не спроектирована под русский. Это не большой всесильный AI, а компактный, быстрый, локально запускаемый классификатор со своей политикой разметки, своим training distribution и своими компромиссами. На чистых и близких к обучению данных он может быть очень силен, на живом русском в zero-shot начинает сильно сбоить.

Но.

OpenAI не скрывает этого и сама пишет про необходимость in-domain evaluation и fine-tuning. В их материалах на это есть жирный намек: на их собственном SPY-датасете они показывают, что дообучение всего на 10% данных поднимает F1 с 0.545 до 0.962 — то есть небольшое доменное дообучение способно радикально изменить картину. Я пока его не пробовал.

Для меня главный итог этого эксперимента не в том, что русский бенчмарк оказался не слишком удачным для Privacy Filter из коробки. Главный итог в другом: это очень правдоподобная демонстрация нового класса моделей: небольшие специализированные сетки, которые умеют одну нишевую вещь, но умеют ее достаточно дешево, прозрачно и локально, будут появляться все чаще. Не «универсальная модель на все», а маленький on-device инструмент для фильтрации, модерации, оценки, OCR-нормализации, извлечения структур, узкой биометрии и всего очень интересного.

Мы эту модельку точно потюним для себя и встроим погонять в один из продуктов, где AI-агент как раз таки ходит по базам, описывает данные и ищет в них всякое интересное, поэтому модель очень интересна как феномен.

И в этом смысле даже неидеальный результат важен: он показывает, что путь к таким моделям лежит не через магическое обещание zero-shot для всех языков, а через узкое доменное дообучение (достаточно несложное), локальные бенчмарки и честную проверку на реальных данных.

Именно поэтому русский прогон получился полезным. Он не опроверг идею маленькой прикладной модели, а скорее приземлил ее на наши суровые реалии. Архитектура у Privacy Filter сильная и аккуратная. Идея запускать такие вещи на устройстве — супер. Но увидеть новость о том, что раз модель от OpenAI, то с ней сразу можно в прод — вообще нет.

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

Ну вот и все. Про свои другие эксперименты я пишу тут.

Спасибо!

Источники: OpenAI blog, «Introducing OpenAI Privacy Filter», OpenAI Privacy Filter Model Card

Комментарии (0)