← Создание агентов на Cloudflare / agents / runtime / operations
Конфигурация
Это руководство охватывает всё необходимое для настройки агентов для локальной разработки и развёртывания в production: настройку конфигурационного файла Wrangler, генерацию типов, переменные окружения и dashboard Cloudflare.
Структура проекта
Типичная структура файлов для проекта Agent, созданного из npm create cloudflare@latest agents-starter -- --template cloudflare/agents-starter выглядит следующим образом:
- src/
- index.ts определение вашего Agent
- public/
- index.html
- test/
- index.spec.ts ваши тесты
- package.json
- tsconfig.json
- vitest.config.mts
- worker-configuration.d.ts
- wrangler.jsonc: конфигурация ваших Workers и Agent
конфигурационный файл Wrangler
wrangler.jsonc файл настраивает ваш Cloudflare Worker и его привязки. Вот полный пример для проекта на агентах:
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-agent-app",
"main": "src/server.ts",
// Set this to today's date
"compatibility_date": "2026-08-28",
"compatibility_flags": ["nodejs_compat"],
// Static assets (optional)
"assets": {
"directory": "public",
"binding": "ASSETS",
},
// Durable Object bindings for agents
"durable_objects": {
"bindings": [
{
"name": "MyAgent",
"class_name": "MyAgent",
},
{
"name": "ChatAgent",
"class_name": "ChatAgent",
},
],
},
// Provision storage for each agent class
"exports": {
"MyAgent": {
"type": "durable-object",
"storage": "sqlite",
},
"ChatAgent": {
"type": "durable-object",
"storage": "sqlite",
},
},
// AI binding (optional, for Workers AI)
"ai": {
"binding": "AI",
},
// Observability (recommended)
"observability": {
"enabled": true,
},
}"$schema" = "node_modules/wrangler/config-schema.json"
name = "my-agent-app"
main = "src/server.ts"
# Set this to today's date
compatibility_date = "2026-08-28"
compatibility_flags = [ "nodejs_compat" ]
[assets]
directory = "public"
binding = "ASSETS"
[[durable_objects.bindings]]
name = "MyAgent"
class_name = "MyAgent"
[[durable_objects.bindings]]
name = "ChatAgent"
class_name = "ChatAgent"
[exports.MyAgent]
type = "durable-object"
storage = "sqlite"
[exports.ChatAgent]
type = "durable-object"
storage = "sqlite"
[ai]
binding = "AI"
[observability]
enabled = trueОсновные поля
compatibility_flags
nodejs_compat флаг обязателен для агентов:
{
"compatibility_flags": ["nodejs_compat"],
}compatibility_flags = [ "nodejs_compat" ]Это включает режим совместимости с Node.js, от которого агенты зависят для crypto, streams и других API Node.js.
durable_objects.bindings
Каждому классу агента нужна привязка:
{
"durable_objects": {
"bindings": [
{
"name": "Counter",
"class_name": "Counter",
},
],
},
}[[durable_objects.bindings]]
name = "Counter"
class_name = "Counter"| Поле | Описание |
|---|---|
name |
Имя свойства в env. Используйте это в коде: env.Counter |
class_name |
Должен точно совпадать с именем экспортируемого класса |
exports
exports поле объявляет каждый класс Agent, который экспортирует ваш Worker, и бэкенд хранилища, который Cloudflare должен для него использовать:
{
"exports": {
"MyAgent": {
"type": "durable-object",
"storage": "sqlite",
},
},
}[exports.MyAgent]
type = "durable-object"
storage = "sqlite"| Поле | Описание |
|---|---|
type |
Тип экспорта. Всегда "durable-object" для Agent. |
storage |
Бэкенд хранилища. Используйте "sqlite" для новых Agent (рекомендуется). |
Подробности о переименовании, удалении или переносе классов Agent см. в Экспорт классов Durable Object. Существующие Workers, использующие устаревший migrations массив продолжают работать, см. Миграции классов Durable Object (устаревший способ).
assets
Для обслуживания статических файлов (HTML, CSS, JS):
{
"assets": {
"directory": "public",
"binding": "ASSETS",
},
}[assets]
directory = "public"
binding = "ASSETS"С помощью привязки можно обслуживать ресурсы программно:
export default {
async fetch(request, env) {
// Static assets are served by the worker automatically by default
// Route the request to the appropriate agent
const agentResponse = await routeAgentRequest(request, env);
if (agentResponse) return agentResponse;
// Add your own routing logic here
return new Response("Not found", { status: 404 });
},
};export default {
async fetch(request: Request, env: Env) {
// Static assets are served by the worker automatically by default
// Route the request to the appropriate agent
const agentResponse = await routeAgentRequest(request, env);
if (agentResponse) return agentResponse;
// Add your own routing logic here
return new Response("Not found", { status: 404 });
},
} satisfies ExportedHandler<Env>;ai
Для интеграции с Workers AI:
{
"ai": {
"binding": "AI",
},
}[ai]
binding = "AI"Доступ в вашем агенте:
const response = await this.env.AI.run("@cf/meta/llama-3-8b-instruct", {
prompt: "Hello!",
});const response = await this.env.AI.run("@cf/meta/llama-3-8b-instruct", {
prompt: "Hello!",
});Конфигурация TypeScript
Agents SDK поставляется с общим tsconfig.json который задаёт все параметры компилятора, необходимые для проектов агентов, включая ES2021 необходимая цель для @callable() декораторы, строгий режим, разрешение модулей в стиле сборщика и типы Workers.
Расширить его в вашем tsconfig.json:
{
"extends": "agents/tsconfig"
}Это эквивалентно:
{
"compilerOptions": {
"target": "ES2021",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"module": "ES2022",
"moduleResolution": "bundler",
"types": ["node", "@cloudflare/workers-types", "vite/client"],
"allowImportingTsExtensions": true,
"noEmit": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}При необходимости вы можете переопределить отдельные параметры:
{
"extends": "agents/tsconfig",
"compilerOptions": {
"jsx": "preserve"
}
}Конфигурация Vite
Agents SDK предоставляет плагин Vite, который обрабатывает трансформации декораторов TC39. Vite 8 использует Oxc для транспиляции, а Oxc пока не поддерживает декораторы TC39: без этого плагина @callable() и другие декораторы завершатся ошибкой во время выполнения.
Добавьте плагин в свой vite.config.ts:
import { cloudflare } from "@cloudflare/vite-plugin";
import react from "@vitejs/plugin-react";
import agents from "agents/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [agents(), react(), cloudflare()],
});import { cloudflare } from "@cloudflare/vite-plugin";
import react from "@vitejs/plugin-react";
import agents from "agents/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [agents(), react(), cloudflare()],
}); agents() плагин можно безопасно подключить, даже если ваш проект не использует декораторы. Он запускает трансформацию только для файлов, которые содержат @ синтаксис.
Стартовый шаблон и все примеры по умолчанию включают этот плагин. Если вы столкнётесь с SyntaxError: Invalid or unexpected token с декораторами см. Callable methods : Устранение неполадок.
Генерация типов
Wrangler может генерировать типы TypeScript для ваших привязок.
Автоматическая генерация
Выполните команду types:
npx wrangler typesЭто создаёт или обновляет worker-configuration.d.ts с вашим Env тип.
Пользовательский путь вывода
Укажите пользовательский путь:
npx wrangler types env.d.tsБез runtime-типов
Для более чистого вывода (рекомендуется для агентов):
npx wrangler types env.d.ts --include-runtime falseЭто генерирует только ваши bindings, без типов Cloudflare runtime.
Пример сгенерированного вывода
// env.d.ts (generated)
declare namespace Cloudflare {
interface Env {
OPENAI_API_KEY: string;
Counter: DurableObjectNamespace;
ChatAgent: DurableObjectNamespace;
}
}
interface Env extends Cloudflare.Env {}Ручное определение типа
Вы также можете определить типы вручную:
// env.d.ts// env.d.ts
import type { Counter } from "./src/agents/counter";
import type { ChatAgent } from "./src/agents/chat";
interface Env {
// Secrets
OPENAI_API_KEY: string;
WEBHOOK_SECRET: string;
// Agent bindings
Counter: DurableObjectNamespace<Counter>;
ChatAgent: DurableObjectNamespace<ChatAgent>;
// Other bindings
AI: Ai;
ASSETS: Fetcher;
MY_KV: KVNamespace;
}Добавление в package.json
Добавьте скрипт для удобной повторной генерации:
{
"scripts": {
"types": "wrangler types env.d.ts --include-runtime false"
}
}Переменные окружения и секреты
Локальная разработка (.env)
Создайте .env файл для локальных секретов (добавьте в .gitignore):
# .env
OPENAI_API_KEY=sk-...
GITHUB_WEBHOOK_SECRET=whsec_...
DATABASE_URL=postgres://...Доступ в вашем агенте:
class MyAgent extends Agent {
async onStart() {
const apiKey = this.env.OPENAI_API_KEY;
}
}class MyAgent extends Agent {
async onStart() {
const apiKey = this.env.OPENAI_API_KEY;
}
}Секреты продакшена
Используйте wrangler secret для продакшена:
# Add a secret
npx wrangler secret put OPENAI_API_KEY
# Enter value when prompted
# List secrets
npx wrangler secret list
# Delete a secret
npx wrangler secret delete OPENAI_API_KEYНесекретные переменные
Для несекретной конфигурации используйте vars в конфигурационном файле Wrangler:
{
"vars": {
"API_BASE_URL": "https://api.example.com",
"MAX_RETRIES": "3",
"DEBUG_MODE": "false",
},
}[vars]
API_BASE_URL = "https://api.example.com"
MAX_RETRIES = "3"
DEBUG_MODE = "false"Все значения должны быть строками. Числа и булевы значения парсите в коде:
const maxRetries = parseInt(this.env.MAX_RETRIES, 10);
const debugMode = this.env.DEBUG_MODE === "true";const maxRetries = parseInt(this.env.MAX_RETRIES, 10);
const debugMode = this.env.DEBUG_MODE === "true";Переменные, специфичные для окружения
Используйте env разделы для разных сред (например, staging, production):
{
"name": "my-agent",
"vars": {
"API_URL": "https://api.example.com",
},
"env": {
"staging": {
"vars": {
"API_URL": "https://staging-api.example.com",
},
},
"production": {
"vars": {
"API_URL": "https://api.example.com",
},
},
},
}name = "my-agent"
[vars]
API_URL = "https://api.example.com"
[env.staging.vars]
API_URL = "https://staging-api.example.com"
[env.production.vars]
API_URL = "https://api.example.com"Разверните в конкретном окружении:
npx wrangler deploy --env staging
npx wrangler deploy --env productionЛокальная разработка
Запуск сервера разработки
С Vite (рекомендуется для full-stack приложений):
npx vite devБез Vite:
npx wrangler devЛокальное сохранение состояния
Состояние Durable Object сохраняется локально в .wrangler/state/:
- .wrangler/
- state/
- v3/
- d1/
- miniflare-D1DatabaseObject/
- ... (файлы SQLite)
- miniflare-D1DatabaseObject/
- d1/
- v3/
- state/
Очистка локального состояния
Чтобы сбросить всё локальное состояние Durable Object:
rm -rf .wrangler/stateИли перезапустите с чистым состоянием:
npx wrangler dev --persist-to=""Просмотр локальной базы SQLite
Вы можете напрямую просматривать состояние агента:
# Find the SQLite file
ls .wrangler/state/v3/d1/
# Open with sqlite3
sqlite3 .wrangler/state/v3/d1/miniflare-D1DatabaseObject/*.sqliteНастройка дашборда
Автоматические ресурсы
При развёртывании Cloudflare автоматически создаёт:
- Worker - Ваш развёрнутый код
- Пространства имён Durable Object - Один на класс агента
- Хранилище SQLite - привязано к каждому пространству имён
Просмотр Durable Objects
Войдите в панель управления Cloudflare, затем перейдите в раздел Durable Objects.
Перейдите в Durable Objects ↗Здесь вы можете:
- Просмотреть все пространства имён Durable Object
- Просмотреть отдельные экземпляры объектов
- Просмотр хранилища (ключи и значения)
- Удаление объектов
Логи в реальном времени
Просмотрите живые логи ваших агентов:
npx wrangler tailИли в дашборде:
- Перейдите к своему Worker.
- Выберите Observability на вкладке.
- Включите логи в реальном времени.
Фильтр по:
- Статус (успех, ошибка)
- Искомый текст
- Частота дискретизации
Развёртывание в продакшене
Базовое развёртывание
npx wrangler deployЭто:
- Упаковывает ваш код
- Загрузки в Cloudflare
- Выделяет хранилище пространства имён Durable Object для Agent
- Делает его доступным по адресу
*.workers.dev
Пользовательский домен
Добавьте route в файле конфигурации Wrangler:
{
"routes": [
{
"pattern": "agents.example.com/*",
"zone_name": "example.com",
},
],
}[[routes]]
pattern = "agents.example.com/*"
zone_name = "example.com"Или используйте пользовательский домен (это проще):
{
"routes": [
{
"pattern": "agents.example.com",
"custom_domain": true,
},
],
}[[routes]]
pattern = "agents.example.com"
custom_domain = trueПревью-деплои
Разверните, не затрагивая продакшн:
npx wrangler deploy --dry-run # See what would be uploaded
npx wrangler versions upload # Upload new version
npx wrangler versions deploy # Gradually roll outОткаты
Откатитесь к предыдущей версии:
npx wrangler rollbackНастройка нескольких сред
Настройка окружения
Определите окружения в файле конфигурации Wrangler:
{
"name": "my-agent",
"main": "src/server.ts",
// Base configuration (shared)
// Set this to today's date
"compatibility_date": "2026-08-28",
"compatibility_flags": ["nodejs_compat"],
"durable_objects": {
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }],
},
"exports": {
"MyAgent": { "type": "durable-object", "storage": "sqlite" },
},
// Environment overrides
"env": {
"staging": {
"name": "my-agent-staging",
"durable_objects": {
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }],
},
"vars": {
"ENVIRONMENT": "staging",
},
},
"production": {
"name": "my-agent-production",
"durable_objects": {
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }],
},
"vars": {
"ENVIRONMENT": "production",
},
},
},
}name = "my-agent"
main = "src/server.ts"
# Set this to today's date
compatibility_date = "2026-08-28"
compatibility_flags = [ "nodejs_compat" ]
[[durable_objects.bindings]]
name = "MyAgent"
class_name = "MyAgent"
[exports.MyAgent]
type = "durable-object"
storage = "sqlite"
[env.staging]
name = "my-agent-staging"
[[env.staging.durable_objects.bindings]]
name = "MyAgent"
class_name = "MyAgent"
[env.staging.vars]
ENVIRONMENT = "staging"
[env.production]
name = "my-agent-production"
[[env.production.durable_objects.bindings]]
name = "MyAgent"
class_name = "MyAgent"
[env.production.vars]
ENVIRONMENT = "production"Развёртывание в окружениях
# Deploy to staging
npx wrangler deploy --env staging
# Deploy to production
npx wrangler deploy --env production
# Set secrets per environment
npx wrangler secret put OPENAI_API_KEY --env staging
npx wrangler secret put OPENAI_API_KEY --env productionОтдельные Durable Objects
Именованные среды не наследуют привязки Durable Object. Повторите привязки для каждой среды, как показано в настройка для нескольких сред. Каждое окружение получает свои собственные Durable Objects. Агенты в staging не разделяют состояние с агентами в production.
Чтобы явно разделить:
{
"env": {
"staging": {
"durable_objects": {
"bindings": [
{
"name": "MyAgent",
"class_name": "MyAgent",
"script_name": "my-agent-staging",
},
],
},
},
},
}[[env.staging.durable_objects.bindings]]
name = "MyAgent"
class_name = "MyAgent"
script_name = "my-agent-staging"Жизненный цикл класса Agent
Каждый Agent соответствует классу Durable Object. Жизненным циклом этих классов (создание, переименование, удаление, перенос) вы управляете через exports поле в конфигурационном файле Wrangler.
Добавление нового агента
Объявите новый класс в exports:
{
"exports": {
"NewAgent": { "type": "durable-object", "storage": "sqlite" },
},
}[exports.NewAgent]
type = "durable-object"
storage = "sqlite"Переименование класса агента
Замените запись для старого имени на renamed tombstone и добавьте активную запись для нового имени:
{
"exports": {
"OldName": {
"type": "durable-object",
"state": "renamed",
"renamed_to": "NewName",
},
"NewName": { "type": "durable-object", "storage": "sqlite" },
},
}[exports.OldName]
type = "durable-object"
state = "renamed"
renamed_to = "NewName"
[exports.NewName]
type = "durable-object"
storage = "sqlite"Также обновите:
- Имя класса в коде.
-
class_nameв привязках. - Операторы export.
Удаление класса агента
Замените запись на deleted tombstone:
{
"exports": {
"AgentToKeep": { "type": "durable-object", "storage": "sqlite" },
"AgentToDelete": { "type": "durable-object", "state": "deleted" },
},
}[exports.AgentToKeep]
type = "durable-object"
storage = "sqlite"
[exports.AgentToDelete]
type = "durable-object"
state = "deleted"Лучшие практики для жизненного цикла класса
- Оставьте
exportsв соответствии с вашим кодом. Для каждого класса Agent, который экспортирует ваш Worker, нужна отдельная запись. - Используйте tombstone-записи, а не тихое удаление. При выводе класса из эксплуатации оставьте
deleted/renamed/transferredtombstone вexportsчтобы Cloudflare явно согласовывал это изменение. - Сначала протестируйте локально. Изменения жизненного цикла применяются к
wrangler deploy. - Создайте резервную копию продакшен-данных перед переименованием или удалением.
Существующие Workers, использующие устаревший migrations массив продолжают работать, см. Миграции классов Durable Object (устаревший способ) для устаревшего справочника, либо Мигрировать с устаревшего migrations поток чтобы перейти к exports.
Устранение неполадок
No such Durable Object class
Класс отсутствует в exports. Объявите класс и его хранилище:
{
"exports": {
"MissingClassName": { "type": "durable-object", "storage": "sqlite" },
},
}[exports.MissingClassName]
type = "durable-object"
storage = "sqlite"Не удаётся найти модуль в типах
Заново сгенерируйте типы:
npx wrangler types env.d.ts --include-runtime falseСекреты не загружаются локально
Проверьте, что .env существует и содержит переменную:
cat .env
# Should show: MY_SECRET=valueКонфликт тега миграции (устаревший migrations только)
Если ваш Worker использует устаревший migrations массиве каждая запись должна иметь уникальный tag:
{
// Wrong - duplicate tags
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["A"] },
{ "tag": "v1", "new_sqlite_classes": ["B"] },
],
}[[migrations]]
tag = "v1"
new_sqlite_classes = [ "A" ]
[[migrations]]
tag = "v1"
new_sqlite_classes = [ "B" ]{
// Correct - sequential tags
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["A"] },
{ "tag": "v2", "new_sqlite_classes": ["B"] },
],
}[[migrations]]
tag = "v1"
new_sqlite_classes = [ "A" ]
[[migrations]]
tag = "v2"
new_sqlite_classes = [ "B" ]Рассмотрите переход на декларативный exports поле.