> ## Content Index
> Fetch the complete content index at: https://matveev.tech/llms.txt
> Use this file to discover other available public pages before exploring further.

# Как запустить OpenAI Privacy Filter локально
- URL: https://matveev.tech/run-openai-privacy-filter-locally/
- Published: 2026-07-21T11:09:11.000Z
- Updated: 2026-07-21T11:24:53.000Z
- Description: OpenAI Privacy Filter ставится в пару команд и маскирует личные данные прямо на твоей машине. Показываю, как запустить его через CLI и Python, разобрать вывод и докрутить под свои тексты.
- Author: Pavel Matveev
- Tags: AI, Безопасность, Open Source, OpenAI, Гайд

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

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

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

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

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

Утилита живёт в [репозитории на GitHub](https://github.com/openai/privacy-filter?ref=matveev.tech). Клонируем, заводим виртуальное окружение и ставим пакет:

```bash
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`:

```bash
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 включается сам). Вот реальный ответ модели на нашу строку, схема описана в [документации репозитория](https://github.com/openai/privacy-filter/blob/main/OUTPUT%5FSCHEMAS.md?ref=matveev.tech):

```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` умеет чистить файл целиком:

```bash
opf -f customer_notes.txt

```

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

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

```

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

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

Когда модель нужна постоянно, как часть пайплайна (предобработка датасета, фильтр перед индексацией, чистка перед логированием), удобнее дёргать её прямо из кода. Privacy Filter — это обычная token-classification модель из [Hugging Face](https://huggingface.co/openai/privacy-filter?ref=matveev.tech), так что подойдёт стандартный `pipeline`:

```python
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`. Остальные флаги смотри в справке:

```bash
opf redact --help

```

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

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

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

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

```bash
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](https://github.com/openai/privacy-filter/blob/main/FINETUNING.md?ref=matveev.tech). Тут я даю это обзорно, полноценное дообучение тянет на отдельный разбор.

## Результат

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

🛠️

Собираю практичные инструменты для разработчиков и разбираю, что из AI реально приносит пользу, а что хайп — [подписывайся в телеге](https://t.me/ctospeech?ref=matveev.tech).

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

`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.GitHub](https://github.com/openai/privacy-filter?ref=matveev.tech)

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

- [OpenAI Privacy Filter: обзор открытой модели для PII](https://matveev.tech/openai-privacy-filter) — что за модель, бенчмарки и честные минусы
- [MiniMax M3: открытая модель бьёт GPT-5.5 в кодинге](https://matveev.tech/minimax-m3-obzor) — ещё один сильный open-weight релиз
- [GLM-5.2 в Claude Code: 1M контекста дешевле Claude](https://matveev.tech/glm-5-2-claude-code) — про запуск открытых моделей с пользой для кошелька