The databasePart 1 of 6

Почему Postgres с разделёнными storage и compute — правильная база данных для AI-агентов

Базы данных больше создаёт не человек, заполняющий форму на провижининг, — это делает агент, поднимающий сотни короткоживущих и почти всё время простаивающих баз. Такая нагрузка ломает предпосылки, на которых строится традиционный подход «один Postgres на приложение». Вот почему разделение storage и compute с branching по принципу копирования при записи и масштабированием до нуля — это архитектура, которая действительно подходит, разобранная примитив за примитивом в проекции на то, что делают агенты.

Почему Postgres с разделёнными storage и compute — правильная база данных для AI-агентов

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

Агент, который строит приложение, хочет получить базу данных так же, как файл: создать на месте, тут же на ней итерировать, выбросить, если она оказалась неправильной. И всё это ему нужно делать неаккуратно — без человека, взвешивающего, безопасна ли миграция, обратим ли backfill, стоит ли поднимать ещё одну базу. Вся ценность агента в том, что он действует; база, вокруг которой приходится ходить на цыпочках, тормозит цикл.

Поэтому настоящий вопрос не «как дать агенту базу данных». Он звучит так: как сделать операции с базой настолько дешёвыми и обратимыми, чтобы агент мог свободно создавать их и итерировать на лету и сам исправлять свои ошибки? Это вопрос архитектуры, и ответ — перестать привязывать данные к запущенному процессу.

Это не умозрительные рассуждения. Когда Databricks приобрела Neon в 2025 году, главной цифрой стало то, что более 80% баз данных на платформе создавались AI-агентами, а не людьми — по сравнению с ~30% годом ранее, причём агенты создавали тысячи баз в день. Модель провижининга, рассчитанная на долгоживущие инстансы в человеческом темпе, для такой нагрузки не годится.

Этот пост — архитектурная аргументация: как на самом деле выглядит агентная нагрузка на базы данных, почему очевидные решения проваливаются и как три примитива — branching по принципу копирования при записи за O(1), compute с масштабированием до нуля и ветвление по LSN — чисто ложатся на то, что делают агенты. Сопутствующие посты подробно разбирают два из этих механизмов (масштабирование до нуля, путешествие во времени); этот же — о том, почему это правильные примитивы.


Как выглядит агентная нагрузка на базы данных

У отношения агента к базе данных есть пять свойств, которых нет у человека:

  • Многочисленность. Один прогон агента может потребовать сразу несколько баз (на приложение, на эксперимент, на тест). В масштабах платформы это тысячи баз, создаваемых программой на машинной скорости.
  • Мгновенность. Агент обращается с базой как с файлом — он рассчитывает создать её и тут же использовать, а не завести тикет и ждать минуты.
  • Почти всегда простаивают. Подавляющее большинство — это эксперименты, недостроенные сборки или приложения, ждущие своего первого пользователя. Совокупная утилизация низкая; длинный хвост огромен.
  • Требуется изоляция. Ошибка агента в базе одного приложения не должна задеть базу другого. Мультитенантность «по фильтру» недостаточна, когда тенант — это бесконтрольная программа.
  • Склонность к ошибкам и необратимость. Агенты выполняют миграции и UPDATE уверенно и временами катастрофически. Данным нужен undo.

AI agent

db: app A — warm

db: app B — idle

db: experiment — idle

db: preview — idle

db: throwaway — idle

Картинка, которую стоит держать в голове: веер из множества баз данных, почти все они серые.


Почему очевидные решения проваливаются

Один инстанс на приложение. Изоляция корректная, но провижининг медленный (секунды и минуты), и каждый инстанс несёт постоянный пол по затратам — RAM, процесс, storage — вне зависимости от того, подключён к нему кто-то или нет. Умножьте это на простаивающий длинный хвост, и счёт будет в основном за базы, которыми никто не пользуется. На агентном масштабе это нежизнеспособно.

Одна большая общая база данных, изолированная по схемам/RLS. Дёшево и быстро, но это отдаёт ту самую изоляцию, которая вам нужнее всего: плохая миграция или зарвавшийся запрос в схеме одного приложения теперь становятся событием с общим радиусом поражения, а «откатить данные этого приложения» означает хирургически распутывать их из данных всех остальных. Приемлемо, когда в цикле есть человек; неприемлемо, когда актор — автономный агент.

Противоречие реальное: вам нужна изоляция уровня инстанса при стоимости и скорости уровня файла. Это возможно, только если перестать привязывать данные базы к запущенному процессу.


Три примитива, которые подходят

Разделите storage и compute — данные живут в версионируемом page store, а процесс Postgres не имеет состояния и читает страницы по запросу — и из этого выпадают три примитива, каждый из которых отвечает на одно свойство нагрузки:

Свойство нагрузки Примитив Почему подходит
Мгновенность, многочисленность Ветка с копированием при записи за O(1) Новая база данных — это указатель в метаданных, а не копия; создаётся за доли секунды независимо от размера. Агент создаёт её как файл.
Почти всегда простаивают Compute с масштабированием до нуля Убираем процесс, когда никто не подключён; данные остаются в page store. Простаивающие базы стоят ~ничего.
Изоляция, undo, экспериментирование Ветвление по LSN Форкаем точное состояние в момент времени, копируя при записи. Дешёвые изолированные копии, мгновенный откат, параллельные попытки.

1. Ветка с копированием при записи → мгновенность, многочисленность

Создание базы данных — это branching таймлайна: дочерняя ветка разделяет неизменённые страницы родителя и пишет страницу только тогда, когда расходится с ним. Ни один байт не копируется, поэтому создание имеет сложность O(1) по метаданным — одинаково, держит родитель килобайт или сотню гигабайт. Агент может за время, нужное на запись файла, развернуть полностью изолированный Postgres, и сделать это тысячу раз без того, чтобы счёт за storage рос вместе с количеством.

2. Масштабирование до нуля → почти всегда простаивают — значит бесплатно

Поскольку данные не привязаны к процессу, процесс можно удалить. Когда никто не подключён, compute масштабируется до нуля; следующее подключение прозрачно его будит. Простаивающий длинный хвост — большая часть парка — стоит только storage, а не запущенных инстансов. Стоимость становится пропорциональна фактически обслуженным запросам, а не развёрнутым базам. (Как пробуждение делается невидимым — разбор wire-протокола, single-flight wake, парковка соединений — в посте про масштабирование до нуля.)

3. Ветвление по LSN → изоляция, undo, экспериментирование

Тот же примитив ветки, но привязанный к конкретной позиции в WAL, — самый релевантный для агентов. Он даёт вам:

  • Обратимость. Помечаем чекпоинт на каждую генерацию; восстановление форкает состояние на этом LSN и направляет приложение туда — код и данные откатываются вместе. Уверенная-но-неправильная миграция агента превращается в undo в один клик. (Подробный разбор — в посте про путешествие во времени.)
  • Безопасное экспериментирование. Агент может форкнуть базу, попробовать разрушительную миграцию или backfill данных, проверить и оставить или выбросить ветку — не трогая реальные данные.
  • Параллельные попытки. Форкаем по одной ветке на подход из одного и того же сида и запускаем их бок о бок; CoW означает, что N веток не стоят как N копий.

restore = fork @ LSN

seed @ LSN

branch: approach A

branch: approach B

checkpoint @ commit

rolled-back state


Выигрыш: агент, которому не нужно быть аккуратным

По отдельности это выигрыш в стоимости и несколько фич. Вместе они меняют то, что агенту позволено делать.

Сделайте создание базы операцией за O(1), а её простой — бесплатным, и агент перестаёт экономить базы данных: он поднимает по одной на приложение, на эксперимент, на превью, прямо посреди задачи, без всяких расчётов стоимости или латентности на пути. Сделайте каждое состояние обратимым через ветвление по LSN — и агент перестаёт быть консервативным в отношении мутаций: он может выполнить миграцию, в которой не уверен, сделать backfill таблицы, попытаться провести разрушительный рефакторинг, потому что цена ошибки — выброшенная ветка или откат в один клик, а не инцидент с потерей данных.

Вот что это открывает. Агент, которому приходится быть аккуратным с базой данных, — это агент, который либо стопорится (останавливается, чтобы спросить человека «это безопасно?»), либо ломает то, что не может откатить. Агент на дешёвом, мгновенном, обратимом storage может делать то, в чём агенты действительно хороши — действовать, наблюдать, исправлять — с данными ровно так же, как он уже делает с кодом: создавать на лету, итерировать на месте, форкать, чтобы попробовать второй подход, откатывать тот, что не сработал. Никаких хождений на цыпочках.

Именно это и делает передачу жизненного цикла базы данных агенту безопасной в принципе. Гарантия не в том, что «агент аккуратен», а в том, что «ошибки агента дёшево откатить». Это очень разные ставки, и к автономности масштабируется только вторая.

Как это компонует Adorable

Примитивы — Neon-овские; композиция для мультитенантного билдера приложений — наша:

  • Один общий тенант Neon обслуживает всю платформу — единый page store и WAL-сервис. Ветвление дёшево именно потому, что всё разделяет storage.
  • Таймлайн на проект — это база данных этого проекта; схемы и роли на каждое приложение изолируют приложения, которые делят ветку проекта.
  • Connection-прокси маршрутизирует по имени базы (proj_{id}), масштабирует compute-Deployment каждого проекта 0↔1 и паркует соединения на время пробуждения — машинерия масштабирования до нуля.
  • Чекпоинты + ветвление по LSN дают каждому проекту путешествие во времени по коду и данным, привязанное к тем же git-коммитам, которые производит агент.

Изоляция живёт на уровне таймлайна + роли + Kubernetes-namespace, а не на уровне тенанта — именно это позволяет тысячам проектных баз дёшево разделять один storage-бэкенд, оставаясь при этом отгороженными друг от друга.


Кульминация — в модели затрат

Проследите за деньгами. При подходе «инстанс на приложение» стоимость ≈ количеству развёрнутых баз данных, навсегда. При разделённом storage + масштабировании до нуля стоимость ≈ фактически обслуженным запросам плюс тонкая линия storage — а копирование при записи держит storage сублинейным по количеству веток. Для парка, который по большей части простаивает и почти полностью создан агентами, это не маленькие различия в постоянном множителе; это разные асимптоты. Это единственная модель, в которой «дать каждому приложению и каждому эксперименту свою настоящую базу данных» экономически вменяемо.

В этом вся ставка, и именно поэтому индустрия сходится здесь: база данных для AI-агентов — это не инстанс поменьше или побыстрее, а тот, в котором данные отвязаны от процесса, так что создание мгновенно, простой бесплатен, а любая точка истории — в одной ветке от вас. Что есть одно и то же, сказанное тремя способами: агент получает возможность обращаться с базой данных как с кодом — создавать на лету, итерировать на месте и откатывать без страха.

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

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

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