AI-агенты против традиционных бэкендов: поток управления, затраты и способы сбоев
Сравните детерминистичный бэкенд с циклом агента на основе LLM, используя пример возврата средств: задержки, стоимость токенов, рост объема контекста, способы сбоев и ситуации, когда гибридный дизайн наиболее подходит.
Источники: AI Agents vs Traditional Backend Applications: What’s Actually Different?
Инженерия бэкенда долгое время опиралась на одно важное свойство — детерминизм. Если написать эндпоинт, который принимает заказ, проверяет наличие товара в PostgreSQL и берет плату с карты через Stripe, то та же последовательность действий будет выполняться каждый раз. При одинаковых входных данных и одинаковом состоянии базы данных строка 42 всегда выполняется до строки 43.
Затем индустрия начала называть ИИ-агентов следующим этапом развития бэкенд-систем. Легко отмахнуться от этого как от маркетинговых уловок, ведь агент также выглядит как сервис в контейнере, который вызывает внешние API и записывает данные в базу данных. Однако на самом деле порядок управления изменился. В классическом бэкенде разработчик заранее предусматривает каждый шаг, ветку и крайний случай. В агенте разработчик задаёт цель и набор инструментов, а вероятностная модель выбирает шаги, их порядок и момент завершения задачи. Если рассматривать агента просто как ещё один микросервис, это приведёт к серьёзным проблемам с задержками, надёжностью, тестированием и счётами за облачные ресурсы.
Фиксированная цепочка обработки против цикла рассуждений
Стандартный бэкенд обрабатывает запрос через ориентированную ациклическую структуру, которая жёстко задаётся программистом:
[Request] ──> [Validate Input] ──> [Database Query] ──> [Transform Data] ──> [Response]
│
└── (Invalid) ──> [Return 400]
Каждый ветвление, будь то if/else, switch или try/catch, определяется заранее. Код не может создать шаг, который вы не написали. Неожиданный ввод приводит к ошибке или к заранее определенному резервному варианту.
Агент не следует статической последовательности действий. Он находится в цикле выполнения, часто построенном по шаблону ReAct, что является сокращением от Reason plus Act. Бэкенд передает управление потоком большой языковой модели:
┌────────────────────────┐
▼ │
[Objective] ──> [LLM Evaluates State] │
│ │
Does it need more info? │
├── Yes ──> [Select Tool & Arguments]
│ │
│ [Execute Tool] ────────┘
│ (API, DB, Search)
│
└── No ──> [Return Final Answer]
Один проход по циклу состоит из четырех этапов:
- Модели предоставляются цель, контекст и ранее выполненные действия.
- Она определяет, хватает ли у нее информации или требуется внешний инструмент.
- Если требуются данные, она отправляет структурированный запрос к инструменту, например для чтения файла, вызова API или выполнения запроса.
- Ваша среда выполнения запускает этот инструмент, помещает полученный результат в окно контекста модели и возобновляет цикл.
Важно то, что модель динамически выбирает последовательность шагов во время выполнения.
Пример: возврат средств за задержку доставки
Рассмотрим внутренний инструмент для возврата средств клиенту, у которого задержалась доставка.
Традиционный способ
В сервисе на Express или FastAPI можно написать обработчик, который находит заказ, применяет строгое правило, осуществляет возврат средств и отправляет уведомление:
// Traditional Backend: Strict, deterministic logic
async function handleRefund(orderId: string, customerReason: string) {
const order = await db.orders.findById(orderId);
if (!order) {
throw new NotFoundError("Order not found");
}
// Strict business rule written by an engineer
const isEligible = order.status === "DELAYED" && order.daysDelayed > 5;
if (!isEligible) {
return { status: "rejected", reason: "Delay does not meet refund criteria." };
}
const refund = await paymentGateway.refund(order.paymentIntentId);
await db.orders.update(orderId, { status: "REFUNDED" });
await emailService.sendRefundNotice(order.customerEmail);
return { status: "success", refundId: refund.id };
}
Этот код выполняется менее чем за 100 миллисекунд, практически не требует вычислительных ресурсов и ведет себя одинаково каждый раз. Однако он крайне уязвим. Предположим, клиент пишет, что посылка прибыла вовремя, но курьер переехал почтовый ящик. Система отклоняет запрос на возврат денег, потому что значение daysDelayed равно нулю — в её жестко заданных правилах нет возможности учитывать факторы, выходящие за их рамки.
Подход с агентом
Агент сам решает, какие инструменты использовать, исходя из объяснений клиента:
// Agent Loop: The model decides which tools to call
import { generateText, tool } from "ai";
import { z } from "zod";
const tools = {
fetchOrder: tool({
description: "Fetch order details and shipping history",
parameters: z.object({ orderId: z.string() }),
execute: async ({ orderId }) => db.orders.findById(orderId),
}),
issueRefund: tool({
description: "Issue a monetary refund to the customer",
parameters: z.object({
paymentIntentId: z.string(),
amount: z.number(),
reason: z.string()
}),
execute: async (args) => paymentGateway.refund(args.paymentIntentId, args.amount),
}),
escalateToHuman: tool({
description: "Escalate edge cases or physical damage to a support manager",
parameters: z.object({ ticketSummary: z.string() }),
execute: async ({ ticketSummary }) => supportDesk.createEscalation(ticketSummary),
})
};
// The execution is governed by an evaluation loop
const response = await generateText({
model: yourConfiguredLLM,
tools,
maxSteps: 5, // Prevents infinite execution loops
prompt: `Customer Issue: "The package arrived on time, but the driver ran over my mailbox. Order #1234."
Evaluate policy guidelines and take appropriate action.`,
});
Здесь модель читает жалобу, запрашивает информацию о заказе, определяет, что проблема связана с повреждением имущества, а не с логистикой доставки, пропускает обычную проверку возможности возврата средств и вызывает функцию escalateToHuman. Такая гибкость имеет свою цену: для обработки потребовалось три запроса к LLM, было потрачено несколько центов в виде токенов, и процесс занял 4 секунды, в то время как оператору хватило бы 50 миллисекунд.
Как они сравниваются
Почти все операционные предположения меняются при переходе от детерминированного бэкенда к агентному системе.
- Поток управления: в одном случае шаги определяются кодом, а в другом — LLM выбирает их внутри цикла.
- Путь выполнения: в детерминированном бэкенде он известен на этапе компиляции, тогда как в агентном системе он определяется во время выполнения.
- Задержка: у бэкенда она составляет примерно 10–200 мс и предсказуема, у агента — от 2 до 30 секунд или больше, и она переменна в зависимости от количества итераций.
Окно контекста как рабочая память
Бэкенд хранит состояние в переменных, ключах Redis или строках базы данных, а функция считывает только те поля, которые ей нужны. Для агента окно контекста представляет собой краткосрочную рабочую память. Каждый раз, когда запускается инструмент, его результат сериализуется в текст, обычно в формате JSON, и добавляется в историю запросов. Типичный цикл развивается следующим образом:
- Шаг 1: запрос пользователя, примерно 50 токенов.
- Шаг 2: запрос модели к инструменту, примерно 40 токенов.
- Шаг 3: результат работы инструмента, примерно 500 токенов.
- Шаг 4: модель анализирует расширенный запрос и отправляет второй вызов, что добавляет ещё примерно 80 токенов.
- Шаг 5: поступает второй результат, что добавляет примерно 1 200 токенов.
С каждым циклом объем запроса увеличивается. Поскольку и стоимость, и время обработки зависят от размера входных данных, пятый шаг значительно медленнее и дороже первого.
Частой ошибкой при разработке является возврат целых строк базы данных или огромных объемов данных через API агенту. Если инструмент searchUsers() загружает в контекст 50 полных профилей, это быстро приведет к исчерпанию времени на обработку информации у модели. Инструменты агентов следует проектировать как публичные API: сокращайте и очищайте выходные данные так, чтобы в них содержались только те поля, которые необходимы модели для принятия следующего решения.
Почему агенты труднее поддерживать в работе
При сбое бэкенда вы получаете трейс ошибки. Вы можете повторно выполнить ту же операцию локально, изучить переменные и исправить баг. Агенты же сбиваются с работой на основе вероятностных факторов.
Бесконечные циклы. Предположим, агент вызывает API и получает тонкую ошибку валидации, такую как invalid_date_format. Он пытается снова, используя немного иной формат даты, затем снова. Поскольку нет жесткого лимита на количество итераций (maxSteps), он может потратить сотни долларов на API-кредиты, пытаясь «победить» механизм валидации.
Вымышленные аргументы инструментов. Схемы и механизмы валидации обеспечивают типобезопасность обычного кода во время выполнения. LLM может генерировать корректный JSON, соответствующий вашей схеме в 98% случаев, но иногда добавлять вымышленный параметр. Чего можно ожидать:
// Expected:
{ "customerId": "cust_123", "amount": 50 }
Что иногда выделяет модель при высокой температуре:
// What the model occasionally outputs under high temperature:
{ "user_id": "cust_123", "refund_value": "$50.00" }
Если среда выполнения не будет применять строгую обработку схемы с использованием таких инструментов, как Zod или Pydantic, перед запуском реальной функции, ваш бэкенд выйдет из строя.
Непредсказуемое маршрутизирование. Запрос, который вчера требовал двух шагов обработки, сегодня может потребовать четырех из-за незначительных изменений в формулировке пользователя. Это затрудняет обеспечение соблюдения условий по времени отклика.
Выбор подходящей архитектуры
Агенты привлекают столько внимания, что разработчики пытаются строить целые системы на их основе, что является дорогостоящей ошибкой.
Оставайтесь при обычном коде бэкенда, когда:
- Бизнес-логика известна и стабильна, как в случае с формированием счетов-фактур, аутентификацией, операциями CRUD и расчетами в корзине.
- Необходимо минимальное время отклика, как в процессах оформления покупки, автодополнении поиска и реальном времени обмене сообщениями.
- Ошибки могут привести к нарушениям нормативов или финансовым рискам, как в случае с учетными книгами, медицинскими записями и контролем прав доступа.
Обращайтесь к агенту в следующих случаях:
- Путь к решению неоднозначен, например необходимо найти рейс с трехчасовой пересадкой, вегетарианской едой и стоимостью менее 800 долларов.
- Данные имеют беспорядочную и неструктурированную форму, например разнообразные PDF-счета, электронные письма свободного формата или отчеты клиентов о сбоях.
- Системе необходимо координировать разные инструменты без общего API, например просматривать внешние сайты, изучать документацию, найденную по пути, или сортировать проблемы между несколькими продуктами.
Работающая гибридная архитектура
В реальных приложениях наиболее надежной архитектурой редко бывает чистый агент. Это детерминистический бэкенд с агентом, находящимся внутри контролируемых границ:
[Incoming Request] ──> [Traditional API Gateway] ──> Authentication / Rate Limiting
│
▼
[Standard Business Logic] ──> Fast DB Reads / Validation
│
▼
[Targeted Agent Boundary] ──> Handles unstructured task
│ (Restricted to 3 safe tools)
▼
[Standard Business Logic] ──> Validates agent output
│
▼
[Final Response] <─── [Structured DB Write]
Храните логику маршрутизации, авторизации, сохранения данных и критической верификации бизнес-логики в детерминистическом коде. Обращайтесь к агенту только для тех подзадач, которым действительно требуется рассуждение в стиле человека и гибкая организация работы инструментов.
Вывод
Агент не лучше традиционного бэкенда — это просто другая парадигма обработки данных. Бэкенды опираются на предсказуемость, скорость и низкую стоимость за счёт выполнения чётких инструкций, тогда как агенты обеспечивают адаптивность и способность к решению проблем, позволяя большой языковой модели выбирать путь выполнения в рамках цикла рассуждений.
Поэтому перед разработкой следующей функции не задавайтесь вопросом, сможет ли это сделать агент — при достаточном количестве токенов он, скорее всего, справится. Спросите себя, знаете ли вы уже шаги, необходимые для решения проблемы. Если да, напишите код сами и оставьте агентов для открытых задач, с которыми обычный код никогда не сможет справиться из-за недостатка гибкости.