LangGraph упёрся в GraphRecursionError: найдите условие выхода из цикла

Агент несколько раз ищет документы, уточняет ответ и должен закончить, когда доказательств достаточно. Вместо ответа приложение получает GraphRecursionError или код GRAPH_RECURSION_LIMIT. Первое желание — поднять recursion_limit. Но если условный переход продолжает возвращать тот же узел, большее значение только продлит цикл и увеличит число вызовов модели и инструментов. Сначала надо увидеть, какое поле состояния должно было остановить граф и почему оно не изменилось.

Где искать петлю

Нарисуйте путь последнего запуска: имя узла, значения полей, по которым ветвится граф, и выбранный следующий узел. Например, search → evaluate → search повторяется, потому что needs_retry остаётся истинным после успешного поиска. Узел мог обновить другое поле, а функция в add_conditional_edges всё ещё читает старый флаг. Или узел вернул новое значение, но reducer слил его со старым так, что флаг остался прежним. Ошибка лимита говорит о количестве шагов, а причина обычно в логике состояния и переходов.

Начните с пары контрольных входов. Для первого ответ находится после одной попытки; для второго поиск действительно должен повториться дважды, а затем закончиться. В журнале фиксируйте номер попытки, оценку достаточности контекста и выбранную ветку. Не пишите только «итерация 17»: по этому числу нельзя понять, почему произошёл переход. Для LLM-решения о достаточности полезно сохранять структурированный результат с причиной и проверять, соответствует ли он найденным фрагментам.

Минимальный граф с явным выходом

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

from typing import TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    tries: int

def attempt(state: State) -> dict:
    return {"tries": state["tries"] + 1}

def next_step(state: State):
    return END if state["tries"] >= 3 else "attempt"

builder = StateGraph(State)
builder.add_node("attempt", attempt)
builder.add_edge(START, "attempt")
builder.add_conditional_edges("attempt", next_step)
graph = builder.compile()

result = graph.invoke({"tries": 0})
print(result["tries"])

Ожидаемый вывод — 3: каждый проход увеличивает tries, а функция маршрутизации читает уже обновлённое состояние. Если условие заменить на return "attempt" без выхода, граф будет повторяться до защитного лимита. Если ограничить recursion_limit ниже числа шагов, корректный, но длинный граф тоже остановится. Поэтому после проверки веток сравнивайте нормальную длину вашего процесса с установленным лимитом.

Когда лимит действительно надо менять

У некоторых процессов много законных шагов: например, обработка двадцати независимых документов по одному. Тогда задайте более высокий recursion_limit в конфигурации вызова, как предусмотрено LangGraph, и отдельно контролируйте бизнес-лимит работы: число документов, вызовов модели и общую стоимость. recursion_limit ограничивает шаги графа, а не токены и не деньги. Поднимать его следует после того, как на тестовом наборе видно конечный маршрут и предельное ожидаемое число шагов.

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

В платном курсе AI Agents PRO: LangGraph, AutoGen и LLMOps в продакшне вы проектируете граф состояний агента, подключаете инструменты и добавляете трассировку и метрики. По трассе можно увидеть, какое решение привело к повтору, а тесты переходов не дадут незаметно вернуть бесконечную петлю. Откройте программу курса, чтобы довести такой граф до сервиса с контролируемыми шагами.

Продолжить на практике

  • AI Agents PRO: LangGraph, AutoGen и LLMOps в продакшне ↗

    Практический курс по AI-агентам. Соберёте продакшн RAG-сервис: от индекса и графа состояний до API, Docker, метрик качества и контроля стоимости. Плюс профессиональные блоки: LangGraph/AutoGen, Qdrant/FAISS+rerank, eval (RAGAS/custom), quality-гейты, OpenTelemetry+Prometheus/Grafana, CI/CD, ретраи/DLQ/идемпотентность, PII/RBAC.