Как вы проектируете «планировщика» (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 с планировщиком:
- Пользовательский запрос → поступает в планировщик.
- Планировщик (LLM с системным промптом) генерирует план.
- План передаётся в executor.
- Executor выполняет шаги последовательно (или параллельно, если шаги независимы).
- Результаты шагов собираются и передаются в генератор ответа (часто тот же LLM, но с другим промптом).
- Финальный ответ возвращается пользователю.
Запрос → [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."
План (упрощённо):
- search("latest AI trends 2025") → результаты A
- search("AI impact on job market 2025") → результаты B
- if A is empty → search("AI trends 2026") → обновить A
- extract(key_trends from A) → список трендов
- extract(job_impacts from B) → список влияний
- transform(input=[step_4, step_5], operation="compare_and_summarize") → итоговое сравнение
- answer(context=step_6) → финальный ответ
Планировщик должен понимать семантику запроса и разбить его на подзадачи. Для этого в промпт включают примеры (few-shot) или используют fine-tuned модель.
8. Интеграция с executor'ом: как план выполняется
Executor — это программа, которая:
- Получает план.
- Строит граф зависимостей (DAG).
- Выполняет шаги в порядке топологической сортировки.
- Для каждого шага вызывает соответствующий инструмент.
- Сохраняет результаты в контексте (например, словарь
step_id -> result). - Передаёт собранные результаты генератору.
Пример 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.
Шаги:
- Написать системный промпт для планировщика с описанием инструментов:
search(query),merge(contexts),answer(context). - Реализовать функцию
planner(user_query)→ возвращает JSON-план. - Реализовать executor, который выполняет шаги (для search использует эмуляцию или реальную векторную БД).
- Протестировать на нескольких запросах.
- Добавить 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? |
Навигация
- Предыдущий: 141
- Следующий: 143
- Индекс: 00. Индекс разборов