Start herePart 1 of 4

Анатомия платформы для AI-приложений, которая доходит до продакшена

Превратить промпт в работающий продукт — это задача не про модель, а про систему. Перед вами карта всей машины: как сообщение в чате становится изолированной нагрузкой в Kubernetes с собственной веткой Postgres, масштабируемой до нуля; почему работу агента оценивают компиляторы и живые пробы, а не его собственное мнение; и как релиз превращается в продвижение ветки базы данных с якорем для отката. Каждый другой пост в этом блоге разбирает один из блоков этой схемы крупным планом.

Анатомия платформы для AI-приложений, которая доходит до продакшена

Попросите языковую модель сделать React-приложение — и вы его получите. Эта часть работает, и работает уже довольно давно. Дистанцию между этим и продуктом, в который ваши пользователи зайдут завтра — с данными, целыми после вашего следующего деплоя, — не покрыть моделью получше. Её покрывает платформа: изоляция, провижининг, верификация, деплой и восстановление, и каждый из этих слоёв построен так, чтобы агенту было позволено ошибаться, а система всё равно сходилась к результату.

Этот пост — карта. Каждый другой пост в блоге разбирает один из её блоков крупным планом.


Как устроена вся машина

Проект в Adorable рождается из сообщения в чате и живёт как настоящая инфраструктура:

reopened

promotion

passing

Kubernetes namespace (per project)

app pods
Vite + tRPC

catalog services
Redis · CMS · …

chat message

System architect
service selection · task plan

ReAct producer
writes code, runs tools

Objective verification
tsc · contract probes · in-pod tests

dev Postgres branch
copy-on-write, scale-to-zero

prod timeline
pinned commit + checkpoint

custom domain
real users

Пять слоёв, пять разных доменов отказа:

  1. Движок генерации, который планирует и пишет код — и считается ненадёжным по умолчанию.
  2. Шлюз верификации, который решает, что значит «готово», — и он не LLM.
  3. Среда исполнения, которая даёт каждому проекту жёсткую изоляцию — отдельный namespace Kubernetes на проект.
  4. Слой базы данных, рассчитанный на тысячи в основном простаивающих, созданных агентом баз — ветки с копированием при записи, масштабируемые до нуля.
  5. Модель деплоя, где релиз — это операция над метаданными с обязательным якорем для отката: продвижение ветки, а не копирование.

Остальная часть поста проходит по слоям. Определения всех введённых терминов лежат в глоссарии.


Слой 1: движок генерации сначала планирует, потом печатает

Запрос на новый проект никогда не уходит сразу в код. Стадия системного архитектора читает полный каталог сервисов, текущее состояние проекта и итог прошлой генерации, после чего фиксирует план: какие сервисы нужны приложению (база данных, API-сервер, очередь, CMS), как они интегрируются, и упорядоченный набор задач с объявленными областями файлов и критериями приёмки.

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

  • Сжатие контекста с трекером прогресса. Выпавшая история суммируется, а не теряется, а выполненные действия (записанные файлы, выполненный SQL) переживают усечение — так что сборка в 200 шагов не переделывает шаг 12.
  • Защита от спиралей. Диагностические циклы без правок кода прерываются принудительно; раздутые однофайловые выдачи отклоняются ещё до записи на диск.

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

Слой 2: «готово» решается доказательствами, а не моделью

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

  • компилятор TypeScript по каждому объявленному файлу, с проверкой формы импортов и графа модулей;
  • контрактная проба: каждая API-процедура, объявленная архитектором, должна отвечать на живом поде без серверных ошибок, и каждая объявленная таблица должна существовать — процедура, которую агент забыл написать, проваливается объективно, потому что контракт — это объявление архитектора, а не воспоминание продюсера;
  • собственные юнит-тесты приложения, выполняемые в его поде — каждый скаффолд поставляется тестопригодным с рождения, с раннером тестов и рабочим npm test с первого коммита;
  • headless-обход запущенного приложения, когда менялись фронтенд-файлы.

Проваленный слой переоткрывает задачу, помещая доказательство отказа в контекст. В этой цепочке сознательно нет «LLM-критика»: модель, оценивающая модель, сходится к правдоподобному, а не к правильному. Компиляторы, пробы и тесты не торгуются.

Слой 3: среда исполнения — это namespace на проект

Каждый проект работает в собственном namespace Kubernetes — со своими квотами ресурсов, лимитами на ресурсы, деплойментами, сервисами и ingress, сгенерированными из декларативной спецификации. Радиус поражения от любого приложения, в том числе сбойного, ограничен его собственным namespace. Маршрутизация по поддоменам для каждого приложения, wildcard-TLS и веб-интерфейсы для каждого сервиса — всё это выпадает из одного и того же генератора манифестов.

Проект не ограничен одним приложением: он может обрасти соседними приложениями и каталожными сервисами в том же namespace, а платформа сходится к объявленному набору в одной точке-горлышке — fail closed, никогда не скатывается к молчаливому фолбэку.

Экономика простоя — конструктивное ограничение первого класса. Приложения, которые никто не смотрит, замораживаются на уровне cgroup (ноль CPU, почти ноль памяти, мгновенная разморозка); их базы данных масштабируют compute до нуля. Флот выходных проектов стоит ровно столько, сколько должен: ничего, пока он спит.

Слой 4: слой базы данных выбран под агентов, а не под людей

Сущность, создающая здесь базы данных, — это агент, который провижинит сотни короткоживущих, в основном простаивающих баз; такая нагрузка ломает допущения схемы «Postgres на приложение». Ответ — Postgres с разделёнными хранилищем и compute и ветвлением через копирование при записи (self-hosted Neon):

Дешёвое ветвление — это ещё и то, что даёт агенту кнопку undo для данных: он делает снапшот перед рискованными миграциями и откатывается, когда какая-то из них ломает данные — код И данные вместе, к одному согласованному моменту.

Слой 5: релиз — это продвижение ветки с якорем для отката

Выход в продакшен не двигает никаких данных. Прод — это долговечный таймлайн; дев — его форк с копированием при записи. Каждый релиз закрепляет git-коммит, архивирует выпущенное дерево, ставит тег pre-deploy чекпойнта на таймлайне прода и применяет отложенные миграции — строка в append-only журнале на каждый релиз. Повторные деплои сохраняют таймлайн данных продакшена; замена данных прода на данные дева — это отдельная, явная, снапшотированная операция, никогда не побочный эффект.

Откат следует той же дисциплине: повторно задеплоить закреплённый коммит, опционально восстановить данные к эпохе того релиза — и платформа явно проговаривает, что откату позволено физически удалить: только то, что восстановимо из git или регенерируемо из спецификации.


Соединительная ткань: построено под прерывания

Всё вышесказанное исходит из того, что отказ — нормальный вход. Сборки умирают на полпути (вытеснение подов существует); проход реконсиляции обнаруживает каждую прерванную сборку и восстанавливает согласованную, возобновляемую картину — состояние задания, цепочку задач, локи, поток чата. Секреты идут единственным обязательным путём через Vault в namespace-Secrets, так что перезапуск контейнера не может потерять свои учётные данные. Трекинг ресурсов записывает всё, что создаёт проект, так что удаление получается полным.

Ничего из этого не появляется в демо. Но именно всё это и есть разница между сгенерированным превью и софтом, который можно отдать клиенту — а это и есть тезис следующего поста.


FAQ

Что происходит, когда ИИ пишет сломанный код? Верификация ловит это с доказательством — ошибкой компиляции, проваленной контрактной пробой, красным тестом — и переоткрывает задачу с этим доказательством в контексте. Агент чинит против фактов, а не против собственного мнения о своей работе.

Где на самом деле работает моё приложение? В собственном namespace Kubernetes на платформе: выделенные поды, квоты, ingress и TLS, со своей веткой PostgreSQL. Не в общей песочнице.

Сколько стоит простаивающее приложение? Фактически ничего. Контейнеры замораживаются (ноль CPU), compute базы данных масштабируется до нуля реплик, и оба прозрачно просыпаются на следующем запросе.

Отделены ли данные продакшена от дева? Да — с первого же деплоя у продакшена свой таймлайн данных. Деплои применяют к нему миграции; они никогда не перезаписывают его данными дева. Деструктивное направление существует только как явное, снапшотированное действие.

Можно ли откатить плохой релиз? Каждый релиз закрепляет коммит и ставит тег pre-deploy чекпойнта. Откат восстанавливает код, а опционально и данные, к эпохе того релиза.

Могу ли я забрать своё приложение в другое место? Проект — это обычный git-репозиторий: Vite + React + tRPC + PostgreSQL, с миграциями в db/migrations. Он синхронизируется с GitHub и запускается везде, где запускается этот стек.

Создавай на той самой платформе, о которой эти посты.

Опиши своё приложение простыми словами — Adorable напишет код, настроит базу данных и выкатит его в онлайн.

Начать бесплатно