中文翻译暂不可用,显示俄语原文。

Как тестировать fallback и graceful degradation?

Краткий тезис

Тестирование fallback (запасных сценариев) и graceful degradation (корректной деградации) — это процесс верификации того, что агентная RAG-система сохраняет работоспособность при отказах отдельных компонентов (LLM API, векторной базы данных, внешних инструментов) и при перегрузках. Основная стратегия — симулировать отказы, измерять метрики (например, долю успешных ответов, задержки, уровень эскалации) и сравнивать с эталонным поведением. Цель — гарантировать, что система не ломается целиком, а либо переключается на резервный компонент, либо выдает осмысленное сообщение об ошибке (graceful degradation), либо передает управление человеку (fallback).

1. Определения: Fallback и Graceful Degradation

  • Fallback (запасной сценарий) — это автоматическое переключение на альтернативный компонент или последовательность действий при отказе основного. Например, если LLM API возвращает 5xx, агент пытается подключиться к другому провайдеру или переходит в режим «только поиск по ключевым словам».
  • Graceful degradation (корректная деградация) — это сохранение части функциональности при снижении качества одного из компонентов. Система не падает целиком, а возвращает урезанный, но все еще полезный ответ (например, только извлеченные документы без генерации, если LLM перегружен).
  • Resilience (устойчивость) — общая способность системы восстанавливаться после сбоев. Fallback и graceful degradation — две ключевые стратегии для достижения resilience.

2. Почему это важно для Agentic RAG

Агентная RAG-система состоит из нескольких звеньев: роутер запросов, LLM-агент, векторная база данных, инструменты (API, калькуляторы, базы знаний). Каждое звено может отказать:

  • LLM API — задержки, таймауты, «галлюцинации» (garbage response).
  • Векторная БД — недоступность индекса, медленный поиск, поврежденные чанки.
  • Инструмент — внешний сервис не отвечает, возвращает ошибку.
  • Rate Limits — превышение квот, перегрузка.

Без тестирования fallback и graceful degradation система рискует:

  • терять пользователей из-за полного отказа (hard failure);
  • давать неверные ответы при деградировавшем LLM;
  • тратить ресурсы на бесконечные ретраи.

Тестирование помогает выявить неочевидные каскадные отказы (например, падение векторной БД приводит к бесконечному циклу ретраев без fallback).

3. Классификация сценариев отказов

КомпонентТип отказаОжидаемое graceful degradationОжидаемый fallback
LLM APIHTTP 500 / Timeout / Garbage responseВернуть ответ «Извините, сервис временно недоступен»; или ответ без генерации (только поиск)Переключиться на другой LLM-провайдер (если есть) или отправить запрос человеку (human-in-the-loop)
Векторная БДConnection refused, corruptionПоиск по кэшу локальных эмбеддингов или fallback на keyword search (BM25)Вернуть пустой контекст с пояснением «Поиск временно недоступен»
Внешний инструментAPI 503, невалидный ответИспользовать кэшированные данные инструмента (если есть), или пропустить шаг, вернув частичный ответВызвать другой аналогичный инструмент (например, погода от OpenWeatherMap вместо AccuWeather)
Rate limit / Overload429 / Retry-AfterУвеличить задержку (backoff), ставить запрос в очередь с приоритетомПонизить качество (меньше кандидатов, тримминг контекста); отправлять часть запросов в batch

4. Метрики для оценки деградации

При тестировании фиксируем как общие метрики, так и метрики для каждого сценария.

МетрикаФормула / описаниеХорошее значение при graceful degradation
Success Rate(успешные ответы) / (все запросы)> 95 % даже при отказе одного компонента
Error Rate(ответы с ошибкой) / всего< 5 % (ошибки должны быть только при множественных отказах)
Fallback Activation Rateдоля запросов, где пришлось использовать fallbackЗависит от частоты отказов; важно, чтобы fallback не срабатывал на каждый запрос (иначе плохая основная система)
Mean Time to Fallbackсреднее время, через которое система переключается на запасной вариант< 2 секунд (иначе пользователь уйдет)
Degradation Impactна сколько ухудшилось качество ответа (оценивается по faithfulness, relevance) по сравнению с безотказным режимомНе более 20 % ухудшения метрик качества

5. Методика тестирования (пошагово)

5.1 Инвентаризация компонентов и точек отказа

Составьте карту всех сервисов, от которых зависит агент: LLM endpoint, векторный индекс, инструменты, кэш, база данных сессий. Для каждого определите типы отказов (сеть, таймаут, ошибочный ответ, перегрузка).

5.2 Создание тестовых сценариев

Для каждого типа отказа напишите:

  • Название сценария (например, «LLM API возвращает 500 после 3 попыток»)
  • Ожидаемое поведение: какой fallback должен активироваться, какой ответ увидит пользователь.
  • Пороговые времена (timeout для первого запроса, интервал retry).

5.3 Симуляция отказов (Mocking и Chaos Engineering)

  • Mocking: при unit-тестах заменяйте реальные вызовы на имитацию (mock) с нужным поведением (поднять исключение, вернуть garbage).
  • Chaos Engineering: для интеграционных/end‑to‑end тестов используйте инструменты вроде Chaos Monkey или вручную блокируйте порты, внедряйте задержки через tc (traffic control), запускайте контейнеры с высокой нагрузкой.
  • Stub-серверы: разверните локально stub для LLM (например, WireMock), который на определенные запросы отвечает 500 или мусором.

5.4 Написание тестов (py.test пример)

import pytest
import requests
from unittest.mock import patch
from my_agent import Agent

@pytest.fixture
def agent():
    return Agent(primary_llm_url="http://mock-llm:8000", fallback_llm_url="http://fallback-llm:8001")

# Сценарий: LLM primary возвращает 500
def test_fallback_on_llm_500(agent):
    with patch('my_agent.requests.post') as mock_post:
        mock_post.side_effect = [
            requests.exceptions.RequestException("500 error"),  # primary
            {"choices": [{"text": "fallback answer"}]}          # fallback success
        ]
        result = agent.process("user query")
        assert result["status"] == "success"
        assert "fallback answer" in result["response"]
        assert mock_post.call_count >= 2

# Сценарий: векторная БД недоступна
def test_graceful_degradation_vector_db_down(agent):
    with patch('my_agent.vector_store.search') as mock_search:
        mock_search.side_effect = ConnectionError("DB unavailable")
        result = agent.process("search query")
        assert result["status"] == "partial"
        assert "keyword search" in result["fallback_method"]
        assert result["response"] is not None

5.5 Проверка метрик и логов

Убедитесь, что логи фиксируют:

  • время начала и окончания каждого вызова;
  • причину отказа (ошибка, таймаут, garbage response);
  • активированный fallback;
  • итоговый статус (full, degraded, error).

Метрики следует отправлять в Prometheus/Grafana и проверять в автоматическом тесте, что после отказа Success Rate не падает ниже порога.

6. Best Practices для тестирования

  • Не переусердствуйте с fallback: частые переключения могут быть хуже, чем явное сообщение об ошибке (например, если fallback-LLM дает еще худший ответ). Устанавливайте четкие критерии активации.
  • Тестируйте timeout'ы: часто fallback срабатывает только после таймаута. Используйте asyncio или ThreadPoolExecutor для установки максимального времени ожидания.
  • Проверяйте идемпотентность: повторные вызовы при fallback не должны дублировать побочные эффекты (например, повторная отправка email).
  • Симулируйте последовательные отказы: что произойдет, если оба LLM и оба инструмента упали? Должна быть эскалация человеку.
  • Используйте FMEA (Failure Mode and Effects Analysis): для каждого компонента оценивайте вероятность отказов и тяжесть последствий, чтобы определить, какие fallback нужно тестировать в первую очередь.

7. Инструменты для симуляции отказов

ИнструментНазначениеПример использования
WireMock / MockServerStub HTTP-серверы для имитации LLM/instrument APIНастройка ответа 500 на определенный эндпоинт
gremlinChaos engineering для KubernetesВнезапная остановка поды с векторной БД
toxiproxyПрокси для внесения сетевых задержек и разрывовДобавить задержки 5 секунд на соединение к инструменту
locustГенерация нагрузки для проверки rate limitingИмитация превышения лимитов вызовов LLM
unittest.mock / pytest-mockСтандартные mock-библиотеки PythonЗамена реальных вызовов на кастомные

8. Пример комплексного теста graceful degradation

# Проверяем, что при отказе LLM и инструмента, но доступной векторной БД,
# система возвращает частичный ответ (только найденные документы)

def test_graceful_degradation_both_llm_and_tool_down(agent):
    with patch('my_agent.llm_client.generate') as mock_llm, \
         patch('my_agent.tools.calculate') as mock_tool, \
         patch('my_agent.vector_store.search') as mock_search:
        mock_llm.side_effect = ValueError("LLM unavailable")
        mock_tool.side_effect = TimeoutError("tool timeout")
        mock_search.return_value = [{"text": "document content", "score": 0.95}]

        result = agent.process("what is 2+2?")
        assert result["status"] == "partial"
        assert result["response"] == "Я не смог вычислить ответ, но нашел документ: document content."
        assert result["fallback_chain"] == ["primary_llm", "tool", "vector_only"]

9. Метрики, которые нужно мониторить в проде

  • p50/p95/p99 latency при нормальной работе и при fallback.
  • Fallback_rate (доля запросов с активацией fallback).
  • Error_distribution (пропорция ошибок по компонентам).
  • Human_escalation_rate (если агент не справился и передал человеку).

Эти метрики помогут не только проверить graceful degradation, но и выявить слабые места, которые нужно укрепить (например, слишком частые fallback на инструмент B).

Пет-проект для закрепления

Задача Разработать простого агента для ответа на вопросы о погоде, который использует:

  • Primary LLM: OpenAI API.
  • Vector DB: FAISS (локально).
  • Инструмент: OpenWeatherMap API (с имитацией отказов). Требуется реализовать fallback: при отказе OpenAI переключиться на локальную модель (Hugging Face pipeline); при отказе инструмента — использовать кэш последнего ответа; при отказе FAISS — вернуть ответ «Поиск по документам недоступен». Написать тесты с помощью pytest и mock.

Инструменты Python, pytest, unittest.mock, requests-mock, FAISS, transformers.

Шаги:

  1. Определите интерфейс агента (process(query) -> dict).
  2. Реализуйте компоненты с возможностью установки режима (норма/отказ/деградация).
  3. Напишите 5 тестов:
    • LLM primary отказ → fallback.
    • VectorDB отказ → graceful degradation.
    • Инструмент отказ → кэш.
    • Все компоненты отказали → human escalation (вернуть сообщение).
    • Превышение rate limit → backoff + очередь.
  4. Убедитесь, что логи содержат всю цепочку решений.
  5. Постройте локальный дашборд (Prometheus + Grafana) для визуализации метрик отказов.

Ожидаемый результат Набор скриптов и тестов, демонстрирующих, что агент не падает при отказах компонентов, а переключается на запасные сценарии, а метрики (Success Rate, Fallback Activation Rate) изменяются ожидаемым образом.

Связь с другими вопросами

ВопросТема
790Как обеспечить отказоустойчивость (resilience) в Agentic RAG
789Graceful degradation в мультимодальных RAG
792Мониторинг и алертинг в Agentic RAG
788Реализация fallback для LLM-вызовов
787Human-in-the-loop при отказах
794Интеграционное тестирование агентов

Навигация