Как вы проектируете «планировщика» (planner) для Agentic RAG?

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

Планировщик (planner) в RAG|Agentic RAG — это отдельный LLM-вызов, который разбивает сложный запрос пользователя на последовательность шагов (инструментов) с условиями и зависимостями. Он критичен для многошаговых рассуждений, адаптивного поиска и выполнения действий, когда одного запроса к векторной базе недостаточно. Планировщик генерирует структурированный план (например, JSON), который затем исполняется executor'ом. Качество плана напрямую влияет на точность и полноту финального ответа.


1. Термин: Планировщик (Planner) в Agentic RAG

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

Agentic RAG — это расширение классического RAG, где агент (LLM) может не только искать документы, но и вызывать внешние инструменты, принимать решения о повторном поиске, уточнять запрос и т.д. Планировщик — «мозг» такого агента.

Executor — компонент, который выполняет шаги плана, вызывает инструменты и возвращает результаты обратно в планировщик или непосредственно в генератор ответа.


2. Зачем нужен отдельный планировщик, а не просто chain-of-thought?

В простых RAG-системах LLM делает один запрос к базе и генерирует ответ. Но для сложных вопросов (сравнение, анализ, многошаговый сбор информации) требуется:

  • Многошаговость: сначала найти общие тренды, потом детали по каждому.
  • Условная логика: если первый поиск не дал результатов, изменить запрос.
  • Параллельные действия: одновременно искать в разных источниках.
  • Зависимости: результат одного шага используется как аргумент для другого.

Chain-of-thought (CoT) — это техника, где LLM рассуждает вслух, но не гарантирует структурированного выполнения шагов. Планировщик же выдаёт формальный план, который можно проверить, логировать и повторно использовать.

АспектChain-of-ThoughtПланировщик
Формат выводаСвободный текстСтруктурированный (JSON, список)
ИсполнениеВнутри одного LLM-вызоваОтдельные вызовы инструментов
КонтрольНет внешнего контроляExecutor проверяет каждый шаг
Повторное использованиеНетПлан можно сохранить и адаптировать
НадёжностьЗависит от одного вызоваКаждый шаг можно перезапустить

3. Архитектура: отдельный LLM-вызов перед execution

Типичная архитектура Agentic RAG с планировщиком:

  1. Пользовательский запрос → поступает в планировщик.
  2. Планировщик (LLM с системным промптом) генерирует план.
  3. План передаётся в executor.
  4. Executor выполняет шаги последовательно (или параллельно, если шаги независимы).
  5. Результаты шагов собираются и передаются в генератор ответа (часто тот же LLM, но с другим промптом).
  6. Финальный ответ возвращается пользователю.
Запрос → [Planner LLM] → План (JSON) → [Executor] → Результаты → [Generator LLM] → Ответ

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


4. Формат плана: структурированный вывод

План должен быть машиночитаемым. Чаще всего используется JSON:

{
  "plan": [
    {
      "step_id": 1,
      "tool": "search",
      "params": {"query": "latest AI trends 2025"},
      "depends_on": []
    },
    {
      "step_id": 2,
      "tool": "search",
      "params": {"query": "AI impact on job market 2025"},
      "depends_on": []
    },
    {
      "step_id": 3,
      "tool": "if_else",
      "params": {
        "condition": "step_1.results is empty",
        "if_branch": [
          {"step_id": 4, "tool": "search", "params": {"query": "AI trends 2026"}, "depends_on": []}
        ],
        "else_branch": []
      },
      "depends_on": [1]
    },
    {
      "step_id": 5,
      "tool": "summarize",
      "params": {"sources": ["step_1", "step_2"]},
      "depends_on": [1, 2]
    }
  ]
}

Ключевые поля

  • step_id — уникальный идентификатор.
  • tool — имя инструмента (search, extract, calculate, answer, if_else, loop).
  • params — параметры для инструмента.
  • depends_on — список step_id, от которых зависит выполнение (обеспечивает порядок).

Термин «Инструмент» (tool) — внешняя функция, которую может вызвать executor: поиск в векторной БД, вызов API, выполнение кода, чтение файла.


5. Типы шагов (инструментов)

Тип шагаОписаниеПример параметров
searchПоиск в векторной БД или вебе{"query": "...", "top_k": 5}
extractИзвлечение конкретной информации из документа{"source": "step_1", "field": "date"}
transformПреобразование данных (суммирование, перевод){"input": "step_2", "operation": "summarize"}
if_elseУсловное ветвление{"condition": "step_1.results is empty", "if_branch": [...], "else_branch": [...]}
loopЦикл по элементам{"over": "step_1.results", "steps": [...]}
answerФинальная генерация ответа{"context": ["step_1", "step_3"]}

Планировщик должен уметь генерировать все эти типы. Для этого в системный промпт включают описание доступных инструментов и их параметров.


6. Обработка ошибок и fallback-стратегии

План может не выполниться идеально. Необходимо предусмотреть:

  • Пустые результаты поиска: планировщик может добавить шаг с альтернативным запросом (как в примере выше).
  • Таймауты: если шаг выполняется слишком долго, executor может пропустить его или повторить.
  • Ошибки инструмента: если API вернул ошибку, планировщик может сгенерировать новый шаг с другим инструментом.
  • Максимальное количество шагов: ограничить план, чтобы избежать бесконечных циклов (например, не более 10 шагов).

Пример fallback в плане

{
  "step_id": 2,
  "tool": "search",
  "params": {"query": "AI trends 2025"},
  "fallback": {
    "tool": "search",
    "params": {"query": "artificial intelligence trends 2025"}
  }
}

7. Пример: планировщик для запроса "Сравнить последние тренды AI и их влияние на рынок труда"

Вход "Compare the latest AI trends and their impact on the job market."

План (упрощённо):

  1. search("latest AI trends 2025") → результаты A
  2. search("AI impact on job market 2025") → результаты B
  3. if A is empty → search("AI trends 2026") → обновить A
  4. extract(key_trends from A) → список трендов
  5. extract(job_impacts from B) → список влияний
  6. transform(input=[step_4, step_5], operation="compare_and_summarize") → итоговое сравнение
  7. answer(context=step_6) → финальный ответ

Планировщик должен понимать семантику запроса и разбить его на подзадачи. Для этого в промпт включают примеры (few-shot) или используют fine-tuned модель.


8. Интеграция с executor'ом: как план выполняется

Executor — это программа, которая:

  1. Получает план.
  2. Строит граф зависимостей (DAG).
  3. Выполняет шаги в порядке топологической сортировки.
  4. Для каждого шага вызывает соответствующий инструмент.
  5. Сохраняет результаты в контексте (например, словарь step_id -> result).
  6. Передаёт собранные результаты генератору.

Пример executor на Python (упрощённо):

def execute_plan(plan, tools):
    results = {}
    for step in plan["plan"]:
        # проверить, что все зависимости выполнены
        if all(dep in results for dep in step["depends_on"]):
            tool_func = tools[step["tool"]]
            result = tool_func(**step["params"])
            results[step["step_id"]] = result
        else:
            raise Exception(f"Missing dependencies for step {step['step_id']}")
    return results

Executor также может обрабатывать параллельные шаги (если depends_on пуст или уже выполнен), используя asyncio или многопоточность.


9. Оценка качества планировщика

Метрики для оценки планировщика:

МетрикаОписаниеКак измерить
Plan AccuracyДоля планов, которые приводят к правильному ответуСравнить финальный ответ с эталонным
Step Success RateДоля шагов, выполненных без ошибокЛоги executor'а
Plan CompletenessПлан покрывает все необходимые подзадачи?Экспертная оценка или LLM-as-judge
Plan EfficiencyКоличество шагов / время выполненияСреднее число шагов на запрос
Fallback UsageКак часто срабатывают fallback-шагиЛоги

Для автоматической оценки можно использовать LLM-as-judge: дать плану и результату другому LLM и попросить оценить, насколько план адекватен.


10. Компромиссы: latency vs качество, стоимость вызовов

  • Один вызов планировщика добавляет latency (обычно 1–3 секунды). Для простых запросов это избыточно.
  • Стоимость: каждый шаг плана может требовать отдельного LLM-вызова (если инструмент — это LLM). Это увеличивает затраты.
  • Решение: использовать планировщик только для сложных запросов (классификатор «простой/сложный» перед планировщиком). Для простых — сразу идти в генератор.

Гибридный подход

  • Если запрос короткий и не требует многошаговости → обычный RAG.
  • Если запрос содержит слова «сравни», «проанализируй», «найди и обобщи» → включается планировщик.

11. Вариации: ReAct, Plan-and-Solve, Tree-of-Thoughts

  • ReAct (Reasoning + Acting): агент чередует рассуждение и действие, но план не выделен явно — каждый шаг генерируется на лету.
  • Plan-and-Solve: сначала генерируется полный план, потом он выполняется (как описано выше). Более надёжно, но менее гибко.
  • Tree-of-Thoughts (ToT): планировщик генерирует несколько вариантов плана, executor пробует их параллельно, выбирается лучший. Дорого, но качественно.

На практике для Agentic RAG чаще используют Plan-and-Solve как компромисс между стоимостью и качеством.


12. Инструменты и фреймворки

  • LangChain: имеет встроенный PlanAndExecute агент, где планировщик — это LLMChain, а executor — AgentExecutor.
  • AutoGPT: использует планировщик на основе GPT-4, но менее структурирован.
  • Microsoft TaskWeaver: фреймворк с явным планировщиком, поддерживает вложенные планы.
  • CrewAI: для multi-agent систем, где каждый агент может иметь свой планировщик.

Пример на LangChain:

from langchain.agents import PlanAndExecuteAgent, AgentExecutor
from langchain.llms import OpenAI

llm = OpenAI(temperature=0)
agent = PlanAndExecuteAgent.from_llm_and_tools(llm, tools)
executor = AgentExecutor.from_agent_and_tools(agent, tools)
executor.run("Compare AI trends and job market impact")

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

Задача Реализовать минимального планировщика для Agentic RAG, который для запроса "Какие новые технологии в NLP появились в 2025 году?" строит план: поиск по двум разным запросам, объединение результатов и генерация ответа.

Инструменты Python, OpenAI API (или любой LLM), простой executor на asyncio.

Шаги:

  1. Написать системный промпт для планировщика с описанием инструментов: search(query), merge(contexts), answer(context).
  2. Реализовать функцию planner(user_query) → возвращает JSON-план.
  3. Реализовать executor, который выполняет шаги (для search использует эмуляцию или реальную векторную БД).
  4. Протестировать на нескольких запросах.
  5. Добавить fallback: если первый поиск пуст, изменить запрос.

Ожидаемый результат Рабочий скрипт, который для запроса "Какие новые технологии в NLP появились в 2025 году?" выводит план и финальный ответ, собранный из двух поисков.


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

ВопросТема
141Что такое Agentic RAG и чем отличается от классического RAG?
143Как вы проектируете executor для Agentic RAG?
144Как вы реализуете вызов инструментов (tool use) в Agentic RAG?
145Как вы управляете памятью (memory) в Agentic RAG?
146Как вы проектируете multi-agent системы для RAG?
147Как вы оцениваете качество Agentic RAG?

Навигация