Скрытие персональных данных
Как это работает
Параметр obfuscate: true в запросе Chat Completions
включает скрытие персональных данных. Перед отправкой провайдеру персональные
данные во всех сообщениях диалога — user, system, assistant — заменяются
на плейсхолдеры вида <<PER0>>, а в ответе модели восстанавливаются обратно.
Восстановление работает и в потоковом режиме (stream: true), и в аргументах
function/tool-вызовов: провайдер и модель видят только обезличенный текст,
клиент получает ответ с настоящими значениями.
Одинаковые значения в рамках запроса получают один и тот же плейсхолдер, поэтому
модель сохраняет связность: «позвони <<PHONE1>>» и «передай <<PHONE1>>» — это
один и тот же номер.
Запрос клиента: Меня зовут Иван Петров, телефон +7 916 245-33-18. Составь подпись к письму.Видит провайдер: Меня зовут <<PER0>>, телефон <<PHONE1>>. Составь подпись к письму.Ответ модели: С уважением, <<PER0>>, тел. <<PHONE1>>Получает клиент: С уважением, Иван Петров, тел. +7 916 245-33-18Формат плейсхолдера
Плейсхолдер — <<ТИП + номер>>. Тип подсказывает модели, что было на этом
месте, не раскрывая значения: без него модель, вызывающая инструменты, путает
поля — кладёт телефон в аргумент имени или выдумывает недостающие данные.
Номер сквозной в пределах запроса и уникален глобально, а не внутри типа:
после <<PER0>> следующий плейсхолдер будет <<PHONE1>>, а не <<PHONE0>>.
| Тип | Что скрыто |
|---|---|
PER | Имена и ФИО |
ORG | Организации |
LOC | Адреса и локации |
PHONE | Телефоны |
EMAIL | Адреса электронной почты |
CARD | Номера банковских карт |
ID | Прочие идентификаторы: документы, счета, токены, пароли, IP |
MSC | Остальное (даты рождения, коды подтверждения) |
| ваша метка | Значения, найденные вашими obfuscate_patterns (см. ниже) |
Что распознаётся
Детектор комбинирует правила с валидацией контрольных сумм (Луна для карт, контрольные цифры ИНН и СНИЛС, mod-97 для IBAN) и две ML-модели для именованных сущностей. Русский язык — основной, имена и названия распознаются во всех падежах и в нижнем регистре.
| Категория | Примеры |
|---|---|
| Имена | ФИО в любом падеже и регистре, фамилия с инициалами, имена в разговорной форме |
| Организации | Названия компаний, банков, учреждений, аббревиатуры |
| Адреса и локации | Города, улицы с номерами домов, полные адреса, квартиры, индексы |
| Документы РФ | Паспорт (все написания), ИНН 10/12 цифр, СНИЛС, ОГРН, ОГРНИП, КПП, кадастровый номер, полис ОМС, код подразделения, свидетельство о рождении, водительское удостоверение |
| Финансы | Карты 13–19 цифр (с валидацией по Луну), срок действия и CVV рядом с номером, расчётные счета, IBAN, криптокошельки BTC/ETH/LTC |
| Контакты | Телефоны России и международные, e-mail, @-аккаунты, ссылки |
| Секреты | Пароли (в том числе в логах и стектрейсах), API-ключи Stripe/OpenAI/Anthropic/GitHub/Google/Slack/AWS, JWT- и Bearer-токены, IP-адреса |
| Даты | Даты рождения в числовых и словесных форматах, год рождения по контексту |
| Коды | Одноразовые коды подтверждения, CVV/CVC по контексту |
Ссылки скрываются целиком и только тогда, когда внутри адреса есть персональные данные (e-mail, телефон, токен в параметрах) — частичная замена внутри URL ломала бы адрес. Обычные ссылки на документацию и сайты остаются как есть.
Подстановка искажённых написаний не отключает распознавание: текст нормализуется до разбора (полноширинные цифры, невидимые символы, URL-кодирование).
Свои паттерны (obfuscate_patterns)
Помимо встроенного детектора можно передать собственные regex-паттерны — для
внутренних идентификаторов, номеров договоров, кодов проектов и всего, что
знает только ваша система. Поле obfuscate_patterns работает вместе с
obfuscate: true:
{ "model": "gpt-4.1", "obfuscate": true, "obfuscate_patterns": [ { "pattern": "ДП-\\d{4}/\\d{4}", "label": "CONTRACT" }, { "pattern": "EMP-(\\d+)", "label": "EMPLOYEE" } ], "messages": [ { "role": "user", "content": "Продли договор ДП-2024/0117 сотрудника EMP-88121" } ]}Модель увидит Продли договор <<CONTRACT0>> сотрудника EMP-<<EMPLOYEE1>>, в
ответе значения восстановятся. Правила:
pattern— регулярное выражение (синтаксис Python/PCRE). Если в паттерне есть группа захвата, маскируется только она — окружение остаётся читаемым.label— необязательная метка: заглавные латинские буквы, цифры и подчёркивание, до 16 символов. Она же становится типом плейсхолдера, так что осмысленная метка помогает модели не перепутать поля. По умолчаниюCUSTOM.- До 20 паттернов на запрос, длина паттерна — до 500 символов.
- Найденное по вашим паттернам маскируется всегда, независимо от встроенных типов детектора.
Паттерн, который не компилируется, превышает лимиты или выполняется дольше
секунды (защита от катастрофических выражений), отклоняет запрос с ошибкой
400 invalid_obfuscate_patterns и текстом причины — молча пропустить такой
паттерн нельзя: вы считали бы текст замаскированным, а он бы им не был.
Что стоит учитывать
- Плейсхолдеры живут в рамках одного запроса. История диалога передаётся клиентом в каждом запросе целиком и шифруется заново — сквозная нумерация между запросами не требуется.
- Изображения не обрабатываются: персональные данные на картинках уходят провайдеру как есть.
- Обфускация добавляет к запросу время работы детектора — от десятков миллисекунд на короткое сообщение до заметно большего на длинной истории.
- Значение, похожее на идентификатор, но с невалидной контрольной суммой, маскируется, если рядом есть контекстное слово («ИНН», «СНИЛС», «карта»): опечатка не должна приводить к утечке.
Пример
import axios from 'axios'
const { data } = await axios.post( 'https://gptunnel.ru/v1/chat/completions', { model: 'gpt-4.1', obfuscate: true, messages: [ { role: 'user', content: 'Составь договор: заказчик Иванов Пётр Сергеевич, ИНН 771234567890, тел. +7 916 245-33-18', }, ], }, { headers: { Authorization: 'shds-....' } },)
console.log(data.choices[0].message.content)import requests
resp = requests.post( "https://gptunnel.ru/v1/chat/completions", headers={"Authorization": "shds-...."}, json={ "model": "gpt-4.1", "obfuscate": True, "messages": [ { "role": "user", "content": "Составь договор: заказчик Иванов Пётр Сергеевич, " "ИНН 771234567890, тел. +7 916 245-33-18", } ], },)
print(resp.json()["choices"][0]["message"]["content"])curl https://gptunnel.ru/v1/chat/completions \ -H "Authorization: shds-...." \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4.1", "obfuscate": true, "messages": [ { "role": "user", "content": "Составь договор: заказчик Иванов Пётр Сергеевич, ИНН 771234567890, тел. +7 916 245-33-18" } ] }'Ошибка при недоступности сервиса
{ "error": { "message": "PII obfuscation is currently unavailable. Retry the request without `obfuscate`.", "type": "obfuscation_unavailable", "param": null, "code": "obfuscation_unavailable" }}Стоимость
Скрытие данных — платная опция: 280 ₽ за 1 млн токенов проверяемого текста,
ответ модели не тарифицируется. Проверяемый текст — текстовые части всех
сообщений запроса (content любой роли): именно они уходят в сервис обфускации.
Описания инструментов, картинки и кэш провайдера в объём не входят, поэтому он
меньше usage.prompt_tokens. Плата берётся за весь проверенный текст, даже если
персональных данных в нём не нашлось.
Плата списывается отдельной строкой сверх цены модели — в истории операций она
подписана «Скрытие персональных данных», и взимается в том числе на бесплатных моделях.
Если запрос завершился ошибкой провайдера, плата за скрытие не списывается.
До отправки запроса мы проверяем, что баланса (и лимита API-ключа) хватает на
скрытие данных: стоимость оценивается по длине текста сообщений. Если не
хватает, запрос не выполняется и возвращается ошибка 402:
{ "error": { "message": "Wallet balance is too low to pay for PII obfuscation of this request (about 0.28 RUB). Top up the balance or retry without `obfuscate`.", "type": "insufficient_balance_error", "param": null, "code": "obfuscation_insufficient_balance" }}Списание после ответа — по точному числу токенов проверенного текста.
Отдельный эндпоинт: POST /v1/obfuscate
Обфускация без вызова модели — например, чтобы обезличить документ перед сохранением или отправкой во внешнюю систему. Тариф тот же: 280 ₽ за 1 млн токенов присланного текста.
| Поле | Тип | Описание |
|---|---|---|
text | string, обязательное | Текст для обезличивания (до 10 млн символов) |
custom_patterns | array | Свои regex-паттерны { pattern, label? } — как obfuscate_patterns выше |
entity_types | array | Сузить набор классов: PER, ORG, LOC, MSC, IDS. Не передано — все классы |
curl https://gptunnel.ru/v1/obfuscate \ -H "Authorization: shds-...." \ -H "Content-Type: application/json" \ -d '{ "text": "Заказчик Иванов Пётр Сергеевич, тел. +7 916 245-33-18" }'{ "id": "6720f0c1a9e4b3d2c1f0e9a8", "obfuscated_text": "Заказчик <<PER_0001>>, тел. <<IDS_0001>>", "mapping": [ { "id": "<<PER_0001>>", "text": "Иванов Пётр Сергеевич" }, { "id": "<<IDS_0001>>", "text": "+7 916 245-33-18" } ], "usage": { "input_tokens": 21, "cost_rub": 0.00588 }}mapping нужен, чтобы восстановить исходный текст на вашей стороне: замените
каждый id на его text. Мы его не храним. usage.cost_rub — цена по тарифу;
фактическое списание с учётом скидок видно в истории операций.
Ошибки:
| HTTP | code | Причина |
|---|---|---|
| 400 | invalid_value | Неверное тело запроса |
| 400 | invalid_obfuscate_patterns | Паттерн из custom_patterns не компилируется или слишком сложен |
| 402 | insufficient_balance_error | Баланса не хватает на обработку текста (оценка по его длине) |
| 402 | api_key_limit_exceeded | Лимит API-ключа не вмещает обработку текста |
| 403 | model_blocked | Доступ к API заблокирован |
| 413 | obfuscation_input_too_large | Текст больше допустимого объёма |
| 503 | obfuscation_unavailable | Сервис обфускации недоступен, плата не списана |