Контент-завод на LLM: архитектура без копирайтеров
TL;DR. Мы построили пайплайн, который превращает базу источников в готовые черновики статей: ингестация данных, RAG-поиск по векторному хранилищу, оркестрация нескольких агентов и отдельный слой контроля качества. Итог за три месяца: время подготовки черновика упало с 6–8 часов до 40–50 минут, стоимость одной статьи — с примерно 4500 до 1300 рублей, точка безубыточности достигнута на четвёртом месяце. Ниже — как это устроено, сколько стоит и где мы набили шишки.
Задача: почему ручная редактура не масштабировалась
Мы выпускаем экспертный контент по нескольким техническим направлениям. До автоматизации типовой цикл выглядел так: редактор собирал источники, вычитывал их, писал черновик, проверял факты, приводил текст к редполитике. На одну статью уходило 6–8 часов, и это без учёта согласований.
Проблема была не в скорости письма, а в подготовке. Большую часть времени съедал поиск и сверка: нужно было держать в голове десятки документов, находить релевантные фрагменты и не переписывать одно и то же по третьему разу. При объёме 30–40 статей в месяц это давало предсказуемый потолок: команда упиралась в часы, а не в идеи.
Мы поставили узкую цель — не «заменить редактора», а снять с него рутину подготовки и первичного черновика. LLM (Large Language Model, большая языковая модель) хорошо генерирует связный текст, но сам по себе не знает наших источников и склонен к галлюцинациям — уверенным выдумкам. Значит, модели нужно давать факты под руку, а результат — проверять. Отсюда выросла архитектура из трёх частей: поиск по знаниям, генерация агентами и контроль качества.
Архитектура пайплайна: от источников к контексту
Первый блок — ингестация данных. Мы собираем материалы из внутренней базы, публичных документов и наших прошлых статей, приводим к единому формату и режем на фрагменты. Чанкинг делаем по смысловым границам, а не по фиксированному числу символов: абзац или логический блок целиком, с небольшим перекрытием. Это заметно поднимает качество последующего поиска, потому что фрагмент не обрывается на середине мысли.
Каждый чанк превращается в эмбеддинги — числовые векторы, кодирующие смысл текста. Для этого мы используем Sentence-transformers: модель работает локально, не гоняет данные наружу и обходится дёшево. Векторы складываем в векторное хранилище. Начинали на ChromaDB — его хватает, чтобы поднять прототип за день. Позже протестировали Weaviate и Pinecone; для нашего объёма (сотни тысяч фрагментов) остались на self-hosted Weaviate из соображений юнит-экономики, но Pinecone держим как запасной управляемый вариант.
Дальше работает RAG (Retrieval-Augmented Generation, генерация с извлечением данных). Когда приходит тема статьи, система выполняет семантический поиск по хранилищу: находит фрагменты, близкие по смыслу к запросу, а не по совпадению слов. Это принципиально — редактор формулирует тему свободно, а не подбирает ключевики. Найденные фрагменты становятся контекстом для модели.
Один нюанс мы поняли не сразу: семантический поиск возвращает много «около-релевантного». Поэтому между поиском и генерацией мы поставили reranker (ранкировщик) — отдельную модель, которая переупорядочивает кандидатов по точной релевантности к запросу и отсекает лишнее. Без него в контекстное окно попадал мусор, и это ело токены и качество. С reranker в модель уходит 8–12 действительно нужных фрагментов вместо 40 случайных.
Смысл RAG в том, чтобы не полагаться только на параметрическую память — то, что модель «помнит» из обучения. Параметрическая память устаревает и не знает наших внутренних данных. RAG подставляет свежие факты в контекст на лету, и статья опирается на проверяемые источники, а не на общие представления модели.
Оркестрация агентов: разделение труда вместо одного промпта
Мы быстро отказались от идеи «один большой промпт делает всё». Такой подход даёт средний результат по всем задачам сразу: и структура рыхлая, и факты плывут. Вместо этого мы разбили работу на роли и связали их в промпт-цепочки (prompt chains) — последовательность шагов, где выход одного становится входом другого.
Оркестрация устроена так. Первый агент собирает структуру: по теме и найденному контексту предлагает план из заголовков H2. Второй наполняет каждый раздел, опираясь строго на переданные фрагменты. Третий приводит текст к нашей редполитике — тон, обращение на «вы», запрет на хайп. Каждый шаг — отдельный вызов с узкой задачей, и это даёт стабильность.
Отдельно стоит агент-критик. Его задача — не писать, а придираться: он проверяет, что каждое фактическое утверждение подкреплено источником из контекста, ищет логические разрывы и отмечает места, где текст ушёл в воду. Если критик находит проблемы, запускается итеративная генерация: раздел переписывается с учётом замечаний. Обычно хватает одного-двух проходов; больше — сигнал, что тема плохо покрыта источниками.
Для оркестрации мы сравнивали LangChain, LlamaIndex и AutoGen. LlamaIndex удобен на этапе индексации и работы с данными, и часть ингестации живёт на нём. LangChain взяли для сборки промпт-цепочек. AutoGen пробовали для многоагентного диалога «писатель — критик»; он выразителен, но для нашего линейного процесса оказался избыточным, и в проде мы оставили более простую собственную оркестрацию поверх LangChain. Здесь важно не гнаться за фреймворком, а брать инструмент под конкретный шаг.
По моделям мы тоже не стали моногамны. Основную генерацию ведёт Claude 3.5 Sonnet — он хорошо держит длинный контекст и стиль. Часть задач, где нужна была другая интонация, гоняли на GPT-4o. Для дешёвых массовых операций — классификации, коротких переформулировок — используем self-hosted LLM на базе Mistral: это снимает нагрузку по токенам с платных API. Часть их пользы для нас — способность следовать сложным инструкциям и держать заданную роль, которую мы не программировали явно.
Контроль качества: как мы боремся с галлюцинациями
Генерация без проверки в редакции недопустима. Поэтому поверх агентов стоит отдельный слой контроля качества (QA layer) — набор автоматических проверок, через которые проходит каждый черновик, прежде чем попасть к человеку.
Первый рубеж — фактчекинг. Для каждого фактического утверждения система сверяет его с фрагментами, которые были в контексте. Если утверждение не находит опоры в источниках, оно помечается как непроверенное. Это прямой ответ на галлюцинации LLM: модель физически не должна вводить факты, которых нет в переданных данных, а если ввела — мы это ловим.
Второй рубеж — формальные проверки. Мы прогоняем текст на соответствие структуре (нужное число разделов, наличие TL;DR), на стоп-слова из редполитики, на длину абзацев. Всё, что нарушает правила, возвращается на доработку до участия человека.
QA layer не делает статью идеальной — он делает её безопасной для редактора. На выходе человек получает черновик, где спорные места уже подсвечены, а не спрятаны. Это меняет саму роль редактора: он не ищет ошибки с нуля, а принимает решения по отмеченным точкам. Финальную ответственность за публикацию мы оставили за человеком осознанно — автоматическому фактчекингу мы доверяем фильтрацию, но не последнее слово.
Готовый и одобренный текст уходит в публикацию через интеграцию с CMS API: пайплайн сам создаёт черновик в нашей системе управления контентом с проставленными заголовками и метаданными. Редактор открывает уже почти готовую запись, а не переносит текст руками.
Юнит-экономика: сколько это стоит и когда окупается
Автоматизация имеет смысл, только если сходится по деньгам. Мы считали юнит-экономику с самого начала, потому что API-вызовы LLM — это переменные расходы, которые легко упустить.
Основная статья затрат — токены. Одна статья проходит через несколько агентов, и каждый вызов тратит токены на вход (контекст плюс инструкции) и на выход. Здесь окупились два решения. Первое — reranker, который урезал контекст и снял лишние токены на входе. Второе — вынос дешёвых операций на self-hosted Mistral, чтобы не платить за них по тарифам GPT-4o и Claude 3.5 Sonnet.
Цифры получились такие:
- Стоимость подготовки одной статьи: с ~4500 до ~1300 рублей.
- Время до готового черновика: с 6–8 часов до 40–50 минут.
- Пропускная способность: с 30–40 до 90–110 статей в месяц без роста команды.
Инфраструктура — векторное хранилище, self-hosted модель, сервисы на FastAPI — даёт фиксированную часть расходов. Мы наложили эти постоянные затраты на экономию с каждой статьи и получили точку безубыточности: при нашем объёме проект вышел в плюс на четвёртом месяце. ROI считаем консервативно, по сэкономленным часам редакторов плюс приросту выпуска: за первый год возврат оцениваем примерно в 2,7x к вложениям в разработку и инфраструктуру.
Важная оговорка про масштаб. Если бы мы выпускали 5 статей в месяц, экономика бы не сошлась: постоянные расходы на инфраструктуру не отбивались бы. Автоматизация окупается на объёме — это стоит честно посчитать до старта, а не после.
Грабли: что мы поняли за три месяца
Первое — промпт-дрейф (prompt drift). Со временем правки в инструкциях накапливались, и поведение агентов незаметно уходило в сторону: то тон плыл, то структура ломалась. Лечится это дисциплиной промпт-инжиниринга: версионирование промптов, набор тестовых тем и регулярный прогон, который показывает, что после правки ничего не поехало.
Второе — качество упирается в источники, а не в модель. Если по теме в базе мало материалов, никакая LLM не спасёт: RAG подставит скудный контекст, и статья выйдет пустой. Мы научились на этапе поиска оценивать покрытие темы и честно возвращать редактору сигнал «данных мало», вместо того чтобы генерировать красивую воду.
Третье — не отдавайте последнее слово автоматике. Наш пайплайн доводит статью до 80–85% готовности, и это правильная граница. Попытки закрыть оставшиеся проценты полной автоматизацией стоили непропорционально дорого и повышали риск незамеченных ошибок. Человек на выходе — не пережиток, а часть архитектуры.
Если обобщить: ценность дал не отдельный «умный» компонент, а связка. RAG даёт факты, оркестрация агентов — структуру и роли, QA layer — безопасность, юнит-экономика — смысл всё это держать. Мы не заменили редакцию — мы убрали из неё рутину и подняли потолок выпуска. Для нас это и есть рабочее применение AI: не обещания, а посчитанный результат.