Сегодня мы представляем Project Think: новое поколение Agents SDK. Project Think — это набор новых примитивов для создания долгоживущих агентов (отказоустойчивое выполнение, под-агенты, изолированное выполнение кода, постоянные сессии) и базовый класс с определённой архитектурой, который объединяет их все. Используйте примитивы, чтобы построить именно то, что вам нужно, или используйте базовый класс для быстрого старта.
В начале этого года произошло нечто, изменившее наше представление об ИИ. Такие инструменты, как Pi, OpenClaw, Claude Code и Codex, доказали простую, но мощную идею: дайте LLM возможность читать файлы, писать код, выполнять его и запоминать изученное, и вы получите нечто, что выглядит меньше как инструмент разработчика, а больше как универсальный помощник.
Эти агенты для написания кода больше не просто пишут код. Люди используют их для управления календарями, анализа наборов данных, ведения переговоров о покупках, подачи налоговых деклараций и автоматизации целых бизнес-процессов. Паттерн всегда один и тот же: агент читает контекст, анализирует его, пишет код для выполнения действия, наблюдает за результатом и итеративно повторяет. Код — это универсальная среда для действий.
Наша команда использует этих агентов для написания кода каждый день. И мы постоянно натыкались на одни и те же стены:
-
Они работают только на вашем ноутбуке или дорогом VPS: нет совместного использования, нет сотрудничества, нет передачи задач между устройствами.
-
Они дороги в простое: фиксированная ежемесячная стоимость независимо от того, работает агент или нет. Масштабируйте это до команды или компании — и расходы быстро растут.
-
Они требуют управления и ручной настройки: установка зависимостей, управление обновлениями, настройка идентификации и секретов.
И есть более глубокая структурная проблема. Традиционные приложения обслуживают многих пользователей из одного экземпляра. Как упоминалось в нашем посте "Добро пожаловать на Неделю агентов", агенты работают по принципу один-на-один. Каждый агент — это уникальный экземпляр, обслуживающий одного пользователя и выполняющий одну задачу. У ресторана есть меню и кухня, оптимизированные для массового производства блюд. Агент больше похож на личного шеф-повара: разные ингредиенты, разные техники, разные инструменты каждый раз.
Это фундаментально меняет математику масштабирования. Если сотни миллионов интеллектуальных работников будут использовать агентов-помощников даже с умеренной параллельной нагрузкой, вам потребуется мощность на десятки миллионов одновременных сессий. При текущей стоимости за контейнер это неустойчиво. Нам нужен другой фундамент.
Вот что мы строили.
Представляем Project Think
Project Think поставляет набор новых примитивов для Agents SDK:
-
Отказоустойчивое выполнение с использованием волокон (fibers): восстановление после сбоев, создание контрольных точек, автоматическое поддержание активности
-
Под-агенты: изолированные дочерние агенты со своей собственной SQLite и типизированным RPC
-
Постоянные сессии: древовидная структура сообщений, ветвление, компрессия, полнотекстовый поиск
-
Изолированное выполнение кода: Динамические Workers, codemode, разрешение зависимостей npm в рантайме
-
Лестница выполнения (execution ladder): рабочее пространство, изоляция, npm, браузер, песочница
-
Самостоятельно созданные расширения: агенты, которые пишут свои собственные инструменты во время выполнения
Каждый из этих примитивов можно использовать напрямую с базовым классом Agent. Создайте именно то, что вам нужно, с помощью примитивов, или используйте базовый класс Think для быстрого старта. Давайте посмотрим, что делает каждый из них.
Долгоживущие агенты
Агенты, какими они существуют сегодня, — эфемерны. Они работают в течение сессии, привязаны к одному процессу или устройству, а затем исчезают. Агент для написания кода, который умирает, когда ваш ноутбук засыпает, — это просто инструмент. Агент, который сохраняется — который может просыпаться по запросу, продолжать работу после прерываний и переносить состояние без зависимости от вашей локальной среды выполнения — это начинает выглядеть как инфраструктура. И это полностью меняет модель масштабирования для агентов.
Agents SDK построен на основе Durable Objects, чтобы дать каждому агенту идентификатор, постоянное состояние и возможность пробуждаться по сообщению. Это модель акторов: каждый агент — это адресуемая сущность со своей собственной базой данных SQLite. Он потребляет ноль вычислительных ресурсов в состоянии гибернации. Когда что-то происходит (HTTP-запрос, сообщение WebSocket, запланированный сигнал, входящее письмо), платформа пробуждает агента, загружает его состояние и передаёт ему событие. Агент выполняет свою работу, а затем снова засыпает.
|
|
Виртуальные машины / Контейнеры |
Durable Objects |
|---|---|---|
|
Стоимость простоя |
Полная стоимость вычислений, всегда |
Ноль (в гибернации) |
|
Масштабирование |
Планирование и управление мощностями |
Автоматическое, для каждого агента |
|
Состояние |
Требуется внешняя база данных |
Встроенная SQLite |
|
Восстановление |
Вы строите это сами (менеджеры процессов, проверки здоровья) |
Платформа перезапускается, состояние сохраняется |
|
Идентификация / Маршрутизация |
Вы строите это сами (балансировщики нагрузки, sticky-сессии) |
Встроенная (имя → агент) |
|
10 000 агентов, каждый активен 1% времени |
10 000 постоянно работающих экземпляров |
~100 активных в любой момент |
Это меняет экономику работы агентов в масштабе. Вместо «один дорогой агент на одного продвинутого пользователя» вы можете создать «один агент на одного клиента», «один агент на одну задачу» или «один агент на одну цепочку писем». Предельная стоимость создания нового агента практически равна нулю.
Переживание сбоев: отказоустойчивое выполнение с волокнами
Вызов LLM занимает 30 секунд. Цикл многошагового агента может выполняться гораздо дольше. В любой момент в течение этого окна среда выполнения может исчезнуть: деплой, перезапуск платформы, достижение лимитов ресурсов. Восходящее соединение с провайдером модели разрывается навсегда, состояние в памяти теряется, а подключенные клиенты видят, как поток останавливается без объяснения причин.
runFiber() решает эту проблему. Волокно (fiber) — это устойчивый вызов функции: регистрируется в SQLite до начала выполнения, может быть сохранено в контрольной точке в любой момент с помощью stash() и восстановлено после перезапуска через onFiberRecovered.
import { Agent } from "agents";
export class ResearchAgent extends Agent {
async startResearch(topic: string) {
void this.runFiber("research", async (ctx) => {
const findings = [];
for (let i = 0; i < 10; i++) {
const result = await this.callLLM(`Research step ${i}: ${topic}`);
findings.push(result);
// Контрольная точка: если прервано, мы возобновим отсюда
ctx.stash({ findings, step: i, topic });
this.broadcast({ type: "progress", step: i });
}
return { findings };
});
}
async onFiberRecovered(ctx) {
if (ctx.name === "research" && ctx.snapshot) {
const { topic } = ctx.snapshot;
await this.startResearch(topic);
}
}
}
SDK автоматически поддерживает жизнь агента во время выполнения волокна, никакой специальной конфигурации не требуется. Для работы, измеряемой в минутах, keepAlive() / keepAliveWhile() предотвращает вытеснение во время активной работы. Для более длительных операций (CI-пайплайны, обзоры дизайна, генерация видео) агент начинает работу, сохраняет идентификатор задачи, переходит в гибернацию и пробуждается по обратному вызову.
Делегирование работы: под-агенты через Facets
Один агент не должен делать всё сам. Под-агенты — это дочерние Durable Objects, размещённые рядом с родительским через Facets, каждый со своей изолированной SQLite и контекстом выполнения:
import { Agent } from "agents";
export class ResearchAgent extends Agent {
async search(query: string) { /* ... */ }
}
export class ReviewAgent extends Agent {
async analyze(query: string) { /* ... */ }
}
export class Orchestrator extends Agent {
async handleTask(task: string) {
const researcher = await this.subAgent(ResearchAgent, "research");
const reviewer = await this.subAgent(ReviewAgent, "review");
const [research, review] = await Promise.all([
researcher.search(task),
reviewer.analyze(task)
]);
return this.synthesize(research, review);
}
}
Под-агенты изолированы на уровне хранилища. Каждый получает свою собственную базу данных SQLite, и между ними нет неявного обмена данными. Это обеспечивается средой выполнения, где задержка RPC под-агента эквивалентна вызову функции. TypeScript отлавливает неправильное использование на этапе компиляции.
Разговоры, которые сохраняются: Session API
Agents that run for days or weeks need more than the typical flat list of messages. The experimental Session API models this explicitly. Available on the Agent base class, conversations are stored as trees, where each message has a parent_id. This enables forking (explore an alternative without losing the original path), non-destructive compaction (summarize older messages rather than deleting them), and full-text search across conversation history via FTS5.
import { Agent } from "agents";
import { Session, SessionManager } from "agents/experimental/memory/session";
export class MyAgent extends Agent {
sessions = SessionManager.create(this);
async onStart() {
const session = this.sessions.create("main");
const history = session.getHistory();
const forked = this.sessions.fork(session.id, messageId, "alternative-approach");
}
}
Session is usable directly with Agent, and it's the storage layer that the Think base class builds on.
From tool calls to code execution
Conventional tool-calling has an awkward shape. The model calls a tool, pulls the result back through the context window, calls another tool, pulls that back, and so on. As the tool surface grows, this gets both expensive and clumsy. A hundred files means a hundred round-trips through the model.
But models are better at writing code to use a system than they are at playing the tool-calling game. This is the insight behind @cloudflare/codemode: instead of sequential tool calls, the LLM writes a single program that handles the entire task.
// The LLM writes this. It runs in a sandboxed Dynamic Worker.
const files = await tools.find({ pattern: "**/*.ts" });
const results = [];
for (const file of files) {
const content = await tools.read({ path: file });
if (content.includes("TODO")) {
results.push({ file, todos: content.match(/// TODO:.*/g) });
}
}
return results;
Instead of 100 round-trips to the model, you just run a single program. This leads to fewer tokens used, faster execution, and better results. The Cloudflare API MCP server demonstrates this at scale. We expose only two tools (search() and execute()), which consume ~1,000 tokens, vs. ~1.17 million tokens for the naive tool-per-endpoint equivalent. This is a 99.9% reduction.
The missing primitive: safe sandboxes
Once you accept that models should write code on behalf of users, the question becomes: where does that code run? Not eventually, not after a product team turns it into a roadmap item. Right now, for this user, against this system, with tightly defined permissions.
Dynamic Workers are that sandbox. A fresh V8 isolate spun up at runtime, in milliseconds, with a few megabytes of memory. That's roughly 100x faster and up to 100x more memory-efficient than a container. You can start a new one for every single request, run a snippet of code, and throw it away.
The critical design choice is the capability model. Instead of starting with a general-purpose machine and trying to constrain it, Dynamic Workers begin with almost no ambient authority (globalOutbound: null, no network access) and the developer grants capabilities explicitly, resource by resource, through bindings. We go from asking "how do we stop this thing from doing too much?" to "what exactly do we want this thing to be able to do?"
This is the right question for agent infrastructure.
The execution ladder
This capability model leads naturally to a spectrum of compute environments, an execution ladder that the agent escalates through as needed:
Tier 0 is the Workspace, a durable virtual filesystem backed by SQLite and R2. Read, write, edit, search, grep, diff. Powered by @cloudflare/shell.
Tier 1 is a Dynamic Worker: LLM-generated JavaScript running in a sandboxed isolate with no network access. Powered by @cloudflare/codemode.
Tier 2 adds npm. @cloudflare/worker-bundler fetches packages from the registry, bundles them with esbuild, and loads the result into the Dynamic Worker. The agent writes import { z } from "zod" and it just works.
Tier 3 is a headless browser via Cloudflare Browser Run. Navigate, click, extract, screenshot. Useful when the service doesn't support agents yet via MCP or APIs.
Tier 4 is a Cloudflare Sandbox configured with your toolchains, repos, and dependencies: git clone, npm test, cargo build, synced bidirectionally with the Workspace.
The key design principle: the agent should be useful at Tier 0 alone, where each tier is additive. The user can add capabilities as they go.
Building blocks, not a framework
All of these primitives are available as standalone packages. Dynamic Workers, @cloudflare/codemode, @cloudflare/worker-bundler, and @cloudflare/shell (a durable filesystem with tools) are all usable directly with the Agent base class. You can combine them to give any agent a workspace, code execution, and runtime package resolution without adopting an opinionated framework.
The platform
Here's the complete stack for building agents on Cloudflare:
|
Capability |
What it does |
Powered by |
|---|---|---|
|
Per-agent isolation |
Every agent is its own world |
Durable Objects (DOs) |
|
Zero cost when idle |
$0 until the agent wakes up |
DO Hibernation |
|
Persistent state |
Queryable, transactional storage |
DO SQLite |
|
Durable filesystem |
Files that survive restarts |
Workspace (SQLite + R2) |
|
Sandboxed code execution |
Run LLM-generated code safely |
Dynamic Workers + |
|
Runtime dependencies |
|
|
|
Web automation |
Browse, navigate, fill forms |
Browser Run |
|
Full OS access |
git, compilers, test runners |
Sandboxes |
|
Scheduled execution |
Proactive, not just reactive |
DO Alarms + Fibers |
|
Real-time streaming |
Token-by-token to any client |
WebSockets |
|
External tools |
Connect to any tool server |
MCP |
|
Agent coordination |
Typed RPC between agents |
Sub-agents (Facets) |
|
Model access |
Connect to an LLM to power the agent |
AI Gateway + Workers AI (or Bring Your Own Model) |
Каждый из этих элементов является строительным блоком. Вместе они образуют нечто новое: платформу, где любой может создавать, разворачивать и запускать ИИ-агентов, столь же мощных, как те, что работают сегодня на вашем локальном компьютере, но бессерверных, устойчивых и безопасных по своей конструкции.
Базовый класс Think
Теперь, когда вы увидели примитивы, вот что происходит, когда вы соединяете их все вместе.
Think — это готовый каркас, который обрабатывает полный жизненный цикл чата: агентный цикл, сохранение сообщений, потоковую передачу, выполнение инструментов, возобновление потоков и расширения. Вы сосредотачиваетесь на том, что делает вашего агента уникальным.
Минимальный подкласс выглядит так:
import { Think } from "@cloudflare/think";
import { createWorkersAI } from "workers-ai-provider";
export class MyAgent extends Think<Env> {
getModel() {
return createWorkersAI({ binding: this.env.AI })(
"@cf/moonshotai/kimi-k2.5"
);
}
}
По сути, это всё, что нужно для рабочего чат-агента с потоковой передачей, сохранением состояния, прерыванием/отменой, обработкой ошибок, возобновляемыми потоками и встроенной файловой системой рабочей области. Разверните с помощью npx wrangler deploy.
Think принимает решения за вас. Когда вам нужен больший контроль, вы можете переопределить те аспекты, которые важны для вас:
|
Переопределение |
Назначение |
|
|
Возвращает используемую |
|
|
Системный промпт |
|
|
Совместимый с AI SDK |
|
|
Максимальное количество раундов вызова инструментов за ход |
|
|
Контекстные блоки, компрессия, поиск, навыки |
Под капотом Think выполняет полный агентный цикл на каждом ходе: собирает контекст (базовые инструкции + описания инструментов + навыки + память + история разговора), вызывает streamText, выполняет вызовы инструментов (с усечением вывода, чтобы предотвратить раздувание контекста), добавляет результаты, цикл продолжается, пока модель не завершит работу или не будет достигнут лимит шагов. Все сообщения сохраняются после каждого хода.
Хуки жизненного цикла
Think предоставляет вам хуки на каждом этапе хода чата, не требуя от вас полного управления всем конвейером:
beforeTurn()
→ streamText()
→ beforeToolCall()
→ afterToolCall()
→ onStepFinish()
→ onChatResponse()
Переключитесь на более дешёвую модель для последующих ходов, ограничьте доступные инструменты и передавайте контекст со стороны клиента на каждом ходе. Также логируйте каждый вызов инструмента в аналитике и автоматически запускайте ещё один дополнительный ход после завершения работы модели — всё это без замены onChatMessage.
Постоянная память и длинные разговоры
Think построен на основе Session API как слоя хранения, предоставляя вам древовидные сообщения со встроенным ветвлением.
Помимо этого, он добавляет постоянную память через контекстные блоки. Это структурированные разделы системного промпта, которые модель может читать и обновлять со временем, и они сохраняются после гибернации. Модель видит «ПАМЯТЬ (Важные факты, используйте set_context для обновления) [42%, 462/1100 токенов]» и может proactively запоминать информацию.
configureSession(session: Session) {
return session
.withContext("soul", {
provider: { get: async () => "You are a helpful coding assistant." }
})
.withContext("memory", {
description: "Important facts learned during conversation.",
maxTokens: 2000
})
.withCachedPrompt();
}
Сессии гибкие. Вы можете вести несколько диалогов на одного агента и разветвлять их, чтобы попробовать другое направление, не теряя оригинал.
По мере роста контекста Think управляет лимитами с помощью недеструктивной компрессии. Старые сообщения суммируются, а не удаляются, в то время как полная история остаётся сохранённой в SQLite.
Поиск также встроен. Используя FTS5, вы можете выполнять запросы к истории разговоров в пределах одной сессии или по всем сессиям. Агент также может искать в своём прошлом с помощью инструмента search_context.
Полная лестница исполнения, подключённая
Think интегрирует всю лестницу исполнения в единый возвращаемый объект getTools():
import { Think } from "@cloudflare/think";
import { createWorkspaceTools } from "@cloudflare/think/tools/workspace";
import { createExecuteTool } from "@cloudflare/think/tools/execute";
import { createBrowserTools } from "@cloudflare/think/tools/browser";
import { createSandboxTools } from "@cloudflare/think/tools/sandbox";
import { createExtensionTools } from "@cloudflare/think/tools/extensions";
export class MyAgent extends Think<Env> {
extensionLoader = this.env.LOADER;
getModel() {
/* ... */
}
getTools() {
return {
execute: createExecuteTool({
tools: createWorkspaceTools(this.workspace),
loader: this.env.LOADER
}),
...createBrowserTools(this.env.BROWSER),
...createSandboxTools(this.env.SANDBOX), // настроено для каждого агента: toolchains, репозитории, снапшоты
...createExtensionTools({ manager: this.extensionManager! }),
...this.extensionManager!.getTools()
};
}
}
Авторские расширения
Think выводит выполнение кода на новый уровень. Агент может писать собственные расширения: программы на TypeScript, которые выполняются в Dynamic Workers, объявляя разрешения для сетевого доступа и операций с рабочей областью.
{
"name": "github",
"description": "Интеграция с GitHub: PR, issues, репозитории",
"tools": ["create_pr", "list_issues", "review_pr"],
"permissions": {
"network": ["api.github.com"],
"workspace": "read-write"
}
}
ExtensionManager Think упаковывает расширение (опционально с npm-зависимостями через @cloudflare/worker-bundler), загружает его в Dynamic Worker и регистрирует новые инструменты. Расширение сохраняется в хранилище Durable Objects и переживает гибернацию. Когда пользователь в следующий раз спросит о pull requests, у агента уже будет инструмент github_create_pr , которого не существовало 30 секунд назад.
Это тот самый цикл самосовершенствования, который со временем делает агентов действительно более полезными. Не через дообучение или RLHF, а через код. Агент способен писать новые возможности для себя, полностью на изолированном, проверяемом и отзывном TypeScript.
RPC под-агентов
Think также работает как под-агент, вызываемый через chat() по RPC от родительского агента, с потоковыми событиями через callback:
const researcher = await this.subAgent(ResearchSession, "research");
const result = await researcher.chat(`Research this: ${task}`, streamRelay);
Каждый дочерний агент получает собственное дерево разговоров, память, инструменты и модель. Родительскому агенту не нужно знать детали.
Начало работы
Проект Think является экспериментальным. API стабилен, но будет продолжать развиваться в ближайшие дни и недели. Мы уже используем его внутри компании для создания собственной инфраструктуры фоновых агентов и делимся им рано, чтобы вы могли строить вместе с нами.
npm install @cloudflare/think agents ai @cloudflare/shell zod workers-ai-provider
// src/server.ts
import { Think } from "@cloudflare/think";
import { createWorkersAI } from "workers-ai-provider";
import { routeAgentRequest } from "agents";
export class MyAgent extends Think<Env> {
getModel() {
return createWorkersAI({ binding: this.env.AI })(
"@cf/moonshotai/kimi-k2.5"
);
}
}
export default {
async fetch(request: Request, env: Env) {
return (
(await routeAgentRequest(request, env)) ||
new Response("Not found", { status: 404 })
);
}
} satisfies ExportedHandler<Env>;
// src/client.tsx
import { useAgent } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";
function Chat() {
const agent = useAgent({ agent: "MyAgent" });
const { messages, sendMessage, status } = useAgentChat({ agent });
// Рендерим ваш интерфейс чата
}
Think использует тот же протокол WebSocket, что и @cloudflare/ai-chat, поэтому существующие UI-компоненты работают из коробки. Если вы строились на основе AIChatAgent, ваш клиентский код не требует изменений.
Третья волна
Мы видим три волны ИИ-агентов:
Первой волной были чат-боты. Они были stateless, реактивными и хрупкими. Каждый разговор начинался с нуля, без памяти, без инструментов и без возможности действовать. Это делало их полезными для ответов на вопросы, но ограничивало их только ответами на вопросы.
Вторая волна — это кодирующие агенты. Это состоятельные, инструментальные и гораздо более мощные инструменты, такие как Pi, Claude Code, OpenClaw и Codex. Эти агенты могут читать базы кода, писать код, выполнять его и итерировать. Они доказали, что LLM с правильными инструментами — это универсальная машина, но они работают на вашем ноутбуке, для одного пользователя, без гарантий долговечности.
Сейчас мы вступаем в третью волну: агенты как инфраструктура. Долговечные, распределенные, структурно безопасные и бессерверные. Это агенты, которые работают в Интернете, переживают сбои, не стоят ничего в простое и обеспечивают безопасность через архитектуру, а не поведение. Агенты, которые любой разработчик может создавать и развертывать для любого количества пользователей.
Это направление, на которое мы делаем ставку.
Agents SDK уже обеспечивает работу тысяч продуктовых агентов. С Project Think и примитивами, которые он вводит, мы добавляем недостающие элементы, чтобы сделать этих агентов значительно более способными: постоянные рабочие пространства, изолированное выполнение кода, долговечные долгоиграющие задачи, структурная безопасность, координация под-агентов и самостоятельно созданные расширения.
Это уже доступно в предварительном просмотре. Мы строим вместе с вами, и нам бы искренне хотелось увидеть, что вы (и ваш кодирующий агент) создадите с его помощью.
Think — часть Cloudflare Agents SDK, доступна как @cloudflare/think. Функции, описанные в этом посте, находятся в предварительном просмотре. API могут измениться по мере учета отзывов. Проверьте документацию и примеры чтобы начать.