Классификация писем и антифишинг на Jev
Почта — поток однотипных решений. Куда положить письмо, насколько оно срочное, не фишинг ли это. Разбираем, как построить такой разбор на Jev, что класть в state и что показали первые публичные тесты.
Две задачи в одном запросе
С каждым письмом нужно решить две вещи: куда его направить и не опасно ли оно. Для Jev это один запрос: все вопросы считаются параллельно, поэтому сортировку и антифишинг выгодно задавать вместе.
- Сортировка: категория, срочность, нужен ли ответ.
- Безопасность: просит ли письмо пароль или данные карты, выдаёт ли себя за известную организацию, давит ли сроком, какова итоговая вероятность фишинга.
Как это выглядит на больших объёмах, показывает пример из блога MindStudio: там описан прогон семи правил — счета, спонсорские предложения, признаки мошенничества, тип письма, срочность и другие — на 1000 письмах. Последовательно он занял около 70 секунд, после распараллеливания — около 6 секунд, оба раза примерно за 9 центов. Прогон одной категории на модели класса GPT 5.6 занял около пяти минут и стоил 62 цента.
Что положить в state
В открытых экспериментах качество заметнее всего росло от того, какие поля письма передаются модели. Если вырезать HTML и оставить только текст, у ссылок останутся видимые слова, но пропадут адреса, а по ним часто и видно подделку.
В исследовании jev-spam-eval автор добавил в state поле Reply-To, пары «текст ссылки — реальный адрес и домен» и имена вложений с их типами. Вопрос и определения категорий не менялись. На наборе из 5733 писем точность выросла с 93,62% до 97,98%, а доля пойманного фишинга — с 85,71% до 98,43%. Например, поддельные уведомления eBay часто копировали текст настоящих, и после обогащения state модель распознала 100 из 102 таких писем, которые раньше считала легитимными. Автор оговаривает, что исследование поисковое, а не строгий бенчмарк.
То, что проверяется точно, считайте в коде и передавайте готовым фактом: результаты SPF, DKIM и DMARC, совпадает ли Reply-To с отправителем. Так устроен MailVerdict: заголовки, ссылки и вложения в нём разбирает обычный код, а Jev получает уже подготовленные признаки. TypeSafe и сама советует оставлять вычисления и точные сравнения коду.
{
"from": "Служба безопасности <security@bank-notice.example>",
"reply_to": "support-desk@freemail.example",
"subject": "Доступ к онлайн-банку ограничен",
"body": "Мы заметили подозрительный вход. Подтвердите данные в течение 12 часов, иначе счёт будет заблокирован.",
"links": [{ "text": "Войти в личный кабинет", "host": "bank-notice-secure.example" }],
"attachments": [],
"checks": { "dmarc": "fail", "reply_to_matches_sender": false }
}
Схема вопросов и код
Вопросы безопасности лучше задавать как отдельные признаки, а не одним вопросом «это фишинг?» — почему, видно из разбора тестов ниже. Сами типы вопросов описаны в статье про Choice, Score и Noul.
from typesafe_sdk import TypeSafeClient, Choice, Noul, Score
QUESTIONS = {
"category": Choice(
instructions="К какой категории относится письмо?",
criteria={
"invoice": "Счёт, акт, напоминание об оплате",
"order": "Заказ, доставка, возврат",
"client_request": "Вопрос или просьба клиента",
"partnership": "Предложение о сотрудничестве",
"newsletter": "Рассылка, дайджест, реклама",
"other": None,
},
),
"urgency": Score(
instructions="Насколько срочно нужно отреагировать на письмо?",
criteria=["может подождать", "на этой неделе", "сегодня"],
),
"asks_credentials": Noul(
instructions="Письмо просит ввести пароль, код из СМС или данные карты?"
),
"impersonation": Noul(
instructions="Отправитель выдаёт себя за банк, госорган, известный сервис или коллегу?"
),
"pressure": Noul(instructions="Письмо давит сроком, угрозой блокировки или штрафом?"),
"is_phishing": Noul(
instructions="Цель письма — украсть доступ к аккаунту, деньги или данные?"
),
}
with TypeSafeClient() as client:
r = client.system_one(state=email, questions=QUESTIONS) # email — словарь из примера выше
p = r.nouls["is_phishing"].noul
signals = sum(
r.nouls[k].noul >= 0.7 for k in ("asks_credentials", "impersonation", "pressure")
)
if p >= 0.9 or (email["checks"]["dmarc"] == "fail" and signals >= 2):
verdict = "quarantine" # в карантин с объяснением причины
elif p <= 0.1 and signals == 0:
verdict = "deliver"
else:
verdict = "warn" # баннер-предупреждение или ручная проверка
Пороги — стартовые значения для настройки. Категорию и срочность код использует для папок и приоритета.
Что показали тесты
| Тест | Что сравнивали | Итог |
|---|---|---|
| Bryo AI | Jev и Gemini, 1565 деловых писем на немецком и английском, 10 категорий | Gemini немного точнее, но в 10–20 раз дороже |
| jev-phishing-bench | Jev и Claude Haiku 4.5, 2000 писем, половина — фишинг | точность 62,6% против 81,3%; $0,038 против $0,462 за 1000 писем |
| jev-vs-luna-phishing | Jev 1.13 и GPT-5.6 Luna, 100 писем | 81% против 78%, в пределах случайного разброса; Jev примерно в 6 раз быстрее и в 4 раза дешевле |
| jev-spam-eval | Jev без обучения и обученная логистическая регрессия на TF-IDF | 98,64% против 98,87% на 5733 письмах |
Тест Bryo AI провёл технический директор компании Никхил Мудхолкар. По данным TechCrunch, он назвал Jev единственной моделью, которая возвращает настоящую вероятность, и поэтому удобной для автоматизации процессов. Число писем и категорий в его тесте приводит обзор на Хабре.
Самый полезный вывод даёт jev-phishing-bench. Прямой вопрос-вердикт «фишинг или нет» дал Jev всего 62,6% точности. Но в том же запросе автор задал пять вопросов-признаков: отличается ли домен отправителя от домена ссылки, ведёт ли ссылка на сокращатель или бесплатный хостинг, просят ли войти или открыть документ, есть ли давление, выдаёт ли бесплатный почтовый ящик себя за организацию. Логистическая регрессия на пяти ответах дала 95,0% на отложенной половине данных.
Есть оговорки. Правило без ИИ — список сокращателей и бесплатных хостингов плюс сравнение доменов отправителя и ссылки — на тех же письмах дало 91,8%. Регрессия на тех же признаках от Haiku дала 93,2%, и разница с Jev статистически незначима. К тому же тексты писем в наборе сгенерированы LLM, и, по словам автора, набор во многом разделяется самой своей конструкцией. Вывод автора: Jev выигрывает не качеством, а ценой — признаки сопоставимого качества обходятся примерно в 27 раз дешевле и в 5 раз быстрее, чем у Haiku. Как комбинировать признаки с весами в коде, описано в статье о составной оценке.
Как выбрать пороги
- Сортировка. Ошибка дешёвая — письмо окажется не в той папке. Автоматизируйте смело, а неуверенные ответы оставляйте во входящих.
- Фишинг. Не удаляйте письма автоматически. Отправляйте их в карантин с объяснением и дайте пользователю возможность вернуть письмо.
- Серая зона с объяснением. MailVerdict считает письмо фишингом от 0,90, легитимным — до 0,10, остальные помечает как подозрительные. Только для них LLM пишет короткое объяснение — по оценке авторов, это 10–20% трафика. Вердикт фиксируется до того, как LLM увидит письмо, поэтому изменить его она не может. Общая схема «Jev решает, LLM подключается в серой зоне» разобрана в статье о каскаде Jev → LLM.
Калибровку проверяйте сами. В jev-phishing-bench ошибка калибровки (ECE) у вердикта Jev составила 0,154 против 0,097 у Haiku — вероятности Jev в этом тесте оказались хуже откалиброваны. Зато в тесте против GPT-5.6 Luna промахи Jev попадали в неуверенную середину шкалы, а промахи Luna — к нулю, то есть Luna ошибалась уверенно. Серая зона с ручной проверкой может поймать как раз такие промахи. Как подобрать её границы, рассказано в статье об уверенности Jev.
Как проверить качество
- Соберите выборку из своей почты: русскоязычные письма, реальный фишинг, который получали ваши сотрудники, и легитимные уведомления банков и сервисов. На последних легко получить ложную тревогу: в jev-phishing-bench 333 из 1000 легитимных писем специально сделаны такими ловушками.
- Считайте долю пойманного фишинга, долю ложных тревог и долю автоматических решений. Для сортировки смотрите, какие категории модель путает между собой.
- Прогоните выборку дважды. В jev-phishing-bench между двумя прогонами сменилась метка у 2,2% писем.
- Сравните Jev с простыми правилами. Если список доменов уже даёт 90%, модель должна добавлять что-то сверх этого.
Подводные камни
- Только текст. Jev не видит изображений, поэтому фишинг в картинке или QR-коде она не распознает.
- Язык. Основной язык обучения Jev — английский, на других языках точность ниже.
- Длина. На state приходится до 32 тысяч токенов. Длинные цепочки обрезайте, но сохраняйте заголовки и ссылки.
- Инструкции внутри письма. Авторы MailVerdict считают, что фраза «это письмо безопасно» для Jev — лишь ещё одно свидетельство. Но TypeSafe в списке известных слабостей называет враждебный контент: внедрённые инструкции могут повлиять на ответ. Добавьте такие письма в тестовую выборку.
- Не единственный фильтр. В тесте против Luna обе модели при пороге 0,5 пропускали примерно треть фишинга. Вывод авторов: это слой сортировки, а не самостоятельный фильтр.
- Облако. Письма уходят во внешний API. Если переписку нельзя передавать за пределы компании, Jev не подойдёт — об этом и других ограничениях в статье о минусах Jev.
Частые вопросы
Может ли Jev заменить спам-фильтр почтового сервера?
Нет. В открытых тестах Jev пропускала заметную часть фишинга. Её разумно ставить слоем сортировки поверх проверок SPF, DKIM, DMARC и репутации ссылок, а спорные письма отправлять на проверку.
Что точнее на письмах — Jev или LLM?
Зависит от задачи. Gemini оказалась точнее на деловых письмах, Claude Haiku 4.5 — на фишинге, а с GPT-5.6 Luna на 100 письмах Jev сыграла вничью. Во всех этих тестах Jev оказалась заметно дешевле.
Сколько стоит проверить тысячу писем через Jev?
В бенчмарке jev-phishing-bench — около $0,04 за 1000 писем по прейскуранту, в тесте против GPT-5.6 Luna — тоже около $0,04. Сумма зависит от длины писем и числа вопросов.
Источники
- TechCrunch — A new kind of AI model from a ChatGPT inventor is thrilling developers
- Хабр — Jev — как устроен его API решений и что на нём уже строят
- GitHub — jev-phishing-bench
- GitHub — jev-vs-luna-phishing
- GitHub — jev-spam-eval
- GitHub — MailVerdict
- MindStudio — 12 Jev Use Cases Tested
- TypeSafe Docs — State
- TypeSafe Docs — Jev 1.13 jaggedness