Метрики нашего детектора лежат в открытом доступе: maskgate.ru/quality. Замер от 10 октября 2026 года: recall 99,78 %, precision 99,92 %, 1 473 записи в тестовом корпусе, 40 категорий данных. Выглядит как цифры из презентации для инвестора. Дальше — откуда они взялись, где врут и почему рядом с ними нет ни одного числа про скорость.
Сразу оговорюсь: я Андрей Цымбалюк, разработчик maskgate.ru. Это разбор замера моего же сервиса, написанный заинтересованным лицом. Читайте с этой поправкой.
Вот итог замера целиком.
| Показатель | Значение |
|---|---|
| recall (доля размеченных значений, которые детектор нашёл) | 99,78 % |
| precision (доля находок, подтверждённых разметкой) | 99,92 % |
| записей в тестовом корпусе | 1 473 |
| категорий данных измерено | 40 |
| TP / FP / FN | 1385 / 1 / 3 |
| версия корпуса | 4.2 |
| дата замера (UTC) | 2026-10-10 |
Источник тот же, maskgate.ru/quality. Там же лежат отпечаток замера sha256 e30922ac… и ревизия кода на момент прогона 8785b3e1…: по ним читатель сверяет свой прогон с нашим.
Одна ложная находка на 1386 срабатываний. Три пропуска на 1388 размеченных значений. Если вы видели такое в пресс-релизе вендора, вы уже решили, что цифры нарисованы. Реакция нормальная. Поэтому дальше про метод.
Каждое размеченное значение корпуса сверяется с находками детектора по пересечению отрезков текста, отдельно по каждой категории. Дальше три счётчика:
recall = TP / (TP + FN), precision = TP / (TP + FP). В корпусе размечено 1388 значений, детектор нашёл 1385. Считаем precision: 1385 / 1386 = 99,9278… %, на странице стоит 99,92 %.
Проценты усечены вниз, а не округлены. Это принципиально: округление вверх завышало бы публичное число, а мне не нужна метрика, которую придётся защищать в комментариях. Рядом с процентами лежат TP, FP и FN, поэтому любой читатель пересчитывает их сам и ловит меня на арифметике, если я где-то сжульничал.
Ещё две вещи, без которых цифры читаются неверно.
Первая. Метрика считается по значениям и категориям. Документ как единица измерения здесь не участвует. «100 %» в таблице по отдельной категории — это результат на десятках размеченных значений, а не гарантия на любом тексте. Когда вам говорят «точность 99 %», первый вопрос — на чём именно.
Вторая. Precision здесь нижняя граница. Разметка перечисляет не все персональные данные страницы, поэтому неподтверждённая находка не обязательно ложная: детектор мог найти реальный паспорт, которого в разметке просто нет. Читать 99,92 % как «мы ошибаемся в 0,08 % случаев» нельзя. Честнее так: в 0,08 % случаев мы не смогли доказать, что не ошиблись.
И про профиль. Замер идёт на конфигурации без NER (enable_ner=false), то есть без модели для имён, организаций и локаций. NER меряется другим прогоном, python -m eval.run_eval --ner, и в этих числах его нет.
До этой недели на сайте стояли recall 95 % и precision 92 %. Их снимали на корпусе из 404 записей версии 3.2, отчёт от 10 сентября 2026 года. Нынешние проценты сняты на корпусе версии 4.2 из 1 473 записей.
Соблазн написать «точность выросла с 92 % до 99,92 %» был. Это была бы неправда. Корпус вырос больше чем втрое, разметка стала плотнее, часть категорий появилась уже после старого замера. Проценты с разных корпусов нельзя вычитать друг из друга и выдавать за прогресс. Поэтому старые числа я просто выбросил: на странице стоит только тот замер, который читатель может воспроизвести сегодня.
Заодно про ловушку в именах файлов, на которую я сам наступил. Один из корпусов называется corpus_256.jsonl, а записей в нём 178. Число в имени — идентификатор задачи, а не количество кейсов. Сначала я написал в отчёте «256 кейсов», потом пересчитал строки и переписал. С тех пор размер корпуса беру из файла, а не из его названия.
Число на странице кто-то должен обновлять руками. Я не хотел, чтобы это делал человек, поэтому метрика стала частью сборки. Тот же прогон, python -m eval.run_eval, стоит гейтом в CI. Сборка падает, если порог нарушен. Пороги такие:
| Требование | Порог |
|---|---|
| Общий recall (structured-RU) | 0,85 |
| Tier 1 (паспорт, СНИЛС, ИНН, карта, ФИО, телефон, почта): recall | 0,97 |
| Tier 1: precision | 0,85 |
| Tier 2 (реквизиты, адрес, дата рождения): recall | 0,95 |
| Tier 3 (шумные и контекстные категории): recall | 0,75 (отчётный, сборку не блокирует) |
| Precision для всех категорий | 0,8 |
| NER-профиль: recall / precision | 0,75 / 0,7 |
Посмотрите на разрыв. Измеренный общий recall 99,78 % при пороге 85 %. Tier 1 измерен выше 99 % при пороге 97 %. Пороги намеренно ниже измеренного. Планка стоит там, где ловит деградацию, и поэтому её трудно заподозрить в подгонке под результат.
Артефакт замера лежит в api/quality_report.json. Из него читают числа и страница /quality, и главная; расхождение ловит тест. Отдельно проверяется свежесть: python scripts/quality_report.py --check-digests сверяет дайджесты корпуса и детектирующих источников за секунды, --check делает полную сверку со свежим прогоном. Правка детектора без перегенерации артефакта расходится с дайджестами и видна сразу. У замера есть sha256-отпечаток: читатель повторяет прогон и сравнивает результат, два прогона подряд дают побайтово одинаковый вывод.
Про Tier 3 отдельно. Это шумные и контекстные категории, где цена ложного срабатывания почти такая же, как цена пропуска. Если детектор начнёт блокировать каждое упоминание слова «договор», пользователь уйдёт и перестанет чем-либо пользоваться. Для Tier 3 порог поэтому отчётный: сборку он не роняет, но цифру мы всё равно показываем. Слабое место, о котором честнее сказать вслух, чем спрятать между строк.
Теперь самая полезная часть. Вот что в этом замере устроено не в мою пользу, и я специально не стал это прятать.
Корпус синтетический. Записи генерирует код, eval/corpus/build_corpus.py, с фиксированным seed. Значения собираются так, чтобы проходить собственные валидаторы детектора. Прочитайте это ещё раз: корпус построен по тем же правилам, по которым работает проверка. Это смещает замер в пользу сервиса, и никакая честная подача смещения не отменяет. Понимать это важнее, чем запоминать проценты.
Отдельной цифры по состязательным примерам нет. В корпусе есть блок из 52 записей с обфускацией и кодированием: гомоглифы, percent-encoding, разбивка разделителями. Он измеряется вместе с остальными. Значит, общий recall нельзя читать как устойчивость к обфускации: сказать «на состязательных примерах у нас столько-то» я не могу и не буду.
Реальные документы клиентов в замер не входят. Пилота на настоящих договорах, реестрах и резюме ещё нет. На живых сканах, сложных таблицах и нетиповых форматах числа будут другими, и увидеть их можно только этим пилотом. Пока его нет, замер описывает корпус. Про «любой документ» он не говорит ничего.
OCR и сканы меряются отдельно. Для них есть свой мини-корпус и своя команда. На /quality этих чисел нет, потому что замер воспроизводится только там, где стоит движок распознавания. Без него прогон честно сообщает, что мерить нечего, и отчёта не пишет.
NER в этих числах нет. Имена, организации и локации идут отдельным профилем с моделью, и порог там другой: 0,75 по полноте и 0,7 по точности против 0,85 общего. Смешивать два профиля в одну цифру я не стал: среднее по разным вещам всегда выглядит лучше, чем работает.
Латентность не публикуем. В прошлой версии статьи у меня стояли красивые «~0,1 мс на значение» и «~5 мс на сообщение в 1000 знаков». Я их убрал: воспроизводимого замера времени ответа нет, а число, зависящее от железа замеряющего, читатель повторить не может. Красивая цифра без возможности проверки — ровно то, за что справедливо прилетает в комментариях. Поэтому вместо числа на /quality стоит явный отказ.
100 % защиты не бывает. Мотивированный инсайдер, стеганография и паспорт, пересказанный своими словами, остаются вне игры. Сервис снижает риск при типовых утечках и не заменяет юридическую оценку вашей ситуации.
Специальные категории облако не обрабатывает. Документы со сведениями о здоровье (ст. 10 152-ФЗ) не принимаются: сервис отказывает в обработке до того, как содержимое куда-либо уйдёт. В журнал попадают только факт отказа, его причина и код категории, ни текста, ни совпавшего значения. Биометрию (ст. 11) детектор не выявляет вовсе, поэтому маскирование её не защитит и загружать такие документы нельзя. Для тех и других есть self-hosted развёртывание, где оператором остаётесь вы.
Цены беру из машиночитаемого источника, maskgate.ru/config/pricing, чтобы статья не разошлась с реальностью через месяц.
| Операция | Цена |
|---|---|
| Проверка текста в интерфейсе | 20 ₽ |
| Проверка документа (DOCX, XLSX, PDF, скан) | 100 ₽ |
| Запрос к API | 1 ₽ |
| Запрос через LLM-прокси | 1 ₽ |
| Восстановление своих данных из vault | 0 ₽ |
| Минимальное пополнение | 100 ₽ |
Бесплатно: 10 проверок текста в сутки без регистрации, 20 в сутки после входа. Сверх — по цене из таблицы.
Лимиты на файл: до 10 файлов за одну операцию, 20 МБ на файл, до 500 страниц в PDF, до 50 страниц распознавания сканов на документ. Готовый документ живёт в памяти сервера, не на диске, и доступен по ссылке со случайным токеном 5 минут; исходный файл пишется во временный и удаляется сразу после разбора. Форматов одиннадцать: DOCX, XLSX, PDF, TXT, CSV, PNG, JPG, JPEG, TIFF, TIF и BMP. Анализ идёт на серверах в России. Маскированные значения лежат в хранилище под AES-256-GCM, а в аудит вместо значений попадают HMAC-токены.
Для компаний с требованием локализации есть self-hosted развёртывание целиком в своём контуре, это страница /business.
Не звёзд на GitHub и не ещё одной статьи. Мне не хватает пилота на реальных документах и людей, которые принесут сценарии, до которых я не додумался. Замер на синтетике я уже сделал и показал; следующий честный шаг — живые договоры, реестры и сканы, где числа почти наверняка окажутся хуже.
Пилот нужен не для красивой цифры в новой статье. Мне важно увидеть, сколько находок детектор пропустит на живых сканах и сколько ложных срабатываний даст на настоящих таблицах. И где человек всё равно обойдёт фильтр руками. Последнее важнее первых двух: если сотрудник перепишет паспорт своими словами, никакая точность на корпусе его не остановит.
Поэтому предложение простое. Попробуйте сломать сервис: пришлите текст, на котором он, по-вашему, ошибётся, пропустит чувствительные данные или сработает зря. Форма /report собирает только категории и структурные признаки: тип документа, категорию ошибки, категорию данных и ожидаемое поведение. Поля для свободного текста там нет, присылать сам документ не нужно. В аудит-журнал попадают метаданные: ни текста, ни файла, ни IP.
99,78 % — это про мои документы? Нет. Это синтетический корпус из 1 473 записей. Пилота на реальных документах пока нет, поэтому замер описывает корпус, а не «любой документ».
Почему precision не 100 %? Одна находка из 1386 не подтверждена разметкой. И это нижняя граница: разметка перечисляет не все персональные данные страницы, так что находка может оказаться настоящей.
Можно проверить замер самому? Да. python scripts/quality_report.py --check-digests сверяет дайджесты за секунды, --check прогоняет эвал заново. Отпечаток замера опубликован на maskgate.ru/quality.
Вы гарантируете соответствие 152-ФЗ? Нет. Сервис снижает риск утечки и не заменяет юридическую оценку вашей ситуации.
Автор: Андрей Цымбалюк, создатель maskgate.ru. Оператор персональных данных: ИП Цымбалюк А.В., запись в реестре операторов персональных данных № 77-25-184814.
Не является юридической консультацией. Проверяйте актуальную редакцию 152-ФЗ.
Проверить свой текст · Метрики и методика · Сообщить об ошибке детекции
Не является юридической консультацией. Проверяйте актуальную редакцию 152-ФЗ.