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

Как вы боретесь с «бесконечным циклом» агента в Agentic RAG?

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

Бесконечный цикл в Agentic RAG — ситуация, когда агент многократно повторяет одни и те же действия (вызов инструментов, чтение документов) без продвижения к ответу. Основные контрмеры: жёсткий лимит шагов (10–15), детекция повторяющихся действий, Human-in-the-loop после N итераций и оценка прогресса (отсутствие изменений за 3 шага → стоп). Комбинация этих методов позволяет гарантировать завершение работы агента за разумное время.


1. Термин: Agentic RAG и проблема бесконечного цикла

Agentic RAG — архитектура, в которой LLM-агент самостоятельно планирует последовательность действий (поиск документов, call|вызов API, рассуждения) для ответа на сложный запрос. Агент может использовать инструменты (векторная БД, калькулятор, веб-поиск) и многократно обращаться к ним.

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

Почему это критично

  • Latency — пользователь ждёт ответа минутами, пока агент бесконечно перебирает варианты.
  • Cost — каждый call|вызов LLM и инструментов стоит денег.
  • User experience — тайм-ауты и пустые ответы подрывают доверие к системе.

2. Причины возникновения циклов

ПричинаОписаниеПример
Некорректные инструментыИнструмент возвращает ошибку или пустой результат, агент пытается сноваПоиск не находит документ → агент повторяет тот же запрос
Неоднозначный запросЗапрос слишком общий, агент не может сузить фокус«Расскажи всё о RAG» → агент бесконечно переключается между темами
Ошибки планированияАгент генерирует план, который зацикливается сам на себеПлан: «найти A → если нет A, найти B → если нет B, найти A»
Отсутствие терминального условияАгент не понимает, когда ответ готов, и продолжает уточнятьПосле получения ответа агент решает «проверить ещё один источник»
Галлюцинации в рассужденияхLLM выдумывает промежуточные шаги, которые ведут в никудаАгент решает, что нужно вызвать несуществующий инструмент

3. Контрмера 1: Лимит шагов (max_iterations)

Самая простая и обязательная защита — установить максимальное количество итераций агента (обычно 10–15). После достижения лимита агент принудительно завершается, возвращая лучший накопленный ответ или сообщение об ошибке.

Реализация (псевдокод):

MAX_ITERATIONS = 12
for step in range(MAX_ITERATIONS):
    action = agent.act(state)
    if action.is_final():
        return action.answer
    state = environment.step(action)
# Если цикл не завершился
return fallback_answer(state)

Плюсы простота, гарантированное завершение.
Минусы агент может оборваться на полпути, не дойдя до хорошего ответа.

Рекомендация лимит должен быть достаточно большим, чтобы покрыть типовые сценарии, но не слишком большим, чтобы не допустить бесконечного ожидания. Для большинства задач 10–15 шагов оптимально.


4. Контрмера 2: Детекция повторяющихся действий

Агент может зациклиться на одних и тех же вызовах инструментов с одинаковыми аргументами. Детекция повторений отслеживает историю действий и сигнализирует о цикле, если последовательность повторяется.

Подходы

  • Хэширование действий сохранять хэш (инструмент + аргументы) каждого шага. Если хэш уже встречался в последних K шагах — цикл.
  • Сравнение последовательностей если последние N шагов совпадают с предыдущими N шагами (с точностью до порядка) — цикл.
  • Мониторинг состояния если состояние агента (накопленный контекст, список найденных документов) не меняется в течение M шагов — стоп.

Пример кода (упрощённый детектор на основе хэшей):

from collections import deque

class CycleDetector:
    def __init__(self, window=5):
        self.window = window
        self.history = deque(maxlen=window)
    
    def check(self, action):
        action_hash = hash((action.tool, tuple(action.args)))
        if action_hash in self.history:
            return True  # цикл обнаружен
        self.history.append(action_hash)
        return False

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


5. Контрмера 3: Human-in-the-loop (HITL) после N шагов

Human-in-the-loop — привлечение человека для разрешения неопределённости. Если агент не завершил задачу за N шагов (например, 8), система запрашивает подтверждение у оператора: «Продолжить? Сменить стратегию? Ответить текущим контекстом?».

Сценарий

  1. Агент делает 8 шагов, не приходя к финальному ответу.
  2. Система отправляет оператору краткий дайджест: текущий контекст, последние действия, гипотезы.
  3. Оператор выбирает одно из действий:
    • Продолжить (дать агенту ещё 5 шагов).
    • Ответить сейчас (использовать накопленное).
    • Изменить запрос (уточнить у пользователя).
    • Отменить (вернуть ошибку).

Плюсы гибкость, возможность спасти сложный запрос.
Минусы задержка из-за ожидания человека, не подходит для fully automated систем.


6. Контрмера 4: Оценка прогресса (нет изменений за 3 шага → стоп)

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

Метрики прогресса

  • Количество уникальных документов в контексте (не растёт → стоп).
  • Уверенность LLM (logprob финального ответа) — если не увеличивается за 3 шага, стоп.
  • Изменение эмбеддинга запроса — если агент переформулирует запрос, но эмбеддинг не меняется, значит он ходит по кругу.

Реализация

class ProgressMonitor:
    def __init__(self, patience=3):
        self.patience = patience
        self.no_progress_steps = 0
        self.last_state = None
    
    def update(self, state):
        if self._is_progress(state):
            self.no_progress_steps = 0
        else:
            self.no_progress_steps += 1
        self.last_state = state
        return self.no_progress_steps >= self.patience

Плюсы ловит «тихие» циклы, где действия разные, но результата нет.
Минусы сложно определить универсальную метрику прогресса для разных задач.


7. Дополнительные техники

ТехникаОписание
Тайм-аутАбсолютное ограничение по времени (например, 30 секунд). Если агент не уложился — принудительный стоп.
Разнообразие инструментовЕсли у агента только один инструмент (поиск), циклы вероятнее. Добавление альтернативных путей (калькулятор, суммаризация) снижает риск.
Логирование и алертыВ production логировать все шаги и отправлять алерт, если агент превысил N шагов. Позволяет выявлять новые паттерны циклов.
Re-prompting с инструкциейВключать в system prompt явное предупреждение: «Если вы заметили, что повторяетесь, остановитесь и дайте лучший ответ на основе имеющегося».
Адаптивный лимитУвеличивать лимит для сложных запросов (определяется по длине запроса или числу сущностей) и уменьшать для простых.

8. Сравнение подходов

МетодГарантия завершенияСохранение качестваСложность реализацииЗатраты
Лимит шагов✅ Высокая⚠️ Может оборвать хороший ответ🟢 НизкаяНизкие
Детекция повторений✅ Высокая (для явных циклов)🟢 Высокая (не прерывает уникальные шаги)🟡 СредняяНизкие
Human-in-the-loop✅ Высокая🟢 Высокая (человек решает)🔴 Высокая (интеграция с UI)Высокие (человек)
Оценка прогресса🟡 Средняя (зависит от метрики)🟢 Высокая (останавливает только бесполезные шаги)🔴 Высокая (нужна кастомная метрика)Средние

Рекомендуемая комбинация лимит шагов (10) + детекция повторений (окно 4) + оценка прогресса (patience=3). Human-in-the-loop опционально для дорогих или критичных запросов.


9. Пример интеграции в код агента (Python)

class SafeAgent:
    def __init__(self, max_steps=12, cycle_window=5, patience=3):
        self.max_steps = max_steps
        self.cycle_detector = CycleDetector(window=cycle_window)
        self.progress_monitor = ProgressMonitor(patience=patience)
    
    def run(self, query):
        state = self._init_state(query)
        for step in range(self.max_steps):
            action = self.llm_act(state)
            
            # Проверка на цикл
            if self.cycle_detector.check(action):
                return self._fallback(state, reason="cycle_detected")
            
            state = self._execute_action(action, state)
            
            # Проверка прогресса
            if self.progress_monitor.update(state):
                return self._fallback(state, reason="no_progress")
            
            if action.is_final():
                return action.answer
        
        return self._fallback(state, reason="max_steps")

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

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

Инструменты

Шаги:

  1. Создайте простого агента с двумя инструментами: search_docs и calculate.
  2. Реализуйте лимит шагов (10), детекцию повторений (окно 3), оценку прогресса (по количеству уникальных документов в контексте).
  3. Сгенерируйте тестовые запросы, которые провоцируют циклы (например, «найди информацию о том, чего нет в документации»).
  4. Добавьте логирование всех шагов в JSON-файл.
  5. Проанализируйте логи: сколько раз сработала каждая контрмера, сколько запросов завершились fallback-ответом.

Ожидаемый результат Агент никогда не зависает, все запросы завершаются за ≤10 шагов, fallback-ответы содержат осмысленное сообщение («Не удалось найти полный ответ, вот что известно...»).


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

ВопросТема
140Архитектура Agentic RAG (общая схема)
141Выбор инструментов для агента
142Планирование последовательности действий
144Управление памятью агента
145Безопасность и контроль доступа агента
5Оценка качества retrieval (влияет на вероятность циклов)

12. Навигация


Навигация