Часть 1 — Сайты под управлением ИИ: что это на самом деле и сколько стоит.
Часть 2 — Вы сейчас здесь
Часть 3 — На подходе
Это вторая часть из трёх. В первой мы разбирались с концепцией: что такое сайт под управлением ИИ на самом деле, чем он не является, сколько стоит, есть ли инференс в рантайме (спойлер: для посетителя — нет). Если читали — отлично. Если нет — здесь будет понятно и без неё, потому что речь пойдёт про другое: про механику.
Здесь я хочу честно показать, как у нас устроено под капотом: где живёт модель, как она правит код, почему она физически не может одним неудачным запросом снести прод, чем гарантируется, что сгенерированный код вообще валиден, и как мы развели версионирование кода и контента, чтобы откат дизайна не уносил с собой свежие статьи. Всё на примере живых стеков, которые как раз и работают под этим управлением.

Сразу оговорюсь про термины. Когда я говорю «нейросеть на сервере», это не self‑hosted LLM — на сервере крутится сайт и тонкий посредник. Интеллект — снаружи, внешним API класса Claude. Это важно для понимания всей архитектуры, поэтому давайте с неё и начнём.
Связка LLM ↔ сайт: MCP‑сервер как руки модели
Первый вопрос, который задаёт любой инженер: а как именно нейросеть‑то правит сайт? Через SSH? Дёргает git? Пишет в файловую систему напрямую? Ребят, всё проще и скучнее, чем рисует воображение.
Между моделью и сервером стоит тонкий посредник — MCP‑сервер. Это, грубо говоря, один файл на Node, примерно 11 КБ, висит на отдельном порту на dev‑сервере. Транспорт — Streamable HTTP плюс SSE, авторизация Bearer‑токеном. Вот и весь «мозговой центр» со стороны железа. Он не думает. Он раздаёт модели руки.
Рук ровно четыре:
|
Инструмент |
Что делает |
|---|---|
|
bash |
выполняет команду на dev‑сервере под обычным пользователем |
|
claude_prompt |
вложенный вызов модели под отдельную подзадачу |
|
list_screenshots |
список автоскриншотов со стейджинга |
|
get_screenshot |
конкретный скриншот — посмотреть на результат глазами |
То есть модель не «подключена к сайту» каким‑то особым протоколом. У неё есть bash на dev‑машине — и всё, что человек‑разработчик делает руками в терминале, она делает теми же командами. Читает код через cat, грепает, правит файлы, гоняет сборку. Для длинных автономных задач — Claude Code в tmux, чтобы сессия не отваливалась.
Принцип за этим тоже простой: интерфейс должен быть тонким и общим. Один bash вместо десятка узких ручек вроде «обнови‑меню», «опубликуй‑пост», «измени‑цвет‑кнопки» — меньше поверхность атаки, проще поддерживать, не нужно вшивать в брокер каждую новую команду, она и так есть.
Теперь самое интересное — полный цикл от запроса до прода. Разложу по шагам, потому что именно в этой цепочке зашита вся безопасность.
-
Запрос на естественном языке. «Поправь блок героя на главной, кнопку прижми к левому краю контейнера». То самое ТЗ, которое в классической студии превращается в три с половиной недели переписки.
-
Модель читает канон и код. cat docs/*.md — проектная база знаний, карта секций, дизайн‑система. Потом смотрит сам код. Это не fine‑tuning, это retrieval по требованию: канон маленький, влезает в контекст, векторная база не нужна.
-
Правит файлы — на dev‑сервере. Это VDS-2 в Нидерландах. Подчёркиваю: на dev, не на проде.
-
Собирает и смотрит на стейджинге. npm run build, затем pm2 restart и автоскриншоты через Playwright — desktop и mobile. Стейджинг живёт на тестовом поддомене.
-
git push в main. И вот тут начинается самое важное.
-
GitHub Actions: npm ci → build → пост‑проверка бандла → rsync каталога.next на прод (VDS-1, Россия) → pm2 restart → health‑check через curl.
Ключевое, ради чего вся конструкция и затевалась: модель не пишет в прод напрямую. Прод обновляется только готовым артефактом сборки через CI. Это не формальность, а несущая стена. Модель живёт на dev‑машине в другой стране и физически не имеет туда руки, которой можно было бы что‑то записать на боевом сервере мимо пайплайна.
Отдельный поток — контент. Тексты, поля ACF — это не git. Это идёт через wp‑cli и админку headless‑WordPress, мимо сборки. Почему так — разберём ниже, в разделе про версионирование. Пока запомните разводку: код едет через CI, контент живёт в базе.

Деньги и «нейросеть на сервере»: что на самом деле крутится на дешёвом VDS
Маленькое отступление, потому что на этом месте инженеры справедливо ловят противоречие. В первой части звучали цифры: VDS за 2–3 тысячи рублей в месяц и «50–100 долларов на нейросеть». И тут же — «разместить нейросеть на сервере». Стоп. На двух‑трёх тысячах рублей self‑hosted LLM не живёт. Это GPU‑инстанс за десятки тысяч.
Всё верно, противоречия нет — потому что на сервере никакой LLM и не размещено. На дешёвом VDS работает только сайт: Next.js, headless WordPress, MariaDB — и тонкий MCP‑брокер. Модель исполняется у провайдера, на его GPU, через внешний API. «Разместить нейросеть на сервере» в исходной, маркетинговой формулировке — это разместить агента‑посредника, который даёт модели руки. Сам интеллект снаружи.
А «50–100 долларов в месяц» — это порядок расходов на API‑токены при активной разработке. Не аренда GPU. И, что важно для расчётов: эта сумма к посещаемости не привязана вообще. Хоть миллион визитов в день — рантайм‑токенов ноль, потому что посетителю отдаётся пререндеренная статика без единого вызова модели. Токены тратятся только когда что‑то меняешь в коде или контенте.
И раз уж зашли так глубоко — два слова о том, на какой машине это всё живёт. Тут есть выбор, и я хочу его проговорить, потому что в комментариях этот вопрос возникает регулярно.
Форматов развёртывания на практике два. Совмещённый — когда dev и prod лежат на одной VDS, в разных каталогах, под разными пользователями: у dev‑пользователя нет прав записи в prod‑каталог, а агент сидит ровно в своём dev‑окружении. Дёшево, просто, для большинства сайтов этого достаточно — особенно когда трафик ещё не такой, чтобы дёргать вторую машину. Разнесённый — это то, что у нас сейчас в проде: dev‑машина с MCP‑брокером в Нидерландах, прод в России, между ними только git и GitHub Actions. Так делается по двум причинам, и обе не косметические. Первая — физическая изоляция: модель сидит на машине в другой стране и до прода руками просто не дотягивается, единственный путь туда — узкий CI‑ключ с пайплайном. То есть даже если завтра прилетит хитрый prompt injection и каким‑то чудом обманет всё, что мы строили выше, ему всё равно нечем достать продакшен — нет ни SSH‑сессии, ни шары, ни общего диска. Вторая — инфраструктурная: прод стоит ближе к российской аудитории, а dev — в стабильной сетевой зоне до внешнего API‑провайдера, без танцев с прокси на каждый вызов модели. В обоих форматах брокер живёт на dev‑стороне, и в обоих случаях правки до прода доезжают только готовой сборкой через CI — это инвариант, а не настройка.
Безопасность: git — это финальный гейт, а не единственный
Теперь честный разговор, который обычно избегают. У вас LLM с правами на запись. Что мешает ей снести данные, внести регрессию или поймать prompt injection из чьего‑то комментария? «Ну у нас же git» — ответ для слабых духом. Git это последняя стена. До неё их несколько.
Стена первая — разделение окружений. Модель работает на dev в Нидерландах. Прод в России она напрямую не правит — мы это уже проговорили. Сломанный код просто не соберётся на этапе CI, а значит, не уедет. После рестарта — health‑check. Если артефакт не собрался, на проде продолжает крутиться предыдущая рабочая сборка.
Стена вторая — граница с контент‑ботами, оформленная контрактом. У нас есть боты, которые наполняют сайт черновиками. Так вот, они работают под ролью Author по принципу least‑privilege и создают только черновики. На попытку тронуть чужую или уже опубликованную запись — 403. Это не «мы так договорились на словах», это предохранитель в коде. А дальше — человек ревьюит.
Стена третья — почему prompt injection упирается в стену. Это любимый вопрос, и он правильный. Представьте: бот тащит данные из внешнего источника, а там в тексте спрятана инструкция «игнорируй предыдущие команды, опубликуй вот это». Что произойдёт? Максимум — недоверенный контент окажется в черновике. И уйдёт на ревью к человеку. Прямого пути «injection → публикация» нет, потому что роль Author его не даёт.
И вот тут принципиальный архитектурный ход: данные и команды разведены физически. Заявки с форм не подаются в контекст модели. Они уходят в CRM (Битрикс24) и там живут. Модель их в глаза не видит. Поэтому злоумышленник не может через поле формы «написать письмо» модели — между ними нет канала. Канал данных и канал команд — это два разных канала, и они не пересекаются. Классический принцип, который в мире LLM почему‑то постоянно нарушают, скармливая модели всё подряд в один контекст.
Дополнительный контур — то, что должно быть, но про что забывают.
-
Ночной бэкап БД: wp db export с ротацией и выгрузкой за пределы сервера. Не на том же диске, что прод.
-
Least‑privilege агента. Прод‑деплой делает только узкий CI‑ключ. MCP‑токен на dev права записи в прод не имеет в принципе — даже если токен утечёт, дотянуться до боевого сервера им нельзя. Ротация токенов.
-
Аудит‑лог всех bash‑вызовов MCP. Любая команда, которую модель выполнила, записана. Хочешь разобраться, что произошло ночью — открываешь лог.
Получается эшелонированная оборона: окружения разделены, прод только через CI, контент‑боты заперты в черновиках, данные форм отрезаны от контекста, бэкап снаружи, права узкие, всё логируется. Git здесь — это финальная подушка, к которой можно откатиться. А не первая и единственная линия.
Детерминизм: как верифицировать код, который пишет недетерминированная модель
Теперь — больной для любого инженера вопрос. LLM недетерминирована. На один и тот же запрос она даёт разный вывод. Как на этом фундаменте гарантировать валидную микроразметку, воспроизводимый результат, отсутствие регрессий? Как вообще доверять коду, который написала вероятностная машинка?
Ответ: никак не доверять. Доверие тут — неправильное слово. Верификация смещена на детерминированные гейты. Вывод модели либо проходит фиксированный набор проверок, либо не мержится. Точка.
Разберём по слоям, от самого важного.
Микроразметка не пишется руками «на глаз». Это, пожалуй, главное непонимание. Кажется, что модель построчно генерирует JSON‑LD для каждой страницы — и тогда да, на 2200 страницах где‑нибудь обязательно проскочит невалидная схема. Но так это не работает. Микроразметка и SEO‑структуры строятся из кода функциями: organizationJsonLd, articleJsonLd, BreadcrumbList, FAQPage. В функцию подставляются данные из WordPress — и на выходе schema валидна по построению. Один шаблон на тип страницы. Модель пишет и сопровождает эти функции, но не штампует разметку поэкземплярно. Воспроизводимость берётся отсюда: не из дисциплины модели, а из того, что генерация сведена к детерминированной операции.
Это общий принцип, и он шире микроразметки. Везде, где можно, свободная генерация заменяется на параметризованный шаблон. Дорогая, недетерминированная генерация зовётся только там, где реально нужен уникальный текст.
TypeScript в строгом режиме плюс ESLint. Первый фильтр. Модель напутала с типами — не компилируется.
next build с пре‑рендером — настоящий детерминизм‑гейт. Вот это ключевое. Сборка с пререндером страниц реально гоняет код и валит билд на расхождениях. Живой пример, не выдуманный: однажды сборка упала на Cannot query field «stageSlide». Что произошло — схема ACF на dev‑WordPress отстала от прода, в GraphQL появилось поле, которого dev ещё не знал. Build упал на пре‑рендере. И — внимание — поломка осталась на стейдже. До прода не доехала, потому что в прод едет только то, что собралось. Вот так детерминированный гейт ловит дрейф схемы, который никакой «проверкой глазами» не выловишь.
Schema.org через Rich Results Test. Проверка валидности микроразметки уже на собранной странице.
Стейджинг плюс Playwright‑скриншоты — desktop и mobile, автоматом после сборки.
Lighthouse скриптовым прогоном. Не разовый скриншот «смотрите, 100%», а повторяемый прогон. Повторяемость — обязательное свойство, иначе это не верификация, а лотерея.
# огрублённая логика гейта между моделью и продомtsc --noEmit # типыeslint . # линтnext build # пре-рендер: падает на дрейфе схемы# → rich results test, lighthouse (скриптом)# только зелёное мержится в main
Логика простая: модель может ошибаться сколько угодно — её на этом ловят детерминированные проверки, а не человеческое «вроде нормально выглядит». Автоматизацию Rich Results Test и Lighthouse прямо в CI мы держим в бэклоге — сейчас часть из этого гоняется отдельным скриптом, но направление понятное: чем больше проверок в пайплайне, тем меньше остаётся на ручной глаз.
Версионирование: код в git, контент в MariaDB — и почему это спасает
Теперь про разводку, которую я обещал. Она объясняет один из самых эффектных кейсов и заодно одну неочевидную ловушку.
Архитектура headless ровно за этим и нужна: код и контент разделены by design. Компоненты, стили, токены дизайна, логика — в git. Контент и поля ACF — в MariaDB. Это два разных мира, версионируемые по‑разному.
Кейс из жизни. Заказчик попросил переделать весь сайт под газету — строгую журнальную типографику заменить на газетную, с вырезками. Сделали за одну сессию. Заказчик покайфовал три дня, потом пришёл: «Верните как было». Откатили через git.
И вот тонкий момент. Откат затронул только код — токены и стили. А кейсы, которые контент‑менеджеры опубликовали за эти три дня, остались на месте. Почему? Потому что они в базе, а откат был кодовым. Газетный эксперимент был чисто визуальным: трогали токены и стили, схему ACF не меняли. Поэтому откат кода свежий контент не унёс.
Но здесь зарыт нюанс, на котором легко обжечься. Если эксперимент меняет схему — добавляет или переименовывает поля ACF (тот самый slide → stageSlide), — то откат кода схему БД назад не вернёт. Код и база разъедутся. Поэтому правило: перед сменой схемы — снапшот базы, wp db export. Откатывается код — да, мгновенно. Контент в базе — нет, и это правильно, иначе каждый эксперимент с дизайном грозил бы потерей свежих публикаций. Просто надо помнить, по какой границе проходит разлом: визуальный эксперимент безопасен, структурный требует снапшота.
|
|
Код |
Контент / ACF |
|---|---|---|
|
Где живёт |
git (репозиторий фронта) |
MariaDB |
|
Как катится |
через CI на прод |
wp‑cli / админка, мимо сборки |
|
Откат |
git revert, мгновенно |
из снапшота wp db export |
|
Эксперимент со стилями |
откат не трогает контент |
контент остаётся |
|
Эксперимент со схемой ACF |
откат кода схему не вернёт |
нужен снапшот ДО |
Стейджинг: отдельный клон базы и дрейф, который ловит сборка
Раз уж всплыл stageSlide, договорим про стейджинг. Тестовый домен — это не прод и не его симлинк. Это отдельный WordPress (dev‑WP на VDS-2) со своим клоном прод‑базы.
Синхронизация — дампом. wp db export с прода, импорт в dev. Имена БД и siteurl совпадают, поэтому search‑replace не нужен — экономит время и нервы. Тяжёлый импорт гоняем фоном через nohup, чтобы не держать сессию. Медиа не копируем вовсе — картинки отдаёт прод со своего origin. Зачем дублировать гигабайты изображений на стейдж.
Слабое место честно назову: синхронизация ручная и периодическая. Между прогонами схема на dev может отстать от прода — как раз и случился stageSlide, когда на проде поле уже было, а на dev ещё нет. Но именно поэтому дрейф схемы и ловит сама сборка на стейдже: build падает на пре‑рендере, поломка остаётся на стейдже, до прода не доходит. Слабое место подстраховано build‑гейтом. Усиление, которое напрашивается, — scheduled‑синхронизация плюс diff схемы через introspection прода против dev перед сборкой. Это в планах. Но даже сейчас цена ошибки — красный билд на стейдже, а не падение прода.
Воспроизводимость: что реально стоит за «1,5 дня на перенос»
И последнее — про сроки, потому что цифра «перенесли сайт за полтора дня» звучит как маркетинговая сказка, и я хочу разобрать её честно, по‑инженерному. Полтора дня — это не разовый рекорд при идеальной погоде и не клон готового образа в одну команду. Это переиспользование скелета стека плюс ручная серверная обвязка по чек‑листу.
Что переиспользуется как шаблон:
-
Репозиторий фронта: Next.js 16 на App Router, Tailwind v4, типовой набор ACF‑блоков. Костяк, который на новом проекте клонируется, а не пишется заново.
-
mu‑плагины: GraphQL‑мосты, форма → CRM, проброс Yoast в GraphQL. Это PHP в wp‑content/mu‑plugins, живёт на сервере.
-
Код MCP‑брокера — тот самый server.mjs.
-
CI‑workflow — deploy.yml.
-
CLAUDE.md — инструкции для модели по проекту.
Новый проект начинается с клонирования этого скелета. Дальше модель адаптирует под конкретную нишу.
Что руками, и от чего полтора дня не сжимаются до полутора часов:
-
Провижининг VDS: Node, PHP‑FPM, MariaDB.
-
Конфиг nginx и pool для PHP‑FPM. Их, кстати, в репозитории нет — серверная обвязка живёт отдельно от кода фронта.
-
SSL, DNS.
То есть «1,5 дня» = клон скелета (быстро) + серверная обвязка по чек‑листу (руками). Честно: пока серверная часть ставится вручную, цифра воспроизводима ровно настолько, насколько аккуратен чек‑лист. Следующий шаг — productization этой части: Ansible или cloud‑init. Когда серверная обвязка станет образом, «полтора дня» сожмутся и перестанут зависеть от того, кто и насколько внимательно прошёл по списку. Это в планах, и я специально не выдаю это за уже сделанное.
Что в сухом остатке
Если свести всю механику к нескольким тезисам:
-
Модель не подключена к сайту магией. У неё bash на dev‑машине через тонкий MCP‑брокер. Всё, что она делает, делает теми же командами, что и человек.
-
В прод она не пишет. Прод обновляется только собранным артефактом через CI. Сломанное не собирается и не уезжает.
-
Недетерминированность LLM компенсируется детерминированными гейтами: типы, линт, next build с пре‑рендером, валидаторы схемы. Микроразметка строится функциями и валидна по построению, а не пишется руками.
-
Безопасность эшелонирована: разделение окружений, least‑privilege, контент‑боты заперты в черновиках, данные форм отрезаны от контекста модели, бэкап снаружи, аудит‑лог.
-
Код и контент разведены: откат дизайна не уносит свежие публикации. Структурные изменения требуют снапшота базы.
Ничего фантастического, обычная «гигиена», выстроенная вокруг того, что одним из исполнителей в команде стала модель.
В третьей, заключительной части: SEO и GEO под капотом, стратегия рендеринга (SSG/ISR и почему контент появляется на статике без передеплоя), как Яндекс видит контент до гидратации, массовые операции на тысячах страниц (1200 страниц за 3,5 часа — батчинг, идемпотентность, цена ночи в токенах), полуавтоматическая перелинковка 2200 страниц, интеграции с 1С и Битрикс24 и механика переезда с сохранением трафика…
ссылка на оригинал статьи https://habr.com/ru/articles/1049876/