Перейти к содержимому
Content 365
Назад

Как убрать маркеры ИИ из текстов: промпт, второй проход и регулярка на примере бота

Обложка статьи «Как убрать маркеры ИИ из текстов: промпт, второй проход и регулярка на примере бота»

Когда бот пишет за автора, читателю нужен текст без нейросети в интонации: без длинных тире там, где человек поставил бы точку, без «дело не в X, а в Y» и без «важно понимать». Модель пишет грамотно, и именно грамотность её выдаёт. Это конспект статьи на Хабре «Как я вычищал ИИ‑маркеры из текстов Claude: промпт, второй проход и регулярка». Автор, разработчик Telegram-бота для блогера, описывает, как закрыл задачу за один день в три слоя.

Ценность материала в последовательности. Автор показывает каждую попытку, объясняет, почему она провалилась, и приходит к схеме, которую считает переносимой на любой генератор текста. Ниже изложены все три слоя, их порядок в коде, обходные пути, которые нашлись уже после починки, и ограничения, которые автор признаёт сам.

Конспект пригодится тем, кто генерирует посты и сценарии моделью и устал руками вычищать одни и те же обороты.

Откуда в текстах нейросети берутся маркеры

Бот из статьи обслуживает одного человека: автора блога, который не хочет садиться за клавиатуру. Он наговаривает мысль голосом, выбирает формат (сценарий сторис, карусель или пост), и бот присылает текст в его манере. В конце стоит блок задания для монтажёров и SMM-специалистов. После кнопки «Принять» бот спрашивает дедлайн и собирает карточку для рабочего чата.

Стек автор перечисляет точно: Python 3.11 и aiogram 3, распознавание речи через Whisper whisper-large-v3-turbo на API Groq, генерация на Claude Sonnet 4.6, роутинг свободного чата на Claude Haiku 4.5. История хранится в SQLite, деплой идёт одним контейнером на VPS через Coolify.

Промпт каждого формата собирается из трёх частей: контекст автора (кто он, тон, словарь, запреты, около 3 КБ), описание формата и правила против маркеров в самом конце. Системный промпт помечен для кэширования. Кэш живёт пять минут, а автор обычно делает генерацию и две-три правки подряд, поэтому повторные запросы читают промпт по цене в десять раз ниже обычной. Температуры подобраны под задачу: генерация 0,7, правки 0,3, чистка 0,2.

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

  1. Длинные тире на месте точки или запятой.
  2. Антитезы: «это не X, это Y», «не X, а Y», «дело не в X, а в Y», «X, а не Y».
  3. Клише и ритм: «важно понимать», «стоит отметить», тройки прилагательных, предложения по 30 слов.

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

Первый слой: правило в промпте

Начал автор с очевидного. Он написал жёсткий чек-лист с примерами «было/стало» и поставил его в промпт группового чата. Через пару дней выяснилось, что генераторы карусели, поста и сторис про правило не знают. Путей генерации в боте больше десятка, а правило жило в одном.

Правило переехало в общую константу, которая дописывается в конец каждого промпта. Самое важное автор вынес первым заголовком в контекст автора: «Главное правило письма, нарушать нельзя, проверяй каждое предложение», с прямым запретом длинных тире и четырёх видов антитез.

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

Стало лучше, но срывы продолжились. Чаще всего модель нарушала правило на длинных сценариях, где инструкция оказывалась в тысячах токенов от места, где писался текст.

Второй слой: улучшить текст нейросетью ещё раз

Следующая идея: отправить готовый текст в ту же модель второй раз с другим системным промптом. Роль узкая, «редактор-чистильщик»: убрать маркеры и ничего больше не трогать. Ключевые требования промпта автор приводит:

Для антитез в промпте есть пары «было/стало» и отдельная фраза «проверяй ОБА порядка». Конструкцию «X, а не Y» модель пропускала чаще, чем «не X, а Y». Температура 0,2, лимит 8000 токенов, чтобы длинный сценарий не обрезался посередине.

Результат автор описывает так: второй проход ловил большую часть антитез, а тире продолжали проскакивать. Объяснение у него техническое. Языковая модель работает с токенами, и просьба «убери все символы U+2014» для неё такая же мягкая, как «пиши короче». Иногда она меняла тире на запятую, иногда ставила новое в переписанном предложении.

Почему текст без нейросети в пунктуации может дать только код

На этом шаге автор формулирует главный тезис статьи: задачу с проверяемым результатом надо решать кодом. Тире удаляются функцией на регулярном выражении, и она стоит на каждом выходе бота.

Тире: замена без исключений

В набор попали пять символов. Модель ставит длинное тире, среднее тире, знак минуса U+2212 и даже горизонтальную черту U+2015. Всё меняется на обычный дефис, поэтому диапазон «1–3» превращается в «1-3» и остаётся читаемым. Символ ━ автор исключил намеренно: на нём держатся разделители секций и нарезка длинных сообщений под лимит Telegram.

Антитезы: только поиск

С антитезами механическая замена не работает. Предложение «не X, а Y» нужно переписать, вырезать его нельзя. Поэтому код антитезы только ищет, четырьмя регулярками под четыре конструкции. Ограничение на 1–40 символов без знаков препинания между частями держит совпадение внутри одного предложения и не даёт склеить «не» из начала абзаца с «а» через три строки.

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

Порядок вызовов

Автор подчёркивает, что порядок здесь важен:

  1. Фильтр тире срабатывает первым, всегда. При любом сбое API пользователь получит текст без тире.
  2. После каждого ответа модели фильтр срабатывает снова: модель может вернуть тире в переписанном куске.
  3. Повторная попытка по антитезам ровно одна. Если антитеза пережила два прохода, это, по опыту автора, почти всегда ложное срабатывание, и третий вызов только потратит токены. Такой случай пишется в лог и разбирается руками.
  4. При исключении возвращается текст, уже прошедший фильтр.

Второй проход выключается флагом. Тогда остаётся только регулярка, и пользователь не ждёт лишний вызов модели.

Обходные пути, пределы схемы и соседние поломки

Шесть выходов мимо фильтра

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

Все три слоя появились за один день, 7 июня, тремя коммитами подряд. Автор считает, что сэкономил бы полдня, если бы начал сразу с третьего.

Чего схема не умеет

Сохранение разметки во втором проходе держится только на инструкции. Если модель потеряет блок задания, автор узнает об этом от пользователя. Правильнее, по его словам, сравнивать количество маркеров разметки и строк «Слайд N» до и после чистки и при расхождении отдавать текст первого прохода. В соседнем модуле, который чистит документы целиком, такая проверка уже есть: если после чистки осталось меньше 60% слов, кусок уходит на повтор, а после второй неудачи остаётся оригинал.

Длину предложений и клише код не проверяет. Клише можно ловить по словарю, но их варианты бесконечны, и автор оставил эту часть модели.

Падение после пересборки

Вторая история из статьи не про маркеры, но про ту же логику. В сентябре бот перестал отвечать на все кнопки: Coolify пересобрал образ, и при зависимости anthropic>=0.40.0 приехал SDK версии 1.x. Вызов с параметром температуры стал падать на сигнатуре метода. Починка заняла один коммит: температура ушла в extra_body, версия SDK ограничена диапазоном >=1,<2. Остальные зависимости по-прежнему указаны только с нижней границей, и автор ждёт следующей поломки оттуда. Lock-файл стоит у него первым в списке дел.

Из инфраструктуры автор отдельно объясняет строку sleep 35 в Dockerfile. Coolify запускает новый контейнер, пока старый ещё работает. Два процесса с одним токеном вызывают getUpdates, Telegram отвечает ошибкой Conflict, один падает. Пауза даёт старому контейнеру остановиться.

Что автор сделал бы иначе

Коротко

Что из этого следует

Разбор применим к любому, кто публикует тексты нейросети под своим именем: от автора с одним каналом до команды с конвейером на n8n или своём коде. Самая переносимая часть статьи не регулярки, а разделение ответственности. Если требование можно проверить программой, промпт для него служит только подсказкой, а гарантию даёт проверка на выходе.

Второе, что стоит проверить у себя, это число путей, по которым текст модели попадает к читателю. У автора правило сначала жило в одном промпте из десятка, а фильтр обходили шесть выходов. В любой системе, которая росла постепенно, такие обходы почти наверняка есть.

Третье: схема из статьи держится на правилах самого автора, и границы у неё названы честно. Клише и ритм код не ловит, сохранность разметки после второго прохода не проверяется. Если вы хотите улучшить текст нейросетью вторым проходом, сверка структуры до и после чистки выглядит дешёвой страховкой, и автор сам называет её правильным следующим шагом.

Цифры и наблюдения из статьи получены на одном боте, одном пользователе и моделях Claude Sonnet 4.6 и Haiku 4.5. На других моделях и других промптах поведение может отличаться. Сам принцип, судя по описанию, от модели не зависит.


Источник: Как я вычищал ИИ‑маркеры из текстов Claude: промпт, второй проход и регулярка


Поделиться статьёй:

Предыдущая статья
Автоматизация создания видео в n8n Cloud: как собрать ролик с озвучкой и субтитрами без Execute Command
Следующая статья
Claude Code лимиты вместо тимлида: как соло-разработчик строит работу вокруг ограничений ИИ-агента