Я разложил по проверкам своего детектора ИИ-текста 12 признаков нейрослопа, то есть текста, который выдала нейросеть и никто не вычитал. Кодом ловятся пять. Остальные семь держатся только на правилах для редактора.

Онлайн-детекторы проверяет тексты, но часто в ответ видишь лишь проценты — непонятно, что именно править. Сам процент тоже ненадёжен: в работе Liang и соавторов семь детекторов в среднем приняли за машинные 61% эссе TOEFL, написанных людьми, для которых английский не родной. OpenAI свой классификатор закрыла летом 2023 года из-за низкой точности.

Моя проверка устроена по-другому: она называет фразу и правило, и с каждым срабатыванием можно спорить отдельно. Редакторы Википедии ведут открытый список признаков ИИ-текста и прямо пишут, что признак указывает на возможную проблему и сам по себе ничего не доказывает. Мой скрипт исходит из того же: он ищет следы невычитанного текста, авторство он не определяет. Общий балл этого детектора уже разбирали на Хабре.

Какие из 12 признаков нейрослопа можно поймать

Тут всё просто. Кодом можно поймать нейрослок так, где есть устойчивая формулировка или словарь:

  1. Анонс вместо содержания: шаблоны начала и конца предложения плюс порог длины.

  2. Пустая вводная часть перед сутью: код ловит частично.

  3. Одинаковые абзацы: разброс длины предложений, ловит косвенно.

  4. Кавычки на обычных словах: регулярно ловит код по ёлочкам и исключения.

  5. Кальки и жаргон: два словаря замен.

Но кодом практически не поймать отсутствие деталей, придуманные числа, взвешенность без позиции, антитеза с перечислением, тройки, рубленые концовки абзацев и тире в каждом предложении.

12 признаков нейрослопа на четырёх уровнях: что ловит код детектора и что остаётся вычитке
Структуру и слова закрывает код, смысл и синтаксис целиком остаются вычитке

Как детектор ловит фразы-анонсы и почему пропускает те, что начинаются не с глагола

Скрипт режет абзац на предложения. Шаблоны анонса проверяют только предложения до 12 слов, длинные он пропускает:

for sent in re.split(r'(?<=[.!?])\s+', para):
    clean = re.sub(r'[*_`]', '', sent).strip()
    if not clean:
        continue
    if any(rx.search(clean) for rx in SELF_TALK_RE):
        bad.append(clean[:70])
        continue
    if len(clean.split()) > 12:                  # длинное предложение анонсом не бывает
        continue

Короткое предложение сверяется с шаблонами. Один из них ищет глагол-обещание в начале фразы:

r'^(?:разберу|разберём|расскажу|расскажем|покажу|покажем|объясню|объясним|'
r'рассмотрим|приведу|приведём|опишу|опишем|перечислю|начн[уё]м|перейд[уё]м)'

Совпадение снимается, если в предложении есть фактический якорь: цифра, код в бэктиках или латинское слово.

FACT_ANCHOR = re.compile(r'\d|`[^`]+`|[A-Za-z]{2,}')

Промах сидит в символе ^. Фраза «В этой статье мы рассмотрим основные признаки» начинается с обстоятельства, глагол стоит четвёртым словом, и шаблон её не видит.

Исправить это непросто. Если снять ^, остаётся условие на хвост после глагола, и фраза всё равно проходит. Если снять и его, шаблон ловит нормальные: «Разберём по шагам», «Пишите, разберём конкретно по вашей нише». Девять таких ложных срабатываний набралось на статьях моего блога. Работает узкий шаблон, привязанный к словам «в этой статье», на тех же статьях у него ложных нет:

r'^в\s+(?:этой|данной)\s+(?:статье|заметке|части)\s+(?:мы\s+|я\s+)?(?:разберу|рассмотрим|покажу|опишу)\b'

Как детектор находит пустые вводные фразы и кавычки на обычных словах

Пустые вводные фразы ищет список из 36 регулярных проверок (регулярок). Одна находка даёт 3 балла, две уже останавливают текст до правки:

LEADIN_PATTERNS = [
    # …
    r'вывод из этого прост',
    # …
    r'давайте (?:разберёмся|разберемся|начнём|начнем)',
    # …
]
score = 10 if n >= 3 else (5 if n == 2 else (3 if n == 1 else 0))

Словарь знает только вписанные фразы. Фразу «Вывод простой» с двоеточием он пропускает: в списке есть лишь оборот со словами «из этого». Добавить её в словарь тоже нельзя: в четырёх других статьях блога после неё идёт сама мысль, и словарь снял бы нормальное предложение.

С кавычками регулярка по ёлочкам простая, вся работа в исключениях:

def ordinary(s):
    s = s.strip()
    if len(s.split()) > 3:            # длинные — обычно цитаты/названия
        return False
    if re.search(r'[A-Za-z+0-9]', s):  # латиница/термины/лейблы — легитимно
        return False
    if s[:1].isupper():               # Заглавная — обычно имя/название
        return False
    # … вопрос, цитата поискового запроса — тоже не флаг
    return True

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

Как детектор замечает монотонный ритм и кальки с английского

Одинаковые абзацы скрипт видит косвенно: считает стандартное отклонение длины предложений в словах по всему тексту. Когда предложения одной длины, разброс маленький и текст звучит монотонно. Абзацы целиком он не сравнивает, поэтому схема из тезиса, трёх пунктов и вывода с предложениями разной длины может пройти.

Кальки ловят два словаря. В первом жаргонные англицизмы с русской заменой: партия вместо кальки с batch, вывод вместо кальки с insight. Во втором полсотни замен из тех, что я уже правил руками в опубликованных текстах. Смысловую кальку, где все слова русские, а оборот английский, словарь не найдёт.

Семь признаков нейрослопа, которые детектор не ловит

Три смысловых: в тексте нет ни одной проверяемой детали, числа никто не считал, всё взвешено и позиции нет. Поиск по строке их не находит. Фраза «рост на 37%» на пробе дала ноль баллов: скрипт не знает, считал ли кто-то эти проценты. Оборота «С одной стороны… с другой» в словаре нет.

Четыре синтаксических: фраза «Не А, а Б, В и Г», тройки ради ритма, рубленая концовка вроде «И это не метафора.» и тире в каждом предложении. Запреты записаны в правилах для редактора, счётчика нет. В списке Википедии о том, как понять, что текст написан нейросетью, они тоже есть. С тире это заметнее всего: лимит в три тире на тысячу знаков в правилах есть, а проверки в коде нет.

Что показал детектор ИИ на пробном тексте из образцов слопа

Скрипт написан на стандартной библиотеке Python и в сеть не ходит. Целиком я его не выкладываю: фрагментов в статье хватит, чтобы собрать свою версию. Проверить текст детектором ИИ можно одной командой:

python3 ai-detector.py статья.md
python3 ai-detector.py статья.md --json

Код выхода говорит вердикт: ноль значит, что текст в норме, единица просит доработки, двойка означает явный ИИ-текст. В норме текст набирает меньше 20 баллов, но часть категорий останавливает его и при малой сумме.

Я собрал короткий пробный текст из образцов слопа по списку. Скрипт поставил 18 баллов из 80: 15 за монотонный ритм и 3 за одну вводку. Два анонса скрипт нашёл отдельно, в эту сумму они не входят. Поэтому 18 баллов ниже порога, а вердикт всё равно требует доработки: анонс останавливает текст сам по себе. Остальные образцы прошли.

Вывод детектора на пробном тексте: пойманные категории с баллами и образцы, прошедшие мимо
Пойманы ритм, вводка и анонсы; антитеза, тройки, тире и выдуманный процент прошли без единого балла

Срабатывание читается только вместе с фразой. Статья про слоп после редактуры у меня всё равно получила вердикт с требованием доработки: детектор нашёл в ней цитаты плохих фраз, которые статья приводит как примеры, и не отличил пример от употребления.

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

Как собрать такую проверку для своих текстов

  1. На каждый признак своя функция, и она возвращает найденную фразу, а не только балл. Без фразы срабатывание не проверить.

  2. Каждый новый шаблон прогнать на своих старых текстах. Снятие якоря ^ даёт ложные срабатывания, надёжнее узкий шаблон под конкретный промах.

  3. Тире посчитать несколькими строками:

def dash_rate(text):
    dashes = len(re.findall(r'\s—\s', text))
    return dashes / max(len(text), 1) * 1000   # тире на 1000 знаков

При лимите три тире на тысячу знаков такой счётчик отметил бы от пятой части до половины моих статей, смотря какие тире считать допустимыми, поэтому порог сначала подбирают по своим текстам. Тире и тройки я закодирую следующими. Для антитезы «не А, а Б» шаблона у меня нет; если вы ловите её без ложных срабатываний, напишите в комментариях, как.

Комментарии (4)


  1. AndreyProgramMaker
    10.10.2026 08:47

    Хорошая статья на актуальную тему


    1. ig_novvv Автор
      10.10.2026 08:47

      Да, нейрослопа дофига сейчас вокруг, боремся как можем


  1. reddice
    10.10.2026 08:47

    Полезно. У меня есть онлайн-инструмент для редакторской проверки текста перед публикацией, вроде микса из Главреда, Орфограммки и Типографа. Сейчас делаю для него Chrome-расширение. Вдохновлюсь парой практик из статьи при доработке местного ИИ-детектора!


    1. ig_novvv Автор
      10.10.2026 08:47

      О, круто) поделись ссылочкой