Почему ваш ИИ-агент продолжает давать сбои в продакшне (И как это исправить)
Большинство продакшн-отказов агентов происходит из-за пяти причин: хрупкие промпты, не обрабатывающие граничные случаи; отсутствие логики повторных попыток для переходящих ошибок API; нулевая наблюдаемость, не позволяющая видеть что ломается; бесконечные циклы без условия выхода; определения инструментов, достаточно неоднозначные, чтобы модель выбрала неправильный. Все пять поддаются исправлению без смены модели или фреймворка.
Каждую среду. 28 400+ читателей. Никакой воды.
✓ Проверьте почту — нажмите ссылку подтверждения, чтобы завершить подписку.
✓ Вы подписаны!
✓ Вы уже в списке.
Содержание
Обновлено июнь 2026.
TL;DR: Большинство продакшн-отказов агентов происходит из-за пяти причин: хрупкие промпты, не обрабатывающие граничные случаи; отсутствие логики повторных попыток для переходящих ошибок API; нулевая наблюдаемость, не позволяющая видеть что ломается; бесконечные циклы без условия выхода; определения инструментов, достаточно неоднозначные, чтобы модель выбрала неправильный. Все пять поддаются исправлению без смены модели или фреймворка.
[Чтение оператора] Я управляю более чем 30 агентами в продакшне. Все эти сбои случались у меня. Те, что сожгли больше всего времени, были не экзотическими — это были скучные инфраструктурные сбои, которые я думал, что обработал.
Сбой 1: Хрупкие промпты, ломающиеся на граничных входных данных
Промпт, работающий на тестовых случаях, провалится на входных данных, которые вы не предвидели. Это не ограничение модели — это проблема написания инструкций.
Симптомы: Агент выдаёт бессмысленный результат, вызывает неправильный инструмент или выдаёт некорректный JSON, когда входные данные слегка отличаются от протестированных.
Первопричина: Ваш системный промпт описывает только счастливый путь. Он не говорит модели, что делать, когда данные отсутствуют, повреждены или неоднозначны.
Исправление: Добавьте явную обработку граничных случаев в системный промпт:
If the input data is missing a required field, return:
{ "status": "error", "reason": "missing_field", "field": "<fieldname>" }
Do NOT attempt to infer or hallucinate missing values.
If you are uncertain which tool to call, call no tool and return:
{ "status": "clarification_needed", "question": "..." }Модель надёжно следует явным инструкциям для граничных случаев. Ошибка — предполагать, что она обобщит инструкции счастливого пути на грязные случаи.
Сбой 2: Отсутствие логики повторных попыток для переходящих ошибок API
Каждый внешний API, который вызывает ваш агент, в какой-то момент даст сбой. API Claude, Meta Graph API, ваша база данных — все они возвращают ошибки 5xx, таймаут или ограничения скорости. Если у агента нет логики повторных попыток, одна переходящая ошибка уничтожает весь прогон.
Симптомы: Прогоны агента случайно завершаются неудачей на разных шагах. Логи показывают 503 или 429 без последующей попытки.
Исправление: Оберните каждый внешний вызов в повторную попытку с экспоненциальной задержкой:
async function withRetry<T>(fn: () => Promise<T>, retries = 3, baseDelayMs = 500): Promise<T> {
for (let attempt = 0; attempt <= retries; attempt++) {
try {
return await fn();
} catch (err: any) {
const isTransient = err.status === 429 || err.status >= 500 || err.code === "ECONNRESET";
if (!isTransient || attempt === retries) throw err;
const delay = baseDelayMs * Math.pow(2, attempt) + Math.random() * 100;
await new Promise((r) => setTimeout(r, delay));
}
}
throw new Error("unreachable");
}
// Usage
const result = await withRetry(() => client.messages.create({ ... }));Три повторные попытки с экспоненциальной задержкой обрабатывают ~99% переходящих сбоев. Добавьте это к каждому внешнему вызову, и половина ваших случайных сбоев исчезнет.
Сбой 3: Нулевая наблюдаемость — вы не можете видеть, что ломается
Это наиболее распространённый режим отказа в продакшне и самый затратный по времени для отладки: агент молча падает или выдаёт неверный результат, и вы понятия не имеете, где в цепочке что-то пошло не так.
Симптомы: Вы знаете, что что-то не так, но не можете определить шаг. Вы добавляете операторы console.log и вручную перезапускаете, пытаясь воспроизвести.
Исправление: Структурированное логирование на каждом шаге с идентификатором прогона, отслеживающим всё выполнение:
function createLogger(runId: string, agentName: string) {
return {
step: (step: string, data: object) =>
console.log(JSON.stringify({ runId, agent: agentName, step, ts: new Date().toISOString(), ...data })),
error: (step: string, err: unknown) =>
console.error(JSON.stringify({ runId, agent: agentName, step, error: String(err), ts: new Date().toISOString() })),
};
}
const log = createLogger(crypto.randomUUID(), "newsletter-agent");
log.step("fetch_topic", { topicId: topic.id, topic: topic.name });
// ... do work ...
log.step("draft_complete", { subject: draft.subject, wordCount: draft.body.split(" ").length });Если вы на Cloudflare Workers, логи идут в Logpush или Workers Tail. При локальном запуске или на VPS направьте в агрегатор логов. Структурированный JSON позволяет фильтровать по runId, чтобы точно видеть, что произошло в одном прогоне.
Сбой 4: Бесконечные циклы без условия выхода
Агентские циклы — где модель вызывает инструменты и итерирует до выполнения условия — могут работать вечно, если условие никогда не выполняется или модель неправильно его идентифицирует.
Симптомы: Агент тратит сотни долларов на API-расходы до таймаута. Или многократно вызывает один и тот же инструмент, не продвигаясь вперёд.
Исправление: Всегда имейте жёсткий лимит итераций и проверку прогресса:
const MAX_ITERATIONS = 10;
let iterations = 0;
let lastToolCallName = "";
let sameToolCallCount = 0;
while (true) {
iterations++;
if (iterations > MAX_ITERATIONS) {
log.error("loop", { reason: "exceeded_max_iterations" });
break;
}
const response = await client.messages.create({ ... });
// Detect stuck loops: same tool called 3x in a row
const toolCall = response.content.find(b => b.type === "tool_use");
if (toolCall?.name === lastToolCallName) {
sameToolCallCount++;
if (sameToolCallCount >= 3) {
log.error("loop", { reason: "stuck_loop", tool: toolCall.name });
break;
}
} else {
sameToolCallCount = 0;
lastToolCallName = toolCall?.name ?? "";
}
if (response.stop_reason === "end_turn") break;
}Это перехватывает как режим «работал слишком долго», так и режим «крутился на месте». Лимит должен быть достаточно щедрым для счастливого пути, но достаточно жёстким, чтобы ограничить радиус поражения.
Сбой 5: Неоднозначные определения инструментов, которые модель разрешает неверно
Если дать модели два инструмента с перекрывающимися описаниями, она иногда вызовет неправильный. Это особенно распространено с инструментами вроде search_database vs get_record или send_email vs create_draft.
Симптомы: Модель вызывает правильную категорию инструмента, но выбирает неправильный конкретный. Или вызывает инструмент в неправильном контексте (использует инструмент записи, когда уместно было только чтение).
Исправление: Сделайте описания инструментов взаимоисключающими и явно добавьте «когда НЕ использовать»:
const tools = [
{
name: "get_subscriber",
description: "Fetch a single subscriber record by email. Use ONLY when you have a specific email address. Do NOT use for searching or listing subscribers.",
input_schema: { ... }
},
{
name: "search_subscribers",
description: "Search subscribers by tag, segment, or status. Use when you need to find subscribers matching a criteria — NOT when you have a specific email address.",
input_schema: { ... }
}
];Оговорка «НЕ использовать, когда X» — часть, которую большинство пропускает. Это самая важная часть. Модели лучше следуют явным негативным ограничениям, чем выводят их из позитивных описаний.
Ещё одна вещь: тестируйте агентов на плохих входных данных
Большинство агентов тестируются только на чистых входных данных счастливого пути. В продакшне грязные входные данные: пустые строки, null-поля, граничные случаи Unicode, ответы API, возвращающие 200, но с неожиданной схемой.
Добавьте тестовый набор, явно упражняющий:
- Пустые или null входные данные
- Входные данные максимальной ожидаемой длины
- Входные данные со специальными символами или не-ASCII-текстом
- Внешние API, возвращающие неожиданные формы ответа
Если агент ломается на любом из них, исправьте это до запуска в продакшн. Производственная среда найдёт каждое сделанное вами предположение.
Итог оператора
Большинство продакшн-отказов агентов — это инфраструктурные проблемы, маскирующиеся под проблемы модели. Прежде чем менять модели, добавьте повторные попытки, структурированное логирование, лимиты циклов и явную обработку граничных случаев в промпты. Исправьте неоднозначные определения инструментов. Затем тестируйте на плохих входных данных. Сделайте всё это прежде чем обвинять модель — по моему опыту, модель обычно последнее, что нуждается в изменении.
Каждую среду. 28 400+ читателей. Никакой воды.
✓ Проверьте почту — нажмите ссылку подтверждения, чтобы завершить подписку.
✓ Вы подписаны!
✓ Вы уже в списке.
Получайте ИИ-руководство на почту
Каждую среду. 28 400+ читателей. Никакой воды.
Проверьте почту.
Мы отправили письмо для подтверждения — нажмите на ссылку, чтобы завершить подписку. Проверьте папку «Спам», если не видите его в течение минуты.
Вы подписаны.
Добро пожаловать — следующий выпуск скоро придёт на вашу почту.
Вы уже в списке — ждите выпуск каждую среду.