Планирование: разбиение цели на подзадачи

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

Планирование (planning) — приём, при котором агент сначала строит список подзадач для достижения цели, а затем выполняет их по порядку, отмечая прогресс.

Зачем планировать

Реактивный ReAct-агент решает «по шагу за раз», глядя только на последнее наблюдение. Для коротких задач этого хватает. Но для длинной цели («подготовь отчёт») полезно сначала составить план — иначе агент легко забудет часть работы или начнёт метаться. План задаёт структуру: что сделать и в каком порядке.

Два режима

  • План заранее (plan-and-execute) — сначала весь список подзадач, потом исполнение. Предсказуемо, видно целиком.
  • План по ходу (ReAct) — следующий шаг выбирается реактивно. Гибко, но легче сбиться на длинной дистанции.

На практике их часто сочетают: общий план + реактивное выполнение каждой подзадачи.

Запускаемый планировщик

Сделаем планировщик-заглушку (разбивает цель на подзадачи) и исполнитель, который идёт по плану и отмечает выполненное.

def plan(goal):
    # детерминированный планировщик: цель -> список подзадач
    catalog = {
        "опубликовать статью": [
            "собрать материал",
            "написать черновик",
            "отредактировать текст",
            "опубликовать",
        ],
    }
    # для неизвестной цели — универсальный шаблон
    return catalog.get(goal.lower(), ["проанализировать", "выполнить", "проверить"])

def execute(subtasks):
    done = []
    for i, task in enumerate(subtasks, 1):
        # здесь настоящий агент решал бы подзадачу (например, циклом ReAct)
        print(f"  {i}. выполняю: {task}")
        done.append(task)
    return done

goal = "Опубликовать статью"
subtasks = plan(goal)
print(f"Цель: {goal}")
print(f"План из {len(subtasks)} подзадач:")
done = execute(subtasks)
print("Готово:", len(done) == len(subtasks))

Вывод:

Цель: Опубликовать статью
План из 4 подзадач:
  1. выполняю: собрать материал
  2. выполняю: написать черновик
  3. выполняю: отредактировать текст
  4. выполняю: опубликовать
Готово: True

В настоящем агенте plan — это вызов LLM с промптом «разбей цель на шаги», а каждая подзадача внутри execute может решаться собственным циклом ReAct с инструментами. Структура же — «спланировать, потом исполнить по списку» — остаётся.

Зависимости между подзадачами

Иногда подзадачи нельзя делать в любом порядке: «опубликовать» обязано идти после «написать». Тогда план — это не просто список, а порядок с зависимостями. Простой случай — выполнять строго по очереди; сложный — граф задач (DAG), где видно, что от чего зависит.

tasks = {
    "написать": [],                 # ни от чего не зависит
    "проверить": ["написать"],      # после «написать»
    "опубликовать": ["проверить"],  # после «проверить»
}

done = []
def ready(task):
    # подзадача готова к запуску, если все её зависимости выполнены
    return all(dep in done for dep in tasks[task])

# простейший проход: повторяем, пока не выполним всё
while len(done) < len(tasks):
    for task in tasks:
        if task not in done and ready(task):
            done.append(task)
            print("выполнено:", task)
print("Порядок:", done)

Вывод:

выполнено: написать
выполнено: проверить
выполнено: опубликовать
Порядок: ['написать', 'проверить', 'опубликовать']

Итог

  • Планирование разбивает большую цель на подзадачи и задаёт порядок их выполнения.
  • Plan-and-execute предсказуем, чистый ReAct гибок; на практике их сочетают.
  • Подзадачи бывают зависимыми — тогда порядок определяется зависимостями (вплоть до графа задач).
Проверьте себя
1. Зачем агенту планировать, а не просто реагировать по шагу за раз?
AПланирование всегда дешевле
BДля длинной цели план задаёт структуру, чтобы агент не забыл часть работы и не метался
CБез плана нельзя вызывать инструменты
DПлан убирает необходимость в модели
2. Чем подход plan-and-execute отличается от чистого ReAct?
AОн не использует инструменты
BСначала строится полный список подзадач, потом он исполняется — это предсказуемее реактивного выбора шагов
CОн работает без модели
DОн не требует памяти
3. Что определяет порядок выполнения, если подзадачи зависят друг от друга?
AАлфавитный порядок названий
BЗависимости: подзадачу можно начать, только когда выполнены те, от которых она зависит
CСлучайный выбор
DДлина названия подзадачи
Поддержать проект