0Pricing
AI Engineering Academy · Урок

Классификация режимов отказа агента

Создайте таксономию отказов агента: ошибки инструментов, некорректные результаты, циклы рассуждений, исчерпание контекста и недоступность внешних сервисов, а затем разработайте стратегии восстановления для каждого случая.

«Классификация режимов отказа агента» — бесплатный урок AI Engineering Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Engineering Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Engineering Academy содержит 4 уроков всего.

Почему агенты терпят неудачу особым образом

Агенты терпят неудачу иначе, чем простые вызовы LLM. Вызов в один этап либо возвращает ответ, либо выдаёт ошибку. Агент, выполняющий многоэтапную задачу, может завершиться сбоем на любом этапе, причём по окончательному результату это может быть незаметно. Понимание таксономии режимов сбоев агентов — первый шаг к созданию агентов, которые обнаруживают, диагностируют и исправляют собственные сбои.

Режим сбоя 1: ошибки инструментов

Ошибки инструментов возникают, когда агент вызывает инструмент с недопустимыми аргументами, инструмент возбуждает исключение или возвращает пустой либо некорректно сформированный результат. Примеры: вызов API поиска с неправильно сформированным запросом, запрос к базе данных с недопустимым SQL или вызов исполнителя кода, который превышает время ожидания. Такие ошибки проще всего обнаружить, поскольку они создают явные сигналы исключений, которые можно перехватить и обработать.

class ToolError(Exception):
    def __init__(self, tool_name: str, args: dict, error: Exception):
        self.tool_name = tool_name
        self.args = args
        self.original_error = error
        super().__init__(f'Tool {tool_name} failed: {error}')

def safe_tool_call(tool_func, args: dict) -> str:
    try:
        result = tool_func(**args)
        if not result:
            return 'Tool returned empty result. Try a different approach.'
        return str(result)
    except Exception as e:
        raise ToolError(tool_func.__name__, args, e)

Режим сбоя 2: некорректно сформированные результаты

Некорректно сформированные результаты возникают, когда агент создаёт текст, не соответствующий ожидаемому формату, например возвращает текст на естественном языке, хотя следующий шаг ожидает JSON, или вызывает инструмент со структурой аргументов неправильного вида. Это часто происходит, когда агент путает текущий этап с предыдущим. Проверяйте формат каждого результата агента перед использованием и повторно отправляйте запрос, если формат неверен.

import json

def validate_agent_output(raw_output: str, expected_format: str) -> dict:
    if expected_format == 'json':
        try:
            return json.loads(raw_output)
        except json.JSONDecodeError as e:
            return {
                'valid': False,
                'error': f'Expected JSON but got invalid JSON: {e}',
                'raw': raw_output[:200]
            }
    return {'valid': True, 'data': raw_output}

Режим сбоя 3: циклы рассуждений

Циклы рассуждений возникают, когда агент бесконечно повторяет одно и то же действие или рассуждение, не продвигаясь вперёд. Например, агент может 10 раз подряд выполнить один и тот же поисковый запрос, получать один и тот же пустой результат и не понимать, что попробовать дальше. Обнаруживайте циклы, отслеживая недавние действия и проверяя их повторы. При обнаружении цикла добавляйте метазапрос, который предлагает агенту попробовать другой подход.

from collections import Counter

class LoopDetector:
    def __init__(self, window: int = 5, threshold: int = 3):
        self.recent_actions = []
        self.window = window
        self.threshold = threshold

    def record(self, action: str) -> bool:
        self.recent_actions.append(action)
        if len(self.recent_actions) > self.window:
            self.recent_actions.pop(0)
        counts = Counter(self.recent_actions)
        most_common_count = counts.most_common(1)[0][1] if counts else 0
        return most_common_count >= self.threshold  # True = loop detected

Режим сбоя 4: исчерпание контекста

Исчерпание контекста происходит, когда накопленная история агента (вызовы инструментов, наблюдения и рассуждения) превышает размер контекстного окна модели. Модель либо молча обрезает историю, теряя важную информацию, либо выдаёт ошибку ограничения числа токенов. Предотвращайте это, отслеживая использование токенов на каждом этапе и сжимая историю (суммируя старые этапы) до достижения ограничения.

import tiktoken

CONTEXT_LIMIT = 100_000  # tokens
COMPRESS_AT = 80_000     # trigger compression with headroom

enc = tiktoken.encoding_for_model('gpt-4o')

def total_tokens(messages: list) -> int:
    return sum(len(enc.encode(str(m))) for m in messages)

def check_context(messages: list) -> str:
    tokens = total_tokens(messages)
    if tokens > COMPRESS_AT:
        return 'compress'
    if tokens > CONTEXT_LIMIT:
        return 'critical'
    return 'ok'

Режим сбоя 5: недоступность внешней службы

Сбои внешних служб возникают, когда базовая служба инструмента недоступна, ограничивает частоту запросов или возвращает непредвиденные ошибки. Агент, который не может обратиться к нужной ему базе данных, застревает. В отличие от циклов рассуждений, вызванных самим агентом, внешние сбои относятся к сбоям среды. Обрабатывайте их с помощью повторных попыток и экспоненциальной задержки, а также предусмотрите резервные инструменты, способные приблизительно получить результат из других источников данных.

import asyncio

async def resilient_tool_call(tool_func, args: dict, max_retries: int = 3) -> str:
    for attempt in range(max_retries):
        try:
            return await tool_func(**args)
        except (ConnectionError, TimeoutError) as e:
            if attempt == max_retries - 1:
                return f'Service unavailable after {max_retries} attempts. Error: {e}'
            wait = 2 ** attempt  # 1s, 2s, 4s
            await asyncio.sleep(wait)
    return 'Unexpected error in resilient_tool_call'

Режим сбоя 6: непонимание цели

Непонимание цели возникает, когда агент неверно истолковывает задачу и стремится к несколько иной цели. Это самый сложный для обнаружения сбой, поскольку агент может успешно завершить работу, но выполнить не ту задачу, которую имел в виду пользователь. Уменьшить риск можно, попросив агента в начале пересказать цель своими словами, а также реализовав финальный этап проверки, который определяет, действительно ли результат отвечает на исходный вопрос.

async def confirm_goal_understanding(original_task: str) -> str:
    resp = await client.chat.completions.create(
        model='gpt-4o',
        messages=[
            {'role': 'system', 'content': 'Restate the task in your own words. Be specific about what the final deliverable should be.'},
            {'role': 'user', 'content': f'Task: {original_task}'}
        ]
    )
    return resp.choices[0].message.content

# Use the restatement as the first step of the agent
# to catch misunderstandings before any tools are called

Создание системы классификации сбоев

Создайте структурированный классификатор сбоев, который присваивает каждому исключению агента его тип. Это обеспечивает автоматическую маршрутизацию к подходящей стратегии восстановления. Сохраняйте журналы сбоев с метками типов, чтобы анализировать, какие режимы сбоев встречаются чаще всего, и в первую очередь устранять именно их. Ошибки инструментов и циклы обычно встречаются чаще всего и лучше всего поддаются исправлению.

from enum import Enum
from dataclasses import dataclass

class FailureType(Enum):
    TOOL_ERROR = 'tool_error'
    MALFORMED_OUTPUT = 'malformed_output'
    REASONING_LOOP = 'reasoning_loop'
    CONTEXT_EXHAUSTION = 'context_exhaustion'
    EXTERNAL_SERVICE = 'external_service'
    GOAL_MISUNDERSTANDING = 'goal_misunderstanding'
    MAX_ITERATIONS = 'max_iterations'
    UNKNOWN = 'unknown'

@dataclass
class AgentFailure:
    failure_type: FailureType
    step: int
    tool_name: str | None
    error_message: str
    recoverable: bool

Сопоставление сбоев с действиями восстановления

Для каждого типа сбоя предусмотрено подходящее действие восстановления. Ошибки инструментов требуют повторной попытки с изменёнными аргументами. При циклах нужен запрос, побуждающий агента попробовать что-то новое. При исчерпании контекста требуется сжатие. При сбоях внешних служб нужны резервные инструменты. При непонимании цели требуется запрос уточнения. Явно задайте эти соответствия в маршрутизаторе восстановления, который среда выполнения агента вызывает при возникновении сбоев.

RECOVERY_ACTIONS = {
    FailureType.TOOL_ERROR:           'retry_with_corrected_args',
    FailureType.MALFORMED_OUTPUT:     'reformat_output',
    FailureType.REASONING_LOOP:       'inject_diversity_prompt',
    FailureType.CONTEXT_EXHAUSTION:   'compress_history',
    FailureType.EXTERNAL_SERVICE:     'use_fallback_tool',
    FailureType.GOAL_MISUNDERSTANDING:'request_clarification',
    FailureType.MAX_ITERATIONS:       'escalate_to_human',
    FailureType.UNKNOWN:              'escalate_to_human'
}

Установка максимального числа итераций

У каждого агента должно быть максимальное число итераций как обязательное ограничение безопасности. Без него агент, попавший в цикл, будет работать бесконечно, расходуя токены и деньги. Устанавливайте ограничение с учётом ожидаемой сложности задачи: для простого агента, отвечающего на вопросы, можно установить предел в 5 шагов, а сложному исследовательскому агенту разрешить 20. При достижении предела запишите сбой в журнал, сохраните частичные результаты и передайте задачу человеку либо верните частичный ответ.

MAX_ITERATIONS = 15

async def run_agent(task: str) -> str:
    messages = [{'role': 'user', 'content': task}]
    loop_detector = LoopDetector()
    for iteration in range(MAX_ITERATIONS):
        response = await get_agent_action(messages)
        if response.is_final:
            return response.answer
        action_key = f'{response.tool}:{response.args}'
        if loop_detector.record(action_key):
            messages.append({'role': 'system', 'content': 'You are repeating yourself. Try a completely different approach.'})
            continue
        result = await execute_tool(response.tool, response.args)
        messages.append({'role': 'tool', 'content': result})
    return 'Task exceeded maximum iterations. Partial results: ' + get_partial_result(messages)

Запись сбоев для анализа после инцидента

Записывайте каждый сбой агента с достаточным контекстом для последующей диагностики: полным описанием задачи, полной историей действий до момента сбоя, типом сбоя и сообщением об ошибке, количеством итераций и использованием токенов. Храните эти данные в таблице сбоев, создав индекс по failure_type и task_id. Регулярно анализируйте журналы сбоев, чтобы определить, какие типы задач чаще подвержены конкретным режимам сбоев, и соответствующим образом расставлять приоритеты исправлений.

import json
from dataclasses import asdict

async def log_agent_failure(task_id: str, failure: AgentFailure, history: list, pool):
    async with pool.acquire() as conn:
        await conn.execute('''
            INSERT INTO agent_failures
            (task_id, failure_type, step, tool_name, error_message,
             recoverable, action_history, failed_at)
            VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())
        ''',
            task_id,
            failure.failure_type.value,
            failure.step,
            failure.tool_name,
            failure.error_message,
            failure.recoverable,
            json.dumps(history)
        )

Быстрая проверка

Проверьте, насколько хорошо вы понимаете классификацию режимов сбоев агентов.

Итоги урока

В этом уроке вы узнали, что к шести основным режимам сбоев агентов относятся ошибки инструментов, некорректно сформированные результаты, циклы рассуждений, исчерпание контекста, сбои внешних служб и непонимание цели; обнаружение циклов по истории действий выявляет повторяющиеся шаблоны до исчерпания бюджета итераций; а сопоставление типов сбоев с действиями восстановления обеспечивает автоматическое самовосстановление. Далее мы реализуем самокоррекцию и рефлексивное построение запросов.

Часто задаваемые вопросы

Урок «Классификация режимов отказа агента» бесплатный?

Да — полный текст урока «Классификация режимов отказа агента» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Engineering Academy, подпишись на CoddyKit PRO. Курс AI Engineering Academy содержит 4 уроков всего.

Чему я научусь в уроке «Классификация режимов отказа агента»?

Создайте таксономию отказов агента: ошибки инструментов, некорректные результаты, циклы рассуждений, исчерпание контекста и недоступность внешних сервисов, а затем разработайте стратегии восстановлен… Ты практикуешь AI Engineering Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать AI Engineering Academy?

Предыдущий опыт не требуется. AI Engineering Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Классификация режимов отказа агента»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке AI Engineering Academy?

Да. Каждый урок AI Engineering Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Классификация режимов отказа агента
  2. Самокоррекция и рефлексивное создание промптов
  3. Контрольные точки и возобновление задач
  4. Эскалация с участием человека
← Назад к AI Engineering Academy