Как запустить OpenAI Privacy Filter локально

OpenAI Privacy Filter ставится в пару команд и маскирует личные данные прямо на твоей машине. Показываю, как запустить его через CLI и Python, разобрать вывод и докрутить под свои тексты.

Как запустить OpenAI Privacy Filter локально
TL;DR: За десять минут поставим OpenAI Privacy Filter на свою машину и научимся прятать персональные данные в тексте: имена, почты, телефоны, номера карт и API-ключи. Всё локально, без отправки на сервер. Разберём CLI-утилиту opf, формат вывода, встраивание в Python, проверим модель на живых данных (включая русские) и настроим под свои тексты.

В обзоре OpenAI Privacy Filter я разбирал, что это за модель и где она сильна. Теперь практическая часть: как поставить и запустить. Модель открытая (Apache 2.0) и маленькая, поэтому работает даже на ноутбуке без видеокарты. Задача гайда — довести тебя от пустого терминала до замаскированного текста.

Что понадобится

  • Python 3.10 или новее (это требование пакета opf)
  • git и pip
  • Примерно 3,5 ГБ места: 2,6 ГБ под веса модели и ещё около гигабайта под зависимости (главная тяжесть — PyTorch)
  • Видеокарта не обязательна, на CPU всё работает, просто медленнее
  • Терминал и базовое знакомство с Python

Шаг 1. Поставить opf

Утилита живёт в репозитории на GitHub. Клонируем, заводим виртуальное окружение и ставим пакет:

git clone https://github.com/openai/privacy-filter.git
cd privacy-filter
python -m venv .venv && source .venv/bin/activate
pip install -e .

pip подтянет зависимости: torch, huggingface_hub, numpy, safetensors, tiktoken. После установки в системе появится команда opf (её же можно звать как python -m opf).

Шаг 2. Первый запуск и первый результат

Самый простой способ проверить, что всё работает, — скормить модели строку. Тут важный нюанс: по умолчанию opf пытается запуститься на CUDA, поэтому на Mac и на любой машине без видеокарты NVIDIA нужен флаг --device cpu:

opf --device cpu "Alice was born on 1990-01-02, write her at alice@corp.com"

Без флага получишь AssertionError: Torch not compiled with CUDA enabled, причём уже после того, как скачаются веса. Я на это наступил, когда проверял гайд на Mac. Если у тебя Linux с картой NVIDIA, флаг не нужен и команда работает как есть.

При первом запуске opf скачает чекпоинт модели (2,8 ГБ) в ~/.opf/privacy_filter — путь можно переопределить переменной OPF_CHECKPOINT или флагом --checkpoint. Скачивание разовое, дальше модель берётся из кеша.

А если запустить opf вообще без текста, он уйдёт в интерактивный режим: вводишь примеры по одному и сразу видишь разметку с цветной подсветкой прямо в терминале. Удобно, чтобы пощупать модель на своих фразах.

Шаг 3. Разобрать, что вернула модель

По умолчанию opf печатает просто строку с плейсхолдерами:

Alice was born on <PRIVATE_DATE>, write her at <PRIVATE_EMAIL>

Для скриптов этого мало, поэтому есть структурированный вывод: добавь флаг --format json (в интерактивном режиме JSON включается сам). Вот реальный ответ модели на нашу строку, схема описана в документации репозитория:

{
  "schema_version": 1,
  "summary": {
    "output_mode": "typed",
    "span_count": 2,
    "by_label": { "private_date": 1, "private_email": 1 },
    "decoded_mismatch": false
  },
  "text": "Alice was born on 1990-01-02, write her at alice@corp.com",
  "detected_spans": [
    {
      "label": "private_date",
      "start": 18,
      "end": 28,
      "text": "1990-01-02",
      "placeholder": "<PRIVATE_DATE>"
    },
    {
      "label": "private_email",
      "start": 43,
      "end": 57,
      "text": "alice@corp.com",
      "placeholder": "<PRIVATE_EMAIL>"
    }
  ],
  "redacted_text": "Alice was born on <PRIVATE_DATE>, write her at <PRIVATE_EMAIL>"
}

Заметь: имя Alice модель не тронула, хотя дату и почту поймала. Это не баг, а консервативный дефолт, к нему вернёмся в шаге 6.

Два поля делают всю работу. detected_spans — это что модель нашла: тип (label), позиции в тексте (start и end) и заготовленный плейсхолдер. А redacted_text — уже готовый текст с подставленными плейсхолдерами, его можно сразу писать обратно в файл.

У вывода есть два режима. По умолчанию работает --output-mode typed: видны конкретные категории (private_person, private_email и так далее). Если типы не нужны и задача просто всё вычистить, бери --output-mode redacted — тогда любой найденный фрагмент схлопывается в один общий ярлык redacted.

Шаг 4. Прогнать файлы и логи

Гонять по одной строке скучно. opf умеет чистить файл целиком:

opf -f customer_notes.txt

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

cat app.log | grep "user=" | opf

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

Шаг 5. Встроить в свой код на Python

Когда модель нужна постоянно, как часть пайплайна (предобработка датасета, фильтр перед индексацией, чистка перед логированием), удобнее дёргать её прямо из кода. Privacy Filter — это обычная token-classification модель из Hugging Face, так что подойдёт стандартный pipeline:

from transformers import pipeline

clf = pipeline(
    "token-classification",
    model="openai/privacy-filter",
    aggregation_strategy="simple",
)

spans = clf("Contact Priya at priya@example.co.uk or +44 20 7946 0299")
for s in spans:
    print(s["entity_group"], "->", s["word"])

На выходе получишь список фрагментов с типами, а чем именно их заменять — плейсхолдером, хешем или пустотой — решаешь сам. Одна оговорка: aggregation_strategy="simple" иногда режет одну сущность на соседние куски (телефон приехал мне двумя спанами), так что перед заменой склеивай соседние фрагменты одного типа. Дальше это встраивается в любой ETL или препроцессинг.

Что Privacy Filter ловит на реальных данных

Синтетический пример с Alice — это одно, живые данные — другое. Я прогнал через модель десяток типичных кусков текста: тикет в поддержку, строку серверного лога, .env с ключами, медицинскую запись и несколько русских примеров.

Английский текст модель разбирает почти идеально. Вот тикет в поддержку целиком:

Hi, this is <PRIVATE_PERSON> from Denver. My order #<ACCOUNT_NUMBER> hasn't arrived.
Call me at <PRIVATE_PHONE> or email <PRIVATE_EMAIL>. My address: <PRIVATE_ADDRESS>.

Имя, телефон, почта, полный адрес и даже номер заказа. Секреты ловятся уверенно: AWS-ключи из .env, ключ OpenAI и Bearer-токен из curl-команды ушли в <SECRET>. Медицинская запись тоже чистая: пациент, номер карты MRN, дата госпитализации, контакт родственника. Порадовал и грязный чат без единой заглавной буквы: в «hey its mike hanson, txt me on 07911 123456» модель нашла и имя, и номер.

Формальный русский оказался лучше, чем я ждал. Анкету «Меня зовут Анна Ковалёва, живу в Москве на улице Тверская 14, кв. 8...» модель вычистила полностью: имя, адрес, телефон, почта, дата рождения. Паспорт и ИНН из договора ушли в <ACCOUNT_NUMBER>.

А вот дальше начинаются дыры, ровно там, где обещает следующий шаг:

  • В неформальном русском чате номер карты «2202 2003 4567 8910» и «вася» с маленькой буквы прошли насквозь, поймался только телефон
  • На русской морфологии ломаются границы спанов: «выдан 15.03.2015» превратилось в «вы<PRIVATE_DATE>», маска откусила полслова
  • «CVV 123» в английском примере ложно пометился как <PRIVATE_ADDRESS>
  • IP-адрес и session id из лога слиплись в один кривой <PRIVATE_URL>: отдельной категории для IP у модели нет, и на логах это будет мешать

По скорости вопросов нет: на CPU обычного ноутбука строка обрабатывается за 150–700 мс (после разовой загрузки модели). Для чистки логов в пайпе и препроцессинга датасетов хватает с запасом.

Шаг 6. Покрутить баланс точности и полноты

Важный момент, на котором спотыкаются. По умолчанию модель консервативна: она настроена на точность и старается не маскировать лишнего. Обратная сторона — она пропускает (в обзоре я приводил тесты Tonic.ai, где полнота на «грязных» данных падала до 10–38%).

Если тебе важнее не упустить персональные данные, чем сохранить контекст, декодер можно сдвинуть в сторону более широкого маскирования через operating points. Честное уточнение: готовых пресетов «строже» и «мягче» в комплекте нет. В скачанном чекпоинте лежит viterbi_calibration.json с единственной точкой default, где все смещения нулевые. Так что придётся сделать копию этого файла, подобрать смещения переходов под свои данные и подложить его через --viterbi-calibration-path. Остальные флаги смотри в справке:

opf redact --help

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

Шаг 7. Дообучить под свои данные

Если домен специфичный (медицинские записи, юридические договоры, свой формат логов), дефолтная модель будет мазать. Лечится это дообучением, и оно недорогое: OpenAI приводит пример, где F1 на узкой задаче вырос с 54% до 96% на небольшом наборе данных.

Минимальный запуск выглядит так:

opf train train.jsonl \
  --validation-dataset val.jsonl \
  --output-dir ./my_checkpoint

Формат данных — JSONL: в каждой строке поле text и размеченные spans. Можно задать собственную таксономию меток через --label-space-json (первой меткой обязательно должна идти фоновая O). На выходе появится папка с config.json и model.safetensors, которую потом подсовываешь через --checkpoint. Подробности и готовые демо-скрипты лежат в FINETUNING.md. Тут я даю это обзорно, полноценное дообучение тянет на отдельный разбор.

Результат

Если всё прошло гладко, у тебя на машине крутится инструмент, который из строки «Иван Петров, +7 900 123-45-67, ключ sk-abc123» делает <PRIVATE_PERSON>, <PRIVATE_PHONE>, ключ <SECRET>, не выходя в интернет. Я проверил на этом самом примере, он работает. Им можно чистить отдельные файлы, пайпить логи и дёргать его из Python внутри своего пайплайна.

🛠️
Собираю практичные инструменты для разработчиков и разбираю, что из AI реально приносит пользу, а что хайп — подписывайся в телеге.

Частые ошибки

pip install падает? Скорее всего, у тебя Python ниже 3.10. Проверь python --version и заведи окружение на свежей версии.

Запуск падает с Torch not compiled with CUDA enabled? Это дефолтный --device cuda, у которого нет автоматического отката на процессор. Добавь --device cpu, на Mac этот флаг обязателен всегда.

Первый запуск долго висит, потому что opf качает веса, а модель весит как полтора миллиарда параметров. На машине без интернета скачай чекпоинт заранее и укажи путь через OPF_CHECKPOINT или --checkpoint.

Если кажется, что модель ничего не находит, это тот самый консервативный дефолт из шага 6. На русском и нетипичном домене она пропускает особенно много. Лечится настройкой полноты или дообучением, переустановка не поможет.

FAQ

Можно ли запустить без Python, прямо в браузере? Да. Модель собрана под Transformers.js и крутится на WebGPU без сервера. Минимальный вызов: pipeline("token-classification", "openai/privacy-filter", { device: "webgpu", dtype: "q4" }), дальше передаёшь текст и получаешь те же размеченные фрагменты.

Работает ли он с русским языком? Частично. Формальный русский текст (анкеты, договоры) модель разбирает на удивление хорошо: имена, адреса, телефоны, паспорта находит. А на неформальном чате мажет: пропускает имена с маленькой буквы и номера карт, откусывает половины слов при маскировании. Для серьёзной работы с русским нужно дообучение на своих данных.

Это делает данные безопасными для GDPR? Нет. Privacy Filter маскирует и минимизирует данные, но не является анонимизацией или сертификацией соответствия. Это лишь один из слоёв защиты, юридической гарантии он не даёт.

Нужна ли видеокарта? Нет. На CPU всё считается, просто медленнее, только не забывай флаг --device cpu. Для разовых задач и небольших объёмов процессора достаточно.

Чем заменяются найденные данные? В режиме typed — типизированными плейсхолдерами вроде <PRIVATE_PERSON> или <PRIVATE_EMAIL>. В режиме redacted — одним общим <REDACTED>.

openai/privacy-filter · GitHub
Исходный код CLI opf, инструкции по установке, дообучению и оценке модели. Лицензия Apache 2.0.

Что ещё почитать