Разработка ИИ-агентов · Модуль 3 · Урок 3.2
Декомпозиция задач: prompt chaining vs динамическая
Разбить большую задачу на шаги
Сложную задачу почти всегда выгодно разложить на части: каждая меньше, проще для модели и легче проверяется. Вопрос в том, кто и когда определяет эти части. Здесь два полюса: статическая декомпозиция (prompt chaining) и динамическая.
Prompt chaining: фиксированная цепочка
Prompt chaining — разработчик заранее задаёт последовательность шагов, и выход одного становится входом следующего. Например: «составить план → написать по плану → отредактировать». Маршрут зашит в коде; модель выполняет каждый шаг, но не выбирает их порядок.
Сильные стороны: предсказуемость, простая отладка, дешевизна. Между шагами удобно ставить программные gate'ы — проверки, которые решают, идти дальше, повторить шаг или прерваться (например, «если план пустой — переспросить»). Это повышает надёжность: ошибка ловится рано, а не в финале. Берите prompt chaining, когда задачу можно разбить на устойчивые шаги заранее — это большинство практических случаев.
Динамическая декомпозиция: план на лету
Когда состав и число подзадач заранее неизвестны, шаги планирует сама модель во время выполнения. Агент-координатор смотрит на задачу, придумывает подзадачи, раздаёт их (себе же на следующих оборотах или субагентам) и адаптируется по ходу. Это нужно для открытых задач: исследование, отладка, работа с непредсказуемым вводом.
Платой за гибкость становятся непредсказуемость, выше стоимость и риск зацикливания — поэтому здесь особенно важны safety-cap, проверки прогресса и грунтинг. Правило выбора: если можете разложить задачу на шаги заранее — делайте prompt chaining (он надёжнее). Динамику включайте, только когда статикой не обойтись. Гибридный вариант тоже частый: фиксированный каркас с одним динамическим шагом внутри.
// Шаг цепочки: преобразует вход в выход.
type Step func(in string) (string, error)
// chain прогоняет вход через шаги по очереди; gate проверяет промежуточный
// результат и может остановить цепочку (вернув ошибку).
func chain(in string, gate func(stepName, out string) error, steps ...struct {
name string
fn Step
}) (string, error) {
cur := in
for _, s := range steps {
out, err := s.fn(cur)
if err != nil {
return "", fmt.Errorf("шаг %s: %w", s.name, err)
}
if gate != nil {
if err := gate(s.name, out); err != nil { // программный gate
return "", fmt.Errorf("gate после %s: %w", s.name, err)
}
}
cur = out // выход шага — вход следующего
}
return cur, nil
}Anti-patterns
| Анти-паттерн | Почему плохо | Как правильно |
|---|---|---|
| Динамический план там, где хватит цепочки | Лишняя непредсказуемость и стоимость | Если шаги известны заранее — prompt chaining |
| Цепочка без проверок между шагами | Ошибка раннего шага тихо тащится в финал | Программные gate'ы между шагами: проверить/повторить/прервать |
| Слишком мелкая декомпозиция | Много лишних вызовов, накладные расходы | Дробить до проверяемых, но осмысленных шагов |
| Динамика без safety-cap и проверки прогресса | Зацикливание, расход токенов | Лимит шагов + контроль, что есть продвижение к цели |
Практическое задание
- Возьмите задачу и разложите её на 2–4 фиксированных шага (prompt chaining).
- Реализуйте цепочку, где выход шага становится входом следующего.
- Вставьте между шагами хотя бы один программный gate (например, проверку непустого/валидного промежуточного результата).
- Придумайте задачу, которую заранее НЕ разложить, и опишите, как её решал бы динамический координатор.
- Сформулируйте для своей задачи правило: когда хватает цепочки, а когда нужна динамика.
Проверка знаний
Чем prompt chaining отличается от динамической декомпозиции?
Верный ответ: B
B верно. Цепочка — фиксированный маршрут в коде; динамика — план на лету от модели. C неверно (LLM используется на каждом шаге), D — наоборот, динамика обычно дороже и менее предсказуема.
Зачем ставить программные gate'ы между шагами цепочки?
Верный ответ: B
B верно. Проверка между шагами повышает надёжность: дефект отлавливается рано. Остальные варианты не отражают цель gate.
Когда оправдана динамическая декомпозиция?
Верный ответ: B
B верно. Динамику включают, когда статикой не обойтись. Для фиксированных шагов (C) лучше prompt chaining. «Всегда» (A) игнорирует её цену и риски.