Hono + Bun для AI-платформ: 6 production-паттернов, которые стоит перенять
Строим AI-платформу на Hono + Bun: 100+ сервисов, SSE-стриминг, изолированное выполнение кода, реалтайм WebSocket. 6 production-паттернов из реального кодовой базы.
У AI-платформ общий набор инфраструктурных потребностей: стриминг в реальном времени, файловые нагрузки, схемно-валидированные протоколы агентов, мультитенантная авторизация и необходимость двигаться быстро, не жертвуя типобезопасностью. Большинство JavaScript-серверных фреймворков были созданы до того, как потоковые LLM-ответы и edge-деплой стали стандартными требованиями.
В QuotyAI мы строим детерминистскую AI-платформу для продаж — такую, которая генерирует TypeScript-функции расчёта цен из естественного языка, выполняет их в песочницах и стримит результаты в UI агентов в реальном времени. Наш бэкенд запускает 100+ сервисов через tsyringe, отдаёт SSE-стримы, обрабатывает WebSocket-события по нескольким каналам сообщений — и всё это в одном процессе Bun.
Hono + Bun — это сочетание, которое делает это возможным. Hono весит менее 14KB без единой зависимости, обеспечивает вывод типов на этапе компиляции через цепочки мидлвари и работает на Bun, Deno, Cloudflare Workers и Node.js без изменений кода. Bun обеспечивает быстрый нативный I/O, встроенные клиенты SQLite и PostgreSQL, и всё больше API уровня ОС, для которых раньше требовались отдельные сервисы.
Это шесть паттернов, которые сложились за шесть месяцев использования в продакшене.
«Hono заставляет тебя правильно выстроить типы. Express позволяет отправить баги в продакшен.»
Внимание на версии: В статье рассматриваются Hono ^4.12.27 и Bun latest (июнь 2026). Примеры кода используют Socket.IO 4.8.3 с
@socket.io/bun-engine0.1.1 — Bun-нативный адаптер ещё молод, об этом мы рассказываем в разделе Что не сработало. Все примеры взяты из монорепозитория QuotyAI.
⚖️ Сравнение фреймворков для AI-нагрузок
| Требование | Express | FastAPI | NestJS | Hono |
|---|---|---|---|---|
| Размер бандла | ~200KB+ | Накладные расходы Python-рантайма | ~40KB + зависимости | 14KB |
| Портируемость рантайма | Только Node.js | Только Python | Node.js | Bun, Deno, CF Workers, Node.js |
| Типобезопасность мидлвари | Нет | Pydantic (рантайм) | На декораторах | Вывод на этапе компиляции |
| Поддержка edge / Workers | Нужен адаптер | Нет | Нужен адаптер | Нативная |
| Стриминг (SSE) | Ручная реализация | Асинхронные генераторы | Ручная реализация | Встроенный streamSSE |
| Холодный старт (serverless) | 50–100мс | 200–500мс | 80–150мс | 5–10мс |
Express относится к типам как к чему-то необязательному — для CRUD-API это работает, но ломается для AI-платформ, где валидация запросов, бизнес-логика, выполнение агентов и сериализация ответов должны опираться на одни и те же типы. Одно несоответствие — и вывод искажён.
FastAPI обеспечивает строгие гарантии типов через Pydantic, но привязывает к Python — проблематично, когда нужен edge-деплой, нативная обработка изображений или мультиплексирование WebSocket из одного процесса.
NestJS добавляет структуру ценой накладных расходов на абстракции. Его система типов на декораторах не распространяется на переменные мидлвари или сквозной контекст запроса.
Вывод типов в Hono уникален среди JS-фреймворков: c.get() и c.set() проверяются на этапе компиляции, а не выполнения. Определите типизированный Variables на приложении — и каждая мидлварь и хэндлер ниже по цепочке должны соответствовать, иначе TypeScript отклонит сборку.
💡 Уникальный инсайт: Изменение
tenantIdсstringнаObjectIdв наших определениях типов выявило 14 обработчиков маршрутов, которые нужно было обновить — на этапе компиляции. В Express это стали бы ошибки рантайма, которые обнаруживают клиенты. Эта одна функция устранила целую категорию багов из нашего цикла разработки.
🏗️ Архитектура: один процесс, 30 файлов маршрутов
Один процесс Bun обслуживает и HTTP, и WebSocket через маршрутизацию на транспортном уровне на основе URL:
import { Server as SocketIOBunEngine } from '@socket.io/bun-engine';
import { Server as SocketIOServer } from 'socket.io';
import { app } from './hono-routes.js';
const io = new SocketIOServer();
const engine = new SocketIOBunEngine();
io.bind(engine);
const realtimeNamespace = io.of('/realtime');
realtimeNamespace.use(async (socket, next) => {
const token = socket.handshake.auth?.token;
const user = await authService.verifyToken(token);
(socket as any).user = user;
next();
});
export default {
port: 3000,
idleTimeout: 30,
fetch(req, server) {
const url = new URL(req.url);
if (url.pathname === '/socket.io/') return engine.handleRequest(req, server);
return app.fetch(req, server);
},
websocket: engine.handler().websocket,
};
Один процесс. Hono обрабатывает HTTP. Socket.IO обрабатывает WebSocket. Никакого прокси, никакого второго порта, никакого адаптерного слоя между Bun и WebSocket-движком.
Hono-роутер монтирует 30 суб-роутеров, каждый со своим стеком мидлвари:
const app = new Hono<{ Variables: AppVariables }>();
app.use('*', cors({ origin: process.env.ALLOWED_ORIGINS?.split(',') }));
app.use('*', rateLimitMiddleware({ windowMs: 60_000, max: 100 }));
app.use('*', commonLoggerContextMiddleware);
app.route('/agent-protocol', agentProtocolApp);
app.route('/chat', chatApp);
app.route('/webhooks', webhooksApp);
// ... ещё 27 групп маршрутов
Маршруты /agent-protocol несут свою DI-мидлварь и проверку авторизации. Маршруты /webhooks имеют верификацию HMAC-подписи. Никакого глобального локатора сервисов, никакого общего состояния между доменами.
📦 Паттерн 1: типизированные переменные устраняют баги контекста
Это функция, которая делает Hono принципиально отличным от Express для мультисервисных AI-платформ.
Определяем общий контекст запроса один раз:
export type AppVariables = {
db: Database;
container: DependencyContainer;
user?: AuthUser;
tenantId?: ObjectId;
};
Каждый вызов c.get() и c.set() проверяется на этапе компиляции во всех мидлвари и хэндлерах. Суб-роутеры расширяют базовый тип собственными зависимостями:
type AgentProtocolVariables = {
agentProtocolService: AgentProtocolService;
user?: { id: string };
tenantId: ObjectId;
authService: AuthService;
};
Каждое суб-приложение объявляет ровно то, что ему нужно. Обратитесь к c.get('somethingUndefined') — и TypeScript отклонит это ещё до первого запуска тестов.
Подробнее о типизированных переменных — в документации Hono по мидлвари.
💡 Уникальный инсайт: Мы храним общий тип
AppVariablesв одном файле, который импортирует каждый модуль маршрутов. Когда новой зависимости нужен контекст на уровне запроса, мы добавляем её в одном месте, и компилятор распространяет ограничение на все 30 групп маршрутов. Никакого discovery в рантайме. Никаких сюрпризов сundefinedв три часа ночи.
🔄 Паттерн 2: SSE-стриминг для коммуникации агентов
AI-агенты общаются потоками. Потоковый вывод LLM-токенов, последовательности вызовов инструментов, рассуждения в длинной форме — всё естественно маппится на Server-Sent Events. Хелпер streamSSE в Hono управляет жизненным циклом с фильтрованными event sink’ами и поддержанием соединения:
import { streamSSE } from 'hono/streaming';
app.post('/threads/:threadId/stream/events', async (c) => {
const params = await c.req.json();
const service = c.get('agentProtocolService');
return streamSSE(c, async (stream) => {
const sinkId = crypto.randomUUID();
let detached = false;
const detachSink = () => {
if (detached) return;
detached = true;
service.detachEventSink(threadId, sinkId);
};
const send = async (event: any) => {
if (detached || stream.aborted) return;
try {
await stream.writeSSE({
id: event.event_id,
event: event.method,
data: JSON.stringify(event),
});
} catch {
detachSink();
}
};
await service.attachFilteredEventSink(threadId, {
id: sinkId,
filter: {
channels: new Set(params.channels ?? ['messages', 'tools', 'lifecycle']),
namespaces: params.namespaces,
},
send,
});
stream.onAbort(detachSink);
const heartbeatTimer = setInterval(async () => {
if (stream.aborted) return clearInterval(heartbeatTimer);
await stream.writeSSE({ event: 'ping', data: '{"type":"heartbeat"}' });
}, 30_000);
await new Promise<void>((resolve) => {
stream.onAbort(() => { detachSink(); resolve(); });
});
});
});
30-секундный heartbeat поддерживает соединение через прокси и балансировщики нагрузки. Паттерн detachSink предотвращает утечки памяти, когда клиенты отключаются без корректного закрытия — а на мобильных сетях это происходит часто.
HTTP-сервер Bun обрабатывает потоковые тела без какой-либо конфигурации. Никаких адаптеров, никаких специальных мидлвари.
💡 Уникальный инсайт: Паттерн-защита
detachSinkпоявился после production-инцидента, когда мобильный клиент ушёл со страницы в середине стрима. Без него каждое прерванное соединение утекало подписку на event sink. Коллбэкstream.onAbortсрабатывает на Bun надёжно, но асинхронный зазор между проверкамиstream.abortedи вызовамиwriteSSEозначает, что для полного покрытия нужны и флаг, и коллбэк.
Подробности API streamSSE — в документации Hono по стримингу.
🏖️ Паттерн 3: изолированное выполнение кода для AI-сгенерированных функций
AI-платформы, которые генерируют и выполняют код, нуждаются в песочнице на уровне рантайма. Модуль vm из Node.js обеспечивает это со строгим списком разрешений и жёстким таймаутом:
import * as vm from 'vm';
const SANDBOX_TIMEOUT_MS = 5000;
function executeCode<T>(code: string, input: unknown, functionName: string): T {
const sandbox = {
console: { log: (...args) => logger.debug(...args) },
Date, Math, Array, Object, String, Number, Boolean, RegExp, JSON,
Error, TypeError, ReferenceError, RangeError,
parseInt, parseFloat, isNaN, isFinite,
};
const context = vm.createContext(sandbox, {
name: 'Sandbox',
codeGeneration: { strings: false, wasm: false },
});
const script = new vm.Script(
`${code}\n__result__ = ${functionName};`,
{ filename: `sandbox-${functionName}.js` }
);
script.runInContext(context, { timeout: SANDBOX_TIMEOUT_MS });
const runner = (sandbox as any).__result__;
return Array.isArray(input) ? runner(...input) : runner(input);
}
Ключевые ограничения:
- Только allowlist:
Date,Math,Array,Object,JSON, базовые конструкторы ошибок,parseInt,parseFloat. Нетrequire, нетimport, нетeval, нетfetch, нетprocess. - Нет динамической генерации кода:
codeGeneration: { strings: false, wasm: false }блокирует eval-подобные паттерны внутри песочницы. - Жёсткий таймаут: 5 секунд убивают бесконечные циклы. AI-сгенерированный код порождает их чаще, чем можно ожидать.
Когда выполнение падает, скрипт сохраняется для отладки:
async function saveFailedScript(code: string, error: Error) {
const filename = `failed-script-${Date.now()}.js`;
await fs.mkdir('./troubleshooting-scripts', { recursive: true });
await fs.writeFile(
`./troubleshooting-scripts/${filename}`,
`// Error: ${error.message}\n\n${code}`
);
}
💡 Уникальный инсайт: Три production-крайних случая удалось поймать таким образом: бесконечные циклы из-за некорректной рекурсии в сгенерированном коде, распространение NaN из-за пропущенных null-проверок и таймаут из-за сгенерированной функции с
while(true). Без сохранённых скриптов каждый из них стал бы многочасовой отладочной сессией. Каталог troubleshooting-scripts теперь первое место, куда мы смотрим при падении выполнения в песочнице.
⚡ Паттерн 4: потоки изменений базы данных в WebSocket
Пайплайны событий в реальном времени для AI-платформ можно построить без брокера сообщений, связав потоки изменений базы данных с WebSocket:
MongoDB ChangeStream (6 коллекций)
→ eventBus.emit() (типизированный EventEmitter, 27 типов событий)
→ Socket.IO адаптер (слушает все 27 событий)
→ Эмиссии в комнаты (tenant:*, conversation:*)
Когда новое сообщение приходит через любой канал (Telegram, Facebook, веб-форма), Change Stream обнаруживает документ, шина событий испускает типизированное событие, и Socket.IO-адаптер транслирует подписчикам:
export function setupSocketIOAdapters(io: SocketIOServer) {
eventBus.on('conversation:message:created', (event) => {
io.to(`conversation:${event.conversationId}`)
.emit('conversation:message:created', event);
});
eventBus.on('agent:status:changed', (event) => {
io.to(`tenant:${event.tenantId}`)
.emit('agent:status:changed', event);
});
// ... ещё 25 типов событий
}
Никакого брокера сообщений, никакого Redis pub/sub. Один процесс обрабатывает пайплайн целиком. Когда потребуется горизонтальное масштабирование, @socket.io/redis-adapter подключается без изменений слоя маппинга событий — адаптер сидит между Socket.IO и Redis, а не между вашим кодом и Socket.IO.
Подробнее о требованиях к настройке (реплика-сет, доступ к oplog) — в документации MongoDB Change Streams.
🛡️ Паттерн 5: RFC 9457 Problem Details для структурированных ошибок
Стандартизированные ответы об ошибках экономят часы отладки. Пакет hono-problem-details маппит ошибки фреймворка в формат RFC 9457:
app.onError(
problemDetailsHandler({
autoInstance: true,
mapError: (error) => {
if (error instanceof HTTPException && error.cause instanceof ZodError) {
return {
status: 422,
title: 'Validation Error',
detail: 'Request validation failed',
extensions: {
errors: error.cause.issues.map((issue) => ({
field: issue.path.join('.'),
message: issue.message,
code: issue.code,
})),
},
};
}
if (error instanceof LlmConfigError) {
return { status: 404, title: 'LLM Configuration Not Found', detail: error.message };
}
if (error instanceof TenantError) {
return { status: 409, title: error.message, detail: error.detail };
}
},
localize: (pd, c) => {
const correlationId = c.req.header('x-correlation-id');
return { ...pd, correlationId, tenantId: c.get('tenantId')?.toString() };
},
}),
);
Каждый ответ об ошибке содержит корреляционный идентификатор, контекст тенанта и структурированные детали валидации. Когда клиент сообщает «API вернул ошибку», вы трейсите её до конкретного запроса, тенанта и сбоя валидации.
💡 Уникальный инсайт: Коллбэк
localizeвproblemDetailsHandler— это хук, который решил нашу проблему «какой тенант сломался?». До добавления корреляционных идентификаторов в каждый ответ об ошибке отладка мультитенантного инцидента означала grep логов по диапазону timestamps. Теперь каждая ошибка несёт контекст тенанта нативно — включая ошибки валидации, которые срабатывают до запуска тенантной мидлвари (используя заголовокx-tenant-idнапрямую из запроса).
Полный API — в документации hono-problem-details.
🧩 Паттерн 6: внедрение зависимостей по уровням
Когда вы регистрируете 100+ сервисов, ручная сортировка становится источником ошибок. Организация регистраций по уровням зависимостей предотвращает циклические разрешения и делает граф зависимостей явным:
export function registerServices(container: DependencyContainer) {
// Уровень 0 — без зависимостей
container.registerSingleton(EncryptionService);
container.registerSingleton(DynamicRunnerService);
// Уровень 1 — зависит от уровня 0
container.registerSingleton(TenantStorage);
container.registerSingleton(ApiKeyStorage);
// Уровень 2 — зависит от уровней 0–1
container.registerSingleton(TenantService);
container.registerSingleton(ApiKeyService);
// ... до уровня 7
}
Каждый файл маршрутов разрешает собственные сервисы через мидлварь, а не через глобальный локатор:
const agentProtocolMiddleware = async (c: Context, next: Next) => {
const service = container.resolve(AgentProtocolService);
const authService = container.resolve(AuthService);
c.set('agentProtocolService', service);
c.set('authService', authService);
await next();
};
Никаких побочных эффектов при импорте. Каждая мидлварь явно объявляет свои зависимости. DI-контейнер разрешает их один раз при старте.
💡 Уникальный инсайт: Мы используем tsyringe с 8 уровнями зависимостей. Уровень 0 — чистые утилиты (шифрование, runner песочницы). Уровень 7 — сквозные concerns (аналитика, обсервабилити). Комментарий с уровнем при каждой регистрации делает циклические зависимости сразу видимыми при code review — вы можете с одного взгляда увидеть, не импортирует ли сервис уровня 2 случайно зависимость уровня 5.
⚠️ Что не сработало
Socket.IO на Bun требует @socket.io/bun-engine. Стандартный сервер Socket.IO рассчитан на Node.js http.Server. Bun-нативный адаптер на версии 0.1.1 — работает, но ожидаются шероховатости с таймаутами и обработкой соединений. Тщательно тестируйте логику переподключения.
Некоторые npm-пакеты рассчитывают на Node.js-нутренности. Две проблемы в продакшене: один пакет использовал process.nextTick так, как Bun обрабатывает иначе, другой ожидал поведения fs.watch, которое Bun не полностью реплицирует. Обе были исправлены за день, но стоит проверить дерево зависимостей до перехода на Bun.
Вывод типов в Hono строг по дизайну. Измените типы c.set() в мидлвари — и каждый хэндлер ниже по цепочке должен соответствовать. Это функция, предотвращающая рантайм-баги, но рефакторинг мидлвари затрагивает больше файлов, чем в Express. Компромисс стоит ради корректности.
Нет production-ready обработки изображений. Bun.Image существует, но для серьёзных нагрузок всё равно понадобится sharp или выделенный сервис. Подход на основе буферов подходит для лёгкого использования.
📊 Цифры производительности
Измерено в продакшене, не в бенчмарках:
| Метрика | Значение |
|---|---|
| Выполнение функции в песочнице | 24мс |
| Ответ API (с LLM) | 1–2с |
| Загрузка одного документа (MongoDB) | 50мс |
| Интервал SSE heartbeat | 30с |
| Таймаут песочницы | 5 000мс |
| Лимит по умолчанию | 100 запросов/60с |
24мс на выполнение в песочнице важно, потому что отделяет детерминистскую бизнес-логику от задержки LLM. Пользователи получают быстрые, предсказуемые результаты для всего, что не требует AI-вызова. Подробнее о расходах на инфраструктуру за этими цифрами — в статье Как я запускаю production AI-стартап за $30 в месяц.
📋 Стек
| Слой | Технология | Версия |
|---|---|---|
| Рантайм | Bun | latest |
| HTTP-фреймворк | Hono | ^4.12.27 |
| WebSocket | Socket.IO + @socket.io/bun-engine | ^4.8.3 / ^0.1.1 |
| DI-контейнер | tsyringe | ^4.10.0 |
| Валидация | Zod | 4.3.6 |
| База данных | MongoDB native driver | ^7.3.0 |
| AI-оркестрация | LangChain + LangGraph | ^1.2.1 / ^1.4.6 |
| Логирование | LogTape + OpenTelemetry | ^2.1.5 |
📋 Когда использовать этот стек
Используйте Hono + Bun, когда:
- Нужна типобезопасность на этапе компиляции через цепочки мидлвари
- Хотите один процесс для HTTP, WebSocket и фоновой работы
- Деплоите и на edge, и на традиционные серверы из одного кода
- Команда пишет на TypeScript и хочет максимального контроля компилятора
Не используйте, когда:
- Зависите от npm-пакетов, рассчитанных на Node.js-нутренности (проверьте зависимости заранее)
- Нужно горизонтальное масштабирование с первого дня (планируйте интеграцию
@socket.io/redis-adapterзаранее) - Команде нужна обширная проверенная документация (документация Hono хорошая, но не уровня Express)
О процессе принятия решения при выборе этих инструментов — в статье Почему я выбрал Bun и Hono.
🗺️ Что дальше
Четыре улучшения на дорожной карте:
- Посекундное ограничение по тенантам. AI-платформы должны предотвращать злоупотребление затратами на промпты. Модель мидлвари Hono делает это композируемым — ключ лимитера по ID тенанта, а не просто по IP.
- Обработка таймаутов стриминга. Когда LLM-апстрим останавливается в середине стрима, SSE-соединение зависает. Хэндлеру
streamSSEнужна логика таймаута с учётом обратного давления. - Фоновые воркеры. Выгрузка генерации эмбеддингов и пакетной оценки в потоки
Bun.Workerподдерживает отзывчивость основного цикла запросов. - Мидлварь отслеживания затрат. Учёт на уровне токенов для каждого запроса, через хуки на ответы, даёт тенантам видимость в стоимость их AI-агентов.
Каждая функция ложится в ту же кодовую базу Hono + Bun. Никакой миграции фреймворка. Никакого переписывания.
В этом и смысл.
TL;DR
| Категория | Паттерн |
|---|---|
| Выбор фреймворка | Hono вместо Express, FastAPI, NestJS для AI-нагрузок |
| Архитектура сервера | Один процесс Bun, Hono HTTP + Socket.IO WebSocket на одном порте |
| Типобезопасность | Типизированный AppVariables — контроль на этапе компиляции во всех мидлвари |
| Стриминг агентов | streamSSE с фильтрованными event sink’ами, heartbeat и detach-on-abort |
| Песочница для кода | vm.createContext() со строгим allowlist, codeGeneration: false, 5с таймаут |
| События в реальном времени | MongoDB ChangeStream → типизированный EventBus → Socket.IO комнаты |
| Обработка ошибок | RFC 9457 Problem Details с корреляционными ID и контекстом тенанта |
| DI | tsyringe с уровнями зависимостей для предотвращения циклических разрешений |
| Стриминг | SSE для однонаправленных событий агентов, WebSocket для двунаправленных UI-взаимодействий |
Что почитать ещё
- Почему я выбрал Bun и Hono — оригинальный разбор решения
- Детерминизм как инфраструктура — почему AI-платформам нужно детерминистическое выполнение
- Как я запускаю production AI-стартап за $30 в месяц — инфраструктура деплоя за этими паттернами
Часто задаваемые вопросы
Почему Hono, а не Express для AI-платформ? Hono весит менее 14KB без единой зависимости, обеспечивает вывод типов TypeScript на этапе компиляции для переменных мидлвари и работает на Bun, Deno, Cloudflare Workers и Node.js без изменений кода. У Express типобезопасность мидлвари — второстепенная задача, а для edge-рантаймов нужны адаптеры.
Bun готов к продакшену для AI-бэкенд-сервисов? Bun справляется с production-нагрузками: HTTP-сервинг, WebSocket-апгрейды, подключения к MongoDB и изолированное выполнение кода. Основной пробел — зрелость экосистемы npm: некоторые пакеты рассчитаны на специфичные для Node.js внутренности. Bun-нативный движок Socket.IO на версии 0.1.1, так что возможны шероховатости.
Как безопасно запускать AI-сгенерированный код в продакшене?
Используйте vm.createContext() из Node.js со строгим списком разрешённых глобальных объектов (Date, Math, Array, Object, JSON), отключённой генерацией кода и 5-секундным таймаутом. Песочница не имеет доступа к файловой системе, сети и процессам. Упавшие скрипты сохраняются на диск с контекстом ошибки для отладки.
В чём разница между SSE и WebSocket для коммуникации агентов?
SSE — однонаправленная передача от сервера к клиенту, идеальна для потокового вывода токенов LLM и событий агентов. WebSocket двунаправленный — нужен для индикаторов набора текста, обновлений UI в реальном времени и оркестрации нескольких агентов, где клиенты отправляют события обратно. Hono поддерживает оба варианта: streamSSE для SSE и Socket.IO в том же процессе Bun для WebSocket.
Как обрабатывать мультитенантный контекст в мидлвари Hono?
Определите типизированный AppVariables на приложении Hono с tenantId: ObjectId. Мидлварь авторизации извлекает тенанта из JWT или заголовка и вызывает c.set('tenantId', ...). Каждый хэндлер ниже по цепочке получает доступ через c.get('tenantId') — проверяется на этапе компиляции, никаких рантайм-lookup’ов.
Теги: hono bun typescript ai-platform backend-architecture
Было полезно? Поделитесь.
Похожие статьи
Почему я выбрал Bun и Hono для бэкенда QuotyAI
Создавайте более быстрые бэкенды, отказавшись от NestJS в пользу Bun и Hono — идеально для независимых основателей, создающих AI-продукты в 2026 году
Читать статьюVibe-кодинг против open source: математика изменилась
Не трать недели на изучение библиотек. Строй именно то, что нужно, быстрее с помощью AI-агентов.
Читать статьюOpenWiki vs QuotyAI: два проекта на LangChain DeepAgents, две архитектуры
OpenWiki использует LangChain DeepAgents для генерации документации к кодовым базам. QuotyAI использует тот же API createDeepAgent для генерации исполняемой бизнес-логики на TypeScript. Техническое сравнение архитектуры агентов, паттернов субагентов и исполнения кода.
Читать статью