Автоматизация создания контента обычно выглядит так: «нейросеть пишет статью, скрипт её публикует». Автор кейса на Хабре «Новостной конвейер на PowerShell: три минуты от ленты источников до готовой страницы» описывает другую схему. Его конвейер выпускает пять материалов в день о мире LLM, и в нём модель вызывается четыре раза под узкие задачи. Человек остаётся в одной точке: на воротах согласования, где у него десять минут на решение.
Это конспект его статьи. Материал рассчитан на десять минут чтения и написан от первого лица автора. Ниже изложено то, что он рассказал: требования к системе, устройство журнала и цепочки шагов, место человека, выгрузка и оповещение поисковиков, пять поломок с их лечением. Оценка собрана в последнем разделе. Все цифры приведены по статье автора и относятся к первым двум неделям работы проекта.
Отдельно о сути эксперимента. Автор проверял не трафик, а инженерную гипотезу: может ли один человек с PowerShell и недорогой моделью держать ежедневный ритм публикаций без редакции.
Задача: новостной сайт на нейросети без редакции и бюджета
Требования автор сформулировал жёстко. Пять материалов в день, между ними не меньше двух часов: иначе лента выглядит как пакет, выпущенный одной командой. Каждый материал проверен по первоисточникам, а не по пересказам. Картинка обязательна, без неё страница не собирается. Темы не повторяются: дубль под другим заголовком должен отсекаться до того, как на него потрачены токены.
Человек согласует каждый материал, и у согласования есть дедлайн. Если за десять минут никто не нажал «да», материал остаётся в холде и не публикуется. В конце цепочки идут выгрузка, карта сайта и оповещение поисковиков.
Инфраструктура минимальная. Сайт статический, из HTML-файлов, лежит на обычном хостинге с FTP, без серверной части и базы данных. Управляет всем PowerShell 5.1 на машине автора: 47 скриптов, около 9,7 тысячи строк.
Результат за две недели:
| Показатель | Значение |
|---|---|
| Карточек в журнале / опубликовано | 61 / 56 |
| Вечерних сводок подряд | 7 |
| Время прогона одного материала | около 3 минут |
| Токенов на материал | 2,5–4,5 тысячи |
| Адресов в карте сайта / в индексе Google на 23 октября | 76 / 54 (71 %) |
| Оповещений IndexNow | 45 |
Трафик, по словам автора, на старте почти нулевой, и он считает это ожидаемым: сайту две недели, а новостные запросы в поиске конкурентны. За это время конвейер не сорвал ни одного дня, а все аварии были техническими и лечились в тот же вечер.
Журнал вместо базы и гейт по файлу
От базы данных автор отказался легко: данные конвейера линейны. Есть карточка темы, её состояние и обогащения. Поэтому журнал — это файл JSONL, одна строка на материал. Каждый шаг читает строку, дописывает свои поля и сохраняет обратно. Ни один шаг не хранит состояние у себя.
В карточке лежат заголовок, адрес первоисточника, рубрика, дата, язык, лид, статус, номер темы, список источников, таблица фактов, вывод, блок «полезно», результат фактчека и FAQ. Постоянный адрес страницы вычисляется из данных: дата плюс первые восемь шестнадцатеричных знаков SHA-1 от адреса первоисточника. Получается короткое имя вроде 2026-10-22-2ea2fcfc.html, без транслита и без коллизий в пределах дня.
Ключевым приёмом автор называет то, что гейт публикации проверяет файл, а не флаг. Материал считается опубликованным, только когда на диске есть его HTML-страница. Из этого следует несколько вещей:
- сводки и ленты строятся по существующим страницам, поэтому битых ссылок нет;
- авария в середине цепочки оставляет карточку без страницы;
- такую карточку видно по счётчику, а сайт при этом не ломается.
Как устроена автоматизация создания контента: цепочка за три минуты
Каждый шаг запускается отдельным процессом PowerShell. Запуск выходит дороже, зато падение одного шага не убивает прогон: конвейер записывает шаг в список упавших и идёт дальше, а материал дорабатывается при следующем запуске. Автор приводит секунды из лога прогона 22 октября:
| Шаг | Что делает | Секунды |
|---|---|---|
| сбор новостей | опрос лент, отбор кандидатов | 29 (17 кандидатов) |
| поиск источников | дополнительные источники по сырому заголовку | 3 |
| адаптация | заголовок 45–65 знаков, лид 200–450 знаков | 6 |
| регистрация темы | номер темы и сверка на дубли по всему журналу | 3 |
| анкоры | факт в 8–14 слов на каждый источник | 17 |
| факты | таблица фактов, «что это значит», «что полезно вам» | 17 |
| проверка фактов | сверка утверждений с текстом первоисточника | 14 |
| автопочинка | исправление неудачных проверок до публикации | 15 |
| картинка | генерация в локальной модели | 68 |
| FAQ | четыре вопроса-ответа для разметки | 6 |
| сборка | страница, лента, карта сайта, RSS | 2 |
Прогон стартовал в 17:00:02, материал зафиксирован в 17:03:04. Дольше всего работает генерация картинки на локальной видеокарте, 68 секунд. LLM-шаги в сумме занимают 46 секунд.
Дедупликацию автор сознательно поставил перед всеми дорогими шагами. Сначала заголовок сверяется со всем журналом, потом идут адаптация, факты и картинка. Платить токенами за материал, который через две минуты отсеется как дубль, он называет самой обидной статьёй расходов.
Четыре узких вызова модели
Целиком статью модель не пишет. Каждый из четырёх вызовов решает узкую задачу и возвращает ответ в жёстком формате. По словам автора, так дешевле и стабильнее, а главное, каждую часть можно перепроверить отдельно.
| Вызов | Задача | Лимит токенов | На замере |
|---|---|---|---|
| адаптация | заголовок и лид из англоязычного материала | 900 | около 950 токенов, 3–4 с |
| анкоры | по факту на каждый источник | 300 | 177 токенов, 1,9 с |
| факты | факты, вывод, «полезно» (300–500 слов) | 2 600 | 1 054 токена, 5,7 с |
| FAQ | четыре пары «вопрос-ответ» | 1 200 | 286 токенов, 2,7 с |
На материал уходит 2,5–4,5 тысячи токенов. Автор оценивает это в доли цента при текущих тарифах и делает вывод, что узкое место — качество контракта, а не деньги. Поэтому факты принимаются только в заданной структуре. Если в ответе нет обязательных полей, шаг переспрашивает модель: три попытки с паузой. Сам вызов — обычный HTTP-запрос из PowerShell, без SDK и внешних библиотек.
Модель вынесена в настройки
В первой версии имя модели, адрес API и имя переменной с ключом были прописаны в каждом из пяти скриптов, которые обращаются к модели. Смена модели означала правку пяти файлов. Забытый шестой, обычно запускаемый раз в сутки, обнаруживался по странному поведению в логах.
Теперь есть один резолвер. Он читает настройки, проверяет, что модель есть в каталоге провайдера, и возвращает адрес, модель, ключ и два флага режима. Внутри кэш на десять минут, сброс по времени изменения файла настроек и запасной провайдер по умолчанию. Автор сменил модель в настройках один раз и получил смену «автора» всех материалов без правки скриптов.
Ворота согласования: автоматический постинг новостей, но не без спроса
Публиковать «в интернет без спроса» автор не хотел даже в собственном проекте. Готовая карточка получает номер темы и попадает в hold-список, из которого страница на сервер не выгружается. Одновременно автору приходит письмо и событие в журнал Windows. Сторож ждёт решения десять минут. При «да» он снимает тему с холда, выгружает сайт, обновляет карту и оповещает поисковики. Если решения нет, тема ждёт следующего раза, а прогон продолжается.
Две детали оказались важнее, чем автор ожидал. Первая — дедлайн: без него «согласую потом» превращается в очередь из двадцати материалов и публикацию пачкой, а это ломает ежедневный ритм. Вторая — согласование держится на hold-списке и отдельном каталоге, а не на флаге в карточке. Что ждёт решения, видно по файлам, даже если почта не открыта.
Выгрузка и поисковики
Деплой идёт по FTP со сверкой MD5 по каждому файлу. Сравнение размеров автор считает бесполезным: правка параметра версии в ссылке на стили меняет содержимое, но не длину файла. Перед выгрузкой сайт пересобирается целиком: лента, страницы, карта сайта, RSS и отдельная карта для новостей.
После успешной выгрузки работают три канала оповещения. Карта сайта уходит через API Search Console. Отдельные адреса отправляются через Indexing API с паузой два дня на адрес, иначе квота сгорает на повторах. Для Яндекса и Bing используется IndexNow. Сбой любого канала деплой не ломает: уведомления копятся в очереди до следующего прогона. API Вебмастера Яндекса на момент статьи не работал у автора тринадцатый день, а сайт продолжал выходить.
Отдельный урок касается FTP-хостинга: листинг не показывает файлы, имя которых начинается с точки. Файл .htaccess с редиректами и заголовками безопасности существует и работает, но в листинге его не видно. Проверять скрытые файлы автор советует запросом самого файла. Иначе можно однажды выгрузить сайт «как есть» и потерять редиректы.
Пять поломок и что автор сделал бы иначе
Автор подчёркивает, что все пять случаев взяты из этой системы и уже исправлены.
- Рассуждающая модель съедает лимит. Модель
deepseek-v4.1-flashна шлюзе B.AI возвращает блок рассуждений, и он считается внутриmax_tokens. При лимите 70 токенов ответ пришёл пустым, с 287 знаками рассуждений. При 400 картина повторилась: 1090 знаков рассуждений и снова пустой ответ. Помог флагreasoning_effort: 'none', после него ответ приходит за 2–6 секунд. Значениеlowне помогает. Совет автора: сначала проверить, входит ли блок рассуждений в лимит, и только потом подниматьmax_tokens. - Регистр в именах переменных. Для PowerShell
$Sи$s— одна переменная. В первый раз цикл затёр путь к папке скриптов. Во второй подключаемый резолвер модели объявил свою переменную с тем же именем, что у пути к кэшу сводки. Текст сводки записался в файл кэша модели, и ни одной ошибки при этом не возникло. Вывод автора: подключение через точку выполняет чужой код в вашей области видимости, поэтому имена в модулях стоит префиксовать. - Скрипт без BOM читается как CP1251. При запуске по расписанию файл в UTF-8 без BOM читается в системной кодировке, и кириллица превращается в мусор вплоть до ошибки парсера. Интерактивный запуск того же файла работает. Автор дописывает BOM после каждой правки и называет забытый BOM причиной половины «мистических» падений по расписанию.
- Двоеточие после переменной. Строка вида
"Итоги за $дата:"не компилируется: двоеточие читается как указание диска. Нужно писать${дата}:. Ошибка прилетает в шаблонах сообщений, то есть в самом конце работы. - Без картинки нет страницы. Если генератор картинки падал по таймауту локальной модели, материал молча выпадал из публикации. Квота дня израсходована, статья «принята», на сайте её нет. Лечение — строгий порядок шагов и блок восстановления: на старте прогона конвейер досоздаёт картинку и страницу для карточек с темой, но без страницы.
Иначе автор сделал бы три вещи. Сразу вынес бы модель в резолвер. С первого дня сделал бы шаги идемпотентными, с кэшем результата: на сводках повторный прогон за прошедшую дату переписывал уже опубликованный и проиндексированный текст. И не отдавал бы код 200 на адреса с index.html: через месяц поисковик насчитал тринадцать дублей страниц и прислал письмо о проблемах индексации.
Коротко
- Модель вызывается четыре раза под узкие задачи с жёстким форматом ответа. Невалидный ответ переспрашивается, расход — 2,5–4,5 тысячи токенов на материал.
- Состояние хранится в одном файле-журнале. Опубликованным материал считается, только когда существует его страница, поэтому аварии не ломают сайт.
- Дедупликация стоит до всех платных шагов. Медленнее всего работает генерация картинки, а не языковая модель.
- Человек согласует каждый материал, у решения дедлайн десять минут, иначе материал ждёт в холде.
- Основные потери времени дали не модели, а среда: лимит рассуждений, регистр переменных, кодировка и скрытые файлы на FTP.
Что из этого следует
Кейс полезен тем, кто собирает автоматизацию контента на любом стеке, не только на PowerShell. Несколько приёмов переносятся без изменений: дробить работу модели на узкие вызовы с проверяемым форматом, отсекать дубли до трат на токены, считать опубликованным только то, что реально лежит на сайте, и давать человеку дедлайн на согласование.
Условия у кейса узкие. Это новостной сайт о LLM, статический хостинг и две недели работы, а метрики относятся к индексации, а не к посещаемости. Сам автор пишет, что трафика пока почти нет. На практике это, скорее всего, значит, что кейс подтверждает выполнимость ритма, а не его отдачу.
У себя стоит проверить три вещи. Входит ли блок рассуждений вашей модели в лимит токенов. Что происходит с материалом, если упал один промежуточный шаг. И видно ли без открытия почты, что сейчас ждёт вашего решения.
Источник: Новостной конвейер на PowerShell: три минуты от ленты источников до готовой страницы
