· 1 мин

Апрув контента кнопками в Telegram: human-in-the-loop для конвейера статей без админки

Ручной апрув встраивают как одну точку остановки в конце конвейера: после автопроверки бот шлёт в Telegram inline-кнопки 'Апрув' и 'Не апрув'. В callback_data кладут id и версию черновика (Telegram даёт до 64 байт), апрув переводит статью в публикацию. Кнопка быстрее админки - решение в один тап с телефона, без логина.

Human-in-the-loop на inline-кнопках Telegram вместо админки: как встроить ручной апрув в автоматический конвейер статей. Разбор callback_data, версий и защиты от гонок на живом пайплайне.

Апрув контента кнопками в Telegram: human-in-the-loop для конвейера статей без админки

Я собрал конвейер, который сам придумывает темы статей, пишет черновики, гоняет их через фактчек и скоркарту и публикует. Красиво. Одна проблема: между "нейронка написала" и "оно ушло в паблик" мне все-таки хочется сказать "да" своими руками. Не открывать ноут, не логиниться в админку - а просто ткнуть кнопку в Telegram с телефона. Вот про эту кнопку и рассказ.

Что такое human-in-the-loop простыми словами

Human-in-the-loop - это когда автоматическая система в ключевой точке останавливается и ждет решения человека, вместо того чтобы гнать до конца сама. AI-агент делает черновую работу, а человек ставит финальную галочку: годится или нет. В моем случае агент пишет и проверяет статью, а я решаю, публиковать ли ее.

Звучит как здравый смысл, но по цифрам это еще и мейнстрим. Gartner прогнозирует, что к 2026 году 90% корпоративных генеративных AI-приложений будут требовать формального human-in-the-loop процесса. То есть полностью автономная генерация контента - это пока красивая мечта, а на земле почти везде остается человек, который жмет "апрув". Я не корпорация, но грабли ровно те же.

Зачем ручной апрув в автоматическом конвейере статей

Затем, что нейронка уверенно врет. У меня перед публикацией стоит своя проверялка - отдельная стадия гоняет каждый источник из факт-листа по URL и выставляет черновику балл по скоркарте (контент, SEO, E-E-A-T, техничка, цитируемость). Если балл ниже порога, статья даже до меня не доедет, ее развернет авторевизия.

Но пройденная скоркарта - это не "статья хорошая". Это "статья не завалила формальные проверки". Тон, неудачная шутка, факт, который технически с источником, но по сути кривой, - все это ловится только глазами. Поэтому последний шаг я себе оставил. Автоматика доводит черновик до состояния "можно смотреть", а публикует его только после моего "да". Один человек, одна галочка, один барьер перед паблишем.

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

Почему кнопки в Telegram удобнее админки

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

С кнопкой в боте это выглядит так: падает уведомление "К публикации: заголовок такой-то, черновик #42, скор 88", под ним две кнопки - "Апрув" и "Не апрув". Я жму прямо из ленты, лежа на диване с телефона ) Ноль логинов, ноль переключений контекста.

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

Как устроен апрув кнопками: callback_data, версии, идемпотентность

Кнопка в Telegram - это inline-клавиатура, где у каждой кнопки есть поле callback_data: строка, которая прилетит боту при нажатии. Я зашил в нее все, что нужно, чтобы понять, что человек нажал:

apprv:<id_черновика>:<версия>:<ok|no>

Например, apprv:42:3:ok - апрув третьей версии черновика №42. Тут важное ограничение платформы: Telegram разрешает в callback_data максимум 64 байта (по официальной документации Bot API). Моя строка - это несколько цифр и пара слов, влезает с огромным запасом. Правило простое: не пихать в callback_data сам контент, только идентификаторы, а тело брать из базы по id.

Дальше три вещи, из-за которых это не разваливается на проде.

Первое - кому вообще слать кнопку. Рассылку запускает конец cron-проверки: после того как черновик получил проходной балл, отдельный скрипт делает approvals.py sweep. Он выбирает только черновики в статусе review, с актуальной пройденной скоркаркой именно этой версии, и которым кнопку этой версии еще не слали. Последнее условие - через отдельную табличку отправленных запросов, так что даже если sweep дернется десять раз, одна кнопка уйдет ровно один раз. Идемпотентность руками, но зато предсказуемо.

Второе - версии. В callback_data лежит номер версии не просто так. Пока кнопка висела у меня в чате, я мог зайти в админку, оставить правку, и черновик пересобрался - стал версией 4. Если я потом тыкну старую кнопку от версии 3, апрув отклонится как устаревший: "черновик изменился, дождись новой кнопки или апрувь в админке". Без этой проверки я бы одним нажатием опубликовал позавчерашний текст поверх свежих правок. Классические гонки, только в интерфейсе.

Третье - кто ловит нажатие. Само нажатие обрабатывает мой Telegram-бот на сервере: разбирает callback_data и дергает draft-approve или draft-decline в базе. Апрув переводит черновик в статус approved (дальше его подхватит паблишер), не-апрув оставляет запись о решении, но статью не трогает. Бот тонкий: вся логика "можно ли апрувить" живет в базе, а не в обработчике кнопки. Так проще - клавиатуру и бота можно переписать, а правила остаются в одном месте.

Где кнопки не заменяют админку

Не заменяют там, где нужна не галочка, а правка. Кнопка умеет ровно два ответа: да и нет. Если я жму "Не апрув", черновик просто остается в review - это не команда "перепиши", а "я пока не готов это публиковать".

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

Поэтому у меня не "бот вместо админки", а "бот перед админкой". Кнопка снимает 90% рутинных апрувов, где смотреть особо нечего - проверки прошли, заголовок норм, жми и лети. А в панель я захожу только когда текст реально надо править руками. Ровно то разделение труда, которого мне не хватало, пока я пытался жить в одной админке.

Выводы

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

А я пойду допиливать сам конвейер дальше. Следите за новостями.

Частые вопросы

Что положить в callback_data кнопки, чтобы не упереться в лимит Telegram?

Только идентификаторы, не сам контент. Telegram даёт под callback_data 64 байта, поэтому в неё кладут id и версию записи (например apprv:42:3:ok), а полный текст берут из базы по id. Так строка влезает с запасом и не ломается на длинных данных.

Что будет, если нажать кнопку апрува после того, как черновик изменился?

Апрув устаревшей версии отклоняется. В callback_data зашита версия черновика: если после отправки кнопки текст пересобрали, старое нажатие вернёт ошибку 'черновик изменился' и попросит дождаться новой кнопки или апрувнуть в админке. Это защита от гонки, когда публикуешь позавчерашний текст.

Заменяют ли кнопки в боте полноценную админку контента?

Нет. Кнопка умеет только 'да' и 'нет' по готовому черновику. Правки, комментарии и история версий остаются в веб-админке. Кнопка снимает рутинные апрувы, а панель нужна, когда текст надо реально править руками.

Влад Новиков
Влад Новиков aka sunm8
Пишу про AI-разработку без глянца. Новые разборы — сначала в канале.
Подписаться