Как Talorys запускает stateful AI-агентов на serverless
Как запустить stateful AI-агента на stateless serverless? Talorys использует Cloudflare Workers, Durable Objects и SQLite, и всё это работает на бесплатном тарифе.

Вот мой контрарианский тезис, и я готов его отстаивать: персональный AI-агент лучше подходит для serverless-инфраструктуры, чем для Raspberry Pi под вашим столом. Проект Talorys, открытый персональный ассистент, который разворачивается в вашем собственном аккаунте Cloudflare одной командой npx create-talorys@latest, — лучшее на сегодня доказательство того, что проблема stateful AI-агента на stateless serverless не просто решаема, а естественно укладывается в эту модель. А спор на Hacker News о том, считать ли это «self-hosted», ведётся совсем не о том.
Я много лет занимаюсь инфраструктурой и подчищаю за ней. Что убивает self-hosted персональный софт, так это не деплой, а третий месяц, когда диск забивается логами, истекает TLS-сертификат и вы не можете вспомнить, какой юнит systemd отвечает за расписание. Talorys обходит весь этот класс проблем, потому что у него вообще нет сервера. Всё нужное, от чата и памяти до задач и плановых напоминаний, работает на бесплатном тарифе Cloudflare: Pages для фронтенда, приватный Worker для API, Durable Object с SQLite для всего состояния и Workers AI для модели. Итого за месяц для одного пользователя: ноль.
Настоящая проблема: агенты хранят состояние, а serverless нет
AI-агент — это набор долгоживущего состояния, который притворяется приложением «запрос-ответ». Ему нужны история диалога, долговременная память, список задач, плановые задания, которые срабатывают в 7 утра независимо от того, залогинен ли кто-то, и место для результатов инструментов, пока выполняется многошаговая цепочка. Всё это враждебно классической serverless-модели, где ваша функция напоминает золотую рыбку: проснулась, обработала один запрос и забыла всё.
Стандартный ответ индустрии — собирать состояние по периферии: Redis для сессий, Postgres для долговременных записей, очередь плюс планировщик для cron, векторная база для семантического поиска. Это работает, но по сути вы заново построили серверную ферму из управляемых сервисов, со всеми счетами и операционной сложностью в придачу. Я видел, как команды тратили на связку пяти stateful-сервисов для агента больше инженерного времени, чем на саму логику агента. Как я уже писал, LLM-агенты — это распределённые системы, а распределённые системы — место, где благие намерения умирают.
Talorys делает противоположную ставку: всё состояние хранится ровно в одном месте. Один Durable Object с именем personal-agent хранит весь мир, включая диалоги, воспоминания, задачи, заметки, проекты, автоматизации, сессии, настройки и учёт использования, во встроенной базе SQLite. Ни KV, ни D1, ни R2, ни Vectorize. В README прямо сказано, что ничего из этого не подключается. Это не случайность, а сама архитектура.
Durable Objects — читерский приём
Durable Objects сейчас самый тихо радикальный примитив в облачных вычислениях, и это не преувеличение. Durable Object — это код с единственным экземпляром и строго согласованным транзакционным хранилищем, физически расположенным рядом с ним. Когда приходит запрос к объекту personal-agent, Cloudflare будит этот объект за миллисекунды из холодного состояния, выполняет ваш код поверх его локального SQLite и замораживает, когда он простаивает. Вы получаете удобство долгоживущего серверного процесса с моделью оплаты Lambda.
Для персонального агента на одного пользователя печально известные ограничения этой модели становятся достоинствами:
- Один писатель — это фича. Один пользователь означает одного писателя. Весь ужас конкурентного доступа в мультитенантном состоянии исчезает: вы получаете сериализованный транзакционный доступ ко всему бесплатно.
- Колокация убивает задержки. Запросы памяти агента, поиск задач и история диалога — это чтения SQLite с локального диска, а не сетевые обращения к базе в другой зоне доступности.
- Alarms заменяют cron. Alarms у Durable Object позволяют объекту планировать собственные пробуждения. Напоминания, регулярные рутины и ежедневные сводки срабатывают без того, чтобы какая-либо машина оставалась онлайн: объект спит, будильник будит его, он делает свою работу и снова засыпает.
- Гибернация бесплатна. Простой ничего не стоит. Персональный ассистент, который простаивает 23 часа в сутки, — ровно та нагрузка, ради которой придумали serverless-ценообразование.
Это та мысль, которую мне хотелось бы, чтобы больше людей вынесли из этого проекта. Если ваше приложение естественно однопользовательское, например персональный инструмент, рабочее пространство для отдельного клиента или координатор для одного устройства, паттерн «один Durable Object на тенанта» даёт то, что раньше требовало VPS: маленький компьютер, который концептуально всегда работает, ничего не стоит в простое и не требует системного администратора. Одна только история с планированием стоит того. Любой, кто держал личный cron-сервер, знает, как это ломается: машина перезагрузилась, демон cron не поднялся, и через две недели вы узнаёте, что напоминания молча перестали приходить. Alarms — это планирование, которым владеет инфраструктура, и одной заботой меньше.
Сетевая модель лучше, чем у большинства продакшен-систем
Вот что заставило меня выпрямиться, учитывая мой бэкграунд в безопасности. Worker агента в Talorys развёрнут с workers_dev: false и preview_urls: false. У него вообще нет публичного URL. Браузер общается только с сайтом *.pages.dev; Pages Function по адресу /api/* пересылает запросы Worker-у через service binding, то есть внутреннее приватное соединение Cloudflare между вычислениями в одном аккаунте. Аутентификация и авторизация происходят в Worker, а не во фронтенде.
Подумайте, что это исключает. Нет публичной API-точки для сканирования. Нет правил файервола, которые можно настроить неправильно. Нет обратного прокси, который забудут обновить. Поверхность атаки бэкенда агента фактически сводится к тому, что вы обязаны пройти через auth-флоу фронтенда. Я проверял продакшен-развёртывания в реальных компаниях, с бюджетами и командами безопасности, у которых сетевая защита была слабее, чем у этого побочного проекта. Самый частый паттерн инцидентов, который я видел в облаке, это внутренний сервис, который был «доступен только изнутри», пока однажды не стал доступен извне, потому что кто-то ошибся в конфиге балансировщика. Service binding нельзя случайно сделать публичным: у него просто нет URL.
Об установщике тоже стоит упомянуть. Он хеширует пароль владельца локально через PBKDF2-SHA256 и сохраняет в Cloudflare secret только хеш, генерирует 256-битный секрет сессии, даёт ресурсам уникальные имена, а затем проверяет живое развёртывание, в том числе убеждается, что неаутентифицированные запросы действительно отклоняются, и не тратит на это квоту AI-инференса. Проверка после деплоя, которая подтверждает, что без аутентификации доступ закрыт, — это то, что я сам вписывал в постмортемы инцидентов. Увидеть такое в установщике в одну команду — приятный сюрприз.

Жизнь в бесплатном тарифе без самообмана
Бесплатный тариф настоящий, но это бюджет, а не шведский стол. Cloudflare даёт бесплатным аккаунтам ежедневную квоту Workers AI, которая измеряется в «Neurons», 10 000 в день, а также квоты на запросы и использование Durable Objects. Эти цифры устанавливает Cloudflare, и они могут меняться. Talorys обрабатывает это честнее, чем большинство проектов с «бесплатным тарифом», которые я видел: когда квота AI заканчивается, чат прямо об этом сообщает и возобновляется после ежедневного сброса, а задачи, заметки, воспоминания и напоминания продолжают работать, потому что ни одной из них модель не нужна.
Защитные механизмы стоит позаимствовать для собственных проектов. Talorys включает настраиваемые лимиты: максимум выходных токенов, максимум контекстных токенов (старая история суммаризируется, а не молча обрезается), максимум вызовов инструментов и шагов рассуждения на запрос, максимум AI-запросов в день и максимум плановых AI-запусков в день. Это зрелая позиция. Неограниченные циклы агента быстрее всего приводят к счёту или сбою из-за квоты, а «агент решил вызвать инструмент 40 раз» — ошибка, которая на моей практике сжигала реальные деньги. Кроме того, решение проекта делать простые напоминания и сводки без AI абсолютно верное. Если путь кода детерминирован, не пускайте его через вероятностную модель. Та же дисциплина лежит в основе ограничения вывода модели структурированными решениями: используйте модель только там, где действительно нужно суждение.
Одно предостережение из обсуждений сообщества: несколько человек жалуются на непрозрачные сюрпризы в счетах при сочетании Workers AI с платными тарифами Workers. Учёт Neurons не совпадал с документированными лимитами, а тикеты в поддержку никуда не вели. Я не могу проверить детали, но это похоже на знакомый мне паттерн: метered-биллинг AI везде запутан, и «дружелюбный к бесплатному тарифу» не означает «невозможно получить счёт». Если вы развернёте это на платном плане, в первый же день настройте оповещение о расходах в панели Cloudflare. Считайте интерфейс использования провайдера источником истины, а не локальными оценками приложения.
Спор о «self-hosted» мимо сути
Теперь уступка, которой требует мой вступительный тезис. Главные комментарии к проекту превратились в войну за слово «self-hosted», и педанты здесь правы: всё это целиком зависит от Cloudflare. Ваши данные лежат в их дата-центрах, инференс работает на их GPU, и если завтра они изменят бесплатный тариф, ваш ассистент изменится вместе с ним. Называть это self-hosting значит растягивать слово за пределы. Доброжелательное прочтение, то есть отсутствие третьей стороны, кроме уже контролируемого вами аккаунта Cloudflare, отсутствие телеметрии разработчикам и отсутствие оператора посередине, лучше описывается как «self-owned» или «self-custodied». Слова важны, и проект получил бы меньше критики с более точными формулировками.
Но здесь педанты меня теряют. Реальная модель угроз для персонального софта — не «условия обслуживания корпорации могут измениться». Это утечка данных, телеметрия и разработчик, который обанкротится и выключит хостед-версию. По всем трём пунктам Talorys действительно силён: нет аналитики и трекинг-кода, ничего не стучится к авторам, и нет хостед-версии, которую можно выключить. Кроме того, код под лицензией MIT, и, как отметил один комментатор, перенаправить AI-вызовы на локальный сервер модели — небольшой патч; весь стек даже запускается локально через wrangler dev с mock-провайдером AI. Если Cloudflare когда-нибудь станет неприемлем, путь к выходу короткий. Сравните с типичным «self-hosted» приложением, которое на деле является файлом Docker Compose, тянущим образы из чьего-то реестра и стучащимся домой для проверки лицензии.
В треде есть и более справедливая критика: нет доказательств, что ассистент на самом деле хорош. Чат-интерфейс, CRUD для памяти, эмбеддинги и cron по отдельности тривиально реализуются; жизнь персональных ассистентов решается в обвязке, промптах, политике извлечения памяти и схемах инструментов, а ничего из этого не демонстрирует чистая архитектурная диаграмма. Это верно почти для любого проекта в этом жанре, и скептицизм здесь уместен. Оценивайте Talorys как инфраструктуру, хорошо спроектированное шасси, а не как доказанного копилота. Если вы взвешиваете модели для чего-то подобного, наш материал о запуске LLM на собственном железе описывает противоположный конец спектра суверенности.

Что стоит позаимствовать из этого дизайна
Даже если вы никогда не развернёте Talorys, архитектура служит хорошим референсом. Переносимые идеи:
- Один объект на тенанта. Если ваше приложение однопользовательское или чисто разделяется, разместите код и состояние в одном Durable Object и уберите слой кеша, очередь сообщений и пул соединений.
- Никакого публичного URL бэкенда. Service bindings с
workers_dev: false— самый дешёвый выигрыш в безопасности в serverless. Сервис, до которого нельзя достучаться, нельзя и атаковать. - Alarms вместо cron-серверов. Планирование, которое живёт вместе с инфраструктурой, переживает перезагрузки, редеплои и вашу собственную забывчивость.
- Деградация с учётом квот. Проектируйте приложение так, чтобы дорогая зависимость (модель) могла упасть или исчерпаться, а ядро продукта продолжало работать. Деградация должна быть функцией, а не простоем.
- Append-only миграции. Пространство имён Durable Object никогда не пересоздаётся при обновлении; миграции схемы выполняются транзакционно при первом запросе. Так обновляется stateful serverless без лотереи с потерей данных.
Общий вывод касается того, куда движется персональный софт. Двадцать лет выбор был бинарным: доверить SaaS-компании свои данные или стать сисадмином на полставки. Durable Objects и копии этих примитивов, которые неизбежно выпустят другие облака, открывают третий путь: софт, которым управляете только вы, работающий на инфраструктуре, которую вы арендуете, и стоящий ничего на личном масштабе. Это не self-hosting. Возможно, это лучше.


