AI-агент на LangGraph: токены, зацикливание и роли — уроки провала | AiManual
AiManual Logo Ai / Manual.
02 Июн 2026 Гайд

Как построить AI-агента: уроки из провала — токены, зацикливание и мультиагентные роли

Разбор трёх фатальных проблем AI-агентов: бесконечные циклы, неконтролируемый расход токенов и почему один агент плох. Решения на LangGraph с мультиагентными ро

Сцена первая: агент-зомби

Год назад я запустил своего первого ReAct-агента. Через 20 минут после деплоя он начал ходить по кругу: вызывал один и тот же инструмент, получал одинаковый ответ и снова его вызывал. Бесконечный цикл, который сожрал $200 на API. Агент превратился в зомби — бессмертный, дорогой и бессмысленный.

Проблема зацикливания — классика жанра. LLM не знает, когда остановиться. Он думает: «Надо ещё раз поискать, вдруг найдётся». И ищет. Ещё раз. Ещё. Пока вы не прервёте процесс принудительно. В простом ReAct-цикле, который описывали в предыдущей статье, нет контроля за повторением действий.

Не советую так делать: полагаться на то, что модель сама решит закончить. Она этого не сделает. Всегда ставьте жёсткий лимит шагов — max_iterations=10 — и детектор повторяющихся паттернов.

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

LangGraph вывозит именно здесь. Вы строите не цикл, а граф, где каждое действие — узел, а переходы контролируются условиями. Добавляем узел-детектор, который смотрит историю: если последние N шагов одинаковые — переходим в специальный узел Fallback, который генерирует итоговый ответ.

from langgraph.constants import START, END
from langgraph.graph import StateGraph

# Определяем граф с состоянием
class AgentState(TypedDict):
    messages: list
    step_count: int
    last_action: str

builder = StateGraph(AgentState)

builder.add_node("action", execute_action)
builder.add_node("detect_loop", loop_detector)
builder.add_node("fallback", generate_fallback)

builder.set_entry_point("action")

# Условие: после action проверяем на зацикливание
builder.add_conditional_edges(
    "action",
    check_loop,  # функция, возвращающая "detect_loop" или "fallback"
    {
        "continue": "detect_loop",
        "loop_detected": "fallback"
    }
)
builder.add_edge("detect_loop", END)  # если цикл не найден — заканчиваем

app = builder.compile()

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

Сцена вторая: токен-апокалипсис

Вторая ловушка — стоимость. Каждый шаг агента — это полный контекст: история диалога, промпт, предыдущие действия. Если сессия длится 500 шагов (ага, зомби-агент), вы платите за 500 раз по 10 000 токенов. $50 за один диалог. Бизнес-юнит рад.

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

Семантический поиск вместо полного контекста

Вместо того, чтобы тащить всю историю в промпт, сохраняйте ключевые моменты в векторной базе (ChromaDB, Qdrant). При каждом шаге агент формирует векторный запрос к своей же истории — и получает только 3-5 релевантных сообщений. Это радикально режет контекст.

💡
Мы уже применяли гибридный поиск в Advanced RAG (см. статью про production-ready агента). Тот же подход работает для контекстной памяти агента. Эмбеддинги + BM25. Только теперь источник — не база знаний, а собственный лог диалога.
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma

# Сохраняем каждое сообщение с эмбеддингом
vectorstore = Chroma(
    collection_name="agent_memory",
    embedding_function=OpenAIEmbeddings()
)

# При новом шаге: ищем похожие шаги
relevant_history = vectorstore.similarity_search(
    current_query, k=5
)
context = "\n".join([doc.page_content for doc in relevant_history])

Грабли: не экономьте на эмбеддингах. Бесплатный text-embedding-ada-002 (или его более свежая версия на июнь 2026) справляется, но если диалог технический — лучше перейти на модель, обученную на коде или технической документации. И не забывайте чистить устаревшие векторы — иначе агент будет отвечать цитатами из прошлого года.

Сцена третья: мультиагентный театр

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

Вспомните принцип из менеджмента: AI-агенты как сотрудники. Вы же не нанимаете одного человека, который будет и разработчиком, и тестировщиком, и продакт-менеджером. Так и с агентами. Разделите роли.

Я использую три роли: Новичок (собирает данные, не анализирует), Исследователь (строит гипотезы, ищет связи), Эксперт (принимает решение, пишет финальный ответ). Это мультиагентная система, где каждый суб-агент — маленький, специализированный, дёшевый в использовании.

Подробнее про суб-агентов читайте в отдельной статье «Как правильно использовать суб-агентов». Там три сценария с кодом.

Оркестрация через LangGraph: планировщик и синтезатор

Каждая роль — узел графа. Планировщик (узел-координатор) получает запрос, разбивает его на подзадачи, отправляет каждой роли. Синтезатор (другой узел) собирает ответы.

from langgraph.graph import StateGraph

class TeamState(TypedDict):
    query: str
    novice_result: str | None
    researcher_result: str | None
    expert_result: str | None
    final_answer: str | None

builder = StateGraph(TeamState)

builder.add_node("planner", route_to_roles)
builder.add_node("novice", NoviceAgent().process)
builder.add_node("researcher", ResearcherAgent().process)
builder.add_node("expert", ExpertAgent().process)
builder.add_node("synthesizer", synthesize)

builder.set_entry_point("planner")

# Параллельные роли
builder.add_edge("planner", "novice")
builder.add_edge("planner", "researcher")
builder.add_edge("planner", "expert")

# Синтезатор запускается после всех ролей (используем fan-in)
builder.add_edge(["novice", "researcher", "expert"], "synthesizer")
builder.add_edge("synthesizer", END)

app = builder.compile()

Ошибка, которую я делал: я давал ролям слишком общие промпты. Эксперт начинал играть роль новичка. Пропишите жёсткие границы: «Ты не имеешь права давать окончательный ответ, твоя задача только собрать данные». И наоборот: «Эксперт, ты обязан опираться только на факты, которые предоставили Новичок и Исследователь».

Нюансы и грабли: что я понял через боль

  • Жёсткие ограничения убивают гибкость. Слишком строгий детектор зацикливания — агент не может выполнить многошаговую задачу. Оптимально: 15 шагов, после 10 — предупреждение в промпт «тебе осталось 5 шагов, завершай».
  • Семантический поиск не панацея. Если контекст резко меняется (например, пользователь переключился с кода на дизайн), векторы из прошлого будут шуметь. Добавьте фильтр по времени: последние 10 сообщений всегда включать в контекст.
  • Роли без проверки качества. Новичок мог найти неправильную информацию, а Эксперт на неё опирается. Добавьте узел-верификатор, который перекрёстно проверяет данные. Это экономит токены, потому что дешёвая модель-верификатор отсеивает мусор до того, как дорогой Эксперт начнёт думать.

Финальный совет: не делайте агента, если не продумали failsafe

Мой первый продакшен-агент сломался, когда пользователь написал ему «привет» 37 раз подряд. Агент пытался ответить на каждое «привет», проваливался в цикл, сжигал квоту. Теперь я ставлю глобальный тайм-аут: если сессия длится больше N секунд — принудительный ответ с извинениями и предложением переформулировать.

И ещё — не забывайте про бюджет токенов. После каждой сессии логируйте затраты. Если средний диалог стоит больше $0.50 — оптимизируйте. Для глубокого понимания работы с LLM и создания качественного AI-контента рекомендую курс AI-креатор: создаём контент с помощью нейросетей от Skillbox. Там учат не только писать промпты, но и проектировать надёжные пайплайны.

Строить AI-агента — это инженерная дисциплина, а не магия. Зацикливание, токен-апокалипсис и путаница ролей — это не баги, это особенности, которые вы обязаны предусмотреть архитектурно. Начните с графа, добавьте семантическое сжатие и разделите обязанности — и ваш агент проживёт достаточно долго, чтобы принести пользу.

Подписаться на канал