Существует проблема описанная тут.

Суть проста — если LLM (или агенты вокруг LLM) вызывают последовательно одни и те же запросы с одним и тем же контекстом, попадание в тупик/цикл — вопрос лишь времени. То есть в случае зацикливания между агентами/контекстами надо менять промты или сам контекст, или последовательность вызова агентов.

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


Одно из решений

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

Чтобы система была устойчивой, нужны:

  • динамические промты,

  • адаптивные конфиги,

  • слой обратной связи,

  • модифицирующие агенты,

  • и эволюционный механизм восстановления прогресса.

Ниже — примеры кода, показывающие, как это реализовать на практике.


Динамические промты и динамический конфиг LLM

Промт — не священный текст, а пластичный материал.
Если агент застрял — промт должен уметь мутировать.


Agent User Layer

Это слой, который работает непосредственно с пользовательским запросом и оформляет задачу в максимально человеческом виде.
Но решение он не пытается сделать сам — лишь задаёт направление.


Feedback Catch Layer

Это слой, который наблюдает за выводами агентов и ловит момент, когда система «встала».

Например, можно использовать простое хеширование ответов, чтобы обнаружить циклы:

import hashlib

def hash_text(text: str) -> str:
    return hashlib.sha256(text.encode()).hexdigest()

class FeedbackCatcher:
    def __init__(self, window=5):
        self.window = window
        self.history = []

    def check(self, output: str):
        h = hash_text(output)
        self.history.append(h)
        if len(self.history) > self.window:
            self.history.pop(0)

        if len(self.history) == self.window and len(set(self.history)) == 1:
            return "stuck"
        return "ok"

Использование:

fc = FeedbackCatcher()

for _ in range(10):
    out = agent.step()
    if fc.check(out) == "stuck":
        print("Цикл обнаружен → требуется модификация.")
        break

Agent Modify Layer

Когда мы понимаем, что система застряла, вступает в игру модификатор промтов.

Простой пример мутаций:

def modify_prompt(original_prompt: str, attempt: int) -> str:
    mutations = [
        "Сформулируй ответ иначе.",
        "Подумай альтернативным способом.",
        "Используй другой порядок шагов.",
        "Предложи неожиданный подход.",
        "Сфокусируйся только на ключевых факторах."
    ]
    mutation = mutations[attempt % len(mutations)]
    return f"{original_prompt}\n\n# Модификация: {mutation}"

Использование:

prompt = base_prompt
for attempt in range(5):
    output = llm(prompt)
    if "ошибка" not in output.lower():
        break
    prompt = modify_prompt(prompt, attempt)

LLM-классификатор «stuck / progress / redundant»

Более продвинутый сценарий — когда само хеширование недостаточно.

def classify_step(prev_output: str, new_output: str) -> str:
    prompt = f"""
Ты анализируешь шаги агента.

Предыдущий вывод:
{prev_output}

Новый вывод:
{new_output}

Классифицируй:
- progress: есть смысловые изменения
- redundant: выводы разные словами, смысл тот же
- stuck: однотипные ответы, движения нет

Ответь одним словом.
"""
    return meta_llm(prompt).strip().lower()

Использование:

prev = None
for _ in range(20):
    out = agent.run()
    if prev:
        status = classify_step(prev, out)
        if status == "stuck":
            print("Stuck → нужно вмешиваться")
            break
    prev = out

Мета-агент, модифицирующий цепочку агентов

Если промтовые хаки не помогают — надо менять саму последовательность шагов.

def modify_chain(chain_description: str) -> str:
    prompt = f"""
Ты — мета-агент. Текущая цепочка:

{chain_description}

Предложи улучшенную версию, чтобы избежать зацикливания.
Измени порядок шагов или добавь вспомогательные.
"""
    return meta_llm(prompt)

Эволюционный подход

Когда линейная коррекция не помогает, мы относимся к цепочке агентов как к популяции моделей.

Каждый прогон → новое поколение.
Метрика → фитнес.
Мутация → новый шанс избежать цикла.


Поколения агентов

def run_generation(prompt, generation_id):
    modified = f"{prompt}\n\n# Генерация {generation_id}: дай лучший вариант."
    return llm(modified)

Фитнес-функция

def fitness(output: str) -> float:
    tokens = output.split()
    diversity = len(set(tokens)) / (len(tokens) + 1)
    return len(output) * diversity

Основной цикл

best_output = None
best_score = -1

for gen in range(5):
    out = run_generation(base_prompt, gen)
    score = fitness(out)

    print(f"Gen {gen}: score={score}")

    if score > best_score:
        best_output = out
        best_score = score

print("Лучший результат:", best_output)

Mutation: внедрение хаоса в промт

import random

def mutate_prompt(prompt: str) -> str:
    mutations = [
        "Представь, что ты эксперт-ревизор.",
        "Смени формат на структурированный.",
        "Введи альтернативную гипотезу.",
        "Добавь контрпример.",
        "Используй другой стиль рассуждений."
    ]
    return prompt + "\n\n" + random.choice(mutations)

Объединённый пример: мини-оркестратор

class ChainManager:
    def __init__(self, base_prompt):
        self.prompt = base_prompt
        self.fc = FeedbackCatcher()

    def step(self):
        output = llm(self.prompt)
        status = self.fc.check(output)

        if status == "stuck":
            self.prompt = mutate_prompt(self.prompt)
            print("→ Застревание. Промт мутирован.")
            return self.step()

        return output

manager = ChainManager("Ты — агент анализа данных. Реши задачу.")
result = manager.step()
print(result)

Итог

Пока LLM остаются статистическими машинами без внутренней модели мира, любые цепочки с повторяемым контекстом рано или поздно зациклятся.
Проблема не в «тупости» конкретной модели, а в том, что без динамики и адаптивности мы даём системе только один узкий коридор.

Чтобы построить устойчивые многошаговые графы агентов, нужны:

  • динамические промты;

  • адаптивные конфигурации;

  • слой отслеживания тупиков;

  • слой модификации цепочек;

  • эволюционный подход для восстановления прогресса.

Без этого агенты будут бесконечно проверять пустые миски — долго, уверенно и методично.

Больше по теме в канале AIGENTTO.

Комментарии (0)