Мой Стек Агентов для Запуска 30+ Продакшн-Агентов (Без Python)
Я запускаю 30+ продакшн-ИИ-агентов с помощью TypeScript, Cloudflare Workers/Queues/KV и моделей Claude — без Python, без агентного фреймворка. Стек намеренно простой: Workers занимаются планированием и очередями, KV хранит состояние, а Anthropic SDK напрямую управляет вызовами модели. Важное ограничение — не слой ИИ, а инфраструктура вокруг него.
Каждую среду. 28 400+ читателей. Никакой воды.
✓ Check your inbox — click the confirmation link to complete sign-up.
✓ You're subscribed!
✓ You're already on the list.
Содержание
Обновлено май 2026.
TL;DR: Я запускаю 30+ продакшн-ИИ-агентов с помощью TypeScript, Cloudflare Workers/Queues/KV и моделей Claude — без Python, без агентного фреймворка. Стек намеренно простой: Workers занимаются планированием и очередями, KV хранит состояние, а Anthropic SDK напрямую управляет вызовами модели. Важное ограничение — не слой ИИ, а инфраструктура вокруг него.
[Взгляд оператора] Я управляю двумя бизнесами: брендом ИИ-консалтинга и Pickleland — площадкой для пиклбола в Пфлюгервилле, штат Техас. Вместе они дают более 30 агентов, работающих в продакшне прямо сейчас. Это реальный стек, а не демо.
Почему без Python
Честный ответ: я пишу TypeScript каждый день для работы с сайтом и продуктами. Добавить второй язык для агентов означает два рантайма, два дерева зависимостей, два деплой-пайплайна. Стоимость производительности не теоретическая — я заплатил её на прошлых проектах и решил больше не повторять.
Вторая причина — Cloudflare. Workers запускает TypeScript нативно на эдже, со встроенными Queues, KV, Durable Objects и Cron Triggers. Вся агентная инфраструктура, которая мне нужна — планирование, состояние, асинхронная обработка задач — доступна одной командой wrangler deploy. Нет Python-эквивалента с такой же операционной простотой.
Третья причина: большинство аргументов “Python-лучше-для-ИИ” на самом деле означают “у Python больше ML-библиотек.” Я не обучаю модели. Я вызываю API. Anthropic SDK — это TypeScript первого класса. LangChain и подобные — это сложность, которую я не хочу. Когда вы деплоите агентов, а не исследуете их, простота побеждает.
Основная инфраструктура: три примитива Cloudflare
Каждый агент, который я запускаю, затрагивает как минимум один из этих трёх:
Cloudflare Workers — вычислительный слой. Worker — это рантайм агента: он получает триггер (cron, сообщение из Queue, HTTP), выполняет вызовы модели и записывает выходные данные куда-то. Cold start менее 5мс. Лимит выполнения — 30 секунд CPU на бесплатном плане, 15 минут на платном. Почти всё, что я строю, помещается в 30 секунд; то, что не помещается, использует Queues для fan-out.
Cloudflare Queues — асинхронная обработка задач. Когда задача может занять больше времени, чем запрос, или когда нужен fan-out (генерация 12 переводов параллельно), я отправляю сообщения в Queue и позволяю привязанным consumers обрабатывать их независимо. Без поллинга, без хаков с setTimeout.
Cloudflare KV — лёгкое состояние. История запусков агентов, последние обработанные временные метки, кешированные ответы API. KV — eventually consistent, что подходит для агентов — я не выполняю транзакции. Это простое key-value хранилище, которое я могу читать/писать из любого Worker без запуска базы данных.
Слой моделей: Anthropic SDK, две модели
Я использую ровно две модели Claude:
claude-sonnet-4-6— для задач, требующих настоящего рассуждения: написание постов в блоге, анализ данных событий, генерация социального контента, планирование последовательностейclaude-haiku-4-5— для быстрой/дешёвой классификации, решений о маршрутизации, коротких извлечений, где полное рассуждение избыточно
Anthropic SDK на TypeScript прямолинеен. Вот паттерн, который я использую для каждого вызова модели:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({ apiKey: env.ANTHROPIC_API_KEY });
async function runAgent(prompt: string, systemPrompt: string): Promise<string> {
const message = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 2048,
system: systemPrompt,
messages: [{ role: "user", content: prompt }],
});
const block = message.content[0];
if (block.type !== "text") throw new Error("Unexpected content type");
return block.text;
}Это весь интерфейс модели. Никаких абстракций поверх. Когда нужен tool use, добавляю массив tools. Когда нужен стриминг, заменяю messages.create на messages.stream. Никакой фреймворк не управляет этим за меня — и я этого не хочу.
Реальный агент: контентный пайплайн
Самый сложный агент, который я запускаю, — это контентный пайплайн. Он генерирует посты в блоге, переводит их на 12 языков, рендерит SVG OG-карточек и составляет промо для LinkedIn — всё в виде черновиков, заблокированных до моего просмотра.
Точка входа Worker выглядит так:
// src/workers/content-pipeline.ts
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const { topic, slug } = await request.json<{ topic: string; slug: string }>();
// Шаг 1: сгенерировать пост EN
const enPost = await generatePost(topic, env);
await env.CONTENT_KV.put(`draft:${slug}:en`, enPost);
// Шаг 2: fan-out переводов через Queue
const locales = ["ar", "de", "es", "fr", "hi", "it", "ja", "ko", "nl", "pt", "ru", "zh"];
for (const locale of locales) {
await env.TRANSLATION_QUEUE.send({ slug, locale, content: enPost });
}
return Response.json({ status: "queued", slug });
},
};Каждый перевод выполняется в собственном вызове Worker. Если один падает, Queue автоматически повторяет попытку. Я получаю 12 параллельных переводов без самостоятельного управления потоками, промисами или rate-limit backoff.
Реальный агент: промоутер событий
Pickleland проводит события по пиклболу. Я создал агента, который сканирует платформу бронирования на события в следующие 4 дня, составляет посты для групп Facebook по каждому событию и представляет их на проверку перед публикацией.
Системный промпт:
const systemPrompt = `You are a community manager for a pickleball facility.
Write Facebook group posts for upcoming events.
Rules:
- Max 150 words per post
- Lead with what's fun about the event, not the price
- Include the booking URL exactly as provided
- Do not use exclamation marks more than once per post
- Tone: friendly, local, not corporate`;Ключевое ограничение здесь — не модель, а рабочий процесс. Агент запускается ежедневно в 8 утра по cron-триггеру. Черновые посты попадают в очередь проверки. Я одобряю или редактирую, затем срабатывает отдельный Worker публикации. Ни одно событие не публикуется без просмотра человеком.
Как управлять 30+ агентами без потери рассудка
Дашборд Cloudflare — мой плоскость управления. Каждый Worker показывает мне количество вызовов, частоту ошибок и время CPU. Каждая Queue показывает пропускную способность сообщений и сбои. KV показывает использование хранилища.
Помимо этого:
- Каждый агент логирует структурированный JSON-объект в конце каждого запуска:
{ agent, status, durationMs, inputTokens, outputTokens, costUsd } - Я отслеживаю накопленные расходы по агентам в месяц в простой базе Airtable
- Агенты, превышающие пороговое значение стоимости, помечаются для проверки — обычно это означает, что промпт слишком многословен или я использую Sonnet там, где хватило бы Haiku
Дисциплина не техническая. Это решение о том, что агент может делать автономно, а что требует моего одобрения. Черновики контента: автономно. Всё, что касается клиента: проверка человеком. Всё, что перемещает деньги: не работа агента.
Что бы я изменил, начиная сегодня
Одно: я бы настроил структурированные выходные данные (режим JSON) с первого дня, а не добавлял их задним числом к уже задеплоенным агентам. Парсинг свободного текста Claude — это налог. Когда вы определяете схему Zod и передаёте её как ожидаемую форму ответа, вы получаете типизированные данные, и downstream Workers не нужно гадать.
import { z } from "zod";
const EventPostSchema = z.object({
headline: z.string().max(80),
body: z.string().max(600),
bookingUrl: z.string().url(),
suggestedPostTime: z.enum(["morning", "afternoon", "evening"]),
});Вывод оператора
Стек агентов, который работает в продакшне, — это тот, который можно дебажить в 22:00, когда что-то сломалось. Для меня это TypeScript + Cloudflare + Anthropic SDK — не потому что это самая гламурная комбинация, а потому что каждый слой наблюдаем, разворачиваем и заменяем независимо. Фреймворки — это ставки на абстракции. Я предпочитаю владеть сантехникой.
Каждую среду. 28 400+ читателей. Никакой воды.
✓ Check your inbox — click the confirmation link to complete sign-up.
✓ You're subscribed!
✓ You're already on the list.
Получайте ИИ-руководство на почту
Каждую среду. 28 400+ читателей. Никакой воды.
Check your inbox.
We sent you a confirmation email — click the link inside to complete your subscription. Check spam if you don't see it within a minute.
You're subscribed.
Welcome — the next edition lands in your inbox soon.
You're already on the list — look for it every Wednesday.