Реализация AI-детекции спама в мобильном приложении
Спам в мобильных приложениях — это не только комментарии «купи крипту». Это массовые регистрации ботов, накрутка лайков через эмулятор, дублирование объявлений с разных аккаунтов, флуд в чатах. Каждый из этих сценариев требует отдельного подхода — единой кнопки «включить антиспам» не существует.
Типичные ошибки при наивной реализации
Самый распространённый антипаттерн — фильтрация по блэклисту слов на клиенте. Во-первых, список легко обойти: «купи» → «к-у-п-и», «кup и», Unicode-homoглифы. Во-вторых, логика на клиенте видна через декомпиляцию. В-третьих, это вообще не ML — это regex.
Второй антипаттерн — отправлять каждое сообщение на сервер для классификации синхронно. При 50 сообщениях в секунду в активном чате это либо деградирует UX (задержка отправки), либо ронет бэкенд.
Как это работает на практике
Поведенческие сигналы + текстовая классификация
Эффективная детекция спама строится на двух уровнях. Первый — поведенческие паттерны: частота действий, интервалы между событиями, device fingerprint, IP/ASN аномалии. Эти сигналы собираются на клиенте и отправляются батчами.
Второй уровень — NLP-классификация текста. Для мобильных приложений хорошо работает дистилированная версия BERT (distilbert-base-multilingual-cased в ONNX, ~265 МБ) на сервере или MobileBERT (~95 МБ) в TFLite для on-device inference. На практике серверный вариант предпочтительнее: модель обновляется без релиза приложения.
// iOS: отправка сообщения с поведенческими метаданными
struct MessagePayload: Encodable {
let text: String
let userId: String
let sessionDuration: TimeInterval
let messageIndexInSession: Int
let typingDurationMs: Int // <300ms — подозрительно
let pasteDetected: Bool
}
func sendMessage(_ text: String) {
let payload = MessagePayload(
text: text,
userId: currentUser.id,
sessionDuration: sessionTimer.elapsed,
messageIndexInSession: messageCount,
typingDurationMs: typingTracker.duration,
pasteDetected: typingTracker.wasPasted
)
api.postMessage(payload) { result in
switch result {
case .success(let msg): self.appendMessage(msg)
case .failure(let error) where error == .spamDetected:
self.showSpamWarning()
}
}
}
Скорость набора typingDurationMs < 300 при длине сообщения > 50 символов — почти наверняка paste-спам или бот. Этот сигнал работает даже без ML.
On-device предфильтр для снижения нагрузки
Для текстовых полей в форумах и маркетплейсах устанавливаем лёгкий on-device фильтр на базе TFLite Text Classification модели (~1.5 МБ). Она отсекает 70–80% очевидного спама без сетевого запроса:
// Android: TFLite inference перед отправкой
class SpamPrefilter(context: Context) {
private val interpreter: Interpreter
private val tokenizer: BertTokenizer
init {
val model = FileUtil.loadMappedFile(context, "spam_lite.tflite")
interpreter = Interpreter(model)
tokenizer = BertTokenizer.createFromAsset(context, "vocab.txt")
}
fun isLikelySpam(text: String): Boolean {
val inputIds = tokenizer.tokenize(text).toIntArray()
val output = Array(1) { FloatArray(2) }
interpreter.run(arrayOf(inputIds), output)
return output[0][1] > 0.85f // spam confidence threshold
}
}
Пограничные случаи (confidence 0.6–0.85) отправляются на серверную модель. Явный спам блокируется немедленно. Это снижает количество API-запросов примерно втрое.
Защита от ботов при регистрации
Для флоу создания аккаунта интегрируем Google Play Integrity API (Android) и DeviceCheck (iOS). Оба дают токен, верифицируемый на сервере — он подтверждает, что запрос пришёл с реального устройства, а не с эмулятора или Appium-скрипта. Это не панацея, но поднимает стоимость спам-регистрации для атакующего.
Процесс работы
Аудит типов спама в приложении: текстовый флуд, фиктивные аккаунты, накрутка, дубли контента.
Проектирование сигналов: поведенческие метаданные, которые клиент должен собирать и передавать.
Разработка on-device предфильтра и серверной классификации.
Настройка пороговых значений: автоматическая блокировка vs human review очередь.
Мониторинг false positive rate через Grafana/Datadog — первую неделю в «теневом» режиме (логируем, не блокируем).
Ориентиры по срокам
Базовая серверная классификация с поведенческими сигналами — 5–7 дней. On-device предфильтр на TFLite + Play Integrity / DeviceCheck — ещё 3–4 дня. Полная система с дашбордом модерации и feedback loop для переобучения модели — 3–5 недель.







