Главная / Статьи

Проектирование устойчивых графов искусственных интеллект-агентов: повторные попытки, альтернативные решения и GraphRAG

Изучите, как создавать рабочие процессы искусственных интеллект-агентов, устойчивых к сбоям, с использованием явных веток обработки ошибок, логики повторных попыток, LangGraph, а также случаев, когда GraphRAG превосходит обычный RAG или циклы агентов.

14 мин чтения3231 слов

Когда возникают сбои: планирование альтернативных маршрутов

Продолжая тему предыдущего обсуждения, представьте, что к этому моменту инструмент финансового анализа стал значительно более совершенным.

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

Однако есть один аспект, который мы пока не рассмотрели: что происходит, если какой-либо шаг в этом процессе нарушается?

Представьте, что инструмент достигает раздела, отвечающего за рыночные данные.

Он отправляет запрос о колебаниях цен и объеме торгов, но поставщик данных не отвечает.

В такой ситуации невозможно сразу перейти к шагу Анализ, делая вид, что ничего не произошло.

В то же время полное прекращение всей операции обычно слишком крайнее решение, поскольку системы производственного уровня требуют наличия какой-либо альтернативной стратегии действий.

Именно поэтому сбой следует рассматривать как отдельную ветвь в графе, а не как второстепенный фактор.

Исходный, простой алгоритм выглядит так:

Search Market Data
        ↓
     Analyze

Мы можем преобразовать его в нечто подобное:

                  Search Market Data
                    /          \
                   ↓            ↓
               Success        Failure
                  ↓              ↓
               Analyze          Retry (how to handle this!?)

Благодаря такой структуре в графе четко определено, что делать при сбое запроса.

Управление логикой повторных попыток

Если повторная попытка увенчается успехом, рабочий процесс просто продолжается в обычном режиме.

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

Вот более подробная версия этого разветвления:

                  Search Market Data
                    /          \
                   ↓            ↓
               Success        Failure
                  ↓              ↓
               Analyze         Retry
                                  ↓
                           ┌──────┴──────┐
                           ↓             ↓
                        Success       Failure
                           ↓             ↓
                        Analyze    Alternative
                                      Source

Здесь важно не то, сколько попыток повторения вы разрешаете — а тот факт, что обработка ошибок заложена в дизайн графа с самого начала. Как показано на диаграмме, разные виды ошибок могут привести к разным путям решения.

Допустим, API с рыночными данными просто тайм-аутит. Повторные попытки разумны, поскольку проблема, скорее всего, временная.

Но предположим, запрос проходит успешно, но просто не возвращает ничего полезного за рассматриваемый период. Повторение того же запроса ничего не даст.

В таком случае лучше будет запросить данные у альтернативного, одобренного источника данных.

Если и в этом случае ничего не получится, вероятно, стоит передать ситуацию на рассмотрение человека-рецензента. Именно такие детали определяют разницу между нестабильным и надежным рабочим процессом.

Функция маршрутизации, отвечающая за это, может выглядеть так:

def route_after_market_search(state):
  if state["market_data"]:
          return "analyze"
      if state["retry_count"] < 2:
          return "retry"
      return "human_review"

Эти условия задают четкие границы для работы графа — повторные попытки допускаются, но не бесконечно.

Тот же принцип применяется ко всему остальному графу, поскольку по пути могут возникнуть многочисленные проблемы:

  • Шаг получения данных может сорваться
  • Запрос к LLM может не увенчаться успехом
  • Тот или иной источник данных может временно стать недоступным
  • Сгенерированный ответ может не пройти проверку на соответствие требованиям

Вместо того чтобы обернуть всё приложение в один огромный обработчик ошибок, можно на уровне каждого узла решать, что делать именно в тот момент, когда что-то ломается.

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

Вместо этого вы можете проследить точный путь выполнения и с уверенностью определить, где именно возникла ошибка:

Understand
    ↓
Search Filings ✓
    ↓
Search Earnings ✓
    ↓
Search Market Data ✗
    ↓
Retry ✓
    ↓
Analyze
    ↓
Write
    ↓
Check

Это даёт вам конкретный объект для анализа, а не просто «чёрную коробку».

Естественно, по мере расширения графа управление всем этим вручную начинает требовать значительных усилий — и это вполне обоснованная проблема.

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

Именно в таких ситуациях фреймворк помогает избежать необходимости заново создавать одни и те же механизмы оркестрации для каждого проекта.

Именно эту проблему предназначен решить LangGraph.

LangGraph

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

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

Вы можете сами реализовать всю оркестрацию, но это повлечёт за собой необходимость обслуживания большого объёма инфраструктуры, сопутствующей основной логике ИИ.

LangGraph разработан именно для обработки такого уровня.

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

Вернувшись к исследовательскому агенту NVIDIA, о котором шла речь ранее, его структуру можно изобразить примерно так:

                      Question
                         ↓
                    Understand
                         ↓
              ┌──────────┼──────────┐
              ↓          ↓          ↓
           Filings    Earnings    Market
              ↓          ↓          ↓
              └──────────┼──────────┘
                         ↓
                      Analyze
                         ↓
                       Write
                         ↓
                       Check
                    ↙    ↓    ↘
                Search  Rewrite  Human
                   ↓       ↓     Review
                   └───────┴───────┘
                           ↓
                          Send

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

Упрощенная реализация LangGraph для того же рабочего процесса может выглядеть так:

from langgraph.graph import StateGraph, END

builder = StateGraph(ResearchState)

builder.add_node("understand", understand)
builder.add_node("search_filings", search_filings)
builder.add_node("search_earnings", search_earnings)
builder.add_node("search_market", search_market)
builder.add_node("analyze", analyze)
builder.add_node("write", write)
builder.add_node("check", check)

builder.set_entry_point("understand")

builder.add_edge("understand", "search_filings")
builder.add_edge("understand", "search_earnings")
builder.add_edge("understand", "search_market")
builder.add_edge("analyze", "write")
builder.add_edge("write", "check")

Приведенный выше фрагмент преднамеренно минимален, чтобы вы могли сосредоточиться на основной концепции — связи узлов, ребер и понятий состояния, описанных ранее в этой серии.

  • Каждый узел обрабатывает одну единицу работы
  • Граф определяет, как эти единицы связаны друг с другом
  • Состояние — это то, что передает информацию от одного узла к другому

На самом деле всё сводится к этому. Эта концепция гораздо проще для понимания, чем попытка вместить всё в один огромный запрос к агенту.

Вы можете посмотреть на сам граф и понять, как должна выполняться рабочая процедура, ещё до того, как начнёте изучать реализацию каждого отдельного узла.

Допустим, вы хотите вставить этап человеческого утверждения перед отправкой окончательного ответа — вам придётся изменять структуру рабочей процедуры напрямую:

Check
  ↓
Human Review
  ↓
Send

Нет необходимости скрывать подобные решения где-то в запросе. Сама структура делает их очевидными и упрощает понимание для вашей команды.

Почему выбирать LangGraph вместо обычного цикла агента?

Традиционный цикл агента обычно имеет следующую структуру:

Think
  ↓
Choose Tool
  ↓
Use Tool
  ↓
Think Again
  ↓
Choose Tool
  ↓
...

В такой конфигурации у модели есть значительная свобода в выборе дальнейших действий. Такая гибкость действительно ценна, когда задача по своей природе является открытой.

Но рабочий процесс финансовых исследований, описанный здесь, включает несколько этапов принятия решений, которые, скорее всего, следует контролировать более строго. Именно в этом и заключается суть проблемы.

Не каждый рабочий процесс требует использования цикла агента.

Рассмотрим несколько примеров:

  • Возможно, системе потребуется собрать определенные доказательства перед тем, как ей разрешат дать ответ.
  • Возможно, вы захотите, чтобы рыночные данные и отчеты собирались независимо друг от друга.
  • Возможно, потребуется этап проверки перед тем, как что-либо будет передано человеку-рецензенту.
  • Возможно, вы захотите, чтобы процесс автоматически останавливался после определенного количества попыток.

Это не те варианты выбора, которые стоит оставлять на усмотрение модели при каждом запуске. Внутри цикла невозможно гарантировать, что модель будет делать один и тот же вызов каждый раз.

Граф позволяет непосредственно встроить эти ограничения в структуру рабочего процесса. Модель по-прежнему может осуществлять логические рассуждения внутри каждого отдельного узла, но окружающая система определяет, куда ей разрешено перейти дальше.

Вот ключевое отличие, которое следует запомнить. Цель не в том, чтобы устранить способность агента к логическим рассуждениям — она заключается в том, чтобы целенаправленно определить, где должны происходить эти рассуждения, а где более подходит детерминистское управление.

По мере разработки рабочих процессов, работающих с структурированными финансовыми данными, возникает новый вопрос.

В настоящее время наш агент извлекает документы и цифры из различных источников. Но что произойдет, когда базовая информация будет содержать важные связи между элементами?

  • Компании нанимают руководителей
  • Эти руководители часто входят в советы директоров компаний
  • Одна компания может приобрести другую
  • В регуляторной заявке может быть упомянута совершенно другая компания
  • Один портфель может включать множество компаний
  • Каждая компания принадлежит к какому-либо отраслевому сектору
  • До этого момента мы рассматривали каждый фрагмент данных как изолированный. Однако вышеупомянутые связи трудно представить, если ваша база знаний состоит лишь из набора отдельных документов.

    Это приводит нас к ещё одной ключевой концепции: GraphRAG.

    GraphRAG

    До сих пор мы использовали графы в основном для регулирования способа поведения агента. Но графы могут выполнять и вторую функцию:

    организация самих знаний.

    В нашем примере традиционная конфигурация RAG могла бы собирать документы, упоминающие доходы NVIDIA, прогнозы развития, показатели выручки, маржи и реакцию рынка.

    Такой подход хорошо работает, когда ответ находится в основном в нескольких соответствующих документах. Но финансовые вопросы не всегда ограничиваются такими рамками.

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

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

    Именно здесь и пригождается граф знаний.

    Вместо хранения знаний исключительно в виде фрагментов текста мы можем моделировать важные энтитеты и связи между ними:

    NVIDIA ──→ produces ──→ GPUs
       │
       ├──→ reports ──→ Earnings
       │
       ├──→ depends on ──→ Suppliers
       │
       ├──→ competes with ──→ AMD
       │
       └──→ operates in ──→ AI Infrastructure
    

    Теперь граф отражает связи, которые никогда не стали бы очевидны при чтении любого отдельного документа.

    RAG по сравнению с GraphRAG

    Стандартный RAG обычно работает путем извлечения релевантных фрагментов и передачи их в модель в качестве контекста. Вот упрощенное описание этого процесса:

    Question
       ↓
    Retrieve relevant chunks
       ↓
    LLM
       ↓
    Answer
    

    GraphRAG вводит дополнительный уровень обработки. Система может использовать связи между сущностями, чтобы определить, какая информация действительно важна:

    Question
       ↓
    Identify entities
       ↓
    Traverse relationships
       ↓
    Retrieve relevant information
       ↓
    LLM
       ↓
    Answer
    

    Для нашего агента для финансовых исследований это становится ценным, когда вопрос требует одновременного учета нескольких сущностей или документов.

    Предположим, менеджер портфеля задает вопрос: какие риски могут возникнуть для NVIDIA в случае снижения спроса на ИИ-инфраструктуру?

    Чтобы хорошо ответить на этот вопрос, возможно потребуется связать NVIDIA с ее продуктами, клиентами, поставщиками, конкурентами, общими рыночными условиями, а также с рисками, уже указанными в предыдущих отчетах.

    Граф предоставляет системе поиска структурированный путь для исследования всех этих связей.

                          NVIDIA
                        /   |   \
                       /    |    \
                  Products Suppliers Competitors
                     |         |         |
                     ↓         ↓         ↓
                 AI GPUs   Supply Risk    AMD
                     |
                     ↓
              AI Infrastructure
                     |
                     ↓
                   Demand
    

    На основе этого модель может анализировать всю информацию, полученную из связанных сущностей.

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

    Если ответ находится целиком в одном отчете о доходах, вероятно, достаточно традиционного механизма поиска.

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

    Здесь также важно различать два понятия: граф рабочего процесса и знаниевый граф — это совершенно разные вещи.

    Граф рабочего процесса отвечает на вопрос о том, что агент должен сделать дальше. Граф знаний отвечает на вопрос о том, что связано с чем в данных, над которыми вы работаете.

    В нашей системе оба этих элемента могут сосуществовать рядом:

    WORKFLOW GRAPH:
    
    Question
       ↓
    Retrieve
       ↓
    Analyze
       ↓
    Write
       ↓
    Check
    

    В то же время на более низком уровне слой поиска работает с:

    KNOWLEDGE GRAPH:
    NVIDIA
     ├── Products
     ├── Suppliers
     ├── Competitors
     ├── Executives
     ├── Filings
     └── Industry
    

    Обратите внимание на разделение обязанностей: одна структура управляет выполнением действий, в то время как другая организует знания и связи между ними.

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

    • Рабочий процесс определяет способ проведения исследования.
    • Граф знаний определяет какие элементы информации связаны между собой.

    Естественно, это вызывает дополнительный вопрос: если графы обеспечивают такой высокий уровень контроля, стоит ли строить каждый рабочий процесс в виде графа?

    Не обязательно.

    Во многих случаях для решения проблемы достаточно простой циклической структуры агента.

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

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

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

    Вернемся к примеру агента финансового исследования. Предположим, пользователь задает вопрос вроде: дай краткое резюме последнего отчета NVIDIA о финансовых результатах.

    Это узкое, самодостаточное требование.

    Его можно выполнить путем загрузки соответствующего отчета и передачи его модели для составления резюме:

    Question
       ↓
    Retrieve Report
       ↓
    Summarize
       ↓
    Answer
    

    Здесь нет сложной ветвления и не требуется управление запутанной логикой. Обычная схема RAG или простой цикл агента вполне справятся с этим.

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

    Это совершенно другой тип задачи.

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

    Теперь процесс работает ближе к следующему варианту:

                          Question
                             ↓
                        Understand
                             ↓
                  ┌──────────┼──────────┐
                  ↓          ↓          ↓
               Filings    Earnings    Market
                  ↓          ↓          ↓
                  └──────────┼──────────┘
                             ↓
                          Analyze
                             ↓
                           Write
                             ↓
                           Check
                        ↙    ↓    ↘
                    Search  Rewrite  Human
                       ↓       ↓     Review
                       └───────┴──────┘
                               ↓
                              Send
    

    На таком уровне сложности прямое описание процесса начинает приносить пользу.

    Так когда достаточно цикла агента?

    Цикл агента обычно является правильным решением, когда модели необходима определённая свобода в выборе инструмента для дальнейших действий.

    Например:

    Question
       ↓
    LLM decides what to do
       ↓
    Tool
       ↓
    LLM decides what to do next
       ↓
    Tool
       ↓
    Answer
    

    Когда задача носит исследовательский характер и невозможно заранее предсказать количество шагов, такая гибкость действительно ценна.

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

    Когда граф становится более понятным?

    Граф приносит пользу тогда, когда процесс работы имеет реально важные правила.

    Для системы финансовых исследований эти правила могут выглядеть так:

    Retrieve evidence
          ↓
    Run analysis
          ↓
    Generate draft
          ↓
    Verify claims
          ↓
    Human review
          ↓
    Publish
    

    Это ограничения на уровне процесса работы, и граф позволяет задать их напрямую, вместо того чтобы рассчитывать на то, что модель сама их выведет.

    Компромисс

    Граф даёт вам контроль, но это также означает необходимость управления более сложной архитектурой.

    Теперь вам придётся тщательно продумать:

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

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

    Вместо этого дополнительная структура должна вводиться только тогда, когда это действительно требуется рабочим процессом:

    • Начните с простого.
    • Добавляйте разветвления тогда, когда они действительно необходимы.
    • Добавляйте параллельную обработку тогда, когда задачи могут действительно выполняться независимо друг от друга.
    • Добавляйте точки контроля тогда, когда рабочему процессу нужно приостановиться или восстановиться после сбоя.
    • Добавляйте этап человеческого рассмотрения тогда, когда степень риска оправдывает дополнительные сложности.
    • Внедряйте GraphRAG тогда, когда отношения внутри самых знаний начинают играть важную роль.

    Таким образом, граф существует потому, что это требуется задачей, а не потому, что он доступен.

    Заключительные мысли

    Вероятно, это главный урок, полученный в процессе разработки этого дизайна.

    Граф существует не для того, чтобы сделать систему ИИ более сложной, а для того, чтобы упростить понимание и контроль рабочего процесса.

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

    Тем не менее всё это не означает, что каждой системе нужен граф. Иногда достаточно простой конвейера RAG, а иногда цикл агента покрывает всё, что требуется задачей.

    Настоящий навык заключается в умении определить то момент, когда проблема становится настолько сложной, что использование графа оправдывает вложения.